honeybee-openstudio 2.31.8 → 2.31.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cebfc1cf27c7e5d2e9bbfed6ece32096ec1cb0eb2a442783b9a7caeeddd136bc
4
- data.tar.gz: 8960a24e1240a7d5e5db87a09455343afde150294bdb5f3fccc7093a67c2d2cc
3
+ metadata.gz: '0891adec59cdacb1d4087ae318d65b3e2c8040001fa6d69004fe6c411f0f8358'
4
+ data.tar.gz: 8ecb557c5ee160e73b3d2976ebf823848e19d5b89a8213444f597427d72601b9
5
5
  SHA512:
6
- metadata.gz: 8ede21274b85d427693c6ca495ce6e100206dfd7af3fba82044f81309e5af160a61aae97ee476afa6bf4bfa3166ccde32ead3dbcbe7a448b9772c17c4b098311
7
- data.tar.gz: f408bfd525685fc1c1e61a7cdd0aa4d0646c6e34e3a68e565f2876b217d031e14cd47523ea5d58de595679ca7ed272631709706c459f3ce51496597fdff3f64e
6
+ metadata.gz: 784f5baee3c3cbbfbeb3062a7da3d5441255638876a78a54ea5fbf125415360f37d66f940a0af79a24dc439780c2cd3af02bf8149c9fe6f8b75ec18be271b085
7
+ data.tar.gz: af83be8893b0c5ad133b8b136c40bdd019ea86f93782189ea93de3a45e4cd5797dc5071ea61537d0d5067adfdbb1bd59ffafd03ca36b92f8d26a7d68ef57a05c
@@ -15,8 +15,8 @@ jobs:
15
15
  run: |
16
16
  echo $(pwd)
17
17
  echo $(ls)
18
- docker pull nrel/openstudio:3.3.0
19
- docker run --name test --rm -d -t -v $(pwd):/work -w /work nrel/openstudio:3.3.0
18
+ docker pull nrel/openstudio:3.4.0
19
+ docker run --name test --rm -d -t -v $(pwd):/work -w /work nrel/openstudio:3.4.0
20
20
  docker exec -t test pwd
21
21
  docker exec -t test ls
22
22
  docker exec -t test bundle update
@@ -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.8'
7
+ spec.version = '2.31.11'
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
 
@@ -53,8 +53,8 @@ module Honeybee
53
53
  outdoor_shades = outdoor_shades_from_space(space)
54
54
  hash[:outdoor_shades] = outdoor_shades if !outdoor_shades.empty?
55
55
 
56
- multipler = multiplier_from_space(space)
57
- hash[:multipler] = multipler if multipler
56
+ multiplier = multiplier_from_space(space)
57
+ hash[:multiplier] = multiplier if multiplier
58
58
 
59
59
  exclude_floor_area = exclude_floor_area_from_space(space)
60
60
  hash[:exclude_floor_area] = exclude_floor_area
@@ -201,6 +201,17 @@ module Honeybee
201
201
  thermal_zone = space.thermalZone
202
202
  unless thermal_zone.empty?
203
203
  thermal_zone = space.thermalZone.get
204
+ # Create ideal_air_system if present
205
+ unless thermal_zone.equipment.nil?
206
+ thermal_zone.equipment.each do |equipment|
207
+ if equipment.to_ZoneHVACIdealLoadsAirSystem.is_initialized
208
+ ideal_air_hash = Honeybee::IdealAirSystemAbridged.from_hvac(
209
+ equipment.to_ZoneHVACIdealLoadsAirSystem.get)
210
+ $hvacs << ideal_air_hash
211
+ hash[:hvac] = ideal_air_hash[:identifier]
212
+ end
213
+ end
214
+ end
204
215
  unless thermal_zone.thermostatSetpointDualSetpoint.empty?
205
216
  hash[:setpoint] = {}
206
217
  hash[:setpoint][:type] = 'SetpointAbridged'
@@ -0,0 +1,75 @@
1
+ # *******************************************************************************
2
+ # 4ju0 d/zf OpenStudio Gem, Copyright (c) 2020, Alliance for Sustainable
3
+ # Energy, LLC, Ladybug Tools LLC and other contributors. All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # (1) Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ #
11
+ # (2) Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # (3) Neither the name of the copyright holder nor the names of any contributors
16
+ # may be used to endorse or promote products derived from this software without
17
+ # specific prior written permission from the respective party.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS
20
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE
23
+ # UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF
24
+ # THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26
+ # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28
+ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
+ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+ # *******************************************************************************
31
+
32
+ require 'honeybee/hvac/ideal_air'
33
+ require 'to_openstudio/model_object'
34
+
35
+ module Honeybee
36
+ class IdealAirSystemAbridged
37
+
38
+ def self.from_hvac(hvac)
39
+ # create an empty hash
40
+ hash = {}
41
+ hash[:type] = 'IdealAirSystemAbridged'
42
+ hash[:identifier] = clean_name(hvac.nameString)
43
+ unless hvac.displayName.empty?
44
+ hash[:display_name] = (hvac.displayName.get).force_encoding("UTF-8")
45
+ end
46
+ hash[:economizer_type] = hvac.outdoorAirEconomizerType
47
+ if hvac.demandControlledVentilationType.downcase == 'none'
48
+ hash[:demand_controlled_ventilation] = false
49
+ else
50
+ hash[:demand_controlled_ventilation] = true
51
+ end
52
+ hash[:sensible_heat_recovery] = hvac.sensibleHeatRecoveryEffectiveness
53
+ hash[:latent_heat_recovery] = hvac.latentHeatRecoveryEffectiveness
54
+ hash[:heating_air_temperature] = hvac.maximumHeatingSupplyAirTemperature
55
+ hash[:cooling_air_temperature] = hvac.minimumCoolingSupplyAirTemperature
56
+ if hvac.heatingLimit == 'NoLimit'
57
+ hash[:heating_limit] = hvac.heatingLimit
58
+ end
59
+ if hvac.coolingLimit == 'NoLimit'
60
+ hash[:cooling_limit] = hvac.coolingLimit
61
+ end
62
+ unless hvac.heatingAvailabilitySchedule.empty?
63
+ schedule = hvac.heatingAvailabilitySchedule.get
64
+ hash[:heating_availability] = schedule.nameString
65
+ end
66
+ unless hvac.coolingAvailabilitySchedule.empty?
67
+ schedule = hvac.coolingAvailabilitySchedule.get
68
+ hash[:coolingAvailabilitySchedule]
69
+ end
70
+
71
+ hash
72
+ end
73
+
74
+ end #IdealAirSystemAbridged
75
+ end #Honeybee
@@ -61,4 +61,4 @@ module Honeybee
61
61
 
62
62
 
63
63
  end #ElectricEquipmentAbridged
64
- end #Honeybee
64
+ end #Honeybee
@@ -51,6 +51,7 @@ module Honeybee
51
51
  $opaque_constructions = {}
52
52
  $window_constructions = {}
53
53
  $shade_constructions = {}
54
+ $hvacs = []
54
55
 
55
56
  hash[:properties] = properties_from_model(openstudio_model)
56
57
 
@@ -126,6 +127,7 @@ module Honeybee
126
127
  hash[:schedule_type_limits] = schedtypelimits_from_model(openstudio_model)
127
128
  hash[:schedules] = schedules_from_model(openstudio_model)
128
129
  hash[:program_types] = programtype_from_model(openstudio_model)
130
+ hash[:hvacs] = $hvacs
129
131
 
130
132
  hash
131
133
  end
@@ -81,6 +81,15 @@ module Honeybee
81
81
  hash[:day_schedules] << ScheduleRulesetAbridged.from_day_schedule(schedule_day)
82
82
  end
83
83
 
84
+ # remove the bogus default day schedule that OpenStudio adds upon import from IDF
85
+ if hash[:default_day_schedule].start_with?('Schedule Day ')
86
+ if hash[:day_schedules][0][:values] == [0] && hash[:schedule_rules].length() > 0
87
+ hash[:default_day_schedule] = hash[:schedule_rules][0][:schedule_day]
88
+ hash[:schedule_rules].pop(0)
89
+ hash[:day_schedules].pop(0)
90
+ end
91
+ end
92
+
84
93
  # assing any schedule type limits if they exist
85
94
  unless schedule_ruleset.scheduleTypeLimits.empty?
86
95
  typ_lim = schedule_ruleset.scheduleTypeLimits.get
@@ -44,6 +44,9 @@ require 'from_openstudio/geometry/face'
44
44
  require 'from_openstudio/geometry/room'
45
45
  require 'from_openstudio/geometry/shade'
46
46
 
47
+ # extend the hvac objects
48
+ require 'from_openstudio/hvac/ideal_air'
49
+
47
50
  # extend the construction objects
48
51
  require 'from_openstudio/construction/opaque'
49
52
  require 'from_openstudio/construction/window'
@@ -118,7 +118,7 @@ module Honeybee
118
118
  end
119
119
 
120
120
  # assign the construction if it exists
121
- if @hash[:properties][:energy][:construction]
121
+ if @hash[:properties].key?(:energy) && @hash[:properties][:energy][:construction]
122
122
  construction_identifier = @hash[:properties][:energy][:construction]
123
123
  construction = openstudio_model.getConstructionByName(construction_identifier)
124
124
  if !construction.empty?
@@ -182,7 +182,7 @@ module Honeybee
182
182
 
183
183
  # get the approriate construction id
184
184
  construction_id = nil
185
- if @hash[:properties][:energy][:construction]
185
+ if @hash[:properties].key?(:energy) && @hash[:properties][:energy][:construction]
186
186
  construction_id = @hash[:properties][:energy][:construction]
187
187
  else
188
188
  construction_id = 'Generic Double Pane'
@@ -118,7 +118,7 @@ module Honeybee
118
118
  end
119
119
 
120
120
  # assign the construction if it exists
121
- if @hash[:properties][:energy][:construction]
121
+ if @hash[:properties].key?(:energy) && @hash[:properties][:energy][:construction]
122
122
  construction_identifier = @hash[:properties][:energy][:construction]
123
123
  construction = openstudio_model.getConstructionByName(construction_identifier)
124
124
  if !construction.empty?
@@ -176,7 +176,7 @@ module Honeybee
176
176
 
177
177
  # get the approriate construction id
178
178
  construction_id = nil
179
- if @hash[:properties][:energy][:construction]
179
+ if @hash[:properties].key?(:energy) && @hash[:properties][:energy][:construction]
180
180
  construction_id = @hash[:properties][:energy][:construction]
181
181
  elsif @hash[:is_glass] == true
182
182
  construction_id = 'Generic Double Pane'
@@ -64,39 +64,41 @@ module Honeybee
64
64
  end
65
65
  os_surface.setSurfaceType(@hash[:face_type])
66
66
 
67
- # assign the construction if it is present
68
- if @hash[:properties][:energy][:construction]
69
- construction_identifier = @hash[:properties][:energy][:construction]
70
- construction = openstudio_model.getConstructionByName(construction_identifier)
71
- unless construction.empty?
72
- os_construction = construction.get
73
- os_surface.setConstruction(os_construction)
67
+ if @hash[:properties].key?(:energy)
68
+ # assign the construction if it is present
69
+ if @hash[:properties][:energy][:construction]
70
+ construction_identifier = @hash[:properties][:energy][:construction]
71
+ construction = openstudio_model.getConstructionByName(construction_identifier)
72
+ unless construction.empty?
73
+ os_construction = construction.get
74
+ os_surface.setConstruction(os_construction)
75
+ end
74
76
  end
75
- end
76
-
77
- # assign the AFN crack if it's specified and we are not using simple infiltration
78
- if !$use_simple_vent && @hash[:properties][:energy][:vent_crack]
79
- unless $interior_afn_srf_hash[@hash[:identifier]] # interior crack that's been accounted for
80
- vent_crack = @hash[:properties][:energy][:vent_crack]
81
- # create the crack object for using default values
82
- flow_exponent = crack_defaults[:flow_exponent][:default].to_f
83
- os_crack = OpenStudio::Model::AirflowNetworkCrack.new(
84
- openstudio_model, vent_crack[:flow_coefficient], flow_exponent,
85
- $afn_reference_crack)
86
77
 
87
- # assign the flow exponent if it's specified
88
- if vent_crack[:flow_exponent]
89
- os_crack.setAirMassFlowExponent(vent_crack[:flow_exponent])
90
- end
78
+ # assign the AFN crack if it's specified and we are not using simple infiltration
79
+ if !$use_simple_vent && @hash[:properties][:energy][:vent_crack]
80
+ unless $interior_afn_srf_hash[@hash[:identifier]] # interior crack that's been accounted for
81
+ vent_crack = @hash[:properties][:energy][:vent_crack]
82
+ # create the crack object for using default values
83
+ flow_exponent = crack_defaults[:flow_exponent][:default].to_f
84
+ os_crack = OpenStudio::Model::AirflowNetworkCrack.new(
85
+ openstudio_model, vent_crack[:flow_coefficient], flow_exponent,
86
+ $afn_reference_crack)
87
+
88
+ # assign the flow exponent if it's specified
89
+ if vent_crack[:flow_exponent]
90
+ os_crack.setAirMassFlowExponent(vent_crack[:flow_exponent])
91
+ end
91
92
 
92
- # if it's a Surface boundary condition ensure the neighbor is not written as a duplicate
93
- if @hash[:boundary_condition][:type] == 'Surface'
94
- $interior_afn_srf_hash[@hash[:boundary_condition][:boundary_condition_objects][0]] = true
95
- end
93
+ # if it's a Surface boundary condition ensure the neighbor is not written as a duplicate
94
+ if @hash[:boundary_condition][:type] == 'Surface'
95
+ $interior_afn_srf_hash[@hash[:boundary_condition][:boundary_condition_objects][0]] = true
96
+ end
96
97
 
97
- # create the AirflowNetworkSurface
98
- os_afn_srf = os_surface.getAirflowNetworkSurface(os_crack)
98
+ # create the AirflowNetworkSurface
99
+ os_afn_srf = os_surface.getAirflowNetworkSurface(os_crack)
99
100
 
101
+ end
100
102
  end
101
103
  end
102
104
 
@@ -206,7 +208,7 @@ module Honeybee
206
208
 
207
209
  # get the approriate construction id
208
210
  construction_id = nil
209
- if @hash[:properties][:energy][:construction]
211
+ if @hash[:properties].key?(:energy) && @hash[:properties][:energy][:construction]
210
212
  construction_id = @hash[:properties][:energy][:construction]
211
213
  elsif @hash[:face_type] == 'Wall'
212
214
  construction_id = 'Generic Exterior Wall'
@@ -84,26 +84,6 @@ module Honeybee
84
84
  os_thermal_zone.setDisplayName(@hash[:display_name])
85
85
  end
86
86
 
87
- # assign the programtype
88
- if @hash[:properties][:energy][:program_type]
89
- space_type = openstudio_model.getSpaceTypeByName(@hash[:properties][:energy][:program_type])
90
- unless space_type.empty?
91
- space_type_object = space_type.get
92
- os_space.setSpaceType(space_type_object)
93
- end
94
- end
95
-
96
- # assign the constructionset
97
- if @hash[:properties][:energy][:construction_set]
98
- construction_set_identifier = @hash[:properties][:energy][:construction_set]
99
- # gets default construction set assigned to room from openstudio_model
100
- construction_set = openstudio_model.getDefaultConstructionSetByName(construction_set_identifier)
101
- unless construction_set.empty?
102
- default_construction_set = construction_set.get
103
- os_space.setDefaultConstructionSet(default_construction_set)
104
- end
105
- end
106
-
107
87
  # assign the multiplier
108
88
  if @hash[:multiplier] and @hash[:multiplier] != 1
109
89
  os_thermal_zone.setMultiplier(@hash[:multiplier])
@@ -142,6 +122,28 @@ module Honeybee
142
122
  end
143
123
  os_space.setBuildingStory(story)
144
124
 
125
+ if @hash[:properties].key?(:energy)
126
+ # assign the programtype
127
+ if @hash[:properties][:energy][:program_type]
128
+ space_type = openstudio_model.getSpaceTypeByName(@hash[:properties][:energy][:program_type])
129
+ unless space_type.empty?
130
+ space_type_object = space_type.get
131
+ os_space.setSpaceType(space_type_object)
132
+ end
133
+ end
134
+
135
+ # assign the constructionset
136
+ if @hash[:properties][:energy][:construction_set]
137
+ construction_set_identifier = @hash[:properties][:energy][:construction_set]
138
+ # gets default construction set assigned to room from openstudio_model
139
+ construction_set = openstudio_model.getDefaultConstructionSetByName(construction_set_identifier)
140
+ unless construction_set.empty?
141
+ default_construction_set = construction_set.get
142
+ os_space.setDefaultConstructionSet(default_construction_set)
143
+ end
144
+ end
145
+ end
146
+
145
147
  # keep track of all window ventilation objects
146
148
  window_vent = {}
147
149
 
@@ -162,9 +164,11 @@ module Honeybee
162
164
  # assign aperture-level shades if they exist
163
165
  if face[:apertures]
164
166
  face[:apertures].each do |aperture|
165
- if aperture[:properties][:energy][:vent_opening]
166
- window_vent[aperture[:identifier]] = \
167
- [aperture[:properties][:energy][:vent_opening], aperture[:boundary_condition][:type]]
167
+ if aperture[:properties].key?(:energy)
168
+ if aperture[:properties][:energy][:vent_opening]
169
+ window_vent[aperture[:identifier]] = \
170
+ [aperture[:properties][:energy][:vent_opening], aperture[:boundary_condition][:type]]
171
+ end
168
172
  end
169
173
  if aperture[:outdoor_shades]
170
174
  unless os_shd_group
@@ -180,9 +184,11 @@ module Honeybee
180
184
  # assign door-level shades if they exist
181
185
  if face[:doors]
182
186
  face[:doors].each do |door|
183
- if door[:properties][:energy][:vent_opening]
184
- window_vent[door[:identifier]] = \
185
- [door[:properties][:energy][:vent_opening], door[:boundary_condition][:type]]
187
+ if door[:properties].key?(:energy)
188
+ if door[:properties][:energy][:vent_opening]
189
+ window_vent[door[:identifier]] = \
190
+ [door[:properties][:energy][:vent_opening], door[:boundary_condition][:type]]
191
+ end
186
192
  end
187
193
  if door[:outdoor_shades]
188
194
  unless os_shd_group
@@ -196,7 +202,7 @@ module Honeybee
196
202
  end
197
203
 
198
204
  # assign interior constructions for adiabatic Faces
199
- if !face[:properties][:energy][:construction]
205
+ if face[:properties].key?(:energy) && !face[:properties][:energy][:construction]
200
206
  if face[:boundary_condition][:type] == 'Adiabatic'
201
207
  # assign default interior construction for Adiabatic Faces
202
208
  if face[:face_type] != 'Wall'
@@ -212,7 +218,7 @@ module Honeybee
212
218
  if face[:face_type] == 'AirBoundary'
213
219
  # assign default air boundary construction for AirBoundary face types
214
220
  air_construction = closest_air_construction(openstudio_model, os_space)
215
- if !face[:properties][:energy][:construction]
221
+ if face[:properties].key?(:energy) && !face[:properties][:energy][:construction]
216
222
  unless air_construction.nil?
217
223
  os_surface.setConstruction(air_construction)
218
224
  end
@@ -256,164 +262,166 @@ module Honeybee
256
262
  end
257
263
 
258
264
  #check whether there are any load objects on the room overriding the programtype
259
- if @hash[:properties][:energy][:people]
260
- unique_program = get_unique_space_type(openstudio_model, os_space)
261
- unique_program_ppl = unique_program.people
262
- unless unique_program_ppl.empty? # remove the previous load definition
263
- unique_program_ppl[0].remove()
265
+ if @hash[:properties].key?(:energy)
266
+ if @hash[:properties][:energy][:people]
267
+ unique_program = get_unique_space_type(openstudio_model, os_space)
268
+ unique_program_ppl = unique_program.people
269
+ unless unique_program_ppl.empty? # remove the previous load definition
270
+ unique_program_ppl[0].remove()
271
+ end
272
+ custom_people = PeopleAbridged.new(@hash[:properties][:energy][:people])
273
+ os_custom_people = custom_people.to_openstudio(openstudio_model)
274
+ os_custom_people.setSpaceType(unique_program) # assign the new load definition
264
275
  end
265
- custom_people = PeopleAbridged.new(@hash[:properties][:energy][:people])
266
- os_custom_people = custom_people.to_openstudio(openstudio_model)
267
- os_custom_people.setSpaceType(unique_program) # assign the new load definition
268
- end
269
276
 
270
- # assign lighting if it exists
271
- if @hash[:properties][:energy][:lighting]
272
- unique_program = get_unique_space_type(openstudio_model, os_space)
273
- unique_program_lght = unique_program.lights
274
- unless unique_program_lght.empty? # remove the previous load definition
275
- unique_program_lght[0].remove()
277
+ # assign lighting if it exists
278
+ if @hash[:properties][:energy][:lighting]
279
+ unique_program = get_unique_space_type(openstudio_model, os_space)
280
+ unique_program_lght = unique_program.lights
281
+ unless unique_program_lght.empty? # remove the previous load definition
282
+ unique_program_lght[0].remove()
283
+ end
284
+ custom_lighting = LightingAbridged.new(@hash[:properties][:energy][:lighting])
285
+ os_custom_lighting = custom_lighting.to_openstudio(openstudio_model)
286
+ os_custom_lighting.setSpaceType(unique_program) # assign the new load definition
276
287
  end
277
- custom_lighting = LightingAbridged.new(@hash[:properties][:energy][:lighting])
278
- os_custom_lighting = custom_lighting.to_openstudio(openstudio_model)
279
- os_custom_lighting.setSpaceType(unique_program) # assign the new load definition
280
- end
281
288
 
282
- # assign electric equipment if it exists
283
- if @hash[:properties][:energy][:electric_equipment]
284
- unique_program = get_unique_space_type(openstudio_model, os_space)
285
- unique_program_ele = unique_program.electricEquipment
286
- unless unique_program_ele.empty? # remove the previous load definition
287
- unique_program_ele[0].remove()
289
+ # assign electric equipment if it exists
290
+ if @hash[:properties][:energy][:electric_equipment]
291
+ unique_program = get_unique_space_type(openstudio_model, os_space)
292
+ unique_program_ele = unique_program.electricEquipment
293
+ unless unique_program_ele.empty? # remove the previous load definition
294
+ unique_program_ele[0].remove()
295
+ end
296
+ custom_electric_equipment = ElectricEquipmentAbridged.new(@hash[:properties][:energy][:electric_equipment])
297
+ os_custom_electric_equipment = custom_electric_equipment.to_openstudio(openstudio_model)
298
+ os_custom_electric_equipment.setSpaceType(unique_program) # assign the new load definition
288
299
  end
289
- custom_electric_equipment = ElectricEquipmentAbridged.new(@hash[:properties][:energy][:electric_equipment])
290
- os_custom_electric_equipment = custom_electric_equipment.to_openstudio(openstudio_model)
291
- os_custom_electric_equipment.setSpaceType(unique_program) # assign the new load definition
292
- end
293
300
 
294
- # assign gas equipment if it exists
295
- if @hash[:properties][:energy][:gas_equipment]
296
- unique_program = get_unique_space_type(openstudio_model, os_space)
297
- unique_program_gas = unique_program.gasEquipment
298
- unless unique_program_gas.empty? # remove the previous load definition
299
- unique_program_gas[0].remove()
301
+ # assign gas equipment if it exists
302
+ if @hash[:properties][:energy][:gas_equipment]
303
+ unique_program = get_unique_space_type(openstudio_model, os_space)
304
+ unique_program_gas = unique_program.gasEquipment
305
+ unless unique_program_gas.empty? # remove the previous load definition
306
+ unique_program_gas[0].remove()
307
+ end
308
+ custom_gas_equipment = GasEquipmentAbridged.new(@hash[:properties][:energy][:gas_equipment])
309
+ os_custom_gas_equipment = custom_gas_equipment.to_openstudio(openstudio_model)
310
+ os_custom_gas_equipment.setSpaceType(unique_program) # assign the new load definition
300
311
  end
301
- custom_gas_equipment = GasEquipmentAbridged.new(@hash[:properties][:energy][:gas_equipment])
302
- os_custom_gas_equipment = custom_gas_equipment.to_openstudio(openstudio_model)
303
- os_custom_gas_equipment.setSpaceType(unique_program) # assign the new load definition
304
- end
305
312
 
306
- # assign service hot water if it exists
307
- if @hash[:properties][:energy][:service_hot_water]
308
- shw_space = ServiceHotWaterAbridged.new(@hash[:properties][:energy][:service_hot_water])
309
- os_shw_space = shw_space.to_openstudio(
310
- openstudio_model, os_space, @hash[:properties][:energy][:shw])
311
- $shw_for_plant = shw_space
312
- end
313
+ # assign service hot water if it exists
314
+ if @hash[:properties][:energy][:service_hot_water]
315
+ shw_space = ServiceHotWaterAbridged.new(@hash[:properties][:energy][:service_hot_water])
316
+ os_shw_space = shw_space.to_openstudio(
317
+ openstudio_model, os_space, @hash[:properties][:energy][:shw])
318
+ $shw_for_plant = shw_space
319
+ end
313
320
 
314
- # assign infiltration if it exists
315
- if @hash[:properties][:energy][:infiltration] && $use_simple_vent # only use infiltration with simple ventilation
316
- unique_program = get_unique_space_type(openstudio_model, os_space)
317
- unique_program_inf = unique_program.spaceInfiltrationDesignFlowRates
318
- unless unique_program_inf.empty? # remove the previous load definition
319
- unique_program_inf[0].remove()
321
+ # assign infiltration if it exists
322
+ if @hash[:properties][:energy][:infiltration] && $use_simple_vent # only use infiltration with simple ventilation
323
+ unique_program = get_unique_space_type(openstudio_model, os_space)
324
+ unique_program_inf = unique_program.spaceInfiltrationDesignFlowRates
325
+ unless unique_program_inf.empty? # remove the previous load definition
326
+ unique_program_inf[0].remove()
327
+ end
328
+ custom_infiltration = InfiltrationAbridged.new(@hash[:properties][:energy][:infiltration])
329
+ os_custom_infiltration = custom_infiltration.to_openstudio(openstudio_model)
330
+ os_custom_infiltration.setSpaceType(unique_program) # assign the new load definition
320
331
  end
321
- custom_infiltration = InfiltrationAbridged.new(@hash[:properties][:energy][:infiltration])
322
- os_custom_infiltration = custom_infiltration.to_openstudio(openstudio_model)
323
- os_custom_infiltration.setSpaceType(unique_program) # assign the new load definition
324
- end
325
332
 
326
- # assign ventilation if it exists
327
- if @hash[:properties][:energy][:ventilation]
328
- unique_program = get_unique_space_type(openstudio_model, os_space)
329
- unique_program.resetDesignSpecificationOutdoorAir()
330
- custom_ventilation = VentilationAbridged.new(@hash[:properties][:energy][:ventilation])
331
- os_custom_ventilation = custom_ventilation.to_openstudio(openstudio_model)
332
- unique_program.setDesignSpecificationOutdoorAir(os_custom_ventilation)
333
- end
333
+ # assign ventilation if it exists
334
+ if @hash[:properties][:energy][:ventilation]
335
+ unique_program = get_unique_space_type(openstudio_model, os_space)
336
+ unique_program.resetDesignSpecificationOutdoorAir()
337
+ custom_ventilation = VentilationAbridged.new(@hash[:properties][:energy][:ventilation])
338
+ os_custom_ventilation = custom_ventilation.to_openstudio(openstudio_model)
339
+ unique_program.setDesignSpecificationOutdoorAir(os_custom_ventilation)
340
+ end
334
341
 
335
- # assign setpoint if it exists
336
- if @hash[:properties][:energy][:setpoint]
337
- # thermostat object is created because heating and cooling schedule are required
338
- setpoint_thermostat_space = SetpointThermostat.new(@hash[:properties][:energy][:setpoint])
339
- os_setpoint_thermostat_space = setpoint_thermostat_space.to_openstudio(openstudio_model)
340
- #set thermostat to thermal zone
341
- os_thermal_zone.setThermostatSetpointDualSetpoint(os_setpoint_thermostat_space)
342
- # humidistat object is created if humidifying or dehumidifying schedule is specified
343
- if @hash[:properties][:energy][:setpoint][:humidifying_schedule] or @hash[:properties][:energy][:setpoint][:dehumidifying_schedule]
344
- setpoint_humidistat_space = SetpointHumidistat.new(@hash[:properties][:energy][:setpoint])
345
- os_setpoint_humidistat_space = setpoint_humidistat_space.to_openstudio(openstudio_model)
346
- os_thermal_zone.setZoneControlHumidistat(os_setpoint_humidistat_space)
342
+ # assign setpoint if it exists
343
+ if @hash[:properties][:energy][:setpoint]
344
+ # thermostat object is created because heating and cooling schedule are required
345
+ setpoint_thermostat_space = SetpointThermostat.new(@hash[:properties][:energy][:setpoint])
346
+ os_setpoint_thermostat_space = setpoint_thermostat_space.to_openstudio(openstudio_model)
347
+ #set thermostat to thermal zone
348
+ os_thermal_zone.setThermostatSetpointDualSetpoint(os_setpoint_thermostat_space)
349
+ # humidistat object is created if humidifying or dehumidifying schedule is specified
350
+ if @hash[:properties][:energy][:setpoint][:humidifying_schedule] or @hash[:properties][:energy][:setpoint][:dehumidifying_schedule]
351
+ setpoint_humidistat_space = SetpointHumidistat.new(@hash[:properties][:energy][:setpoint])
352
+ os_setpoint_humidistat_space = setpoint_humidistat_space.to_openstudio(openstudio_model)
353
+ os_thermal_zone.setZoneControlHumidistat(os_setpoint_humidistat_space)
354
+ end
347
355
  end
348
- end
349
356
 
350
- # assign daylight control if it exists
351
- if @hash[:properties][:energy][:daylighting_control]
352
- dl_control = DaylightingControl.new(@hash[:properties][:energy][:daylighting_control])
353
- os_dl_control = dl_control.to_openstudio(openstudio_model, os_thermal_zone, os_space)
354
- end
357
+ # assign daylight control if it exists
358
+ if @hash[:properties][:energy][:daylighting_control]
359
+ dl_control = DaylightingControl.new(@hash[:properties][:energy][:daylighting_control])
360
+ os_dl_control = dl_control.to_openstudio(openstudio_model, os_thermal_zone, os_space)
361
+ end
355
362
 
356
- # assign window ventilation objects if they exist
357
- if $use_simple_vent && !window_vent.empty? # write simple WindAndStack ventilation
358
- window_vent.each do |sub_f_id, open_prop|
359
- opening = open_prop[0]
360
- bc = open_prop[1]
361
- if bc == 'Outdoors'
363
+ # assign window ventilation objects if they exist
364
+ if $use_simple_vent && !window_vent.empty? # write simple WindAndStack ventilation
365
+ window_vent.each do |sub_f_id, open_prop|
366
+ opening = open_prop[0]
367
+ bc = open_prop[1]
368
+ if bc == 'Outdoors'
369
+ opt_sub_f = openstudio_model.getSubSurfaceByName(sub_f_id)
370
+ unless opt_sub_f.empty?
371
+ sub_f = opt_sub_f.get
372
+ vent_open = VentilationOpening.new(opening)
373
+ os_vent_open = vent_open.to_openstudio(
374
+ openstudio_model, sub_f, @hash[:properties][:energy][:window_vent_control])
375
+ os_vent_open.addToThermalZone(os_thermal_zone)
376
+ end
377
+ end
378
+ end
379
+ elsif !$use_simple_vent # we're using the AFN!
380
+ # write an AirflowNetworkZone object in for the Room
381
+ os_afn_room_node = os_thermal_zone.getAirflowNetworkZone
382
+ os_afn_room_node.setVentilationControlMode('NoVent')
383
+ # write the opening objects for each Aperture / Door
384
+ operable_subfs = [] # collect the sub-face objects for the EMS
385
+ opening_factors = [] # collect the maximum opening factors for the EMS
386
+ window_vent.each do |sub_f_id, open_prop|
387
+ opening = open_prop[0]
362
388
  opt_sub_f = openstudio_model.getSubSurfaceByName(sub_f_id)
363
389
  unless opt_sub_f.empty?
364
390
  sub_f = opt_sub_f.get
365
- vent_open = VentilationOpening.new(opening)
366
- os_vent_open = vent_open.to_openstudio(
367
- openstudio_model, sub_f, @hash[:properties][:energy][:window_vent_control])
368
- os_vent_open.addToThermalZone(os_thermal_zone)
369
- end
370
- end
371
- end
372
- elsif !$use_simple_vent # we're using the AFN!
373
- # write an AirflowNetworkZone object in for the Room
374
- os_afn_room_node = os_thermal_zone.getAirflowNetworkZone
375
- os_afn_room_node.setVentilationControlMode('NoVent')
376
- # write the opening objects for each Aperture / Door
377
- operable_subfs = [] # collect the sub-face objects for the EMS
378
- opening_factors = [] # collect the maximum opening factors for the EMS
379
- window_vent.each do |sub_f_id, open_prop|
380
- opening = open_prop[0]
381
- opt_sub_f = openstudio_model.getSubSurfaceByName(sub_f_id)
382
- unless opt_sub_f.empty?
383
- sub_f = opt_sub_f.get
384
- if sub_f.adjacentSubSurface.empty? # not an interior window that's already in the AFN
385
- vent_open = VentilationOpening.new(opening)
386
- open_fac = vent_open.to_openstudio_afn(openstudio_model, sub_f)
387
- unless open_fac.nil? # nil is used for horizontal exterior skylights
388
- operable_subfs << sub_f
389
- opening_factors << open_fac
391
+ if sub_f.adjacentSubSurface.empty? # not an interior window that's already in the AFN
392
+ vent_open = VentilationOpening.new(opening)
393
+ open_fac = vent_open.to_openstudio_afn(openstudio_model, sub_f)
394
+ unless open_fac.nil? # nil is used for horizontal exterior skylights
395
+ operable_subfs << sub_f
396
+ opening_factors << open_fac
397
+ end
390
398
  end
391
399
  end
392
400
  end
401
+ # add the control startegy of the ventilation openings using the EMS
402
+ if @hash[:properties][:energy][:window_vent_control]
403
+ vent_control = VentilationControlAbridged.new(@hash[:properties][:energy][:window_vent_control])
404
+ vent_control.to_openstudio(
405
+ openstudio_model, os_thermal_zone, operable_subfs, opening_factors)
406
+ end
393
407
  end
394
- # add the control startegy of the ventilation openings using the EMS
395
- if @hash[:properties][:energy][:window_vent_control]
396
- vent_control = VentilationControlAbridged.new(@hash[:properties][:energy][:window_vent_control])
397
- vent_control.to_openstudio(
398
- openstudio_model, os_thermal_zone, operable_subfs, opening_factors)
399
- end
400
- end
401
408
 
402
- # assign any internal masses if specified
403
- if @hash[:properties][:energy][:internal_masses]
404
- @hash[:properties][:energy][:internal_masses].each do |int_mass|
405
- hb_int_mass = InternalMassAbridged.new(int_mass)
406
- os_int_mass = hb_int_mass.to_openstudio(openstudio_model, os_space)
407
- os_int_mass.setSpace(os_space)
409
+ # assign any internal masses if specified
410
+ if @hash[:properties][:energy][:internal_masses]
411
+ @hash[:properties][:energy][:internal_masses].each do |int_mass|
412
+ hb_int_mass = InternalMassAbridged.new(int_mass)
413
+ os_int_mass = hb_int_mass.to_openstudio(openstudio_model, os_space)
414
+ os_int_mass.setSpace(os_space)
415
+ end
408
416
  end
409
- end
410
417
 
411
- # assign any process loads if specified
412
- if @hash[:properties][:energy][:process_loads]
413
- @hash[:properties][:energy][:process_loads].each do |p_load|
414
- hb_p_load = ProcessAbridged.new(p_load)
415
- os_p_load = hb_p_load.to_openstudio(openstudio_model)
416
- os_p_load.setSpace(os_space)
418
+ # assign any process loads if specified
419
+ if @hash[:properties][:energy][:process_loads]
420
+ @hash[:properties][:energy][:process_loads].each do |p_load|
421
+ hb_p_load = ProcessAbridged.new(p_load)
422
+ os_p_load = hb_p_load.to_openstudio(openstudio_model)
423
+ os_p_load.setSpace(os_space)
424
+ end
417
425
  end
418
426
  end
419
427
 
@@ -61,23 +61,26 @@ module Honeybee
61
61
  unless @hash[:display_name].nil?
62
62
  os_shading_surface.setDisplayName(@hash[:display_name])
63
63
  end
64
- # assign the construction if it exists
65
- if @hash[:properties][:energy][:construction]
66
- construction_identifier = @hash[:properties][:energy][:construction]
67
- construction = openstudio_model.getConstructionByName(construction_identifier)
68
- unless construction.empty?
69
- os_construction = construction.get
70
- os_shading_surface.setConstruction(os_construction)
64
+
65
+ if @hash[:properties].key?(:energy)
66
+ # assign the construction if it exists
67
+ if @hash[:properties][:energy][:construction]
68
+ construction_identifier = @hash[:properties][:energy][:construction]
69
+ construction = openstudio_model.getConstructionByName(construction_identifier)
70
+ unless construction.empty?
71
+ os_construction = construction.get
72
+ os_shading_surface.setConstruction(os_construction)
73
+ end
71
74
  end
72
- end
73
75
 
74
- # assign the transmittance schedule if it exists
75
- if @hash[:properties][:energy][:transmittance_schedule]
76
- schedule_identifier = @hash[:properties][:energy][:transmittance_schedule]
77
- schedule = openstudio_model.getScheduleByName(schedule_identifier)
78
- unless schedule.empty?
79
- os_schedule = schedule.get
80
- os_shading_surface.setTransmittanceSchedule(os_schedule)
76
+ # assign the transmittance schedule if it exists
77
+ if @hash[:properties][:energy][:transmittance_schedule]
78
+ schedule_identifier = @hash[:properties][:energy][:transmittance_schedule]
79
+ schedule = openstudio_model.getScheduleByName(schedule_identifier)
80
+ unless schedule.empty?
81
+ os_schedule = schedule.get
82
+ os_shading_surface.setTransmittanceSchedule(os_schedule)
83
+ end
81
84
  end
82
85
  end
83
86
 
@@ -150,7 +150,7 @@ class OpenStudio::Model::Model
150
150
  if radiant_type == 'floorwithcarpet'
151
151
  radiant_type = 'floor'
152
152
  include_carpet = true
153
- elsif radiant_type == 'ceilingmetalpanel'
153
+ elsif radiant_type == 'ceilingmetalpanel' || radiant_type == 'floorwithhardwood'
154
154
  control_strategy = 'default'
155
155
  end
156
156
  else
@@ -251,6 +251,7 @@ class OpenStudio::Model::Model
251
251
  end
252
252
  end
253
253
  end
254
+
254
255
  # if no values were set, just set the system to be on all of the time
255
256
  if start_hour == 12 or start_hour == 0
256
257
  start_hour = 1
@@ -282,15 +283,30 @@ class OpenStudio::Model::Model
282
283
  OpenStudio.logFree(OpenStudio::Warn, 'openstudio.Model.Model', "Replacing constructions with new radiant slab constructions.")
283
284
 
284
285
  # create materials
286
+ # concrete slab materials
285
287
  mat_concrete_3_5in = OpenStudio::Model::StandardOpaqueMaterial.new(self, 'MediumRough', 0.0889, 2.31, 2322, 832)
286
288
  mat_concrete_3_5in.setName('Radiant Slab Concrete - 3.5 in.')
287
289
  mat_concrete_1_5in = OpenStudio::Model::StandardOpaqueMaterial.new(self, 'MediumRough', 0.0381, 2.31, 2322, 832)
288
290
  mat_concrete_1_5in.setName('Radiant Slab Concrete - 1.5 in')
289
291
 
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')
292
+ metal_mat = nil
293
+ air_gap_mat = nil
294
+ wood_mat = nil
295
+ wood_floor_insulation = nil
296
+ gypsum_ceiling_mat = nil
297
+ if radiant_type == 'ceilingmetalpanel'
298
+ metal_mat = OpenStudio::Model::StandardOpaqueMaterial.new(self, 'MediumSmooth', 0.003175, 30, 7680, 418)
299
+ metal_mat.setName('Radiant Metal Layer - 0.125 in')
300
+ air_gap_mat = OpenStudio::Model::MasslessOpaqueMaterial.new(self, 'Smooth', 0.004572)
301
+ air_gap_mat.setName('Generic Ceiling Air Gap - R 0.025')
302
+ elsif radiant_type == 'floorwithhardwood'
303
+ wood_mat = OpenStudio::Model::StandardOpaqueMaterial.new(self, 'MediumSmooth', 0.01905, 0.15, 608, 1629)
304
+ wood_mat.setName('Radiant Hardwood Flooring - 0.75 in')
305
+ wood_floor_insulation = OpenStudio::Model::StandardOpaqueMaterial.new(self, 'Rough', 0.0508, 0.02, 56.06, 1210)
306
+ wood_floor_insulation.setName('Radiant Subfloor Insulation - 4.0 in')
307
+ gypsum_ceiling_mat = OpenStudio::Model::StandardOpaqueMaterial.new(self, 'Smooth', 0.0127, 0.16, 800, 1089)
308
+ gypsum_ceiling_mat.setName('Gypsum Ceiling for Radiant Hardwood Flooring - 0.5 in')
309
+ end
294
310
 
295
311
  mat_refl_roof_membrane = self.getStandardOpaqueMaterialByName('Roof Membrane - Highly Reflective')
296
312
  if mat_refl_roof_membrane.is_initialized
@@ -331,83 +347,125 @@ class OpenStudio::Model::Model
331
347
  # create radiant internal source constructions
332
348
  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
349
 
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
350
+ radiant_ground_slab_construction = nil
351
+ radiant_exterior_slab_construction = nil
352
+ radiant_interior_floor_slab_construction = nil
353
+ radiant_interior_ceiling_slab_construction = nil
354
+ radiant_ceiling_slab_construction = nil
355
+ radiant_interior_ceiling_metal_construction = nil
356
+ radiant_ceiling_metal_construction = nil
357
+
358
+ if radiant_type == 'floor'
359
+ layers = []
360
+ layers << mat_slab_insulation
361
+ layers << mat_concrete_3_5in
362
+ layers << mat_concrete_1_5in
363
+ layers << mat_thin_carpet_tile if include_carpet
364
+ radiant_ground_slab_construction = OpenStudio::Model::ConstructionWithInternalSource.new(layers)
365
+ radiant_ground_slab_construction.setName('Radiant Ground Slab Construction')
366
+ radiant_ground_slab_construction.setSourcePresentAfterLayerNumber(2)
367
+ radiant_ground_slab_construction.setTemperatureCalculationRequestedAfterLayerNumber(3)
368
+ radiant_ground_slab_construction.setTubeSpacing(0.2286) # 9 inches
369
+
370
+ layers = []
371
+ layers << mat_ext_insulation
372
+ layers << mat_concrete_3_5in
373
+ layers << mat_concrete_1_5in
374
+ layers << mat_thin_carpet_tile if include_carpet
375
+ radiant_exterior_slab_construction = OpenStudio::Model::ConstructionWithInternalSource.new(layers)
376
+ radiant_exterior_slab_construction.setName('Radiant Exterior Slab Construction')
377
+ radiant_exterior_slab_construction.setSourcePresentAfterLayerNumber(2)
378
+ radiant_exterior_slab_construction.setTemperatureCalculationRequestedAfterLayerNumber(3)
379
+ radiant_exterior_slab_construction.setTubeSpacing(0.2286) # 9 inches
380
+
381
+ layers = []
382
+ layers << mat_concrete_3_5in
383
+ layers << mat_concrete_1_5in
384
+ layers << mat_thin_carpet_tile if include_carpet
385
+ radiant_interior_floor_slab_construction = OpenStudio::Model::ConstructionWithInternalSource.new(layers)
386
+ radiant_interior_floor_slab_construction.setName('Radiant Interior Floor Slab Construction')
387
+ radiant_interior_floor_slab_construction.setSourcePresentAfterLayerNumber(1)
388
+ radiant_interior_floor_slab_construction.setTemperatureCalculationRequestedAfterLayerNumber(2)
389
+ radiant_interior_floor_slab_construction.setTubeSpacing(0.2286) # 9 inches
390
+ elsif radiant_type == 'ceiling'
391
+ layers = []
392
+ layers << mat_thin_carpet_tile if include_carpet
393
+ layers << mat_concrete_3_5in
394
+ layers << mat_concrete_1_5in
395
+ radiant_interior_ceiling_slab_construction = OpenStudio::Model::ConstructionWithInternalSource.new(layers)
396
+ radiant_interior_ceiling_slab_construction.setName('Radiant Interior Ceiling Slab Construction')
397
+ slab_src_loc = include_carpet ? 2 : 1
398
+ radiant_interior_ceiling_slab_construction.setSourcePresentAfterLayerNumber(slab_src_loc)
399
+ radiant_interior_ceiling_slab_construction.setTemperatureCalculationRequestedAfterLayerNumber(slab_src_loc + 1)
400
+ radiant_interior_ceiling_slab_construction.setTubeSpacing(0.2286) # 9 inches
401
+
402
+ layers = []
403
+ layers << mat_refl_roof_membrane
404
+ layers << mat_roof_insulation
405
+ layers << mat_concrete_3_5in
406
+ layers << mat_concrete_1_5in
407
+ radiant_ceiling_slab_construction = OpenStudio::Model::ConstructionWithInternalSource.new(layers)
408
+ radiant_ceiling_slab_construction.setName('Radiant Exterior Ceiling Slab Construction')
409
+ radiant_ceiling_slab_construction.setSourcePresentAfterLayerNumber(3)
410
+ radiant_ceiling_slab_construction.setTemperatureCalculationRequestedAfterLayerNumber(4)
411
+ radiant_ceiling_slab_construction.setTubeSpacing(0.2286) # 9 inches
412
+ elsif radiant_type == 'ceilingmetalpanel'
413
+ layers = []
414
+ layers << mat_concrete_3_5in
415
+ layers << air_gap_mat
416
+ layers << metal_mat
417
+ layers << metal_mat
418
+ radiant_interior_ceiling_metal_construction = OpenStudio::Model::ConstructionWithInternalSource.new(layers)
419
+ radiant_interior_ceiling_metal_construction.setName('Radiant Interior Ceiling Metal Construction')
420
+ radiant_interior_ceiling_metal_construction.setSourcePresentAfterLayerNumber(3)
421
+ radiant_interior_ceiling_metal_construction.setTemperatureCalculationRequestedAfterLayerNumber(4)
422
+ radiant_interior_ceiling_metal_construction.setTubeSpacing(0.1524) # 6 inches
423
+
424
+ layers = []
425
+ layers << mat_refl_roof_membrane
426
+ layers << mat_roof_insulation
427
+ layers << mat_concrete_3_5in
428
+ layers << air_gap_mat
429
+ layers << metal_mat
430
+ layers << metal_mat
431
+ radiant_ceiling_metal_construction = OpenStudio::Model::ConstructionWithInternalSource.new(layers)
432
+ radiant_ceiling_metal_construction.setName('Radiant Ceiling Metal Construction')
433
+ radiant_ceiling_metal_construction.setSourcePresentAfterLayerNumber(5)
434
+ radiant_ceiling_metal_construction.setTemperatureCalculationRequestedAfterLayerNumber(6)
435
+ radiant_ceiling_metal_construction.setTubeSpacing(0.1524) # 6 inches
436
+ elsif radiant_type == 'floorwithhardwood'
437
+ layers = []
438
+ layers << mat_slab_insulation
439
+ layers << mat_concrete_3_5in
440
+ layers << wood_mat
441
+ layers << mat_thin_carpet_tile if include_carpet
442
+ radiant_ground_wood_construction = OpenStudio::Model::ConstructionWithInternalSource.new(layers)
443
+ radiant_ground_wood_construction.setName('Radiant Ground Slab Wood Floor Construction')
444
+ radiant_ground_wood_construction.setSourcePresentAfterLayerNumber(2)
445
+ radiant_ground_wood_construction.setTemperatureCalculationRequestedAfterLayerNumber(3)
446
+ radiant_ground_wood_construction.setTubeSpacing(0.2286) # 9 inches
447
+
448
+ layers = []
449
+ layers << mat_ext_insulation
450
+ layers << wood_mat
451
+ layers << mat_thin_carpet_tile if include_carpet
452
+ radiant_exterior_wood_construction = OpenStudio::Model::ConstructionWithInternalSource.new(layers)
453
+ radiant_exterior_wood_construction.setName('Radiant Exterior Wood Floor Construction')
454
+ radiant_exterior_wood_construction.setSourcePresentAfterLayerNumber(1)
455
+ radiant_exterior_wood_construction.setTemperatureCalculationRequestedAfterLayerNumber(2)
456
+ radiant_exterior_wood_construction.setTubeSpacing(0.2286) # 9 inches
457
+
458
+ layers = []
459
+ layers << gypsum_ceiling_mat
460
+ layers << wood_floor_insulation
461
+ layers << wood_mat
462
+ layers << mat_thin_carpet_tile if include_carpet
463
+ radiant_interior_wood_floor_construction = OpenStudio::Model::ConstructionWithInternalSource.new(layers)
464
+ radiant_interior_wood_floor_construction.setName('Radiant Interior Wooden Floor Construction')
465
+ radiant_interior_wood_floor_construction.setSourcePresentAfterLayerNumber(2)
466
+ radiant_interior_wood_floor_construction.setTemperatureCalculationRequestedAfterLayerNumber(3)
467
+ radiant_interior_wood_floor_construction.setTubeSpacing(0.2286) # 9 inches
468
+ end
411
469
 
412
470
  # default temperature controls for radiant system
413
471
  zn_radiant_htg_dsgn_temp_f = 68.0
@@ -488,6 +546,16 @@ class OpenStudio::Model::Model
488
546
  surface.setConstruction(radiant_interior_ceiling_metal_construction)
489
547
  end
490
548
  end
549
+ elsif radiant_type == 'floorwithhardwood'
550
+ if surface.surfaceType == 'Floor'
551
+ if surface.outsideBoundaryCondition == 'Ground'
552
+ surface.setConstruction(radiant_ground_wood_construction)
553
+ elsif surface.outsideBoundaryCondition == 'Outdoors'
554
+ surface.setConstruction(radiant_exterior_wood_construction)
555
+ else # interior floor
556
+ surface.setConstruction(radiant_interior_wood_floor_construction)
557
+ end
558
+ end
491
559
  end
492
560
  end
493
561
  end
@@ -500,6 +568,8 @@ class OpenStudio::Model::Model
500
568
  radiant_loop.setRadiantSurfaceType('Ceilings')
501
569
  elsif radiant_type == 'ceilingmetalpanel'
502
570
  radiant_loop.setRadiantSurfaceType('Ceilings')
571
+ elsif radiant_type == 'floorwithhardwood'
572
+ radiant_loop.setRadiantSurfaceType('Floors')
503
573
  end
504
574
 
505
575
  # radiant loop layout details
@@ -260,6 +260,10 @@ module Honeybee
260
260
  h_stat = zone.zoneControlHumidistat
261
261
  unless h_stat.empty?
262
262
  humidistat_exists = true
263
+ if equipment_type.to_s.include? 'DOAS'
264
+ z_sizing = zone.sizingZone
265
+ z_sizing.setDedicatedOutdoorAirSystemControlStrategy('NeutralDehumidifiedSupplyAir')
266
+ end
263
267
  end
264
268
  end
265
269
  if humidistat_exists
@@ -269,12 +273,6 @@ module Honeybee
269
273
  end
270
274
  end
271
275
 
272
- # set all plants to non-coincident sizing to avoid simualtion control issues on design days
273
- openstudio_model.getPlantLoops.each do |loop|
274
- sizing = loop.sizingPlant
275
- sizing.setSizingOption('NonCoincident')
276
- end
277
-
278
276
  end
279
277
 
280
278
  private
@@ -109,7 +109,7 @@ module Honeybee
109
109
 
110
110
  # initialize a global variable for whether the AFN is used instead of simple ventilation
111
111
  $use_simple_vent = true
112
- if @hash[:properties][:energy][:ventilation_simulation_control]
112
+ if @hash[:properties].key?(:energy) && @hash[:properties][:energy][:ventilation_simulation_control]
113
113
  vent_sim_control = @hash[:properties][:energy][:ventilation_simulation_control]
114
114
  if vent_sim_control[:vent_control_type] && vent_sim_control[:vent_control_type] != 'SingleZone'
115
115
  $use_simple_vent = false
@@ -129,42 +129,44 @@ module Honeybee
129
129
  $shw_for_plant = nil # track whether a hot water plant is needed
130
130
 
131
131
  # create all of the non-geometric model elements
132
- if log_report # schedules are used by all other objects and come first
133
- puts 'Translating Schedules'
134
- end
135
- if @hash[:properties][:energy][:schedule_type_limits]
136
- create_schedule_type_limits(@hash[:properties][:energy][:schedule_type_limits])
137
- end
138
- if @hash[:properties][:energy][:schedules]
139
- create_schedules(@hash[:properties][:energy][:schedules], false, true)
140
- end
132
+ if @hash[:properties].key?(:energy)
133
+ if log_report # schedules are used by all other objects and come first
134
+ puts 'Translating Schedules'
135
+ end
136
+ if @hash[:properties][:energy][:schedule_type_limits]
137
+ create_schedule_type_limits(@hash[:properties][:energy][:schedule_type_limits])
138
+ end
139
+ if @hash[:properties][:energy][:schedules]
140
+ create_schedules(@hash[:properties][:energy][:schedules], false, true)
141
+ end
141
142
 
142
- if log_report
143
- puts 'Translating Materials'
144
- end
145
- if @hash[:properties][:energy][:materials]
146
- create_materials(@hash[:properties][:energy][:materials])
147
- end
143
+ if log_report
144
+ puts 'Translating Materials'
145
+ end
146
+ if @hash[:properties][:energy][:materials]
147
+ create_materials(@hash[:properties][:energy][:materials])
148
+ end
148
149
 
149
- if log_report
150
- puts 'Translating Constructions'
151
- end
152
- if @hash[:properties][:energy][:constructions]
153
- create_constructions(@hash[:properties][:energy][:constructions])
154
- end
150
+ if log_report
151
+ puts 'Translating Constructions'
152
+ end
153
+ if @hash[:properties][:energy][:constructions]
154
+ create_constructions(@hash[:properties][:energy][:constructions])
155
+ end
155
156
 
156
- if log_report
157
- puts 'Translating ConstructionSets'
158
- end
159
- if @hash[:properties][:energy][:construction_sets]
160
- create_construction_sets(@hash[:properties][:energy][:construction_sets])
161
- end
157
+ if log_report
158
+ puts 'Translating ConstructionSets'
159
+ end
160
+ if @hash[:properties][:energy][:construction_sets]
161
+ create_construction_sets(@hash[:properties][:energy][:construction_sets])
162
+ end
162
163
 
163
- if log_report
164
- puts 'Translating ProgramTypes'
165
- end
166
- if @hash[:properties][:energy][:program_types]
167
- create_program_types(@hash[:properties][:energy][:program_types])
164
+ if log_report
165
+ puts 'Translating ProgramTypes'
166
+ end
167
+ if @hash[:properties][:energy][:program_types]
168
+ create_program_types(@hash[:properties][:energy][:program_types])
169
+ end
168
170
  end
169
171
 
170
172
  # create the default construction set to catch any cases of unassigned constructions
@@ -196,8 +198,10 @@ module Honeybee
196
198
  if log_report
197
199
  puts 'Translating HVAC Systems'
198
200
  end
199
- create_hvacs
200
- create_hot_water_plant
201
+ if @hash[:properties].key?(:energy)
202
+ create_hvacs
203
+ create_hot_water_plant
204
+ end
201
205
 
202
206
  if log_report
203
207
  puts 'Translating Context Shade Geometry'
@@ -445,32 +449,34 @@ module Honeybee
445
449
  openstudio_room = room_object.to_openstudio(@openstudio_model)
446
450
 
447
451
  # for rooms with hot water objects definied in the ProgramType, make a new WaterUse:Equipment
448
- if room[:properties][:energy][:program_type] && !room[:properties][:energy][:service_hot_water]
449
- program_type_id = room[:properties][:energy][:program_type]
450
- shw_hash = $programtype_shw_hash[program_type_id]
451
- unless shw_hash.nil?
452
- shw_object = ServiceHotWaterAbridged.new(shw_hash)
453
- openstudio_shw = shw_object.to_openstudio(
454
- @openstudio_model, openstudio_room, room[:properties][:energy][:shw])
455
- $shw_for_plant = shw_object
452
+ if room[:properties].key?(:energy)
453
+ if room[:properties][:energy][:program_type] && !room[:properties][:energy][:service_hot_water]
454
+ program_type_id = room[:properties][:energy][:program_type]
455
+ shw_hash = $programtype_shw_hash[program_type_id]
456
+ unless shw_hash.nil?
457
+ shw_object = ServiceHotWaterAbridged.new(shw_hash)
458
+ openstudio_shw = shw_object.to_openstudio(
459
+ @openstudio_model, openstudio_room, room[:properties][:energy][:shw])
460
+ $shw_for_plant = shw_object
461
+ end
456
462
  end
457
- end
458
463
 
459
- # for rooms with setpoint objects defined in the ProgramType, make a new thermostat
460
- if room[:properties][:energy][:program_type] && !room[:properties][:energy][:setpoint]
461
- thermal_zone = openstudio_room.thermalZone()
462
- unless thermal_zone.empty?
463
- thermal_zone_object = thermal_zone.get
464
- program_type_id = room[:properties][:energy][:program_type]
465
- setpoint_hash = $programtype_setpoint_hash[program_type_id]
466
- unless setpoint_hash.nil? # program type has no setpoint
467
- thermostat_object = SetpointThermostat.new(setpoint_hash)
468
- openstudio_thermostat = thermostat_object.to_openstudio(@openstudio_model)
469
- thermal_zone_object.setThermostatSetpointDualSetpoint(openstudio_thermostat)
470
- if setpoint_hash[:humidifying_schedule] or setpoint_hash[:dehumidifying_schedule]
471
- humidistat_object = SetpointHumidistat.new(setpoint_hash)
472
- openstudio_humidistat = humidistat_object.to_openstudio(@openstudio_model)
473
- thermal_zone_object.setZoneControlHumidistat(openstudio_humidistat)
464
+ # for rooms with setpoint objects defined in the ProgramType, make a new thermostat
465
+ if room[:properties][:energy][:program_type] && !room[:properties][:energy][:setpoint]
466
+ thermal_zone = openstudio_room.thermalZone()
467
+ unless thermal_zone.empty?
468
+ thermal_zone_object = thermal_zone.get
469
+ program_type_id = room[:properties][:energy][:program_type]
470
+ setpoint_hash = $programtype_setpoint_hash[program_type_id]
471
+ unless setpoint_hash.nil? # program type has no setpoint
472
+ thermostat_object = SetpointThermostat.new(setpoint_hash)
473
+ openstudio_thermostat = thermostat_object.to_openstudio(@openstudio_model)
474
+ thermal_zone_object.setThermostatSetpointDualSetpoint(openstudio_thermostat)
475
+ if setpoint_hash[:humidifying_schedule] or setpoint_hash[:dehumidifying_schedule]
476
+ humidistat_object = SetpointHumidistat.new(setpoint_hash)
477
+ openstudio_humidistat = humidistat_object.to_openstudio(@openstudio_model)
478
+ thermal_zone_object.setZoneControlHumidistat(openstudio_humidistat)
479
+ end
474
480
  end
475
481
  end
476
482
  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.8
4
+ version: 2.31.11
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-05-24 00:00:00.000000000 Z
14
+ date: 2022-07-07 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -177,6 +177,7 @@ files:
177
177
  - lib/from_openstudio/geometry/face.rb
178
178
  - lib/from_openstudio/geometry/room.rb
179
179
  - lib/from_openstudio/geometry/shade.rb
180
+ - lib/from_openstudio/hvac/ideal_air.rb
180
181
  - lib/from_openstudio/load/daylight.rb
181
182
  - lib/from_openstudio/load/electric_equipment.rb
182
183
  - lib/from_openstudio/load/gas_equipment.rb