honeybee-openstudio 2.0.3 → 2.1.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.
@@ -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