honeybee-openstudio 2.3.1 → 2.5.2

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.
@@ -100,7 +100,7 @@ module FromHoneybee
100
100
  end
101
101
 
102
102
  # assign limits to the system's heating capacity
103
- if @hash[:heating_limit] == {'type': 'NoLimit'}
103
+ if @hash[:heating_limit] == {:type => 'NoLimit'}
104
104
  os_ideal_air.setHeatingLimit('NoLimit')
105
105
  else
106
106
  os_ideal_air.setHeatingLimit('LimitCapacity')
@@ -112,7 +112,7 @@ module FromHoneybee
112
112
  end
113
113
 
114
114
  # assign limits to the system's cooling capacity
115
- if @hash[:cooling_limit] == {'type': 'NoLimit'}
115
+ if @hash[:cooling_limit] == {:type => 'NoLimit'}
116
116
  os_ideal_air.setCoolingLimit('NoLimit')
117
117
  else
118
118
  os_ideal_air.setCoolingLimit('LimitFlowRateAndCapacity')
@@ -0,0 +1,201 @@
1
+ # *******************************************************************************
2
+ # Honeybee OpenStudio Gem, Copyright (c) 2020, Alliance for Sustainable
3
+ # Energy, LLC, Ladybug Tools LLC and other contributors. All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # (1) Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ #
11
+ # (2) Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # (3) Neither the name of the copyright holder nor the names of any contributors
16
+ # may be used to endorse or promote products derived from this software without
17
+ # specific prior written permission from the respective party.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS
20
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE
23
+ # UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF
24
+ # THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26
+ # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28
+ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
+ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+ # *******************************************************************************
31
+
32
+ require 'openstudio-standards'
33
+ require_relative 'Model.hvac'
34
+
35
+ require 'from_honeybee/extension'
36
+ require 'from_honeybee/model_object'
37
+
38
+ module FromHoneybee
39
+ class TemplateHVAC < ModelObject
40
+ attr_reader :errors, :warnings
41
+
42
+ @@all_air_types = ['VAV', 'PVAV', 'PSZ', 'PTAC', 'ForcedAirFurnace']
43
+ @@doas_types = ['FCUwithDOAS', 'WSHPwithDOAS', 'VRFwithDOAS']
44
+ @@heat_cool_types = ['FCU', 'WSHP', 'VRF', 'Baseboard', 'EvaporativeCooler',
45
+ 'Residential', 'WindowAC', 'GasUnitHeater']
46
+ @@types = @@all_air_types + @@doas_types + @@heat_cool_types
47
+
48
+ def initialize(hash = {})
49
+ super(hash)
50
+ end
51
+
52
+ def self.types
53
+ # array of all supported template HVAC systems
54
+ @@types
55
+ end
56
+
57
+ def self.all_air_types
58
+ # array of the All Air HVAC types
59
+ @@all_air_types
60
+ end
61
+
62
+ def self.doas_types
63
+ # array of the DOAS HVAC types
64
+ @@doas_types
65
+ end
66
+
67
+ def self.heat_cool_types
68
+ # array of the system types providing heating and cooling only
69
+ @@heat_cool_types
70
+ end
71
+
72
+ def defaults(system_type)
73
+ @@schema[:components][:schemas][system_type.to_sym][:properties]
74
+ end
75
+
76
+ def to_openstudio(openstudio_model, room_ids)
77
+ # get the defaults for the specific system type
78
+ hvac_defaults = defaults(@hash[:type])
79
+
80
+ # make the standard applier
81
+ if @hash[:vintage]
82
+ standard = Standard.build(@hash[:vintage])
83
+ else
84
+ standard = Standard.build(hvac_defaults[:vintage][:default])
85
+ end
86
+
87
+ # get the default equipment type
88
+ if @hash[:equipment_type]
89
+ equipment_type = @hash[:equipment_type]
90
+ else
91
+ equipment_type = hvac_defaults[:equipment_type][:default]
92
+ end
93
+
94
+ # get all of the thermal zones from the Model using the room identifiers
95
+ zones = []
96
+ room_ids.each do |room_id|
97
+ zone_get = openstudio_model.getThermalZoneByName(room_id)
98
+ unless zone_get.empty?
99
+ os_thermal_zone = zone_get.get
100
+ zones << os_thermal_zone
101
+ end
102
+ end
103
+
104
+ # create the HVAC system and assign the display name to the air loop name if it exists
105
+ os_hvac = openstudio_model.add_cbecs_hvac_system(standard, equipment_type, zones)
106
+ os_air_loop = nil
107
+ air_loops = openstudio_model.getAirLoopHVACs
108
+ unless air_loops.length == $air_loop_count # check if any new loops were added
109
+ $air_loop_count = air_loops.length
110
+ os_air_loop = air_loops[-1]
111
+ loop_name = os_air_loop.name
112
+ unless loop_name.empty?
113
+ if @hash[:display_name]
114
+ os_air_loop.setName(@hash[:display_name] + ' - ' + loop_name.get)
115
+ end
116
+ end
117
+ end
118
+
119
+ # TODO: consider adding the ability to decentralize the plant by changing loop names
120
+ #os_hvac.each do |hvac_loop|
121
+ # loop_name = hvac_loop.name
122
+ # unless loop_name.empty?
123
+ # hvac_loop.setName(@hash[:identifier] + ' - ' + loop_name.get)
124
+ # end
125
+ #end
126
+
127
+ # assign the economizer type if there's an air loop and the economizer is specified
128
+ if @hash[:economizer_type] && @hash[:economizer_type] != 'Inferred' && os_air_loop
129
+ oasys = os_air_loop.airLoopHVACOutdoorAirSystem
130
+ unless oasys.empty?
131
+ os_oasys = oasys.get
132
+ oactrl = os_oasys.getControllerOutdoorAir
133
+ oactrl.setEconomizerControlType(@hash[:economizer_type])
134
+ end
135
+ end
136
+
137
+ # set the sensible heat recovery if there's an air loop and the heat recovery is specified
138
+ if @hash[:sensible_heat_recovery] && @hash[:sensible_heat_recovery] != {:type => 'Autosize'} && os_air_loop
139
+ erv = get_existing_erv(os_air_loop)
140
+ unless erv
141
+ erv = create_erv(openstudio_model, os_air_loop)
142
+ end
143
+ eff_at_max = @hash[:sensible_heat_recovery] * (0.76 / 0.81) # taken from OpenStudio defaults
144
+ erv.setSensibleEffectivenessat100CoolingAirFlow(eff_at_max)
145
+ erv.setSensibleEffectivenessat100HeatingAirFlow(eff_at_max)
146
+ erv.setSensibleEffectivenessat75CoolingAirFlow(@hash[:sensible_heat_recovery])
147
+ erv.setSensibleEffectivenessat75HeatingAirFlow(@hash[:sensible_heat_recovery])
148
+ end
149
+
150
+ # set the latent heat recovery if there's an air loop and the heat recovery is specified
151
+ if @hash[:latent_heat_recovery] && @hash[:latent_heat_recovery] != {:type => 'Autosize'} && os_air_loop
152
+ erv = get_existing_erv(os_air_loop)
153
+ unless erv
154
+ erv = create_erv(openstudio_model, os_air_loop)
155
+ end
156
+ eff_at_max = @hash[:latent_heat_recovery] * (0.68 / 0.73) # taken from OpenStudio defaults
157
+ erv.setLatentEffectivenessat100CoolingAirFlow(eff_at_max)
158
+ erv.setLatentEffectivenessat100HeatingAirFlow(eff_at_max)
159
+ erv.setLatentEffectivenessat75CoolingAirFlow(@hash[:latent_heat_recovery])
160
+ erv.setLatentEffectivenessat75HeatingAirFlow(@hash[:latent_heat_recovery])
161
+ end
162
+
163
+ os_hvac
164
+ end
165
+
166
+ def get_existing_erv(os_air_loop)
167
+ # get an existing heat ecovery unit from an air loop; will be nil if there is none
168
+ os_air_loop.oaComponents.each do |supply_component|
169
+ if not supply_component.to_HeatExchangerAirToAirSensibleAndLatent.empty?
170
+ erv = supply_component.to_HeatExchangerAirToAirSensibleAndLatent.get
171
+ return erv
172
+ end
173
+ end
174
+ nil
175
+ end
176
+
177
+ def create_erv(model, os_air_loop)
178
+ # create a heat recovery unit with default zero efficiencies
179
+ heat_ex = OpenStudio::Model::HeatExchangerAirToAirSensibleAndLatent.new(model)
180
+ heat_ex.setEconomizerLockout(false)
181
+ heat_ex.setName(@hash[:identifier] + '_Heat Recovery Unit')
182
+ heat_ex.setSensibleEffectivenessat100CoolingAirFlow(0)
183
+ heat_ex.setSensibleEffectivenessat100HeatingAirFlow(0)
184
+ heat_ex.setSensibleEffectivenessat75CoolingAirFlow(0)
185
+ heat_ex.setSensibleEffectivenessat75HeatingAirFlow(0)
186
+ heat_ex.setLatentEffectivenessat100CoolingAirFlow(0)
187
+ heat_ex.setLatentEffectivenessat100HeatingAirFlow(0)
188
+ heat_ex.setLatentEffectivenessat75CoolingAirFlow(0)
189
+ heat_ex.setLatentEffectivenessat75HeatingAirFlow(0)
190
+
191
+ # add the heat exchanger to the air loop
192
+ outdoor_node = os_air_loop.reliefAirNode
193
+ unless outdoor_node.empty?
194
+ os_outdoor_node = outdoor_node.get
195
+ heat_ex.addToNode(os_outdoor_node)
196
+ end
197
+ heat_ex
198
+ end
199
+
200
+ end #TemplateHVAC
201
+ end #FromHoneybee
@@ -46,6 +46,7 @@ require 'from_honeybee/geometry/room'
46
46
 
47
47
  # import the HVAC objects
48
48
  require 'from_honeybee/hvac/ideal_air'
49
+ require 'from_honeybee/hvac/template'
49
50
 
50
51
  # import the construction objects
51
52
  require 'from_honeybee/construction/opaque'
@@ -497,13 +498,14 @@ module FromHoneybee
497
498
 
498
499
  def create_hvacs
499
500
  if @hash[:properties][:energy][:hvacs]
501
+ $air_loop_count = 0 # track the total number of air loops in the model
500
502
  # gather all of the hashes of the HVACs
501
503
  hvac_hashes = Hash.new
502
504
  @hash[:properties][:energy][:hvacs].each do |hvac|
503
505
  hvac_hashes[hvac[:identifier]] = hvac
504
506
  hvac_hashes[hvac[:identifier]]['rooms'] = []
505
507
  end
506
- # loop through the rooms and trach which are assigned to each HVAC
508
+ # loop through the rooms and track which are assigned to each HVAC
507
509
  if @hash[:rooms]
508
510
  @hash[:rooms].each do |room|
509
511
  if room[:properties][:energy][:hvac]
@@ -514,8 +516,7 @@ module FromHoneybee
514
516
 
515
517
  hvac_hashes.each_value do |hvac|
516
518
  system_type = hvac[:type]
517
- case system_type
518
- when 'IdealAirSystemAbridged'
519
+ if system_type == 'IdealAirSystemAbridged'
519
520
  ideal_air_system = IdealAirSystemAbridged.new(hvac)
520
521
  os_ideal_air_system = ideal_air_system.to_openstudio(@openstudio_model)
521
522
  hvac['rooms'].each do |room_id|
@@ -525,6 +526,9 @@ module FromHoneybee
525
526
  os_ideal_air_system.addToThermalZone(os_thermal_zone)
526
527
  end
527
528
  end
529
+ elsif TemplateHVAC.types.include?(system_type)
530
+ template_system = TemplateHVAC.new(hvac)
531
+ os_template_system = template_system.to_openstudio(@openstudio_model, hvac['rooms'])
528
532
  end
529
533
  end
530
534
  end
@@ -59,11 +59,11 @@ module FromHoneybee
59
59
  os_type_limit = OpenStudio::Model::ScheduleTypeLimits.new(openstudio_model)
60
60
  os_type_limit.setName(@hash[:identifier])
61
61
 
62
- if @hash[:lower_limit] != nil and @hash[:lower_limit] != {'type': 'NoLimit'}
62
+ if @hash[:lower_limit] != nil and @hash[:lower_limit] != {:type => 'NoLimit'}
63
63
  os_type_limit.setLowerLimitValue(@hash[:lower_limit])
64
64
  end
65
65
 
66
- if @hash[:upper_limit] != nil and @hash[:upper_limit] != {'type': 'NoLimit'}
66
+ if @hash[:upper_limit] != nil and @hash[:upper_limit] != {:type => 'NoLimit'}
67
67
  os_type_limit.setUpperLimitValue(@hash[:upper_limit])
68
68
  end
69
69
 
@@ -0,0 +1,160 @@
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
+
34
+ require 'openstudio'
35
+
36
+ module FromHoneybee
37
+ class VentilationOpening < ModelObject
38
+ attr_reader :errors, :warnings
39
+
40
+ def initialize(hash = {})
41
+ super(hash)
42
+ end
43
+
44
+ def defaults
45
+ @@schema[:components][:schemas][:VentilationOpening][:properties]
46
+ end
47
+
48
+ def defaults_control
49
+ @@schema[:components][:schemas][:VentilationControlAbridged][:properties]
50
+ end
51
+
52
+ def to_openstudio(openstudio_model, parent, vent_control_hash)
53
+ # create wind and stack object and set identifier
54
+ os_opening = OpenStudio::Model::ZoneVentilationWindandStackOpenArea.new(openstudio_model)
55
+ os_opening.setName(parent.name.get + '_Opening')
56
+
57
+ # assign the opening area
58
+ if @hash[:fraction_area_operable]
59
+ os_opening.setOpeningArea(@hash[:fraction_area_operable] * parent.netArea)
60
+ else
61
+ os_opening.setOpeningArea(
62
+ defaults[:fraction_area_operable][:default] * parent.netArea)
63
+ end
64
+
65
+ # assign the height
66
+ if @hash[:fraction_height_operable]
67
+ os_opening. setHeightDifference(
68
+ @hash[:fraction_height_operable] * compute_height(parent))
69
+ else
70
+ os_opening. setHeightDifference(
71
+ defaults[:fraction_height_operable][:default] * compute_height(parent))
72
+ end
73
+
74
+ # assign the azimuth
75
+ az_degrees = parent.azimuth * 180 / Math::PI
76
+ os_opening.setEffectiveAngle(az_degrees.round())
77
+
78
+ # assign the discharge coefficient
79
+ if @hash[:discharge_coefficient]
80
+ os_opening.setDischargeCoefficientforOpening(@hash[:discharge_coefficient])
81
+ else
82
+ os_opening.setDischargeCoefficientforOpening(
83
+ defaults[:discharge_coefficient][:default])
84
+ end
85
+
86
+ # assign the wind pressure coefficient
87
+ if @hash[:wind_cross_vent]
88
+ os_opening.autocalculateOpeningEffectiveness()
89
+ else
90
+ os_opening.setOpeningEffectiveness(0)
91
+ end
92
+
93
+ # set all of the ventilation control properties
94
+ if vent_control_hash
95
+ # assign min_indoor_temperature
96
+ if vent_control_hash[:min_indoor_temperature]
97
+ os_opening.setMinimumIndoorTemperature(vent_control_hash[:min_indoor_temperature])
98
+ else
99
+ os_opening.setMinimumIndoorTemperature(
100
+ defaults_control[:min_indoor_temperature][:default])
101
+ end
102
+ # assign max_indoor_temperature
103
+ if vent_control_hash[:max_indoor_temperature]
104
+ os_opening.setMaximumIndoorTemperature(vent_control_hash[:max_indoor_temperature])
105
+ else
106
+ os_opening.setMaximumIndoorTemperature(
107
+ defaults_control[:max_indoor_temperature][:default])
108
+ end
109
+ # assign min_outdoor_temperature
110
+ if vent_control_hash[:min_outdoor_temperature]
111
+ os_opening.setMinimumOutdoorTemperature(vent_control_hash[:min_outdoor_temperature])
112
+ else
113
+ os_opening.setMinimumOutdoorTemperature(
114
+ defaults_control[:min_outdoor_temperature][:default])
115
+ end
116
+ # assign max_outdoor_temperature
117
+ if vent_control_hash[:max_outdoor_temperature]
118
+ os_opening.setMaximumOutdoorTemperature(vent_control_hash[:max_outdoor_temperature])
119
+ else
120
+ os_opening.setMaximumOutdoorTemperature(
121
+ defaults_control[:max_outdoor_temperature][:default])
122
+ end
123
+ # assign delta_temperature
124
+ if vent_control_hash[:delta_temperature]
125
+ os_opening.setDeltaTemperature(vent_control_hash[:delta_temperature])
126
+ else
127
+ os_opening.setDeltaTemperature(
128
+ defaults_control[:delta_temperature][:default])
129
+ end
130
+ # assign schedule if it exists
131
+ if vent_control_hash[:schedule]
132
+ vent_sch = openstudio_model.getScheduleByName(vent_control_hash[:schedule])
133
+ unless vent_sch.empty?
134
+ vent_sch_object = vent_sch.get
135
+ os_opening.setOpeningAreaFractionSchedule(vent_sch_object)
136
+ end
137
+ end
138
+ end
139
+
140
+ os_opening
141
+ end
142
+
143
+ def compute_height(surface)
144
+ # derive the height (difference in z values) of a surface
145
+ verts = surface.vertices
146
+ min_pt = verts[0].z
147
+ max_pt = verts[0].z
148
+ verts.each do |v|
149
+ if v.z < min_pt
150
+ min_pt = v.z
151
+ elsif v.z > max_pt
152
+ max_pt = v.z
153
+ end
154
+ end
155
+ max_pt - min_pt
156
+ end
157
+
158
+ end #VentilationOpening
159
+ end #FromHoneybee
160
+
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.3.1
4
+ version: 2.5.2
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-07-09 00:00:00.000000000 Z
14
+ date: 2020-08-11 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -181,7 +181,9 @@ files:
181
181
  - lib/from_honeybee/geometry/face.rb
182
182
  - lib/from_honeybee/geometry/room.rb
183
183
  - lib/from_honeybee/geometry/shade.rb
184
+ - lib/from_honeybee/hvac/Model.hvac.rb
184
185
  - lib/from_honeybee/hvac/ideal_air.rb
186
+ - lib/from_honeybee/hvac/template.rb
185
187
  - lib/from_honeybee/load/electric_equipment.rb
186
188
  - lib/from_honeybee/load/gas_equipment.rb
187
189
  - lib/from_honeybee/load/infiltration.rb
@@ -208,6 +210,7 @@ files:
208
210
  - lib/from_honeybee/simulation/designday.rb
209
211
  - lib/from_honeybee/simulation/extension.rb
210
212
  - lib/from_honeybee/simulation/parameter.rb
213
+ - lib/from_honeybee/ventcool/opening.rb
211
214
  - lib/measures/.gitkeep
212
215
  - lib/measures/from_honeybee_model/LICENSE.md
213
216
  - lib/measures/from_honeybee_model/README.md