honeybee-openstudio 2.4.0 → 2.5.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.
@@ -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,198 @@
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 identifier 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 == 0
109
+ os_air_loop = air_loops[-1]
110
+ loop_name = os_air_loop.name
111
+ unless loop_name.empty?
112
+ os_air_loop.setName(@hash[:identifier] + ' - ' + loop_name.get)
113
+ end
114
+ end
115
+
116
+ # TODO: consider adding the ability to decentralize the plant by changing loop names
117
+ #os_hvac.each do |hvac_loop|
118
+ # loop_name = hvac_loop.name
119
+ # unless loop_name.empty?
120
+ # hvac_loop.setName(@hash[:identifier] + ' - ' + loop_name.get)
121
+ # end
122
+ #end
123
+
124
+ # assign the economizer type if there's an air loop and the economizer is specified
125
+ if @hash[:economizer_type] && @hash[:economizer_type] != 'Inferred' && os_air_loop
126
+ oasys = os_air_loop.airLoopHVACOutdoorAirSystem
127
+ unless oasys.empty?
128
+ os_oasys = oasys.get
129
+ oactrl = os_oasys.getControllerOutdoorAir
130
+ oactrl.setEconomizerControlType(@hash[:economizer_type])
131
+ end
132
+ end
133
+
134
+ # set the sensible heat recovery if there's an air loop and the heat recovery is specified
135
+ if @hash[:sensible_heat_recovery] && @hash[:sensible_heat_recovery] != {:type => 'Autosize'} && os_air_loop
136
+ erv = get_existing_erv(os_air_loop)
137
+ unless erv
138
+ erv = create_erv(openstudio_model, os_air_loop)
139
+ end
140
+ eff_at_max = @hash[:sensible_heat_recovery] * (0.76 / 0.81) # taken from OpenStudio defaults
141
+ erv.setSensibleEffectivenessat100CoolingAirFlow(eff_at_max)
142
+ erv.setSensibleEffectivenessat100HeatingAirFlow(eff_at_max)
143
+ erv.setSensibleEffectivenessat75CoolingAirFlow(@hash[:sensible_heat_recovery])
144
+ erv.setSensibleEffectivenessat75HeatingAirFlow(@hash[:sensible_heat_recovery])
145
+ end
146
+
147
+ # set the latent heat recovery if there's an air loop and the heat recovery is specified
148
+ if @hash[:latent_heat_recovery] && @hash[:latent_heat_recovery] != {:type => 'Autosize'} && os_air_loop
149
+ erv = get_existing_erv(os_air_loop)
150
+ unless erv
151
+ erv = create_erv(openstudio_model, os_air_loop)
152
+ end
153
+ eff_at_max = @hash[:latent_heat_recovery] * (0.68 / 0.73) # taken from OpenStudio defaults
154
+ erv.setLatentEffectivenessat100CoolingAirFlow(eff_at_max)
155
+ erv.setLatentEffectivenessat100HeatingAirFlow(eff_at_max)
156
+ erv.setLatentEffectivenessat75CoolingAirFlow(@hash[:latent_heat_recovery])
157
+ erv.setLatentEffectivenessat75HeatingAirFlow(@hash[:latent_heat_recovery])
158
+ end
159
+
160
+ os_hvac
161
+ end
162
+
163
+ def get_existing_erv(os_air_loop)
164
+ # get an existing heat ecovery unit from an air loop; will be nil if there is none
165
+ os_air_loop.oaComponents.each do |supply_component|
166
+ if not supply_component.to_HeatExchangerAirToAirSensibleAndLatent.empty?
167
+ erv = supply_component.to_HeatExchangerAirToAirSensibleAndLatent.get
168
+ return erv
169
+ end
170
+ end
171
+ nil
172
+ end
173
+
174
+ def create_erv(model, os_air_loop)
175
+ # create a heat recovery unit with default zero efficiencies
176
+ heat_ex = OpenStudio::Model::HeatExchangerAirToAirSensibleAndLatent.new(model)
177
+ heat_ex.setEconomizerLockout(false)
178
+ heat_ex.setName(@hash[:identifier] + '_Heat Recovery Unit')
179
+ heat_ex.setSensibleEffectivenessat100CoolingAirFlow(0)
180
+ heat_ex.setSensibleEffectivenessat100HeatingAirFlow(0)
181
+ heat_ex.setSensibleEffectivenessat75CoolingAirFlow(0)
182
+ heat_ex.setSensibleEffectivenessat75HeatingAirFlow(0)
183
+ heat_ex.setLatentEffectivenessat100CoolingAirFlow(0)
184
+ heat_ex.setLatentEffectivenessat100HeatingAirFlow(0)
185
+ heat_ex.setLatentEffectivenessat75CoolingAirFlow(0)
186
+ heat_ex.setLatentEffectivenessat75HeatingAirFlow(0)
187
+
188
+ # add the heat exchanger to the air loop
189
+ outdoor_node = os_air_loop.reliefAirNode
190
+ unless outdoor_node.empty?
191
+ os_outdoor_node = outdoor_node.get
192
+ heat_ex.addToNode(os_outdoor_node)
193
+ end
194
+ heat_ex
195
+ end
196
+
197
+ end #TemplateHVAC
198
+ 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'
@@ -503,7 +504,7 @@ module FromHoneybee
503
504
  hvac_hashes[hvac[:identifier]] = hvac
504
505
  hvac_hashes[hvac[:identifier]]['rooms'] = []
505
506
  end
506
- # loop through the rooms and trach which are assigned to each HVAC
507
+ # loop through the rooms and track which are assigned to each HVAC
507
508
  if @hash[:rooms]
508
509
  @hash[:rooms].each do |room|
509
510
  if room[:properties][:energy][:hvac]
@@ -514,8 +515,7 @@ module FromHoneybee
514
515
 
515
516
  hvac_hashes.each_value do |hvac|
516
517
  system_type = hvac[:type]
517
- case system_type
518
- when 'IdealAirSystemAbridged'
518
+ if system_type == 'IdealAirSystemAbridged'
519
519
  ideal_air_system = IdealAirSystemAbridged.new(hvac)
520
520
  os_ideal_air_system = ideal_air_system.to_openstudio(@openstudio_model)
521
521
  hvac['rooms'].each do |room_id|
@@ -525,6 +525,9 @@ module FromHoneybee
525
525
  os_ideal_air_system.addToThermalZone(os_thermal_zone)
526
526
  end
527
527
  end
528
+ elsif TemplateHVAC.types.include?(system_type)
529
+ template_system = TemplateHVAC.new(hvac)
530
+ os_template_system = template_system.to_openstudio(@openstudio_model, hvac['rooms'])
528
531
  end
529
532
  end
530
533
  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
 
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.4.0
4
+ version: 2.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tanushree Charan
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: exe
13
13
  cert_chain: []
14
- date: 2020-07-20 00:00:00.000000000 Z
14
+ date: 2020-08-07 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