honeybee-openstudio 2.2.0 → 2.5.0

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.
@@ -100,7 +100,7 @@ module FromHoneybee
100
100
  end
101
101
 
102
102
  # assign limits to the system's heating capacity
103
- if @hash[:heating_limit] == {'type': 'NoLimit'}
103
+ if @hash[:heating_limit] == {:type => 'NoLimit'}
104
104
  os_ideal_air.setHeatingLimit('NoLimit')
105
105
  else
106
106
  os_ideal_air.setHeatingLimit('LimitCapacity')
@@ -112,7 +112,7 @@ module FromHoneybee
112
112
  end
113
113
 
114
114
  # assign limits to the system's cooling capacity
115
- if @hash[:cooling_limit] == {'type': 'NoLimit'}
115
+ if @hash[:cooling_limit] == {:type => 'NoLimit'}
116
116
  os_ideal_air.setCoolingLimit('NoLimit')
117
117
  else
118
118
  os_ideal_air.setCoolingLimit('LimitFlowRateAndCapacity')
@@ -0,0 +1,198 @@
1
+ # *******************************************************************************
2
+ # Honeybee 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 'openstudio-standards'
33
+ require_relative 'Model.hvac'
34
+
35
+ require 'from_honeybee/extension'
36
+ require 'from_honeybee/model_object'
37
+
38
+ module FromHoneybee
39
+ class TemplateHVAC < ModelObject
40
+ attr_reader :errors, :warnings
41
+
42
+ @@all_air_types = ['VAV', 'PVAV', 'PSZ', 'PTAC', 'ForcedAirFurnace']
43
+ @@doas_types = ['FCUwithDOAS', 'WSHPwithDOAS', 'VRFwithDOAS']
44
+ @@heat_cool_types = ['FCU', 'WSHP', 'VRF', 'Baseboard', 'EvaporativeCooler',
45
+ 'Residential', 'WindowAC', 'GasUnitHeater']
46
+ @@types = @@all_air_types + @@doas_types + @@heat_cool_types
47
+
48
+ def initialize(hash = {})
49
+ super(hash)
50
+ end
51
+
52
+ def self.types
53
+ # array of all supported template HVAC systems
54
+ @@types
55
+ end
56
+
57
+ def self.all_air_types
58
+ # array of the All Air HVAC types
59
+ @@all_air_types
60
+ end
61
+
62
+ def self.doas_types
63
+ # array of the DOAS HVAC types
64
+ @@doas_types
65
+ end
66
+
67
+ def self.heat_cool_types
68
+ # array of the system types providing heating and cooling only
69
+ @@heat_cool_types
70
+ end
71
+
72
+ def defaults(system_type)
73
+ @@schema[:components][:schemas][system_type.to_sym][:properties]
74
+ end
75
+
76
+ def to_openstudio(openstudio_model, room_ids)
77
+ # get the defaults for the specific system type
78
+ hvac_defaults = defaults(@hash[:type])
79
+
80
+ # make the standard applier
81
+ if @hash[:vintage]
82
+ standard = Standard.build(@hash[:vintage])
83
+ else
84
+ standard = Standard.build(hvac_defaults[:vintage][:default])
85
+ end
86
+
87
+ # get the default equipment type
88
+ if @hash[:equipment_type]
89
+ equipment_type = @hash[:equipment_type]
90
+ else
91
+ equipment_type = hvac_defaults[:equipment_type][:default]
92
+ end
93
+
94
+ # get all of the thermal zones from the Model using the room identifiers
95
+ zones = []
96
+ room_ids.each do |room_id|
97
+ zone_get = openstudio_model.getThermalZoneByName(room_id)
98
+ unless zone_get.empty?
99
+ os_thermal_zone = zone_get.get
100
+ zones << os_thermal_zone
101
+ end
102
+ end
103
+
104
+ # create the HVAC system and assign the identifier to the air loop name if it exists
105
+ os_hvac = openstudio_model.add_cbecs_hvac_system(standard, equipment_type, zones)
106
+ os_air_loop = nil
107
+ air_loops = openstudio_model.getAirLoopHVACs
108
+ unless air_loops.length == 0
109
+ os_air_loop = air_loops[-1]
110
+ loop_name = os_air_loop.name
111
+ unless loop_name.empty?
112
+ os_air_loop.setName(@hash[:identifier] + ' - ' + loop_name.get)
113
+ end
114
+ end
115
+
116
+ # TODO: consider adding the ability to decentralize the plant by changing loop names
117
+ #os_hvac.each do |hvac_loop|
118
+ # loop_name = hvac_loop.name
119
+ # unless loop_name.empty?
120
+ # hvac_loop.setName(@hash[:identifier] + ' - ' + loop_name.get)
121
+ # end
122
+ #end
123
+
124
+ # assign the economizer type if there's an air loop and the economizer is specified
125
+ if @hash[:economizer_type] && @hash[:economizer_type] != 'Inferred' && os_air_loop
126
+ oasys = os_air_loop.airLoopHVACOutdoorAirSystem
127
+ unless oasys.empty?
128
+ os_oasys = oasys.get
129
+ oactrl = os_oasys.getControllerOutdoorAir
130
+ oactrl.setEconomizerControlType(@hash[:economizer_type])
131
+ end
132
+ end
133
+
134
+ # set the sensible heat recovery if there's an air loop and the heat recovery is specified
135
+ if @hash[:sensible_heat_recovery] && @hash[:sensible_heat_recovery] != {:type => 'Autosize'} && os_air_loop
136
+ erv = get_existing_erv(os_air_loop)
137
+ unless erv
138
+ erv = create_erv(openstudio_model, os_air_loop)
139
+ end
140
+ eff_at_max = @hash[:sensible_heat_recovery] * (0.76 / 0.81) # taken from OpenStudio defaults
141
+ erv.setSensibleEffectivenessat100CoolingAirFlow(eff_at_max)
142
+ erv.setSensibleEffectivenessat100HeatingAirFlow(eff_at_max)
143
+ erv.setSensibleEffectivenessat75CoolingAirFlow(@hash[:sensible_heat_recovery])
144
+ erv.setSensibleEffectivenessat75HeatingAirFlow(@hash[:sensible_heat_recovery])
145
+ end
146
+
147
+ # set the latent heat recovery if there's an air loop and the heat recovery is specified
148
+ if @hash[:latent_heat_recovery] && @hash[:latent_heat_recovery] != {:type => 'Autosize'} && os_air_loop
149
+ erv = get_existing_erv(os_air_loop)
150
+ unless erv
151
+ erv = create_erv(openstudio_model, os_air_loop)
152
+ end
153
+ eff_at_max = @hash[:latent_heat_recovery] * (0.68 / 0.73) # taken from OpenStudio defaults
154
+ erv.setLatentEffectivenessat100CoolingAirFlow(eff_at_max)
155
+ erv.setLatentEffectivenessat100HeatingAirFlow(eff_at_max)
156
+ erv.setLatentEffectivenessat75CoolingAirFlow(@hash[:latent_heat_recovery])
157
+ erv.setLatentEffectivenessat75HeatingAirFlow(@hash[:latent_heat_recovery])
158
+ end
159
+
160
+ os_hvac
161
+ end
162
+
163
+ def get_existing_erv(os_air_loop)
164
+ # get an existing heat ecovery unit from an air loop; will be nil if there is none
165
+ os_air_loop.oaComponents.each do |supply_component|
166
+ if not supply_component.to_HeatExchangerAirToAirSensibleAndLatent.empty?
167
+ erv = supply_component.to_HeatExchangerAirToAirSensibleAndLatent.get
168
+ return erv
169
+ end
170
+ end
171
+ nil
172
+ end
173
+
174
+ def create_erv(model, os_air_loop)
175
+ # create a heat recovery unit with default zero efficiencies
176
+ heat_ex = OpenStudio::Model::HeatExchangerAirToAirSensibleAndLatent.new(model)
177
+ heat_ex.setEconomizerLockout(false)
178
+ heat_ex.setName(@hash[:identifier] + '_Heat Recovery Unit')
179
+ heat_ex.setSensibleEffectivenessat100CoolingAirFlow(0)
180
+ heat_ex.setSensibleEffectivenessat100HeatingAirFlow(0)
181
+ heat_ex.setSensibleEffectivenessat75CoolingAirFlow(0)
182
+ heat_ex.setSensibleEffectivenessat75HeatingAirFlow(0)
183
+ heat_ex.setLatentEffectivenessat100CoolingAirFlow(0)
184
+ heat_ex.setLatentEffectivenessat100HeatingAirFlow(0)
185
+ heat_ex.setLatentEffectivenessat75CoolingAirFlow(0)
186
+ heat_ex.setLatentEffectivenessat75HeatingAirFlow(0)
187
+
188
+ # add the heat exchanger to the air loop
189
+ outdoor_node = os_air_loop.reliefAirNode
190
+ unless outdoor_node.empty?
191
+ os_outdoor_node = outdoor_node.get
192
+ heat_ex.addToNode(os_outdoor_node)
193
+ end
194
+ heat_ex
195
+ end
196
+
197
+ end #TemplateHVAC
198
+ end #FromHoneybee
@@ -46,6 +46,7 @@ require 'from_honeybee/geometry/room'
46
46
 
47
47
  # import the HVAC objects
48
48
  require 'from_honeybee/hvac/ideal_air'
49
+ require 'from_honeybee/hvac/template'
49
50
 
50
51
  # import the construction objects
51
52
  require 'from_honeybee/construction/opaque'
@@ -95,12 +96,12 @@ module FromHoneybee
95
96
  # initialize class variable @@extension only once
96
97
  @@extension ||= Extension.new
97
98
  @@schema ||= @@extension.schema
99
+ @@standards ||= @@extension.standards
98
100
 
99
101
  @hash = hash
100
102
  @type = @hash[:type]
101
103
  raise 'Unknown model type' if @type.nil?
102
104
  raise "Incorrect model type '#{@type}'" unless @type == 'Model'
103
-
104
105
  end
105
106
 
106
107
  # check if the model is valid
@@ -157,34 +158,58 @@ module FromHoneybee
157
158
  building = @openstudio_model.getBuilding
158
159
  building.setStandardsBuildingType('MediumOffice')
159
160
 
161
+ # initialize global hashes for various model properties
162
+ $gas_gap_hash = Hash.new # hash to track gas gaps in case they are split by shades
163
+ $air_boundary_hash = Hash.new # hash to track any air boundary constructions
164
+ $window_shade_hash = Hash.new # hash to track any window constructions with shade
165
+ $programtype_setpoint_hash = Hash.new # hash to track Setpoint objects
166
+
160
167
  # create all of the non-geometric model elements
161
168
  if log_report
162
169
  puts 'Translating Materials'
163
170
  end
164
- create_materials
171
+ if @hash[:properties][:energy][:materials]
172
+ create_materials(@hash[:properties][:energy][:materials])
173
+ end
165
174
 
166
175
  if log_report
167
176
  puts 'Translating Constructions'
168
177
  end
169
- create_constructions
178
+ if @hash[:properties][:energy][:constructions]
179
+ create_constructions(@hash[:properties][:energy][:constructions])
180
+ end
170
181
 
171
182
  if log_report
172
183
  puts 'Translating ConstructionSets'
173
184
  end
174
- create_construction_set
175
- create_global_construction_set
185
+ if @hash[:properties][:energy][:construction_sets]
186
+ create_construction_sets(@hash[:properties][:energy][:construction_sets])
187
+ end
176
188
 
177
189
  if log_report
178
190
  puts 'Translating Schedules'
179
191
  end
180
- create_schedule_type_limits
181
- create_schedules
192
+ if @hash[:properties][:energy][:schedule_type_limits]
193
+ create_schedule_type_limits(@hash[:properties][:energy][:schedule_type_limits])
194
+ end
195
+ if @hash[:properties][:energy][:schedules]
196
+ create_schedules(@hash[:properties][:energy][:schedules])
197
+ end
182
198
 
183
199
  if log_report
184
200
  puts 'Translating ProgramTypes'
185
201
  end
186
- create_program_types
202
+ if @hash[:properties][:energy][:program_types]
203
+ create_program_types(@hash[:properties][:energy][:program_types])
204
+ end
205
+
206
+ # create the default construction set to catch any cases of unassigned constructions
207
+ if log_report
208
+ puts 'Translating Default ConstructionSet'
209
+ end
210
+ create_default_construction_set
187
211
 
212
+ # create the geometry and add any extra properties to it
188
213
  if log_report
189
214
  puts 'Translating Room Geometry'
190
215
  end
@@ -211,103 +236,139 @@ module FromHoneybee
211
236
  create_orphaned_doors
212
237
  end
213
238
 
214
- def create_materials
215
- $gas_gap_hash = Hash.new # hash to track gas gaps in case they are split by shades
239
+ def create_materials(material_dicts, check_existing=false)
240
+ material_dicts.each do |material|
241
+ # check if there's already a material in the model with the identifier
242
+ add_obj = true
243
+ if check_existing
244
+ object = @openstudio_model.getMaterialByName(material[:identifier])
245
+ if object.is_initialized
246
+ add_obj = false
247
+ end
248
+ end
216
249
 
217
- @hash[:properties][:energy][:materials].each do |material|
218
- material_type = material[:type]
219
-
220
- case material_type
221
- when 'EnergyMaterial'
222
- material_object = EnergyMaterial.new(material)
223
- when 'EnergyMaterialNoMass'
224
- material_object = EnergyMaterialNoMass.new(material)
225
- when 'EnergyWindowMaterialGas'
226
- material_object = EnergyWindowMaterialGas.new(material)
227
- $gas_gap_hash[material[:identifier]] = material_object
228
- when 'EnergyWindowMaterialGasMixture'
229
- material_object = EnergyWindowMaterialGasMixture.new(material)
230
- $gas_gap_hash[material[:identifier]] = material_object
231
- when 'EnergyWindowMaterialGasCustom'
232
- material_object = EnergyWindowMaterialGasCustom.new(material)
233
- $gas_gap_hash[material[:identifier]] = material_object
234
- when 'EnergyWindowMaterialSimpleGlazSys'
235
- material_object = EnergyWindowMaterialSimpleGlazSys.new(material)
236
- when 'EnergyWindowMaterialBlind'
237
- material_object = EnergyWindowMaterialBlind.new(material)
238
- when 'EnergyWindowMaterialGlazing'
239
- material_object = EnergyWindowMaterialGlazing.new(material)
240
- when 'EnergyWindowMaterialShade'
241
- material_object = EnergyWindowMaterialShade.new(material)
242
- else
243
- raise "Unknown material type #{material_type}"
250
+ # add the material object to the Model
251
+ if add_obj
252
+ material_type = material[:type]
253
+ case material_type
254
+ when 'EnergyMaterial'
255
+ material_object = EnergyMaterial.new(material)
256
+ when 'EnergyMaterialNoMass'
257
+ material_object = EnergyMaterialNoMass.new(material)
258
+ when 'EnergyWindowMaterialGas'
259
+ material_object = EnergyWindowMaterialGas.new(material)
260
+ $gas_gap_hash[material[:identifier]] = material_object
261
+ when 'EnergyWindowMaterialGasMixture'
262
+ material_object = EnergyWindowMaterialGasMixture.new(material)
263
+ $gas_gap_hash[material[:identifier]] = material_object
264
+ when 'EnergyWindowMaterialGasCustom'
265
+ material_object = EnergyWindowMaterialGasCustom.new(material)
266
+ $gas_gap_hash[material[:identifier]] = material_object
267
+ when 'EnergyWindowMaterialSimpleGlazSys'
268
+ material_object = EnergyWindowMaterialSimpleGlazSys.new(material)
269
+ when 'EnergyWindowMaterialBlind'
270
+ material_object = EnergyWindowMaterialBlind.new(material)
271
+ when 'EnergyWindowMaterialGlazing'
272
+ material_object = EnergyWindowMaterialGlazing.new(material)
273
+ when 'EnergyWindowMaterialShade'
274
+ material_object = EnergyWindowMaterialShade.new(material)
275
+ else
276
+ raise "Unknown material type #{material_type}"
277
+ end
278
+ material_object.to_openstudio(@openstudio_model)
244
279
  end
245
- material_object.to_openstudio(@openstudio_model)
246
280
  end
247
281
  end
248
282
 
249
- def create_constructions
250
- $air_boundary_hash = Hash.new # hash to track any air boundary constructions
251
- $window_shade_hash = Hash.new # hash to track any window constructions with shade
283
+ def create_constructions(construction_dicts, check_existing=false)
284
+ construction_dicts.each do |construction|
285
+ # check if there's already a construction in the model with the identifier
286
+ add_obj = true
287
+ if check_existing
288
+ object = @openstudio_model.getConstructionByName(construction[:identifier])
289
+ if object.is_initialized
290
+ add_obj = false
291
+ end
292
+ end
252
293
 
253
- @hash[:properties][:energy][:constructions].each do |construction|
254
- identifier = construction[:identifier]
255
- construction_type = construction[:type]
256
-
257
- case construction_type
258
- when 'OpaqueConstructionAbridged'
259
- construction_object = OpaqueConstructionAbridged.new(construction)
260
- when 'WindowConstructionAbridged'
261
- construction_object = WindowConstructionAbridged.new(construction)
262
- when 'WindowConstructionShadeAbridged'
263
- construction_object = WindowConstructionShadeAbridged.new(construction)
264
- $window_shade_hash[construction[:identifier]] = construction_object
265
- when 'ShadeConstruction'
266
- construction_object = ShadeConstruction.new(construction)
267
- when 'AirBoundaryConstructionAbridged'
268
- construction_object = AirBoundaryConstructionAbridged.new(construction)
269
- $air_boundary_hash[construction[:identifier]] = construction
270
- else
271
- raise "Unknown construction type #{construction_type}."
294
+ # add the construction object to the Model
295
+ if add_obj
296
+ construction_type = construction[:type]
297
+ case construction_type
298
+ when 'OpaqueConstructionAbridged'
299
+ construction_object = OpaqueConstructionAbridged.new(construction)
300
+ when 'WindowConstructionAbridged'
301
+ construction_object = WindowConstructionAbridged.new(construction)
302
+ when 'WindowConstructionShadeAbridged'
303
+ construction_object = WindowConstructionShadeAbridged.new(construction)
304
+ $window_shade_hash[construction[:identifier]] = construction_object
305
+ when 'ShadeConstruction'
306
+ construction_object = ShadeConstruction.new(construction)
307
+ when 'AirBoundaryConstructionAbridged'
308
+ construction_object = AirBoundaryConstructionAbridged.new(construction)
309
+ $air_boundary_hash[construction[:identifier]] = construction
310
+ else
311
+ raise "Unknown construction type #{construction_type}."
312
+ end
313
+ construction_object.to_openstudio(@openstudio_model)
272
314
  end
273
- construction_object.to_openstudio(@openstudio_model)
274
315
  end
275
316
  end
276
317
 
277
- def create_construction_set
278
- if @hash[:properties][:energy][:construction_sets]
279
- @hash[:properties][:energy][:construction_sets].each do |construction_set|
280
- construction_set_object = ConstructionSetAbridged.new(construction_set)
281
- construction_set_object.to_openstudio(@openstudio_model)
318
+ def create_construction_sets(construction_set_dicts, check_existing=false)
319
+ construction_set_dicts.each do |construction_set|
320
+ # check if there's already a construction set in the model with the identifier
321
+ add_obj = true
322
+ if check_existing
323
+ object = @openstudio_model.getDefaultConstructionSetByName(
324
+ construction_set[:identifier])
325
+ if object.is_initialized
326
+ add_obj = false
327
+ end
282
328
  end
283
- end
284
- end
285
329
 
286
- def create_global_construction_set
287
- if @hash[:properties][:energy][:global_construction_set]
288
- construction_id = @hash[:properties][:energy][:global_construction_set]
289
- construction = @openstudio_model.getDefaultConstructionSetByName(construction_id)
290
- unless construction.empty?
291
- openstudio_construction = construction.get
330
+ # add the construction set object to the Model
331
+ if add_obj
332
+ construction_set_object = ConstructionSetAbridged.new(construction_set)
333
+ construction_set_object.to_openstudio(@openstudio_model)
292
334
  end
293
- @openstudio_model.getBuilding.setDefaultConstructionSet(openstudio_construction)
294
335
  end
295
336
  end
296
337
 
297
- def create_schedule_type_limits
298
- if @hash[:properties][:energy][:schedule_type_limits]
299
- @hash[:properties][:energy][:schedule_type_limits].each do |schedule_type_limit|
338
+ def create_schedule_type_limits(stl_dicts, check_existing=false)
339
+ stl_dicts.each do |schedule_type_limit|
340
+ # check if there's already a schedule type limit in the model with the identifier
341
+ add_obj = true
342
+ if check_existing
343
+ object = @openstudio_model.getScheduleTypeLimitsByName(
344
+ schedule_type_limit[:identifier])
345
+ if object.is_initialized
346
+ add_obj = false
347
+ end
348
+ end
349
+
350
+ # add the schedule type limit object to the Model
351
+ if add_obj
300
352
  schedule_type_limit_object = ScheduleTypeLimit.new(schedule_type_limit)
301
353
  schedule_type_limit_object.to_openstudio(@openstudio_model)
302
354
  end
303
355
  end
304
356
  end
305
357
 
306
- def create_schedules
307
- if @hash[:properties][:energy][:schedules]
308
- @hash[:properties][:energy][:schedules].each do |schedule|
309
- schedule_type = schedule[:type]
358
+ def create_schedules(schedule_dicts, check_existing=false)
359
+ schedule_dicts.each do |schedule|
360
+ # check if there's already a schedule in the model with the identifier
361
+ add_obj = true
362
+ if check_existing
363
+ object = @openstudio_model.getScheduleByName(schedule[:identifier])
364
+ if object.is_initialized
365
+ add_obj = false
366
+ end
367
+ end
310
368
 
369
+ # add the schedule object to the Model
370
+ if add_obj
371
+ schedule_type = schedule[:type]
311
372
  case schedule_type
312
373
  when 'ScheduleRulesetAbridged'
313
374
  schedule_object = ScheduleRulesetAbridged.new(schedule)
@@ -317,21 +378,56 @@ module FromHoneybee
317
378
  raise("Unknown schedule type #{schedule_type}.")
318
379
  end
319
380
  schedule_object.to_openstudio(@openstudio_model)
320
-
321
381
  end
322
382
  end
323
383
  end
324
384
 
325
- def create_program_types
326
- if @hash[:properties][:energy][:program_types]
327
- $programtype_setpoint_hash = Hash.new # hash to track Setpoint objects
328
- @hash[:properties][:energy][:program_types].each do |space_type|
385
+ def create_program_types(program_dicts, check_existing=false)
386
+ program_dicts.each do |space_type|
387
+ # check if there's already a space type in the model with the identifier
388
+ add_obj = true
389
+ if check_existing
390
+ object = @openstudio_model.getSpaceTypeByName(space_type[:identifier])
391
+ if object.is_initialized
392
+ add_obj = false
393
+ end
394
+ end
395
+
396
+ # add the space type object to the Model
397
+ if add_obj
329
398
  space_type_object = ProgramTypeAbridged.new(space_type)
330
399
  space_type_object.to_openstudio(@openstudio_model)
331
400
  end
332
401
  end
333
402
  end
334
403
 
404
+ def create_default_construction_set
405
+ # create the materials, constructions and construction set
406
+ create_materials(@@standards[:materials], true)
407
+ create_constructions(@@standards[:constructions], true)
408
+ create_construction_sets(@@standards[:construction_sets], true)
409
+
410
+ # write the fractional schedule type and always on schedule if they are not there
411
+ @@standards[:schedule_type_limits].each do |sch_type_limit|
412
+ if sch_type_limit[:identifier] == 'Fractional'
413
+ create_schedule_type_limits([sch_type_limit], true)
414
+ end
415
+ end
416
+ @@standards[:schedules].each do |schedule|
417
+ if schedule[:identifier] == 'Always On'
418
+ create_schedules([schedule], true)
419
+ end
420
+ end
421
+
422
+ # set the default construction set to the building level of the Model
423
+ construction_id = 'Default Generic Construction Set'
424
+ construction = @openstudio_model.getDefaultConstructionSetByName(construction_id)
425
+ unless construction.empty?
426
+ os_constructionset = construction.get
427
+ @openstudio_model.getBuilding.setDefaultConstructionSet(os_constructionset)
428
+ end
429
+ end
430
+
335
431
  def create_rooms
336
432
  if @hash[:rooms]
337
433
  $air_mxing_array = [] # list to track any air mixing between Rooms
@@ -408,7 +504,7 @@ module FromHoneybee
408
504
  hvac_hashes[hvac[:identifier]] = hvac
409
505
  hvac_hashes[hvac[:identifier]]['rooms'] = []
410
506
  end
411
- # loop through the rooms and trach which are assigned to each HVAC
507
+ # loop through the rooms and track which are assigned to each HVAC
412
508
  if @hash[:rooms]
413
509
  @hash[:rooms].each do |room|
414
510
  if room[:properties][:energy][:hvac]
@@ -419,8 +515,7 @@ module FromHoneybee
419
515
 
420
516
  hvac_hashes.each_value do |hvac|
421
517
  system_type = hvac[:type]
422
- case system_type
423
- when 'IdealAirSystemAbridged'
518
+ if system_type == 'IdealAirSystemAbridged'
424
519
  ideal_air_system = IdealAirSystemAbridged.new(hvac)
425
520
  os_ideal_air_system = ideal_air_system.to_openstudio(@openstudio_model)
426
521
  hvac['rooms'].each do |room_id|
@@ -430,6 +525,9 @@ module FromHoneybee
430
525
  os_ideal_air_system.addToThermalZone(os_thermal_zone)
431
526
  end
432
527
  end
528
+ elsif TemplateHVAC.types.include?(system_type)
529
+ template_system = TemplateHVAC.new(hvac)
530
+ os_template_system = template_system.to_openstudio(@openstudio_model, hvac['rooms'])
433
531
  end
434
532
  end
435
533
  end