honeybee-openstudio 2.3.0 → 2.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.0
4
+ version: 2.5.1
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-06-30 00:00:00.000000000 Z
14
+ date: 2020-08-08 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -149,6 +149,7 @@ extensions: []
149
149
  extra_rdoc_files: []
150
150
  files:
151
151
  - ".coveralls.yml"
152
+ - ".github/workflows/emit-release-event.yaml"
152
153
  - ".gitignore"
153
154
  - ".releaserc.json"
154
155
  - ".travis.yml"
@@ -180,7 +181,9 @@ files:
180
181
  - lib/from_honeybee/geometry/face.rb
181
182
  - lib/from_honeybee/geometry/room.rb
182
183
  - lib/from_honeybee/geometry/shade.rb
184
+ - lib/from_honeybee/hvac/Model.hvac.rb
183
185
  - lib/from_honeybee/hvac/ideal_air.rb
186
+ - lib/from_honeybee/hvac/template.rb
184
187
  - lib/from_honeybee/load/electric_equipment.rb
185
188
  - lib/from_honeybee/load/gas_equipment.rb
186
189
  - lib/from_honeybee/load/infiltration.rb
@@ -207,6 +210,7 @@ files:
207
210
  - lib/from_honeybee/simulation/designday.rb
208
211
  - lib/from_honeybee/simulation/extension.rb
209
212
  - lib/from_honeybee/simulation/parameter.rb
213
+ - lib/from_honeybee/ventcool/opening.rb
210
214
  - lib/measures/.gitkeep
211
215
  - lib/measures/from_honeybee_model/LICENSE.md
212
216
  - lib/measures/from_honeybee_model/README.md