openstudio-model-articulation 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -2
  3. data/CHANGELOG.md +8 -0
  4. data/README.md +8 -3
  5. data/lib/measures/AssignConstructionSetToBuilding/measure.xml +10 -10
  6. data/lib/measures/AssignSpaceTypeBySpaceName/measure.xml +27 -9
  7. data/lib/measures/AssignSpaceTypeToBuilding/measure.xml +10 -10
  8. data/lib/measures/AssignSpacesToStories/measure.rb +2 -4
  9. data/lib/measures/AssignSpacesToStories/measure.xml +10 -10
  10. data/lib/measures/BarAspectRatioStudy/measure.rb +2 -1
  11. data/lib/measures/BarAspectRatioStudy/measure.xml +4 -4
  12. data/lib/measures/CleanupSpaceOrigins/measure.rb +3 -0
  13. data/lib/measures/CleanupSpaceOrigins/measure.xml +10 -10
  14. data/lib/measures/FindAndReplaceObjectNames/measure.xml +8 -8
  15. data/lib/measures/InjectOsmGeometryIntoAnExternalIdf/measure.rb +2 -2
  16. data/lib/measures/InjectOsmGeometryIntoAnExternalIdf/measure.xml +22 -4
  17. data/lib/measures/RemoveHardAssignedConstructions/measure.xml +8 -8
  18. data/lib/measures/RenameSpaceSurfacesBasedonParentSpaceandOrientation/measure.xml +37 -7
  19. data/lib/measures/RotateBuilding/measure.xml +8 -8
  20. data/lib/measures/SetExtWallToGroundBoundaryConditionByStory/measure.xml +13 -7
  21. data/lib/measures/SetInteriorWallsAndFloorsToAdiabatic/measure.rb +1 -1
  22. data/lib/measures/SetInteriorWallsAndFloorsToAdiabatic/measure.xml +10 -10
  23. data/lib/measures/SetInteriorWallsToSelectedConstruction/measure.rb +1 -1
  24. data/lib/measures/SetInteriorWallsToSelectedConstruction/measure.xml +10 -10
  25. data/lib/measures/SetWindowToWallRatioByFacade/README.md +11 -0
  26. data/lib/measures/SetWindowToWallRatioByFacade/measure.rb +84 -143
  27. data/lib/measures/SetWindowToWallRatioByFacade/measure.xml +32 -17
  28. data/lib/measures/SetWindowToWallRatioByFacade/resources/functions.rb +176 -0
  29. data/lib/measures/SimplifyGeometryToSlicedBar/measure.rb +8 -4
  30. data/lib/measures/SimplifyGeometryToSlicedBar/measure.xml +31 -13
  31. data/lib/measures/SimplifyGeometryToSlicedBar/resources/os_lib_cofee.rb +6 -4
  32. data/lib/measures/SimplifyGeometryToSlicedBar/resources/os_lib_geometry.rb +13 -8
  33. data/lib/measures/SimplifyGeometryToSlicedBar/resources/os_lib_helper_methods.rb +2 -4
  34. data/lib/measures/SpaceTypeAndConstructionSetWizard/measure.rb +1 -1
  35. data/lib/measures/SpaceTypeAndConstructionSetWizard/measure.xml +4 -4
  36. data/lib/measures/SurfaceMatching/measure.rb +1 -0
  37. data/lib/measures/SurfaceMatching/measure.xml +10 -10
  38. data/lib/measures/blended_space_type_from_floor_area_ratios/measure.rb +4 -3
  39. data/lib/measures/blended_space_type_from_floor_area_ratios/measure.xml +4 -4
  40. data/lib/measures/blended_space_type_from_model/{resources → docs}/replace_occupied_spaces_with_blended_space_type_design_doc.txt +0 -0
  41. data/lib/measures/blended_space_type_from_model/measure.rb +15 -3
  42. data/lib/measures/blended_space_type_from_model/measure.xml +15 -21
  43. data/lib/measures/clone_building_from_external_model/measure.xml +3 -3
  44. data/lib/measures/create_DOE_prototype_building/measure.rb +2 -2
  45. data/lib/measures/create_DOE_prototype_building/measure.xml +442 -438
  46. data/lib/measures/create_and_assign_thermal_zones_for_unassigned_spaces/measure.xml +3 -3
  47. data/lib/measures/create_bar_from_building_type_ratios/measure.rb +3 -3
  48. data/lib/measures/create_bar_from_building_type_ratios/measure.xml +14 -14
  49. data/lib/measures/create_bar_from_deer_building_type_ratios/measure.rb +3 -3
  50. data/lib/measures/create_bar_from_deer_building_type_ratios/measure.xml +16 -16
  51. data/lib/measures/create_bar_from_doe_building_type_ratios/measure.rb +3 -3
  52. data/lib/measures/create_bar_from_doe_building_type_ratios/measure.xml +14 -14
  53. data/lib/measures/create_bar_from_model/measure.rb +10 -6
  54. data/lib/measures/create_bar_from_model/measure.xml +4 -4
  55. data/lib/measures/create_bar_from_space_type_ratios/measure.rb +3 -3
  56. data/lib/measures/create_bar_from_space_type_ratios/measure.xml +16 -16
  57. data/lib/measures/create_baseline_building/measure.rb +3 -2
  58. data/lib/measures/create_baseline_building/measure.xml +4 -4
  59. data/lib/measures/create_deer_prototype_building/measure.xml +3 -3
  60. data/lib/measures/create_parametric_schedules/measure.rb +15 -10
  61. data/lib/measures/create_parametric_schedules/measure.xml +4 -4
  62. data/lib/measures/create_typical_building_from_model/measure.rb +1 -1
  63. data/lib/measures/create_typical_building_from_model/measure.xml +21 -21
  64. data/lib/measures/create_typical_deer_building_from_model/measure.rb +1 -1
  65. data/lib/measures/create_typical_deer_building_from_model/measure.xml +21 -21
  66. data/lib/measures/create_typical_doe_building_from_model/measure.rb +1 -1
  67. data/lib/measures/create_typical_doe_building_from_model/measure.xml +21 -21
  68. data/lib/measures/deer_space_type_and_construction_set_wizard/measure.rb +1 -1
  69. data/lib/measures/deer_space_type_and_construction_set_wizard/measure.xml +4 -4
  70. data/lib/measures/find_and_replace_in_all_thermal_zone_names/measure.xml +3 -3
  71. data/lib/measures/make_shading_surfaces_based_on_zone_multipliers/measure.rb +2 -0
  72. data/lib/measures/make_shading_surfaces_based_on_zone_multipliers/measure.xml +4 -4
  73. data/lib/measures/merge_floorspace_js_with_model/measure.rb +4 -1
  74. data/lib/measures/merge_floorspace_js_with_model/measure.xml +4 -4
  75. data/lib/measures/merge_spaces_from_external_file/measure.xml +3 -3
  76. data/lib/measures/radiance_measure/measure.rb +62 -56
  77. data/lib/measures/radiance_measure/measure.xml +4 -4
  78. data/lib/measures/radiant_slab_with_doas/measure.rb +4 -1
  79. data/lib/measures/radiant_slab_with_doas/measure.xml +4 -4
  80. data/lib/measures/replace_geometry_by_story/measure.rb +4 -0
  81. data/lib/measures/replace_geometry_by_story/measure.xml +4 -4
  82. data/lib/measures/scale_geometry/measure.xml +3 -3
  83. data/lib/openstudio/model_articulation/version.rb +1 -1
  84. data/openstudio-model-articulation.gemspec +1 -1
  85. metadata +7 -7
  86. data/lib/measures/blended_space_type_from_model/resources/os_lib_model_simplification.rb +0 -1049
@@ -3,8 +3,8 @@
3
3
  <schema_version>3.0</schema_version>
4
4
  <name>set_ext_wall_to_ground_boundary_condition_by_story</name>
5
5
  <uid>a6da6f2b-2d07-4d25-b2b4-4b1dd62df237</uid>
6
- <version_id>561e388e-2470-4fe4-89dd-53da429a4faa</version_id>
7
- <version_modified>20210423T142510Z</version_modified>
6
+ <version_id>1aca0c67-bb5a-4d0d-ad64-42f3829fe1ba</version_id>
7
+ <version_modified>20220505T182931Z</version_modified>
8
8
  <xml_checksum>0F858D9E</xml_checksum>
9
9
  <class_name>SetExtWallToGroundBoundaryConditionByStory</class_name>
10
10
  <display_name>SetExtWallToGroundBoundaryConditionByStory</display_name>
@@ -76,17 +76,23 @@
76
76
  <usage_type>script</usage_type>
77
77
  <checksum>D74BDE59</checksum>
78
78
  </file>
79
+ <file>
80
+ <filename>LICENSE.md</filename>
81
+ <filetype>md</filetype>
82
+ <usage_type>license</usage_type>
83
+ <checksum>A21A3ED2</checksum>
84
+ </file>
79
85
  <file>
80
86
  <filename>SetExtWallToGroundByStory_Test.rb</filename>
81
87
  <filetype>rb</filetype>
82
88
  <usage_type>test</usage_type>
83
- <checksum>250AF3F7</checksum>
89
+ <checksum>43480F51</checksum>
84
90
  </file>
85
91
  <file>
86
- <filename>LICENSE.md</filename>
87
- <filetype>md</filetype>
88
- <usage_type>license</usage_type>
89
- <checksum>A21A3ED2</checksum>
92
+ <filename>3Story2Space/run.db</filename>
93
+ <filetype>db</filetype>
94
+ <usage_type>test</usage_type>
95
+ <checksum>761DC6F7</checksum>
90
96
  </file>
91
97
  </files>
92
98
  </measure>
@@ -69,7 +69,7 @@ class SetInteriorWallsAndFloorsToAdiabatic < OpenStudio::Measure::ModelMeasure
69
69
  end
70
70
 
71
71
  # looping through sorted hash of storys
72
- construction_args_hash.sort.map do |key, value| # todo - could filter this so only constructions that are valid on opaque surfaces will show up.
72
+ construction_args_hash.sort.map do |key, value| # TODO: - could filter this so only constructions that are valid on opaque surfaces will show up.
73
73
  construction_handles << value.handle.to_s
74
74
  construction_display_names << key
75
75
  end
@@ -3,8 +3,8 @@
3
3
  <schema_version>3.0</schema_version>
4
4
  <name>set_interior_walls_and_floors_to_adiabatic</name>
5
5
  <uid>78cbde97-d7c4-425f-ab74-5053a681cc4b</uid>
6
- <version_id>f5114792-b53a-425c-911d-10fd356d8e79</version_id>
7
- <version_modified>20210423T142510Z</version_modified>
6
+ <version_id>4ceba5f6-8f6f-4969-848c-0e5ffbfdfe75</version_id>
7
+ <version_modified>20220505T182932Z</version_modified>
8
8
  <xml_checksum>1E963D9C</xml_checksum>
9
9
  <class_name>SetInteriorWallsAndFloorsToAdiabatic</class_name>
10
10
  <display_name>SetInteriorWallsAndFloorsToAdiabatic</display_name>
@@ -55,6 +55,12 @@
55
55
  <usage_type>readme</usage_type>
56
56
  <checksum>26905DFE</checksum>
57
57
  </file>
58
+ <file>
59
+ <filename>LICENSE.md</filename>
60
+ <filetype>md</filetype>
61
+ <usage_type>license</usage_type>
62
+ <checksum>A21A3ED2</checksum>
63
+ </file>
58
64
  <file>
59
65
  <version>
60
66
  <software_program>OpenStudio</software_program>
@@ -64,19 +70,13 @@
64
70
  <filename>measure.rb</filename>
65
71
  <filetype>rb</filetype>
66
72
  <usage_type>script</usage_type>
67
- <checksum>CEFB1A45</checksum>
73
+ <checksum>3EC935EF</checksum>
68
74
  </file>
69
75
  <file>
70
76
  <filename>SetInteriorWallsAndFloorsToSelectedConstruction_Test.rb</filename>
71
77
  <filetype>rb</filetype>
72
78
  <usage_type>test</usage_type>
73
- <checksum>39534274</checksum>
74
- </file>
75
- <file>
76
- <filename>LICENSE.md</filename>
77
- <filetype>md</filetype>
78
- <usage_type>license</usage_type>
79
- <checksum>A21A3ED2</checksum>
79
+ <checksum>55AAC4F2</checksum>
80
80
  </file>
81
81
  </files>
82
82
  </measure>
@@ -66,7 +66,7 @@ class SetInteriorWallsToSelectedConstruction < OpenStudio::Measure::ModelMeasure
66
66
  end
67
67
 
68
68
  # looping through sorted hash of constructions
69
- construction_args_hash.sort.map do |key, value| # todo - could filter this so only constructions that are valid on opaque surfaces will show up.
69
+ construction_args_hash.sort.map do |key, value| # TODO: - could filter this so only constructions that are valid on opaque surfaces will show up.
70
70
  construction_handles << value.handle.to_s
71
71
  construction_display_names << key
72
72
  end
@@ -3,8 +3,8 @@
3
3
  <schema_version>3.0</schema_version>
4
4
  <name>set_interior_walls_to_selected_construction</name>
5
5
  <uid>e3d59d0d-1ce8-4cb2-ae59-001f0fa2ac46</uid>
6
- <version_id>b3a51cf7-1156-4d3b-9c68-3f76f16ae570</version_id>
7
- <version_modified>20210423T142511Z</version_modified>
6
+ <version_id>bb0dd052-2f62-49ef-8e20-2e9c39786802</version_id>
7
+ <version_modified>20220505T182927Z</version_modified>
8
8
  <xml_checksum>1E963D9C</xml_checksum>
9
9
  <class_name>SetInteriorWallsToSelectedConstruction</class_name>
10
10
  <display_name>SetInteriorWallsToSelectedConstruction</display_name>
@@ -55,6 +55,12 @@
55
55
  <usage_type>readme</usage_type>
56
56
  <checksum>C8974F9D</checksum>
57
57
  </file>
58
+ <file>
59
+ <filename>LICENSE.md</filename>
60
+ <filetype>md</filetype>
61
+ <usage_type>license</usage_type>
62
+ <checksum>A21A3ED2</checksum>
63
+ </file>
58
64
  <file>
59
65
  <version>
60
66
  <software_program>OpenStudio</software_program>
@@ -64,19 +70,13 @@
64
70
  <filename>measure.rb</filename>
65
71
  <filetype>rb</filetype>
66
72
  <usage_type>script</usage_type>
67
- <checksum>0293AC5B</checksum>
73
+ <checksum>DC3C3C85</checksum>
68
74
  </file>
69
75
  <file>
70
76
  <filename>SetInteriorWallstoSelectedConstruction_Test.rb</filename>
71
77
  <filetype>rb</filetype>
72
78
  <usage_type>test</usage_type>
73
- <checksum>EE1A5054</checksum>
74
- </file>
75
- <file>
76
- <filename>LICENSE.md</filename>
77
- <filetype>md</filetype>
78
- <usage_type>license</usage_type>
79
- <checksum>A21A3ED2</checksum>
79
+ <checksum>17B7EFF1</checksum>
80
80
  </file>
81
81
  </files>
82
82
  </measure>
@@ -100,6 +100,17 @@ This will only impact exterior surfaces with specified orientation
100
100
 
101
101
 
102
102
 
103
+ ### Triangulation Minimum Area (m^2)
104
+ Triangulated surfaces less than this will not be created.
105
+ **Name:** triangulation_min_area,
106
+ **Type:** Double,
107
+ **Units:** ,
108
+ **Required:** true,
109
+ **Model Dependent:** false
110
+
111
+
112
+
113
+
103
114
 
104
115
 
105
116
 
@@ -33,6 +33,8 @@
33
33
  # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
34
  # *******************************************************************************
35
35
 
36
+ require_relative 'resources/functions'
37
+
36
38
  class SetWindowToWallRatioByFacade < OpenStudio::Measure::ModelMeasure
37
39
  # override name to return the name of your script
38
40
  def name
@@ -97,6 +99,13 @@ class SetWindowToWallRatioByFacade < OpenStudio::Measure::ModelMeasure
97
99
  triangulate.setDefaultValue(true)
98
100
  args << triangulate
99
101
 
102
+ # triangulation minimum area
103
+ triangulation_min_area = OpenStudio::Measure::OSArgument.makeDoubleArgument('triangulation_min_area', true)
104
+ triangulation_min_area.setDisplayName('Triangulation Minimum Area (m^2)')
105
+ triangulation_min_area.setDescription('Triangulated surfaces less than this will not be created.')
106
+ triangulation_min_area.setDefaultValue(0.001) # Two vertices < 0.01 meters apart are coincident in EnergyPlus (SurfaceGeometry.cc).
107
+ args << triangulation_min_area
108
+
100
109
  return args
101
110
  end
102
111
 
@@ -117,6 +126,7 @@ class SetWindowToWallRatioByFacade < OpenStudio::Measure::ModelMeasure
117
126
  split_at_doors = runner.getStringArgumentValue('split_at_doors', user_arguments)
118
127
  inset_tri_sub = runner.getBoolArgumentValue('inset_tri_sub', user_arguments)
119
128
  triangulate = runner.getBoolArgumentValue('triangulate', user_arguments)
129
+ triangulation_min_area = runner.getDoubleArgumentValue('triangulation_min_area', user_arguments)
120
130
 
121
131
  # check reasonableness of fraction
122
132
  if wwr == 0
@@ -192,6 +202,7 @@ class SetWindowToWallRatioByFacade < OpenStudio::Measure::ModelMeasure
192
202
  surfaces = []
193
203
  model.getSpaces.sort.each do |space|
194
204
  next if !space.partofTotalFloorArea
205
+
195
206
  space.surfaces.sort.each do |surface|
196
207
  surfaces << surface
197
208
  end
@@ -201,79 +212,14 @@ class SetWindowToWallRatioByFacade < OpenStudio::Measure::ModelMeasure
201
212
  end
202
213
 
203
214
  # used for new sub surfaces to find target construction
204
- orig_sub_surf_const_for_target_facade = {}
205
- orig_sub_surf_const_for_target_all_ext = {}
206
-
207
- # pre-loop through sub-surfaces to store constructions
208
- model.getSubSurfaces.sort.each do |sub_surf|
209
- # store constructions for entire building
210
- next if sub_surf.subSurfaceType == 'Door' || sub_surf.subSurfaceType == 'OverheadDoor'
211
- if sub_surf.construction.is_initialized
212
- if orig_sub_surf_const_for_target_all_ext.key?(sub_surf.construction.get)
213
- orig_sub_surf_const_for_target_all_ext[sub_surf.construction.get] += 1
214
- else
215
- orig_sub_surf_const_for_target_all_ext[sub_surf.construction.get] = 1
216
- end
217
- end
218
-
219
- # get the absoluteAzimuth for the surface so we can categorize it
220
- absoluteAzimuth = OpenStudio.convert(sub_surf.azimuth, 'rad', 'deg').get + sub_surf.surface.get.space.get.directionofRelativeNorth + model.getBuilding.northAxis
221
- absoluteAzimuth -= 360.0 until absoluteAzimuth < 360.0
222
-
223
- if facade == 'North'
224
- next if !((absoluteAzimuth >= 315.0) || (absoluteAzimuth < 45.0))
225
- elsif facade == 'East'
226
- next if !((absoluteAzimuth >= 45.0) && (absoluteAzimuth < 135.0))
227
- elsif facade == 'South'
228
- next if !((absoluteAzimuth >= 135.0) && (absoluteAzimuth < 225.0))
229
- elsif facade == 'West'
230
- next if !((absoluteAzimuth >= 225.0) && (absoluteAzimuth < 315.0))
231
- elsif facade == 'All'
232
- # no next needed
233
- else
234
- runner.registerError('Unexpected value of facade: ' + facade + '.')
235
- return false
236
- end
237
-
238
- # store constructions for this facade
239
- if sub_surf.construction.is_initialized
240
- if orig_sub_surf_const_for_target_facade.key?(sub_surf.construction.get)
241
- orig_sub_surf_const_for_target_facade[sub_surf.construction.get] += 1
242
- else
243
- orig_sub_surf_const_for_target_facade[sub_surf.construction.get] = 1
244
- end
245
- end
246
- end
215
+ subsurfaces_by_facade = Functions.get_surfaces_or_subsurfaces_by_facade(model.getSubSurfaces, facade)
216
+ orig_sub_surf_const_for_target_facade = Functions.get_orig_sub_surf_const_for_target(subsurfaces_by_facade)
217
+ orig_sub_surf_const_for_target_all_ext = Functions.get_orig_sub_surf_const_for_target(model.getSubSurfaces)
247
218
 
248
219
  # hash for sub surfaces removed from non rectangular surfaces
249
220
  non_rect_parent = {}
250
221
 
251
- surfaces.sort.each do |s|
252
- next if s.surfaceType != 'Wall'
253
- next if s.outsideBoundaryCondition != 'Outdoors'
254
- if s.space.empty?
255
- runner.registerWarning("#{s.name} doesn't have a parent space and won't be included in the measure reporting or modifications.")
256
- next
257
- end
258
-
259
- # get the absoluteAzimuth for the surface so we can categorize it
260
- absoluteAzimuth = OpenStudio.convert(s.azimuth, 'rad', 'deg').get + s.space.get.directionofRelativeNorth + model.getBuilding.northAxis
261
- absoluteAzimuth -= 360.0 until absoluteAzimuth < 360.0
262
-
263
- if facade == 'North'
264
- next if !((absoluteAzimuth >= 315.0) || (absoluteAzimuth < 45.0))
265
- elsif facade == 'East'
266
- next if !((absoluteAzimuth >= 45.0) && (absoluteAzimuth < 135.0))
267
- elsif facade == 'South'
268
- next if !((absoluteAzimuth >= 135.0) && (absoluteAzimuth < 225.0))
269
- elsif facade == 'West'
270
- next if !((absoluteAzimuth >= 225.0) && (absoluteAzimuth < 315.0))
271
- elsif facade == 'All'
272
- # no next needed
273
- else
274
- runner.registerError('Unexpected value of facade: ' + facade + '.')
275
- return false
276
- end
222
+ Functions.get_surfaces_or_subsurfaces_by_facade(model.getSurfaces, facade).sort.each do |s|
277
223
  exterior_walls = true
278
224
 
279
225
  # get surface area adjusting for zone multiplier
@@ -320,7 +266,8 @@ class SetWindowToWallRatioByFacade < OpenStudio::Measure::ModelMeasure
320
266
 
321
267
  # remove windows before split at doors
322
268
  s.subSurfaces.each do |sub_surface|
323
- next if ['Door','OverheadDoor'].include? sub_surface.subSurfaceType
269
+ next if ['Door', 'OverheadDoor'].include? sub_surface.subSurfaceType
270
+
324
271
  sub_surface.remove
325
272
  end
326
273
 
@@ -339,22 +286,7 @@ class SetWindowToWallRatioByFacade < OpenStudio::Measure::ModelMeasure
339
286
  all_surfaces.sort.each do |ss|
340
287
  # see if surface is rectangular (only checking non rotated on vertical wall)
341
288
  # todo - add in more robust rectangle check that can look for rotate and tilted rectangles
342
- rect_tri = false
343
- x_vals = []
344
- y_vals = []
345
- z_vals = []
346
- vertices = ss.vertices
347
- flag = false
348
- vertices.each do |vertex|
349
- # initialize new vertex to old vertex
350
- # rounding values to address tolerance issue 10 digits digits in
351
- x_vals << vertex.x.round(4)
352
- y_vals << vertex.y.round(4)
353
- z_vals << vertex.z.round(4)
354
- end
355
- if x_vals.uniq.size <= 2 && y_vals.uniq.size <= 2 && z_vals.uniq.size <= 2
356
- rect_tri = true
357
- end
289
+ rect_tri = Functions.rectangle?(ss)
358
290
 
359
291
  has_doors = false
360
292
  ss.subSurfaces.sort.each do |subSurface|
@@ -384,8 +316,14 @@ class SetWindowToWallRatioByFacade < OpenStudio::Measure::ModelMeasure
384
316
  subSurface.remove
385
317
  end
386
318
 
319
+ # triangulate surface
387
320
  ss.triangulation.each do |tri|
388
321
  new_surface = OpenStudio::Model::Surface.new(tri, model)
322
+ if new_surface.grossArea < triangulation_min_area
323
+ runner.registerWarning("triangulation produced a surface with area less than minimum for surface = #{ss.name}")
324
+ new_surface.remove
325
+ next
326
+ end
389
327
  new_surface.setSpace(ss.space.get)
390
328
  if ss.construction.is_initialized && !ss.isConstructionDefaulted
391
329
  new_surface.setConstruction(ss.construction.get)
@@ -409,6 +347,7 @@ class SetWindowToWallRatioByFacade < OpenStudio::Measure::ModelMeasure
409
347
  orig_sub_surf_constructions = {}
410
348
  ss.subSurfaces.sort.each do |sub_surf|
411
349
  next if sub_surf.subSurfaceType == 'Door' || sub_surf.subSurfaceType == 'OverheadDoor'
350
+
412
351
  if sub_surf.construction.is_initialized
413
352
  if orig_sub_surf_constructions.key?(sub_surf.construction.get)
414
353
  orig_sub_surf_constructions[sub_surf.construction.get] += 1
@@ -432,38 +371,35 @@ class SetWindowToWallRatioByFacade < OpenStudio::Measure::ModelMeasure
432
371
  if wwr > 0 && new_window.empty?
433
372
 
434
373
  # if new window is empty then inset base surface to add window (check may need to skip on base surfaces with doors)
435
- if inset_tri_sub
436
-
437
- # skip of surface already has sub-surfaces or if not triangle
438
- if ss.subSurfaces.empty? && ss.vertices.size <= 3
439
- # get centroid
440
- vertices = ss.vertices
441
- centroid = OpenStudio.getCentroid(vertices).get
442
- x_cent = centroid.x
443
- y_cent = centroid.y
444
- z_cent = centroid.z
445
-
446
- # reduce vertices towards centroid
447
- scale = Math.sqrt(wwr)
448
- new_vertices = OpenStudio::Point3dVector.new
449
- vertices.each do |vertex|
450
- x = (vertex.x * scale + x_cent * (1.0 - scale))
451
- y = (vertex.y * scale + y_cent * (1.0 - scale))
452
- z = (vertex.z * scale + z_cent * (1.0 - scale))
453
- new_vertices << OpenStudio::Point3d.new(x, y, z)
454
- end
455
-
456
- # create inset window
457
- new_window = OpenStudio::Model::SubSurface.new(new_vertices, model)
458
- new_window.setSurface(ss)
459
- new_window.setSubSurfaceType('FixedWindow')
460
- if non_rect_parent.key?(ss)
461
- new_window.setConstruction(non_rect_parent[ss])
462
- end
463
- window_confirmed = true
374
+ # skip of surface already has sub-surfaces or if not triangle
375
+ if inset_tri_sub && (ss.subSurfaces.empty? && ss.vertices.size <= 3)
376
+ # get centroid
377
+ vertices = ss.vertices
378
+ centroid = OpenStudio.getCentroid(vertices).get
379
+ x_cent = centroid.x
380
+ y_cent = centroid.y
381
+ z_cent = centroid.z
382
+
383
+ # reduce vertices towards centroid
384
+ scale = Math.sqrt(wwr)
385
+ new_vertices = OpenStudio::Point3dVector.new
386
+ vertices.each do |vertex|
387
+ x = (vertex.x * scale + x_cent * (1.0 - scale))
388
+ y = (vertex.y * scale + y_cent * (1.0 - scale))
389
+ z = (vertex.z * scale + z_cent * (1.0 - scale))
390
+ new_vertices << OpenStudio::Point3d.new(x, y, z)
464
391
  end
465
392
 
393
+ # create inset window
394
+ new_window = OpenStudio::Model::SubSurface.new(new_vertices, model)
395
+ new_window.setSurface(ss)
396
+ new_window.setSubSurfaceType('FixedWindow')
397
+ if non_rect_parent.key?(ss)
398
+ new_window.setConstruction(non_rect_parent[ss])
399
+ end
400
+ window_confirmed = true
466
401
  end
402
+
467
403
  else
468
404
  if wwr > 0
469
405
  new_window = new_window.get
@@ -472,7 +408,38 @@ class SetWindowToWallRatioByFacade < OpenStudio::Measure::ModelMeasure
472
408
  end
473
409
 
474
410
  if !window_confirmed
475
- runner.registerWarning("Fenestration could not be added for #{ss.name}. Surface may not be rectangular or triangular, may have a door, or the requested WWR may be too large.")
411
+ case ss.vertices.size
412
+ when 3
413
+ if !inset_tri_sub
414
+ runner.registerWarning("window could not be added because the surface has 3 sides, but the inset_tri_sub argument is false = #{ss.name}")
415
+ end
416
+ when 4
417
+ case Functions.rectangle?(ss)
418
+ when true
419
+ # if Functions.requested_window_area_greater_than_max?(ss, wwr)
420
+ # runner.registerWarning("window could not be added because the surface has 4 sides and is rectangular, but the WWR exceeds the maximum = #{ss.name}")
421
+ # end
422
+ # HACK until requested_window_area_greater_than_max? works. reduce by 0.01 to find the "maximum".
423
+ (1..(wwr / 0.1).floor).each do |i|
424
+ wwr_adj = wwr - (i / 100.0)
425
+ new_window = ss.setWindowToWallRatio(wwr_adj, sillHeight_si.value, true)
426
+ unless new_window.empty?
427
+ new_window = new_window.get
428
+ window_confirmed = true
429
+ runner.registerWarning("window-to-wall ratio exceeds maximum and was reduced to #{wwr_adj.round(3)} for surface = #{ss.name}")
430
+ break
431
+ end
432
+ end
433
+ when false
434
+ if !triangulate
435
+ runner.registerWarning("window could not be added because the surface has 4 sides, but is not rectangular and the triangulate argument is false = #{ss.name}")
436
+ end
437
+ end
438
+ else
439
+ if !triangulate
440
+ runner.registerWarning("window could not be added because the surface has more than 4 sides and the triangulate argument is false = #{ss.name}")
441
+ end
442
+ end
476
443
  end
477
444
 
478
445
  # warn user if resulting window doesn't have a construction, as it will result in failed simulation. In the future may use logic from starting windows to apply construction to new window.
@@ -529,33 +496,7 @@ class SetWindowToWallRatioByFacade < OpenStudio::Measure::ModelMeasure
529
496
  end
530
497
 
531
498
  # data for final condition wwr
532
- surfaces.sort.each do |s|
533
- next if s.surfaceType != 'Wall'
534
- next if s.outsideBoundaryCondition != 'Outdoors'
535
- if s.space.empty?
536
- runner.registerWarning("#{s.name} doesn't have a parent space and won't be included in the measure reporting or modifications.")
537
- next
538
- end
539
-
540
- # get the absoluteAzimuth for the surface so we can categorize it
541
- absoluteAzimuth = OpenStudio.convert(s.azimuth, 'rad', 'deg').get + s.space.get.directionofRelativeNorth + model.getBuilding.northAxis
542
- absoluteAzimuth -= 360.0 until absoluteAzimuth < 360.0
543
-
544
- if facade == 'North'
545
- next if !((absoluteAzimuth >= 315.0) || (absoluteAzimuth < 45.0))
546
- elsif facade == 'East'
547
- next if !((absoluteAzimuth >= 45.0) && (absoluteAzimuth < 135.0))
548
- elsif facade == 'South'
549
- next if !((absoluteAzimuth >= 135.0) && (absoluteAzimuth < 225.0))
550
- elsif facade == 'West'
551
- next if !((absoluteAzimuth >= 225.0) && (absoluteAzimuth < 315.0))
552
- elsif facade == 'All'
553
- # no next needed
554
- else
555
- runner.registerError('Unexpected value of facade: ' + facade + '.')
556
- return false
557
- end
558
-
499
+ Functions.get_surfaces_or_subsurfaces_by_facade(model.getSurfaces, facade).sort.each do |s|
559
500
  # get surface area adjusting for zone multiplier
560
501
  space = s.space
561
502
  if !space.empty?
@@ -3,8 +3,8 @@
3
3
  <schema_version>3.0</schema_version>
4
4
  <name>set_window_to_wall_ratio_by_facade</name>
5
5
  <uid>c567a0bf-a7d9-4a06-afe9-bf7df79e6bf8</uid>
6
- <version_id>a02e024d-a1ca-413a-90e2-372cfc217228</version_id>
7
- <version_modified>20210929T221458Z</version_modified>
6
+ <version_id>d0d69032-509b-4257-a4c5-74e0e4615cc4</version_id>
7
+ <version_modified>20220505T182928Z</version_modified>
8
8
  <xml_checksum>6DE831F7</xml_checksum>
9
9
  <class_name>SetWindowToWallRatioByFacade</class_name>
10
10
  <display_name>Set Window to Wall Ratio by Facade</display_name>
@@ -153,6 +153,15 @@ The measure doesn?t have any cost or lifecycle arguments, however If lifecycle o
153
153
  </choice>
154
154
  </choices>
155
155
  </argument>
156
+ <argument>
157
+ <name>triangulation_min_area</name>
158
+ <display_name>Triangulation Minimum Area (m^2)</display_name>
159
+ <description>Triangulated surfaces less than this will not be created.</description>
160
+ <type>Double</type>
161
+ <required>true</required>
162
+ <model_dependent>false</model_dependent>
163
+ <default_value>0.001</default_value>
164
+ </argument>
156
165
  </arguments>
157
166
  <outputs />
158
167
  <provenances />
@@ -212,17 +221,29 @@ The measure doesn?t have any cost or lifecycle arguments, however If lifecycle o
212
221
  <usage_type>readmeerb</usage_type>
213
222
  <checksum>232D0477</checksum>
214
223
  </file>
224
+ <file>
225
+ <filename>LICENSE.md</filename>
226
+ <filetype>md</filetype>
227
+ <usage_type>license</usage_type>
228
+ <checksum>A21A3ED2</checksum>
229
+ </file>
230
+ <file>
231
+ <filename>prototype_sec_sch.osm</filename>
232
+ <filetype>osm</filetype>
233
+ <usage_type>test</usage_type>
234
+ <checksum>581DA01B</checksum>
235
+ </file>
215
236
  <file>
216
237
  <filename>README.md</filename>
217
238
  <filetype>md</filetype>
218
239
  <usage_type>readme</usage_type>
219
- <checksum>C85B9D94</checksum>
240
+ <checksum>7FCCDC8E</checksum>
220
241
  </file>
221
242
  <file>
222
- <filename>LICENSE.md</filename>
223
- <filetype>md</filetype>
224
- <usage_type>license</usage_type>
225
- <checksum>A21A3ED2</checksum>
243
+ <filename>SetWindowToWallRatioByFacade_Test.rb</filename>
244
+ <filetype>rb</filetype>
245
+ <usage_type>test</usage_type>
246
+ <checksum>2FAF08A3</checksum>
226
247
  </file>
227
248
  <file>
228
249
  <version>
@@ -233,19 +254,13 @@ The measure doesn?t have any cost or lifecycle arguments, however If lifecycle o
233
254
  <filename>measure.rb</filename>
234
255
  <filetype>rb</filetype>
235
256
  <usage_type>script</usage_type>
236
- <checksum>6631CF18</checksum>
257
+ <checksum>E1F85411</checksum>
237
258
  </file>
238
259
  <file>
239
- <filename>SetWindowToWallRatioByFacade_Test.rb</filename>
260
+ <filename>functions.rb</filename>
240
261
  <filetype>rb</filetype>
241
- <usage_type>test</usage_type>
242
- <checksum>0F626DE3</checksum>
243
- </file>
244
- <file>
245
- <filename>prototype_sec_sch.osm</filename>
246
- <filetype>osm</filetype>
247
- <usage_type>test</usage_type>
248
- <checksum>581DA01B</checksum>
262
+ <usage_type>resource</usage_type>
263
+ <checksum>8AFBC32D</checksum>
249
264
  </file>
250
265
  </files>
251
266
  </measure>