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.
- checksums.yaml +4 -4
- data/.github/workflows/emit-release-event.yaml +32 -0
- data/honeybee-openstudio.gemspec +1 -1
- data/lib/files/urbanopt_Gemfile +1 -1
- data/lib/from_honeybee/_defaults/energy_default.json +1682 -0
- data/lib/from_honeybee/{_openapi → _defaults}/model.json +2154 -375
- data/lib/from_honeybee/{_openapi → _defaults}/simulation-parameter.json +175 -187
- data/lib/from_honeybee/construction/windowshade.rb +7 -3
- data/lib/from_honeybee/extension.rb +21 -1
- data/lib/from_honeybee/geometry/room.rb +26 -4
- data/lib/from_honeybee/hvac/Model.hvac.rb +635 -0
- data/lib/from_honeybee/hvac/ideal_air.rb +2 -2
- data/lib/from_honeybee/hvac/template.rb +198 -0
- data/lib/from_honeybee/model.rb +188 -90
- data/lib/from_honeybee/schedule/type_limit.rb +2 -2
- data/lib/from_honeybee/simulation/extension.rb +1 -1
- data/lib/from_honeybee/ventcool/opening.rb +160 -0
- metadata +9 -4
@@ -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] == {
|
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] == {
|
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
|
data/lib/from_honeybee/model.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
175
|
-
|
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
|
-
|
181
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
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
|
-
|
251
|
-
|
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
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
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
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
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
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
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
|
-
|
299
|
-
|
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
|
-
|
308
|
-
|
309
|
-
|
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
|
-
|
327
|
-
|
328
|
-
|
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
|
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
|
-
|
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
|