honeybee-openstudio 2.0.3 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -74,7 +74,6 @@ module FromHoneybee
74
74
 
75
75
  end #WindowConstructionAbridged
76
76
  end #FromHoneybee
77
-
78
77
 
79
78
 
80
79
 
@@ -0,0 +1,207 @@
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 'from_honeybee/model_object'
33
+ require 'from_honeybee/construction/window'
34
+
35
+ require 'openstudio'
36
+
37
+ module FromHoneybee
38
+ class WindowConstructionShadeAbridged < ModelObject
39
+ attr_reader :errors, :warnings
40
+
41
+ def initialize(hash = {})
42
+ super(hash)
43
+ @construction = nil
44
+ @shade_construction = nil
45
+ @shade_location = nil
46
+ @shade_material = nil
47
+ @control_type = nil
48
+ @setpoint = nil
49
+ @schedule = nil
50
+ end
51
+
52
+ def defaults
53
+ @@schema[:components][:schemas][:WindowConstructionShadeAbridged][:properties]
54
+ end
55
+
56
+ def find_existing_openstudio_object(openstudio_model)
57
+ object = openstudio_model.getConstructionByName(@hash[:identifier])
58
+ return object.get if object.is_initialized
59
+ nil
60
+ end
61
+
62
+ def to_openstudio(openstudio_model)
63
+ # write the shaded and unsaded versions of the construciton into the model
64
+ # reverse the shaded and unshaded identifiers so unshaded one is assigned to apertures
65
+ unshd_id = @hash[:identifier]
66
+ shd_id = @hash[:window_construction][:identifier]
67
+ @hash[:window_construction][:identifier] = unshd_id
68
+ @hash[:identifier] = shd_id
69
+
70
+ # create the unshaded construction
71
+ unshd_constr_obj = WindowConstructionAbridged.new(@hash[:window_construction])
72
+ @construction = unshd_constr_obj.to_openstudio(openstudio_model)
73
+
74
+ # create the shaded construction
75
+ @shade_construction = OpenStudio::Model::Construction.new(openstudio_model)
76
+ @shade_construction.setName(shd_id)
77
+
78
+ # create the layers of the unshaded construction into which we will insert the shade
79
+ os_materials = []
80
+ @hash[:window_construction][:layers].each do |layer|
81
+ material_identifier = layer
82
+ material = openstudio_model.getMaterialByName(material_identifier)
83
+ unless material.empty?
84
+ os_material = material.get
85
+ os_materials << os_material
86
+ end
87
+ end
88
+
89
+ # figure out where to insert the shade material and insert it
90
+ if @hash[:shade_location]
91
+ @shade_location = @hash[:shade_location]
92
+ else
93
+ @shade_location = defaults[:shade_location][:default]
94
+ end
95
+
96
+ # insert the shade material
97
+ shd_mat_name = openstudio_model.getMaterialByName(@hash[:shade_material])
98
+ unless shd_mat_name.empty?
99
+ @shade_material = shd_mat_name.get
100
+ end
101
+ unless @shade_material.nil?
102
+ if @shade_material.is_a? OpenStudio::Model::StandardGlazing
103
+ if @shade_location == 'Interior'
104
+ os_materials[-1] = @shade_material
105
+ elsif @shade_location == 'Exterior' | os_materials.length < 2
106
+ os_materials[0] = @shade_material
107
+ else # middle glass pane
108
+ os_materials[-3] = @shade_material
109
+ end
110
+ else
111
+ if @shade_location == 'Interior'
112
+ os_materials << @shade_material
113
+ elsif @shade_location == 'Exterior'
114
+ os_materials.unshift(@shade_material)
115
+ else # between glass shade/blind
116
+ split_gap = split_gas_gap(openstudio_model, os_materials[-2], @shade_material)
117
+ os_materials[-2] = split_gap
118
+ os_materials.insert(-2, @shade_material)
119
+ os_materials.insert(-2, split_gap)
120
+ end
121
+ end
122
+ end
123
+
124
+ # assign the layers to the shaded construction
125
+ os_materials_vec = OpenStudio::Model::MaterialVector.new
126
+ os_materials.each do |mat|
127
+ os_materials_vec << mat
128
+ end
129
+ @shade_construction.setLayers(os_materials)
130
+
131
+ # set defaults for control type, setpoint, and schedule
132
+ if @hash[:control_type]
133
+ @control_type = @hash[:control_type]
134
+ else
135
+ @control_type = defaults[:control_type][:default]
136
+ end
137
+
138
+ if @hash[:setpoint]
139
+ @setpoint = @hash[:setpoint]
140
+ else
141
+ @setpoint = defaults[:setpoint][:default]
142
+ end
143
+
144
+ unless @hash[:schedule].nil?
145
+ schedule_ref = openstudio_model.getScheduleByName(@hash[:schedule])
146
+ unless schedule_ref.empty?
147
+ @schedule = schedule_ref.get
148
+ if @control_type == 'AlwaysOn'
149
+ @control_type = 'OnIfScheduleAllows'
150
+ end
151
+ end
152
+ end
153
+
154
+ @shade_construction
155
+ end
156
+
157
+ def to_openstudio_shading_control(openstudio_model)
158
+ # add a WindowShadingControl object to a model for a given aperture and room
159
+ os_shade_control = OpenStudio::Model::ShadingControl.new(@shade_construction)
160
+
161
+ # figure out the shading type
162
+ if @shade_material.is_a? OpenStudio::Model::StandardGlazing
163
+ shd_type = 'SwitchableGlazing'
164
+ elsif @shade_material.is_a? OpenStudio::Model::Blind
165
+ if @shade_location == 'Between'
166
+ shd_type = 'BetweenGlassBlind'
167
+ else
168
+ shd_type = @shade_location + 'Blind'
169
+ end
170
+ else
171
+ if @shade_location == 'Between'
172
+ shd_type = 'BetweenGlassShade'
173
+ else
174
+ shd_type = @shade_location + 'Shade'
175
+ end
176
+ end
177
+ os_shade_control.setShadingType(shd_type)
178
+
179
+ # set the shade control type and schedule
180
+ os_shade_control.setShadingControlType(@control_type)
181
+ unless @setpoint.nil?
182
+ os_shade_control.setSetpoint(@setpoint)
183
+ end
184
+ unless @schedule.nil?
185
+ os_shade_control.setSchedule(@schedule)
186
+ end
187
+
188
+ os_shade_control
189
+ end
190
+
191
+ def split_gas_gap(openstudio_model, original_gap, shade_material)
192
+ # split a gas gap material in two when it is interrupeted by a shade/blind
193
+ if shade_material.is_a? OpenStudio::Model::Blind
194
+ shd_thick = 0
195
+ else
196
+ shd_thick = shade_material.thickness
197
+ end
198
+ gap_thick = (original_gap.thickness - shd_thick) / 2
199
+ gap_obj = $gas_gap_hash[original_gap.name.get]
200
+ new_gap = gap_obj.to_openstudio(openstudio_model)
201
+ new_gap.setName(original_gap.name.get + gap_thick.to_s)
202
+ new_gap.setThickness(gap_thick)
203
+ new_gap
204
+ end
205
+
206
+ end #WindowConstructionShadeAbridged
207
+ end #FromHoneybee
@@ -50,6 +50,7 @@ require 'from_honeybee/hvac/ideal_air'
50
50
  # import the construction objects
51
51
  require 'from_honeybee/construction/opaque'
52
52
  require 'from_honeybee/construction/window'
53
+ require 'from_honeybee/construction/windowshade'
53
54
  require 'from_honeybee/construction/shade'
54
55
  require 'from_honeybee/construction/air'
55
56
 
@@ -184,12 +185,23 @@ module FromHoneybee
184
185
  end
185
186
  create_program_types
186
187
 
187
- # create all of the model geometry
188
188
  if log_report
189
189
  puts 'Translating Room Geometry'
190
190
  end
191
191
  create_rooms
192
192
 
193
+ unless $window_shade_hash.empty?
194
+ if log_report
195
+ puts 'Translating Window Shading Control'
196
+ end
197
+ create_shading_control
198
+ end
199
+
200
+ if log_report
201
+ puts 'Translating HVAC Systems'
202
+ end
203
+ create_hvacs
204
+
193
205
  if log_report
194
206
  puts 'Translating Context Shade Geometry'
195
207
  end
@@ -197,15 +209,11 @@ module FromHoneybee
197
209
  create_orphaned_faces
198
210
  create_orphaned_apertures
199
211
  create_orphaned_doors
200
-
201
- # create the hvac systems
202
- if log_report
203
- puts 'Translating HVAC Systems'
204
- end
205
- create_hvacs
206
212
  end
207
213
 
208
214
  def create_materials
215
+ $gas_gap_hash = Hash.new # hash to track gas gaps in case they are split by shades
216
+
209
217
  @hash[:properties][:energy][:materials].each do |material|
210
218
  material_type = material[:type]
211
219
 
@@ -216,8 +224,13 @@ module FromHoneybee
216
224
  material_object = EnergyMaterialNoMass.new(material)
217
225
  when 'EnergyWindowMaterialGas'
218
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
219
231
  when 'EnergyWindowMaterialGasCustom'
220
232
  material_object = EnergyWindowMaterialGasCustom.new(material)
233
+ $gas_gap_hash[material[:identifier]] = material_object
221
234
  when 'EnergyWindowMaterialSimpleGlazSys'
222
235
  material_object = EnergyWindowMaterialSimpleGlazSys.new(material)
223
236
  when 'EnergyWindowMaterialBlind'
@@ -235,6 +248,7 @@ module FromHoneybee
235
248
 
236
249
  def create_constructions
237
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
238
252
 
239
253
  @hash[:properties][:energy][:constructions].each do |construction|
240
254
  identifier = construction[:identifier]
@@ -245,6 +259,9 @@ module FromHoneybee
245
259
  construction_object = OpaqueConstructionAbridged.new(construction)
246
260
  when 'WindowConstructionAbridged'
247
261
  construction_object = WindowConstructionAbridged.new(construction)
262
+ when 'WindowConstructionShadeAbridged'
263
+ construction_object = WindowConstructionShadeAbridged.new(construction)
264
+ $window_shade_hash[construction[:identifier]] = construction_object
248
265
  when 'ShadeConstruction'
249
266
  construction_object = ShadeConstruction.new(construction)
250
267
  when 'AirBoundaryConstructionAbridged'
@@ -344,7 +361,7 @@ module FromHoneybee
344
361
  end
345
362
  end
346
363
 
347
- # Create mixing objects between Rooms
364
+ # create mixing objects between Rooms
348
365
  $air_mxing_array.each do |air_mix_props|
349
366
  zone_mixing = OpenStudio::Model::ZoneMixing.new(air_mix_props[0])
350
367
  zone_mixing.setDesignFlowRate(air_mix_props[1])
@@ -361,35 +378,25 @@ module FromHoneybee
361
378
  end
362
379
  end
363
380
  end
364
-
365
-
366
- def create_orphaned_shades
367
- if @hash[:orphaned_shades]
368
- shading_surface_group = OpenStudio::Model::ShadingSurfaceGroup.new(@openstudio_model)
369
- shading_surface_group.setShadingSurfaceType('Building')
370
- @hash[:orphaned_shades].each do |shade|
371
- shade_object = Shade.new(shade)
372
- openstudio_shade = shade_object.to_openstudio(@openstudio_model)
373
- openstudio_shade.setShadingSurfaceGroup(shading_surface_group)
374
- end
375
- end
376
- end
377
381
 
378
- def create_orphaned_faces
379
- if @hash[:orphaned_faces]
380
- raise "Orphaned Faces are not translatable to OpenStudio."
381
- end
382
- end
383
-
384
- def create_orphaned_apertures
385
- if @hash[:orphaned_apertures]
386
- raise "Orphaned Apertures are not translatable to OpenStudio."
387
- end
388
- end
389
-
390
- def create_orphaned_doors
391
- if @hash[:orphaned_doors]
392
- raise "Orphaned Doors are not translatable to OpenStudio."
382
+ def create_shading_control
383
+ # assign any shading control objects to windows with shades
384
+ # this is run as a separate step once all logic about construction sets is in place
385
+ sub_faces = @openstudio_model.getSubSurfaces()
386
+ sub_faces.each do |sub_face|
387
+ constr_ref = sub_face.construction
388
+ unless constr_ref.empty?
389
+ constr = constr_ref.get
390
+ constr_name_ref = constr.name
391
+ unless constr_name_ref.empty?
392
+ constr_name = constr_name_ref.get
393
+ unless $window_shade_hash[constr_name].nil?
394
+ window_shd_constr = $window_shade_hash[constr_name]
395
+ os_shd_control = window_shd_constr.to_openstudio_shading_control(@openstudio_model)
396
+ sub_face.setShadingControl(os_shd_control)
397
+ end
398
+ end
399
+ end
393
400
  end
394
401
  end
395
402
 
@@ -428,6 +435,36 @@ module FromHoneybee
428
435
  end
429
436
  end
430
437
 
438
+ def create_orphaned_shades
439
+ if @hash[:orphaned_shades]
440
+ shading_surface_group = OpenStudio::Model::ShadingSurfaceGroup.new(@openstudio_model)
441
+ shading_surface_group.setShadingSurfaceType('Building')
442
+ @hash[:orphaned_shades].each do |shade|
443
+ shade_object = Shade.new(shade)
444
+ openstudio_shade = shade_object.to_openstudio(@openstudio_model)
445
+ openstudio_shade.setShadingSurfaceGroup(shading_surface_group)
446
+ end
447
+ end
448
+ end
449
+
450
+ def create_orphaned_faces
451
+ if @hash[:orphaned_faces]
452
+ raise "Orphaned Faces are not translatable to OpenStudio."
453
+ end
454
+ end
455
+
456
+ def create_orphaned_apertures
457
+ if @hash[:orphaned_apertures]
458
+ raise "Orphaned Apertures are not translatable to OpenStudio."
459
+ end
460
+ end
461
+
462
+ def create_orphaned_doors
463
+ if @hash[:orphaned_doors]
464
+ raise "Orphaned Doors are not translatable to OpenStudio."
465
+ end
466
+ end
467
+
431
468
  #TODO: create runlog for errors.
432
469
 
433
470
  end # Model
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.0.3
4
+ version: 2.1.0
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: 2020-05-29 00:00:00.000000000 Z
14
+ date: 2020-06-02 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -171,6 +171,7 @@ files:
171
171
  - lib/from_honeybee/construction/opaque.rb
172
172
  - lib/from_honeybee/construction/shade.rb
173
173
  - lib/from_honeybee/construction/window.rb
174
+ - lib/from_honeybee/construction/windowshade.rb
174
175
  - lib/from_honeybee/construction_set.rb
175
176
  - lib/from_honeybee/extension.rb
176
177
  - lib/from_honeybee/geometry/aperture.rb