honeybee-openstudio 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.
Files changed (130) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yaml +88 -0
  3. data/.gitignore +33 -0
  4. data/.releaserc.json +7 -0
  5. data/Gemfile +14 -0
  6. data/LICENSE.md +23 -0
  7. data/README.md +95 -0
  8. data/Rakefile +16 -0
  9. data/doc_templates/LICENSE.md +23 -0
  10. data/doc_templates/README.md.erb +42 -0
  11. data/doc_templates/copyright_erb.txt +32 -0
  12. data/doc_templates/copyright_js.txt +5 -0
  13. data/doc_templates/copyright_ruby.txt +30 -0
  14. data/honeybee-openstudio.gemspec +38 -0
  15. data/lib/files/Honeybee.rb +113 -0
  16. data/lib/files/honeybee_workflow.osw +48 -0
  17. data/lib/files/urbanopt_Gemfile +32 -0
  18. data/lib/from_openstudio.rb +49 -0
  19. data/lib/from_openstudio/geometry/aperture.rb +136 -0
  20. data/lib/from_openstudio/geometry/door.rb +136 -0
  21. data/lib/from_openstudio/geometry/face.rb +174 -0
  22. data/lib/from_openstudio/geometry/room.rb +121 -0
  23. data/lib/from_openstudio/geometry/shade.rb +87 -0
  24. data/lib/from_openstudio/model.rb +123 -0
  25. data/lib/from_openstudio/model_object.rb +43 -0
  26. data/lib/from_openstudio/simulation/design_day.rb +123 -0
  27. data/lib/from_openstudio/simulation/parameter_model.rb +93 -0
  28. data/lib/from_openstudio/simulation/simulation_output.rb +67 -0
  29. data/lib/honeybee.rb +93 -0
  30. data/lib/honeybee/_defaults/energy_default.json +1682 -0
  31. data/lib/honeybee/_defaults/model.json +11311 -0
  32. data/lib/honeybee/_defaults/simulation-parameter.json +973 -0
  33. data/lib/honeybee/construction/air.rb +42 -0
  34. data/lib/honeybee/construction/opaque.rb +42 -0
  35. data/lib/honeybee/construction/shade.rb +42 -0
  36. data/lib/honeybee/construction/window.rb +51 -0
  37. data/lib/honeybee/construction/windowshade.rb +43 -0
  38. data/lib/honeybee/construction_set.rb +42 -0
  39. data/lib/honeybee/extension.rb +129 -0
  40. data/lib/honeybee/geometry/aperture.rb +42 -0
  41. data/lib/honeybee/geometry/door.rb +42 -0
  42. data/lib/honeybee/geometry/face.rb +48 -0
  43. data/lib/honeybee/geometry/room.rb +56 -0
  44. data/lib/honeybee/geometry/shade.rb +42 -0
  45. data/lib/honeybee/hvac/ideal_air.rb +42 -0
  46. data/lib/honeybee/hvac/template.rb +73 -0
  47. data/lib/honeybee/load/electric_equipment.rb +42 -0
  48. data/lib/honeybee/load/gas_equipment.rb +42 -0
  49. data/lib/honeybee/load/infiltration.rb +42 -0
  50. data/lib/honeybee/load/lighting.rb +43 -0
  51. data/lib/honeybee/load/people.rb +42 -0
  52. data/lib/honeybee/load/setpoint_humidistat.rb +46 -0
  53. data/lib/honeybee/load/setpoint_thermostat.rb +46 -0
  54. data/lib/honeybee/load/ventilation.rb +42 -0
  55. data/lib/honeybee/material/opaque.rb +42 -0
  56. data/lib/honeybee/material/opaque_no_mass.rb +42 -0
  57. data/lib/honeybee/material/window_blind.rb +42 -0
  58. data/lib/honeybee/material/window_gas.rb +42 -0
  59. data/lib/honeybee/material/window_gas_custom.rb +42 -0
  60. data/lib/honeybee/material/window_gas_mixture.rb +42 -0
  61. data/lib/honeybee/material/window_glazing.rb +42 -0
  62. data/lib/honeybee/material/window_shade.rb +42 -0
  63. data/lib/honeybee/material/window_simpleglazsys.rb +42 -0
  64. data/lib/honeybee/model.rb +87 -0
  65. data/lib/honeybee/model_object.rb +108 -0
  66. data/lib/honeybee/program_type.rb +56 -0
  67. data/lib/honeybee/schedule/fixed_interval.rb +42 -0
  68. data/lib/honeybee/schedule/ruleset.rb +42 -0
  69. data/lib/honeybee/schedule/type_limit.rb +42 -0
  70. data/lib/honeybee/simulation/design_day.rb +42 -0
  71. data/lib/honeybee/simulation/parameter_model.rb +86 -0
  72. data/lib/honeybee/simulation/simulation_output.rb +42 -0
  73. data/lib/honeybee/ventcool/control.rb +42 -0
  74. data/lib/honeybee/ventcool/opening.rb +46 -0
  75. data/lib/honeybee/ventcool/simulation.rb +42 -0
  76. data/lib/measures/.gitkeep +0 -0
  77. data/lib/measures/from_honeybee_model/LICENSE.md +23 -0
  78. data/lib/measures/from_honeybee_model/README.md +32 -0
  79. data/lib/measures/from_honeybee_model/measure.rb +91 -0
  80. data/lib/measures/from_honeybee_model/measure.xml +80 -0
  81. data/lib/measures/from_honeybee_model/tests/from_honeybee_model_test.rb +126 -0
  82. data/lib/measures/from_honeybee_simulation_parameter/LICENSE.md +23 -0
  83. data/lib/measures/from_honeybee_simulation_parameter/README.md +32 -0
  84. data/lib/measures/from_honeybee_simulation_parameter/measure.rb +95 -0
  85. data/lib/measures/from_honeybee_simulation_parameter/measure.xml +86 -0
  86. data/lib/measures/from_honeybee_simulation_parameter/tests/from_honeybee_simulation_parameter_test.rb +109 -0
  87. data/lib/to_openstudio.rb +92 -0
  88. data/lib/to_openstudio/construction/air.rb +56 -0
  89. data/lib/to_openstudio/construction/opaque.rb +67 -0
  90. data/lib/to_openstudio/construction/shade.rb +99 -0
  91. data/lib/to_openstudio/construction/window.rb +70 -0
  92. data/lib/to_openstudio/construction/windowshade.rb +196 -0
  93. data/lib/to_openstudio/construction_set.rb +266 -0
  94. data/lib/to_openstudio/geometry/aperture.rb +157 -0
  95. data/lib/to_openstudio/geometry/door.rb +150 -0
  96. data/lib/to_openstudio/geometry/face.rb +178 -0
  97. data/lib/to_openstudio/geometry/room.rb +442 -0
  98. data/lib/to_openstudio/geometry/shade.rb +79 -0
  99. data/lib/to_openstudio/hvac/Model.hvac.rb +641 -0
  100. data/lib/to_openstudio/hvac/ideal_air.rb +141 -0
  101. data/lib/to_openstudio/hvac/template.rb +169 -0
  102. data/lib/to_openstudio/load/electric_equipment.rb +87 -0
  103. data/lib/to_openstudio/load/gas_equipment.rb +88 -0
  104. data/lib/to_openstudio/load/infiltration.rb +86 -0
  105. data/lib/to_openstudio/load/lighting.rb +89 -0
  106. data/lib/to_openstudio/load/people.rb +91 -0
  107. data/lib/to_openstudio/load/setpoint_humidistat.rb +66 -0
  108. data/lib/to_openstudio/load/setpoint_thermostat.rb +62 -0
  109. data/lib/to_openstudio/load/ventilation.rb +87 -0
  110. data/lib/to_openstudio/material/opaque.rb +85 -0
  111. data/lib/to_openstudio/material/opaque_no_mass.rb +85 -0
  112. data/lib/to_openstudio/material/window_blind.rb +229 -0
  113. data/lib/to_openstudio/material/window_gas.rb +67 -0
  114. data/lib/to_openstudio/material/window_gas_custom.rb +108 -0
  115. data/lib/to_openstudio/material/window_gas_mixture.rb +70 -0
  116. data/lib/to_openstudio/material/window_glazing.rb +157 -0
  117. data/lib/to_openstudio/material/window_shade.rb +151 -0
  118. data/lib/to_openstudio/material/window_simpleglazsys.rb +64 -0
  119. data/lib/to_openstudio/model.rb +497 -0
  120. data/lib/to_openstudio/model_object.rb +52 -0
  121. data/lib/to_openstudio/program_type.rb +104 -0
  122. data/lib/to_openstudio/schedule/fixed_interval.rb +105 -0
  123. data/lib/to_openstudio/schedule/ruleset.rb +164 -0
  124. data/lib/to_openstudio/schedule/type_limit.rb +76 -0
  125. data/lib/to_openstudio/simulation/design_day.rb +96 -0
  126. data/lib/to_openstudio/simulation/parameter_model.rb +243 -0
  127. data/lib/to_openstudio/ventcool/control.rb +185 -0
  128. data/lib/to_openstudio/ventcool/opening.rb +189 -0
  129. data/lib/to_openstudio/ventcool/simulation.rb +101 -0
  130. metadata +301 -0
@@ -0,0 +1,178 @@
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 'honeybee/geometry/face'
33
+
34
+ require 'to_openstudio/model_object'
35
+
36
+ module Honeybee
37
+ class Face < ModelObject
38
+
39
+ def find_existing_openstudio_object(openstudio_model)
40
+ model_surf = openstudio_model.getSurfaceByName(@hash[:identifier])
41
+ return model_surf.get unless model_surf.empty?
42
+ nil
43
+ end
44
+
45
+ def to_openstudio(openstudio_model)
46
+ # reorder the vertices to ensure they start from the upper-left corner
47
+ os_vertices = OpenStudio::Point3dVector.new
48
+ @hash[:geometry][:boundary].each do |vertex|
49
+ os_vertices << OpenStudio::Point3d.new(vertex[0], vertex[1], vertex[2])
50
+ end
51
+ reordered_vertices = OpenStudio.reorderULC(os_vertices)
52
+
53
+ # create the openstudio surface and assign the type
54
+ os_surface = OpenStudio::Model::Surface.new(reordered_vertices, openstudio_model)
55
+ os_surface.setName(@hash[:identifier])
56
+ os_surface.setSurfaceType(@hash[:face_type])
57
+
58
+ # assign the construction if it is present
59
+ if @hash[:properties][:energy][:construction]
60
+ construction_identifier = @hash[:properties][:energy][:construction]
61
+ construction = openstudio_model.getConstructionByName(construction_identifier)
62
+ unless construction.empty?
63
+ os_construction = construction.get
64
+ os_surface.setConstruction(os_construction)
65
+ end
66
+ end
67
+
68
+ # assign the AFN crack if it's specified and we are not using simple infiltration
69
+ if !$use_simple_vent && @hash[:properties][:energy][:vent_crack]
70
+ unless $interior_afn_srf_hash[@hash[:identifier]] # interior crack that's been accounted for
71
+ vent_crack = @hash[:properties][:energy][:vent_crack]
72
+ # create the crack object for using default values
73
+ flow_exponent = crack_defaults[:flow_exponent][:default].to_f
74
+ os_crack = OpenStudio::Model::AirflowNetworkCrack.new(
75
+ openstudio_model, vent_crack[:flow_coefficient], flow_exponent,
76
+ $afn_reference_crack)
77
+
78
+ # assign the flow exponent if it's specified
79
+ if vent_crack[:flow_exponent]
80
+ os_crack. setAirMassFlowExponent(vent_crack[:flow_exponent])
81
+ end
82
+
83
+ # if it's a Surface boundary condition ensure the neighbor is not written as a duplicate
84
+ if @hash[:boundary_condition][:type] == 'Surface'
85
+ $interior_afn_srf_hash[@hash[:boundary_condition][:boundary_condition_objects][0]] = true
86
+ end
87
+
88
+ # create the AirflowNetworkSurface
89
+ os_afn_srf = os_surface.getAirflowNetworkSurface(os_crack)
90
+
91
+ end
92
+ end
93
+
94
+ # assign the boundary condition
95
+ boundary_condition = (@hash[:boundary_condition][:type])
96
+ case boundary_condition
97
+ when 'Outdoors'
98
+ if @hash[:boundary_condition][:sun_exposure] == false
99
+ os_surface.setSunExposure('NoSun')
100
+ else
101
+ os_surface.setSunExposure('SunExposed')
102
+ end
103
+ if @hash[:boundary_condition][:wind_exposure] == false
104
+ os_surface.setWindExposure('NoWind')
105
+ else
106
+ os_surface.setWindExposure('WindExposed')
107
+ end
108
+ if @hash[:boundary_condition][:view_factor].is_a? Numeric
109
+ os_surface.setViewFactortoGround(@hash[:boundary_condition][:view_factor])
110
+ else
111
+ os_surface.autocalculateViewFactortoGround
112
+ end
113
+ when 'Surface'
114
+ # get adjacent surface by identifier from openstudio model
115
+ adj_srf_identifier = @hash[:boundary_condition][:boundary_condition_objects][0]
116
+ surface_object = openstudio_model.getSurfaceByName(adj_srf_identifier)
117
+ unless surface_object.empty?
118
+ surface = surface_object.get
119
+ os_surface.setAdjacentSurface(surface)
120
+ end
121
+ end
122
+ unless @hash[:boundary_condition][:type] == 'Surface'
123
+ os_surface.setOutsideBoundaryCondition(@hash[:boundary_condition][:type])
124
+ end
125
+
126
+ # assign apertures if they exist
127
+ if @hash[:apertures]
128
+ @hash[:apertures].each do |aperture|
129
+ ladybug_aperture = Aperture.new(aperture)
130
+ os_subsurface_apertures = ladybug_aperture.to_openstudio(openstudio_model)
131
+ os_subsurface_apertures.each do |os_subsurface_aperture|
132
+ if @hash[:face_type] == 'RoofCeiling' or @hash[:face_type] == 'Floor'
133
+ if @hash[:boundary_condition][:type] == 'Outdoors' && aperture[:is_operable] == false
134
+ os_subsurface_aperture.setSubSurfaceType('Skylight')
135
+ end
136
+ end
137
+ os_subsurface_aperture.setSurface(os_surface)
138
+ end
139
+ end
140
+ end
141
+
142
+ # assign doors if they exist
143
+ if @hash[:doors]
144
+ @hash[:doors].each do |door|
145
+ honeybee_door = Door.new(door)
146
+ os_subsurface_doors = honeybee_door.to_openstudio(openstudio_model)
147
+ os_subsurface_doors.each do |os_subsurface_door|
148
+ os_subsurface_door.setSurface(os_surface)
149
+ if door[:is_glass] == true
150
+ os_subsurface_door.setSubSurfaceType('GlassDoor')
151
+ elsif (@hash[:face_type] == 'RoofCeiling' or @hash[:face_type] == 'Floor') && @hash[:boundary_condition][:type] == 'Outdoors'
152
+ os_subsurface_door.setSubSurfaceType('OverheadDoor')
153
+ elsif door[:is_glass] == false or door[:is_glass].nil?
154
+ os_subsurface_door.setSubSurfaceType('Door')
155
+ end
156
+ end
157
+ end
158
+ end
159
+
160
+ os_surface.subSurfaces.each do |os_subsurface|
161
+ if os_subsurface.hasAdditionalProperties
162
+ adj_sub_srf_identifier = os_subsurface.additionalProperties.getFeatureAsString("AdjacentSubSurfaceName")
163
+ unless adj_sub_srf_identifier.empty?
164
+ adj_sub_srf = openstudio_model.getSubSurfaceByName(adj_sub_srf_identifier.get)
165
+ unless adj_sub_srf.empty?
166
+ os_subsurface.setAdjacentSubSurface(adj_sub_srf.get)
167
+ end
168
+ end
169
+
170
+ # clean up, we don't need this object any more
171
+ os_subsurface.removeAdditionalProperties
172
+ end
173
+ end
174
+
175
+ os_surface
176
+ end
177
+ end # Face
178
+ end # Honeybee
@@ -0,0 +1,442 @@
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 'honeybee/geometry/room'
33
+
34
+ require 'to_openstudio/model_object'
35
+
36
+ module Honeybee
37
+ class Room
38
+
39
+ attr_reader :unique_space_type
40
+
41
+ def find_existing_openstudio_object(openstudio_model)
42
+ model_space = openstudio_model.getSpaceByName(@hash[:identifier])
43
+ return model_space.get unless model_space.empty?
44
+ nil
45
+ end
46
+
47
+ def get_unique_space_type(openstudio_model, os_space)
48
+ # get a space type that is unique to the room
49
+ if @unique_space_type.nil?
50
+ space_type = os_space.spaceType
51
+ unless space_type.empty?
52
+ # copy the space type that is already assigned to the room
53
+ space_type_object = space_type.get
54
+ space_type_mod_obj = space_type_object.clone(openstudio_model)
55
+ new_space_type = space_type_mod_obj.to_SpaceType.get
56
+ # give the space type a new unique name and assign it to the room
57
+ st_name = space_type_object.name
58
+ unless space_type.empty?
59
+ st_name = st_name.get
60
+ else
61
+ st_name = 'CustomSpaceType'
62
+ end
63
+ else
64
+ # create a new space type as there is currently none assigned to the room
65
+ new_space_type = OpenStudio::Model::SpaceType.new(openstudio_model)
66
+ st_name = 'CustomSpaceType'
67
+ end
68
+ new_space_type.setName(st_name + '_' + @hash[:identifier])
69
+ os_space.setSpaceType(new_space_type)
70
+ @unique_space_type = new_space_type
71
+ end
72
+ @unique_space_type
73
+ end
74
+
75
+ def to_openstudio(openstudio_model)
76
+ # create the space and thermal zone
77
+ os_space = OpenStudio::Model::Space.new(openstudio_model)
78
+ os_space.setName(@hash[:identifier])
79
+ os_thermal_zone = OpenStudio::Model::ThermalZone.new(openstudio_model)
80
+ os_thermal_zone.setName(@hash[:identifier])
81
+ os_space.setThermalZone(os_thermal_zone)
82
+
83
+ # assign the programtype
84
+ if @hash[:properties][:energy][:program_type]
85
+ space_type = openstudio_model.getSpaceTypeByName(@hash[:properties][:energy][:program_type])
86
+ unless space_type.empty?
87
+ space_type_object = space_type.get
88
+ os_space.setSpaceType(space_type_object)
89
+ end
90
+ end
91
+
92
+ # assign the constructionset
93
+ if @hash[:properties][:energy][:construction_set]
94
+ construction_set_identifier = @hash[:properties][:energy][:construction_set]
95
+ # gets default construction set assigned to room from openstudio_model
96
+ construction_set = openstudio_model.getDefaultConstructionSetByName(construction_set_identifier)
97
+ unless construction_set.empty?
98
+ default_construction_set = construction_set.get
99
+ os_space.setDefaultConstructionSet(default_construction_set)
100
+ end
101
+ end
102
+
103
+ # assign the multiplier
104
+ if @hash[:multiplier] and @hash[:multiplier] != 1
105
+ os_thermal_zone.setMultiplier(@hash[:multiplier])
106
+ end
107
+
108
+ # assign the story
109
+ if @hash[:story] # the users has specified the name of the story
110
+ story = openstudio_model.getBuildingStoryByName(@hash[:story])
111
+ if story.empty? # first time that this story has been referenced
112
+ story = OpenStudio::Model::BuildingStory.new(openstudio_model)
113
+ story.setName(@hash[:story])
114
+ else
115
+ story = story.get
116
+ end
117
+ else # give the room a dummy story so that it works with David's measures
118
+ story = openstudio_model.getBuildingStoryByName('UndefiniedStory')
119
+ if story.empty? # first time that this story has been referenced
120
+ story = OpenStudio::Model::BuildingStory.new(openstudio_model)
121
+ story.setName('UndefiniedStory')
122
+ else
123
+ story = story.get
124
+ end
125
+ end
126
+ os_space.setBuildingStory(story)
127
+
128
+ # keep track of all window ventilation objects
129
+ window_vent = {}
130
+
131
+ # assign all of the faces to the room
132
+ @hash[:faces].each do |face|
133
+ ladybug_face = Face.new(face)
134
+ os_surface = ladybug_face.to_openstudio(openstudio_model)
135
+ os_surface.setSpace(os_space)
136
+
137
+ # assign face-level shades if they exist
138
+ if face[:outdoor_shades]
139
+ os_shd_group = make_shade_group(openstudio_model, os_surface, os_space)
140
+ face[:outdoor_shades].each do |outdoor_shade|
141
+ add_shade_to_group(openstudio_model, os_shd_group, outdoor_shade)
142
+ end
143
+ end
144
+
145
+ # assign aperture-level shades if they exist
146
+ if face[:apertures]
147
+ face[:apertures].each do |aperture|
148
+ if aperture[:properties][:energy][:vent_opening]
149
+ window_vent[aperture[:identifier]] = \
150
+ [aperture[:properties][:energy][:vent_opening], aperture[:boundary_condition][:type]]
151
+ end
152
+ if aperture[:outdoor_shades]
153
+ unless os_shd_group
154
+ os_shd_group = make_shade_group(openstudio_model, os_surface, os_space)
155
+ end
156
+ aperture[:outdoor_shades].each do |outdoor_shade|
157
+ add_shade_to_group(openstudio_model, os_shd_group, outdoor_shade)
158
+ end
159
+ end
160
+ end
161
+ end
162
+
163
+ # assign door-level shades if they exist
164
+ if face[:doors]
165
+ face[:doors].each do |door|
166
+ if door[:properties][:energy][:vent_opening]
167
+ window_vent[door[:identifier]] = \
168
+ [door[:properties][:energy][:vent_opening], door[:boundary_condition][:type]]
169
+ end
170
+ if door[:outdoor_shades]
171
+ unless os_shd_group
172
+ os_shd_group = make_shade_group(openstudio_model, os_surface, os_space)
173
+ end
174
+ door[:outdoor_shades].each do |outdoor_shade|
175
+ add_shade_to_group(openstudio_model, os_shd_group, outdoor_shade)
176
+ end
177
+ end
178
+ end
179
+ end
180
+
181
+ if !face[:properties][:energy][:construction]
182
+ if face[:boundary_condition][:type] == 'Adiabatic'
183
+ # assign default interior construciton for Adiabatic Faces
184
+ if face[:face_type] != 'Wall'
185
+ interior_construction = closest_interior_construction(openstudio_model, os_space, face[:face_type])
186
+ unless interior_construction.nil?
187
+ os_surface.setConstruction(interior_construction)
188
+ end
189
+ end
190
+ elsif face[:face_type] == 'AirBoundary'
191
+ # assign default air boundary construciton for AirBoundary face types
192
+ air_construction = closest_air_construction(openstudio_model, os_space)
193
+ unless air_construction.nil?
194
+ os_surface.setConstruction(air_construction)
195
+ end
196
+ # add air mixing properties to the global list that tracks them
197
+ if $use_simple_vent # only use air mixing objects when simple ventilation is requested
198
+ air_hash = $air_boundary_hash[air_construction.name.to_s]
199
+ if air_hash[:air_mixing_per_area]
200
+ air_mix_area = air_hash[:air_mixing_per_area]
201
+ else
202
+ air_default = @@schema[:components][:schemas][:AirBoundaryConstructionAbridged]
203
+ air_mix_area = air_default[:properties][:air_mixing_per_area][:default]
204
+ end
205
+ flow_rate = os_surface.netArea * air_mix_area
206
+ flow_sch_id = air_hash[:air_mixing_schedule]
207
+ adj_zone_id = face[:boundary_condition][:boundary_condition_objects][-1]
208
+ $air_mxing_array << [os_thermal_zone, flow_rate, flow_sch_id, adj_zone_id]
209
+ end
210
+ end
211
+ end
212
+ end
213
+
214
+ # assign any room-level outdoor shades if they exist
215
+ if @hash[:outdoor_shades]
216
+ os_shd_group = OpenStudio::Model::ShadingSurfaceGroup.new(openstudio_model)
217
+ os_shd_group.setSpace(os_space)
218
+ os_shd_group.setShadingSurfaceType("Space")
219
+ @hash[:outdoor_shades].each do |outdoor_shade|
220
+ add_shade_to_group(openstudio_model, os_shd_group, outdoor_shade)
221
+ end
222
+ end
223
+
224
+ #check whether there are any load objects on the room overriding the programtype
225
+ if @hash[:properties][:energy][:people]
226
+ unique_program = get_unique_space_type(openstudio_model, os_space)
227
+ unique_program_ppl = unique_program.people
228
+ unless unique_program_ppl.empty? # remove the previous load definition
229
+ unique_program_ppl[0].remove()
230
+ end
231
+ custom_people = PeopleAbridged.new(@hash[:properties][:energy][:people])
232
+ os_custom_people = custom_people.to_openstudio(openstudio_model)
233
+ os_custom_people.setSpaceType(unique_program) # assign the new load definition
234
+ end
235
+
236
+ # assign lighting if it exists
237
+ if @hash[:properties][:energy][:lighting]
238
+ unique_program = get_unique_space_type(openstudio_model, os_space)
239
+ unique_program_lght = unique_program.lights
240
+ unless unique_program_lght.empty? # remove the previous load definition
241
+ unique_program_lght[0].remove()
242
+ end
243
+ custom_lighting = LightingAbridged.new(@hash[:properties][:energy][:lighting])
244
+ os_custom_lighting = custom_lighting.to_openstudio(openstudio_model)
245
+ os_custom_lighting.setSpaceType(unique_program) # assign the new load definition
246
+ end
247
+
248
+ # assign electric equipment if it exists
249
+ if @hash[:properties][:energy][:electric_equipment]
250
+ unique_program = get_unique_space_type(openstudio_model, os_space)
251
+ unique_program_ele = unique_program.electricEquipment
252
+ unless unique_program_ele.empty? # remove the previous load definition
253
+ unique_program_ele[0].remove()
254
+ end
255
+ custom_electric_equipment = ElectricEquipmentAbridged.new(@hash[:properties][:energy][:electric_equipment])
256
+ os_custom_electric_equipment = custom_electric_equipment.to_openstudio(openstudio_model)
257
+ os_custom_electric_equipment.setSpaceType(unique_program) # assign the new load definition
258
+ end
259
+
260
+ # assign gas equipment if it exists
261
+ if @hash[:properties][:energy][:gas_equipment]
262
+ unique_program = get_unique_space_type(openstudio_model, os_space)
263
+ unique_program_gas = unique_program.gasEquipment
264
+ unless unique_program_gas.empty? # remove the previous load definition
265
+ unique_program_gas[0].remove()
266
+ end
267
+ custom_gas_equipment = GasEquipmentAbridged.new(@hash[:properties][:energy][:gas_equipment])
268
+ os_custom_gas_equipment = custom_gas_equipment.to_openstudio(openstudio_model)
269
+ os_custom_gas_equipment.setSpaceType(unique_program) # assign the new load definition
270
+ end
271
+
272
+ # assign infiltration if it exists
273
+ if @hash[:properties][:energy][:infiltration] && $use_simple_vent # only use infiltration with simple ventilation
274
+ unique_program = get_unique_space_type(openstudio_model, os_space)
275
+ unique_program_inf = unique_program.spaceInfiltrationDesignFlowRates
276
+ unless unique_program_inf.empty? # remove the previous load definition
277
+ unique_program_inf[0].remove()
278
+ end
279
+ custom_infiltration = InfiltrationAbridged.new(@hash[:properties][:energy][:infiltration])
280
+ os_custom_infiltration = custom_infiltration.to_openstudio(openstudio_model)
281
+ os_custom_infiltration.setSpaceType(unique_program) # assign the new load definition
282
+ end
283
+
284
+ # assign ventilation if it exists
285
+ if @hash[:properties][:energy][:ventilation]
286
+ unique_program = get_unique_space_type(openstudio_model, os_space)
287
+ unique_program.resetDesignSpecificationOutdoorAir()
288
+ custom_ventilation = VentilationAbridged.new(@hash[:properties][:energy][:ventilation])
289
+ os_custom_ventilation = custom_ventilation.to_openstudio(openstudio_model)
290
+ unique_program.setDesignSpecificationOutdoorAir(os_custom_ventilation)
291
+ end
292
+
293
+ # assign setpoint if it exists
294
+ if @hash[:properties][:energy][:setpoint]
295
+ # thermostat object is created because heating and cooling schedule are required
296
+ setpoint_thermostat_space = SetpointThermostat.new(@hash[:properties][:energy][:setpoint])
297
+ os_setpoint_thermostat_space = setpoint_thermostat_space.to_openstudio(openstudio_model)
298
+ #set thermostat to thermal zone
299
+ os_thermal_zone.setThermostatSetpointDualSetpoint(os_setpoint_thermostat_space)
300
+ # humidistat object is created if humidifying or dehumidifying schedule is specified
301
+ if @hash[:properties][:energy][:setpoint][:humidifying_schedule] or @hash[:properties][:energy][:setpoint][:dehumidifying_schedule]
302
+ setpoint_humidistat_space = SetpointHumidistat.new(@hash[:properties][:energy][:setpoint])
303
+ os_setpoint_humidistat_space = setpoint_humidistat_space.to_openstudio(openstudio_model)
304
+ os_thermal_zone.setZoneControlHumidistat(os_setpoint_humidistat_space)
305
+ end
306
+ end
307
+
308
+ # assign window ventilation objects if they exist
309
+ if $use_simple_vent && !window_vent.empty? # write simple WindAndStack ventilation
310
+ window_vent.each do |sub_f_id, open_prop|
311
+ opening = open_prop[0]
312
+ bc = open_prop[1]
313
+ if bc == 'Outdoors'
314
+ opt_sub_f = openstudio_model.getSubSurfaceByName(sub_f_id)
315
+ unless opt_sub_f.empty?
316
+ sub_f = opt_sub_f.get
317
+ vent_open = VentilationOpening.new(opening)
318
+ os_vent_open = vent_open.to_openstudio(
319
+ openstudio_model, sub_f, @hash[:properties][:energy][:window_vent_control])
320
+ os_vent_open.addToThermalZone(os_thermal_zone)
321
+ end
322
+ end
323
+ end
324
+ elsif !$use_simple_vent # we're using the AFN!
325
+ # write an AirflowNetworkZone object in for the Room
326
+ os_afn_room_node = os_thermal_zone.getAirflowNetworkZone
327
+ os_afn_room_node.setVentilationControlMode('NoVent')
328
+ # write the opening objects for each Aperture / Door
329
+ operable_subfs = [] # collect the sub-face objects for the EMS
330
+ opening_factors = [] # collect the maximum opening factors for the EMS
331
+ window_vent.each do |sub_f_id, open_prop|
332
+ opening = open_prop[0]
333
+ opt_sub_f = openstudio_model.getSubSurfaceByName(sub_f_id)
334
+ unless opt_sub_f.empty?
335
+ sub_f = opt_sub_f.get
336
+ if sub_f.adjacentSubSurface.empty? # not an interior window that's already in the AFN
337
+ vent_open = VentilationOpening.new(opening)
338
+ open_fac = vent_open.to_openstudio_afn(openstudio_model, sub_f)
339
+ operable_subfs << sub_f
340
+ opening_factors << open_fac
341
+ end
342
+ end
343
+ end
344
+ # add the control startegy of the ventilation openings using the EMS
345
+ if @hash[:properties][:energy][:window_vent_control]
346
+ vent_control = VentilationControlAbridged.new(@hash[:properties][:energy][:window_vent_control])
347
+ vent_control.to_openstudio(
348
+ openstudio_model, os_thermal_zone, operable_subfs, opening_factors)
349
+ end
350
+ end
351
+
352
+ os_space
353
+ end
354
+
355
+ # method to make a space-assigned Shade group for shades assigned to parent objects
356
+ def make_shade_group(openstudio_model, os_surface, os_space)
357
+ os_shd_group = OpenStudio::Model::ShadingSurfaceGroup.new(openstudio_model)
358
+ os_shd_group.setShadedSurface(os_surface)
359
+ os_shd_group.setSpace(os_space)
360
+ os_shd_group.setShadingSurfaceType("Space")
361
+
362
+ os_shd_group
363
+ end
364
+
365
+ # method to create a Shade and add it to a shade group
366
+ def add_shade_to_group(openstudio_model, os_shd_group, outdoor_shade)
367
+ hb_outdoor_shade = Shade.new(outdoor_shade)
368
+ os_outdoor_shade = hb_outdoor_shade.to_openstudio(openstudio_model)
369
+ os_outdoor_shade.setShadingSurfaceGroup(os_shd_group)
370
+ end
371
+
372
+ # method to check for the closest-assigned interior ceiling or floor construction
373
+ def closest_interior_construction(openstudio_model, os_space, surface_type)
374
+ # first check the space-assigned construction set
375
+ constr_set_space = os_space.defaultConstructionSet
376
+ unless constr_set_space.empty?
377
+ constr_set_space_object = constr_set_space.get
378
+ default_interior_srf_set = constr_set_space_object.defaultInteriorSurfaceConstructions
379
+ unless default_interior_srf_set.empty?
380
+ default_interior_srf_set = default_interior_srf_set.get
381
+ if surface_type == 'RoofCeiling'
382
+ interior_construction = default_interior_srf_set.roofCeilingConstruction
383
+ else
384
+ interior_construction = default_interior_srf_set.floorConstruction
385
+ end
386
+ unless interior_construction.empty?
387
+ return interior_construction.get
388
+ end
389
+ end
390
+ end
391
+ # if no construction was found, check the building-assigned construction set
392
+ building = openstudio_model.building
393
+ unless building.empty?
394
+ building = building.get
395
+ construction_set_bldg = building.defaultConstructionSet
396
+ unless construction_set_bldg.empty?
397
+ construction_set_bldg_object = construction_set_bldg.get
398
+ default_interior_srf_set = construction_set_bldg_object.defaultInteriorSurfaceConstructions
399
+ unless default_interior_srf_set.empty?
400
+ default_interior_srf_set = default_interior_srf_set.get
401
+ if surface_type == 'RoofCeiling'
402
+ interior_construction = default_interior_srf_set.roofCeilingConstruction
403
+ else
404
+ interior_construction = default_interior_srf_set.floorConstruction
405
+ end
406
+ unless interior_construction.empty?
407
+ return interior_construction.get
408
+ end
409
+ end
410
+ end
411
+ end
412
+ nil # no construction was found
413
+ end
414
+
415
+ # method to check for the closest-assigned air boundary construction
416
+ def closest_air_construction(openstudio_model, os_space)
417
+ # first check the space-assigned construction set
418
+ constr_set_ref = os_space.defaultConstructionSet
419
+ unless constr_set_ref.empty?
420
+ constr_set_space = constr_set_ref.get
421
+ air_constr_ref = constr_set_space.interiorPartitionConstruction
422
+ unless air_constr_ref.empty?
423
+ return air_constr_ref.get
424
+ end
425
+ end
426
+ # if no construction was found, check the building-assigned construction set
427
+ building_ref = openstudio_model.building
428
+ unless building_ref.empty?
429
+ building = building_ref.get
430
+ constr_set_bldg_ref = building.defaultConstructionSet
431
+ unless constr_set_bldg_ref.empty?
432
+ constr_set_bldg = constr_set_bldg_ref.get
433
+ air_constr_ref = constr_set_bldg.interiorPartitionConstruction
434
+ unless air_constr_ref.empty?
435
+ return air_constr_ref.get
436
+ end
437
+ end
438
+ end
439
+ end
440
+
441
+ end #Room
442
+ end #Honeybee