buildingsync 0.2.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.
- checksums.yaml +7 -0
- data/.github/workflows/continuous_integration.yml +146 -0
- data/.gitignore +33 -0
- data/.rspec +3 -0
- data/.rubocop.yml +10 -0
- data/CHANGELOG.md +50 -0
- data/Gemfile +31 -0
- data/Jenkinsfile +10 -0
- data/LICENSE.md +29 -0
- data/README.md +105 -0
- data/Rakefile +77 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/buildingsync.gemspec +37 -0
- data/config.rb.in +26 -0
- data/doc_templates/LICENSE.md +29 -0
- data/doc_templates/README.md.erb +42 -0
- data/doc_templates/copyright_erb.txt +38 -0
- data/doc_templates/copyright_js.txt +5 -0
- data/doc_templates/copyright_ruby.txt +36 -0
- data/lib/buildingsync.rb +43 -0
- data/lib/buildingsync/all_resource_total.rb +54 -0
- data/lib/buildingsync/audit_date.rb +54 -0
- data/lib/buildingsync/constants.rb +49 -0
- data/lib/buildingsync/contact.rb +54 -0
- data/lib/buildingsync/extension.rb +57 -0
- data/lib/buildingsync/generator.rb +584 -0
- data/lib/buildingsync/get_bcl_weather_file.rb +326 -0
- data/lib/buildingsync/helpers/Model.hvac.rb +216 -0
- data/lib/buildingsync/helpers/helper.rb +494 -0
- data/lib/buildingsync/helpers/xml_get_set.rb +215 -0
- data/lib/buildingsync/makers/phase_zero_base.osw +178 -0
- data/lib/buildingsync/makers/workflow_maker.json +811 -0
- data/lib/buildingsync/makers/workflow_maker.rb +581 -0
- data/lib/buildingsync/makers/workflow_maker_base.rb +167 -0
- data/lib/buildingsync/model_articulation/building.rb +1119 -0
- data/lib/buildingsync/model_articulation/building_and_system_types.json +121 -0
- data/lib/buildingsync/model_articulation/building_section.rb +190 -0
- data/lib/buildingsync/model_articulation/building_system.rb +49 -0
- data/lib/buildingsync/model_articulation/envelope_system.rb +102 -0
- data/lib/buildingsync/model_articulation/exterior_floor_system_type.rb +64 -0
- data/lib/buildingsync/model_articulation/facility.rb +439 -0
- data/lib/buildingsync/model_articulation/foundation_system_type.rb +64 -0
- data/lib/buildingsync/model_articulation/hvac_system.rb +395 -0
- data/lib/buildingsync/model_articulation/lighting_system.rb +102 -0
- data/lib/buildingsync/model_articulation/loads_system.rb +287 -0
- data/lib/buildingsync/model_articulation/location_element.rb +129 -0
- data/lib/buildingsync/model_articulation/measure.rb +57 -0
- data/lib/buildingsync/model_articulation/roof_system_type.rb +64 -0
- data/lib/buildingsync/model_articulation/service_hot_water_system.rb +87 -0
- data/lib/buildingsync/model_articulation/site.rb +242 -0
- data/lib/buildingsync/model_articulation/spatial_element.rb +343 -0
- data/lib/buildingsync/model_articulation/wall_system_type.rb +64 -0
- data/lib/buildingsync/report.rb +217 -0
- data/lib/buildingsync/resource_use.rb +55 -0
- data/lib/buildingsync/scenario.rb +622 -0
- data/lib/buildingsync/selection_tool.rb +98 -0
- data/lib/buildingsync/time_series.rb +85 -0
- data/lib/buildingsync/translator.rb +167 -0
- data/lib/buildingsync/utility.rb +67 -0
- data/lib/buildingsync/version.rb +45 -0
- metadata +223 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# *******************************************************************************
|
4
|
+
# OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
|
5
|
+
# BuildingSync(R), Copyright (c) 2015-2020, Alliance for Sustainable Energy, LLC.
|
6
|
+
# All rights reserved.
|
7
|
+
#
|
8
|
+
# Redistribution and use in source and binary forms, with or without
|
9
|
+
# modification, are permitted provided that the following conditions are met:
|
10
|
+
#
|
11
|
+
# (1) Redistributions of source code must retain the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer.
|
13
|
+
#
|
14
|
+
# (2) Redistributions in binary form must reproduce the above copyright notice,
|
15
|
+
# this list of conditions and the following disclaimer in the documentation
|
16
|
+
# and/or other materials provided with the distribution.
|
17
|
+
#
|
18
|
+
# (3) Neither the name of the copyright holder nor the names of any contributors
|
19
|
+
# may be used to endorse or promote products derived from this software without
|
20
|
+
# specific prior written permission from the respective party.
|
21
|
+
#
|
22
|
+
# (4) Other than as required in clauses (1) and (2), distributions in any form
|
23
|
+
# of modifications or other derivative works may not use the "OpenStudio"
|
24
|
+
# trademark, "OS", "os", or any other confusingly similar designation without
|
25
|
+
# specific prior written permission from Alliance for Sustainable Energy, LLC.
|
26
|
+
#
|
27
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS
|
28
|
+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
29
|
+
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
30
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE
|
31
|
+
# UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF
|
32
|
+
# THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
33
|
+
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
34
|
+
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
35
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
36
|
+
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
37
|
+
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
38
|
+
# *******************************************************************************
|
39
|
+
|
40
|
+
module BuildingSync
|
41
|
+
# Foundation System Type
|
42
|
+
class FoundationSystemType
|
43
|
+
# initialize a foundation system type given a ref
|
44
|
+
# @param doc [REXML::Document]
|
45
|
+
# @param ns [String]
|
46
|
+
# @param ref [String]
|
47
|
+
def initialize(doc, ns, ref)
|
48
|
+
@id = nil
|
49
|
+
doc.elements.each("#{ns}:Systems/#{ns}:FoundationSystems/#{ns}:FoundationSystem") do |foundation_system|
|
50
|
+
if foundation_system.attributes['ID'] == ref
|
51
|
+
read(foundation_system, ns)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# read
|
57
|
+
# @param foundation_system [REXML:Element]
|
58
|
+
# @param ns [String]
|
59
|
+
def read(foundation_system, ns)
|
60
|
+
# ID
|
61
|
+
@id = foundation_system.attributes['ID'] if foundation_system.attributes['ID']
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,395 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# *******************************************************************************
|
4
|
+
# OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
|
5
|
+
# BuildingSync(R), Copyright (c) 2015-2020, Alliance for Sustainable Energy, LLC.
|
6
|
+
# All rights reserved.
|
7
|
+
#
|
8
|
+
# Redistribution and use in source and binary forms, with or without
|
9
|
+
# modification, are permitted provided that the following conditions are met:
|
10
|
+
#
|
11
|
+
# (1) Redistributions of source code must retain the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer.
|
13
|
+
#
|
14
|
+
# (2) Redistributions in binary form must reproduce the above copyright notice,
|
15
|
+
# this list of conditions and the following disclaimer in the documentation
|
16
|
+
# and/or other materials provided with the distribution.
|
17
|
+
#
|
18
|
+
# (3) Neither the name of the copyright holder nor the names of any contributors
|
19
|
+
# may be used to endorse or promote products derived from this software without
|
20
|
+
# specific prior written permission from the respective party.
|
21
|
+
#
|
22
|
+
# (4) Other than as required in clauses (1) and (2), distributions in any form
|
23
|
+
# of modifications or other derivative works may not use the "OpenStudio"
|
24
|
+
# trademark, "OS", "os", or any other confusingly similar designation without
|
25
|
+
# specific prior written permission from Alliance for Sustainable Energy, LLC.
|
26
|
+
#
|
27
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS
|
28
|
+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
29
|
+
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
30
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE
|
31
|
+
# UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF
|
32
|
+
# THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
33
|
+
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
34
|
+
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
35
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
36
|
+
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
37
|
+
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
38
|
+
# *******************************************************************************
|
39
|
+
require 'buildingsync/helpers/helper'
|
40
|
+
require 'buildingsync/helpers/xml_get_set'
|
41
|
+
|
42
|
+
module BuildingSync
|
43
|
+
# HVACSystem class
|
44
|
+
class HVACSystem < BuildingSystem
|
45
|
+
include BuildingSync::Helper
|
46
|
+
include BuildingSync::XmlGetSet
|
47
|
+
# initialize
|
48
|
+
# @param system_element [REXML::Element]
|
49
|
+
# @param ns [String]
|
50
|
+
def initialize(base_xml, ns = 'auc')
|
51
|
+
@base_xml = base_xml
|
52
|
+
@ns = ns
|
53
|
+
|
54
|
+
help_element_class_type_check(base_xml, 'HVACSystem')
|
55
|
+
|
56
|
+
# code to initialize
|
57
|
+
read_xml
|
58
|
+
end
|
59
|
+
|
60
|
+
# read xml
|
61
|
+
def read_xml; end
|
62
|
+
|
63
|
+
def get_linked_ids; end
|
64
|
+
|
65
|
+
# get principal hvac system type
|
66
|
+
# @return [String]
|
67
|
+
def get_principal_hvac_system_type
|
68
|
+
return xget_text('PrincipalHVACSystemType')
|
69
|
+
end
|
70
|
+
|
71
|
+
# adding the principal hvac system type to the hvac systems, overwrite existing values or create new elements if none are present
|
72
|
+
# @param id [String]
|
73
|
+
# @param principal_hvac_type [String]
|
74
|
+
def set_principal_hvac_system_type(principal_hvac_type)
|
75
|
+
xset_or_create('PrincipalHVACSystemType', principal_hvac_type)
|
76
|
+
end
|
77
|
+
|
78
|
+
# add exhaust
|
79
|
+
# @param model [OpenStudio::Model]
|
80
|
+
# @param standard [Standard]
|
81
|
+
# @param kitchen_makeup [String]
|
82
|
+
# @param remove_objects [Boolean]
|
83
|
+
def add_exhaust(model, standard, kitchen_makeup, remove_objects)
|
84
|
+
# remove exhaust objects
|
85
|
+
if remove_objects
|
86
|
+
model.getFanZoneExhausts.each(&:remove)
|
87
|
+
end
|
88
|
+
|
89
|
+
zone_exhaust_fans = standard.model_add_exhaust(model, kitchen_makeup) # second argument is strategy for finding makeup zones for exhaust zones
|
90
|
+
zone_exhaust_fans.each do |k, v|
|
91
|
+
max_flow_rate_ip = OpenStudio.convert(k.maximumFlowRate.get, 'm^3/s', 'cfm').get
|
92
|
+
if v.key?(:zone_mixing)
|
93
|
+
zone_mixing = v[:zone_mixing]
|
94
|
+
mixing_source_zone_name = zone_mixing.sourceZone.get.name
|
95
|
+
mixing_design_flow_rate_ip = OpenStudio.convert(zone_mixing.designFlowRate.get, 'm^3/s', 'cfm').get
|
96
|
+
OpenStudio.logFree(OpenStudio::Info, 'BuildingSync.HVACSystem.add_exhaust', "Adding #{OpenStudio.toNeatString(max_flow_rate_ip, 0, true)} (cfm) of exhaust to #{k.thermalZone.get.name}, with #{OpenStudio.toNeatString(mixing_design_flow_rate_ip, 0, true)} (cfm) of makeup air from #{mixing_source_zone_name}")
|
97
|
+
else
|
98
|
+
OpenStudio.logFree(OpenStudio::Info, 'BuildingSync.HVACSystem.add_exhaust', "Adding #{OpenStudio.toNeatString(max_flow_rate_ip, 0, true)} (cfm) of exhaust to #{k.thermalZone.get.name}")
|
99
|
+
end
|
100
|
+
end
|
101
|
+
return true
|
102
|
+
end
|
103
|
+
|
104
|
+
# add thermostats
|
105
|
+
# @param model [OpenStudio::Model]
|
106
|
+
# @param standard [Standard]
|
107
|
+
# @param remove_objects [Boolean]
|
108
|
+
def add_thermostats(model, standard, remove_objects)
|
109
|
+
# remove thermostats
|
110
|
+
if remove_objects
|
111
|
+
model.getThermostatSetpointDualSetpoints.each(&:remove)
|
112
|
+
end
|
113
|
+
|
114
|
+
model.getSpaceTypes.each do |space_type|
|
115
|
+
# create thermostat schedules
|
116
|
+
# apply internal load schedules
|
117
|
+
# the last bool test it to make thermostat schedules. They are added to the model but not assigned
|
118
|
+
standard.space_type_apply_internal_load_schedules(space_type, false, false, false, false, false, false, true)
|
119
|
+
|
120
|
+
# identify thermal thermostat and apply to zones (apply_internal_load_schedules names )
|
121
|
+
model.getThermostatSetpointDualSetpoints.each do |thermostat|
|
122
|
+
next if !thermostat.name.to_s.include?(space_type.name.to_s)
|
123
|
+
if !thermostat.coolingSetpointTemperatureSchedule.is_initialized
|
124
|
+
OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.HVACSystem.add_thermostats', "#{thermostat.name} has no cooling setpoint.")
|
125
|
+
end
|
126
|
+
if !thermostat.heatingSetpointTemperatureSchedule.is_initialized
|
127
|
+
OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.HVACSystem.add_thermostats', "#{thermostat.name} has no heating setpoint.")
|
128
|
+
end
|
129
|
+
|
130
|
+
OpenStudio.logFree(OpenStudio::Info, 'BuildingSync.HVACSystem.add_thermostats', "Assigning #{thermostat.name} to thermal zones with #{space_type.name} assigned.")
|
131
|
+
puts "BuildingSync.HVACSystem.add_thermostats - Assigning #{thermostat.name} to thermal zones with #{space_type.name} assigned."
|
132
|
+
space_type.spaces.each do |space|
|
133
|
+
next if !space.thermalZone.is_initialized
|
134
|
+
|
135
|
+
space.thermalZone.get.setThermostatSetpointDualSetpoint(thermostat)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
puts "ThermalZones: #{model.getThermalZones.size}"
|
140
|
+
puts "ThermostatDSPs: #{model.getThermostatSetpointDualSetpoints.size}"
|
141
|
+
add_setpoints_to_thermostats_if_none(model)
|
142
|
+
return true
|
143
|
+
end
|
144
|
+
|
145
|
+
# @return [Boolean] true if ALL thermostats have heating and cooling setpoints
|
146
|
+
def add_setpoints_to_thermostats_if_none(model)
|
147
|
+
successful = true
|
148
|
+
|
149
|
+
# seperate out thermostats that need heating vs. cooling schedules
|
150
|
+
tstats_cooling = []
|
151
|
+
tstats_heating = []
|
152
|
+
model.getThermalZones.each do |tz|
|
153
|
+
if tz.thermostatSetpointDualSetpoint.is_initialized
|
154
|
+
tstat = tz.thermostatSetpointDualSetpoint.get
|
155
|
+
tstats_cooling << tstat if !tstat.coolingSetpointTemperatureSchedule.is_initialized
|
156
|
+
tstats_heating << tstat if !tstat.heatingSetpointTemperatureSchedule.is_initialized
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
puts "BuildingSync.HVACSystem.add_setpoints_to_thermostats_if_none - (#{tstats_cooling.size}) thermostats needing cooling schedule"
|
161
|
+
puts "BuildingSync.HVACSystem.add_setpoints_to_thermostats_if_none - (#{tstats_heating.size}) thermostats needing heating schedule"
|
162
|
+
|
163
|
+
htg_setpoints = [
|
164
|
+
# [Time.new(days, hours, mins seconds), temp_value_celsius]
|
165
|
+
[OpenStudio::Time.new(0, 9, 0, 0), 17],
|
166
|
+
[OpenStudio::Time.new(0, 17, 0, 0), 20],
|
167
|
+
[OpenStudio::Time.new(0, 24, 0, 0), 17]
|
168
|
+
]
|
169
|
+
clg_setpoints = [
|
170
|
+
# [Time.new(days, hours, mins seconds), temp_value_celsius]
|
171
|
+
[OpenStudio::Time.new(0, 9, 0, 0), 23],
|
172
|
+
[OpenStudio::Time.new(0, 17, 0, 0), 20],
|
173
|
+
[OpenStudio::Time.new(0, 24, 0, 0), 23]
|
174
|
+
]
|
175
|
+
|
176
|
+
heating_sp_schedule = create_schedule_ruleset(model, htg_setpoints, 'Thermostat Heating SP')
|
177
|
+
cooling_sp_schedule = create_schedule_ruleset(model, clg_setpoints, 'Thermostat Cooling SP')
|
178
|
+
|
179
|
+
tstats_cooling.each do |thermostat|
|
180
|
+
success = thermostat.setCoolingSetpointTemperatureSchedule(cooling_sp_schedule)
|
181
|
+
if success
|
182
|
+
OpenStudio.logFree(OpenStudio::Info, 'BuildingSync.HVACSystem.add_setpoints_to_thermostats_if_none', "Cooling Schedule (#{cooling_sp_schedule.nameString}) added to Thermostat: #{thermostat.nameString}")
|
183
|
+
puts "BuildingSync.HVACSystem.add_setpoints_to_thermostats_if_none - Cooling Schedule (#{cooling_sp_schedule.nameString}) added to Thermostat: #{thermostat.nameString}"
|
184
|
+
else
|
185
|
+
successful = false
|
186
|
+
OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.HVACSystem.add_setpoints_to_thermostats_if_none', "No Cooling Schedule for Thermostat: #{thermostat.nameString}")
|
187
|
+
puts "BuildingSync.HVACSystem.add_setpoints_to_thermostats_if_none - No Cooling Schedule for Thermostat: #{thermostat.nameString}"
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
tstats_heating.each do |thermostat|
|
192
|
+
success = thermostat.setHeatingSetpointTemperatureSchedule(heating_sp_schedule)
|
193
|
+
if success
|
194
|
+
OpenStudio.logFree(OpenStudio::Info, 'BuildingSync.HVACSystem.add_setpoints_to_thermostats_if_none', "Heating Schedule (#{heating_sp_schedule.nameString}) added to Thermostat: #{thermostat.nameString}")
|
195
|
+
puts "BuildingSync.HVACSystem.add_setpoints_to_thermostats_if_none - Heating Schedule (#{heating_sp_schedule.nameString}) added to Thermostat: #{thermostat.nameString}"
|
196
|
+
else
|
197
|
+
successful = false
|
198
|
+
OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.HVACSystem.add_setpoints_to_thermostats_if_none', "No Heating Schedule for Thermostat: #{thermostat.nameString}")
|
199
|
+
puts "BuildingSync.HVACSystem.add_setpoints_to_thermostats_if_none - No Heating Schedule for Thermostat: #{thermostat.nameString}"
|
200
|
+
end
|
201
|
+
end
|
202
|
+
return successful
|
203
|
+
end
|
204
|
+
|
205
|
+
# @param model [OpenStudio::Model::Model]
|
206
|
+
# @param values [Array<Array<OpenStudio::Time, Float>>] [[cutoff_time, value_until_cutoff]]
|
207
|
+
# @return [OpenStudio::Model::ScheduleRuleset] a new schedule ruleset with values added to the default day
|
208
|
+
def create_schedule_ruleset(model, values, name)
|
209
|
+
ruleset = OpenStudio::Model::ScheduleRuleset.new(model)
|
210
|
+
ruleset.setName(name)
|
211
|
+
dd = ruleset.defaultDaySchedule
|
212
|
+
values.each do |v|
|
213
|
+
dd.addValue(v[0], v[1])
|
214
|
+
end
|
215
|
+
return ruleset
|
216
|
+
end
|
217
|
+
|
218
|
+
# map principal hvac system type to cbecs system type
|
219
|
+
# @param principal_hvac_system_type [String]
|
220
|
+
# @param fallback_system_type [String] the default system_type to use if the other is not found
|
221
|
+
# @return [String]
|
222
|
+
def map_to_cbecs(principal_hvac_system_type, fallback_system_type)
|
223
|
+
case principal_hvac_system_type
|
224
|
+
when 'Packaged Terminal Air Conditioner'
|
225
|
+
return 'PTAC with hot water heat'
|
226
|
+
when 'Packaged Terminal Heat Pump'
|
227
|
+
return 'PTHP'
|
228
|
+
when 'Packaged Rooftop Air Conditioner'
|
229
|
+
return 'PSZ-AC with gas coil heat'
|
230
|
+
when 'Packaged Rooftop Heat Pump'
|
231
|
+
return 'PSZ-HP'
|
232
|
+
when 'Packaged Rooftop VAV with Hot Water Reheat'
|
233
|
+
return 'PVAV with reheat'
|
234
|
+
when 'Packaged Rooftop VAV with Electric Reheat'
|
235
|
+
return 'PVAV with PFP boxes'
|
236
|
+
when 'VAV with Hot Water Reheat'
|
237
|
+
return 'VAV with reheat'
|
238
|
+
when 'VAV with Electric Reheat'
|
239
|
+
return 'VAV with PFP boxes'
|
240
|
+
else
|
241
|
+
OpenStudio.logFree(OpenStudio::Error, 'BuildingSync.HVACSystem.map_to_cbecs', "HVACSystem ID: #{xget_id}: No mapping for #{principal_hvac_system_type} to CBECS. Using the system type from standards: #{fallback_system_type}")
|
242
|
+
return fallback_system_type
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# add hvac
|
247
|
+
# @param model [OpenStudio::Model]
|
248
|
+
# @param zone_hash [hash]
|
249
|
+
# @param standard [Standard]
|
250
|
+
# @param system_type [String]
|
251
|
+
# @param hvac_delivery_type [String]
|
252
|
+
# @param htg_src [String]
|
253
|
+
# @param clg_src [String]
|
254
|
+
# @param remove_objects [Boolean]
|
255
|
+
# @return [Boolean]
|
256
|
+
def add_hvac(model, zone_hash, standard, system_type, hvac_delivery_type = 'Forced Air', htg_src = 'NaturalGas', clg_src = 'Electricity', remove_objects = false)
|
257
|
+
# remove HVAC objects
|
258
|
+
if remove_objects
|
259
|
+
standard.model_remove_prm_hvac(model)
|
260
|
+
end
|
261
|
+
|
262
|
+
puts "HVAC System ID: #{xget_id}. System_type derived from standards: #{system_type} and principal hvac system type override is: #{get_principal_hvac_system_type}"
|
263
|
+
temp = get_principal_hvac_system_type
|
264
|
+
if !temp.nil? && !temp.empty?
|
265
|
+
previous_system_type = system_type
|
266
|
+
system_type = map_to_cbecs(get_principal_hvac_system_type, previous_system_type)
|
267
|
+
OpenStudio.logFree(OpenStudio::Info, 'BuildingSync.HVACSystem.add_hvac', "HVAC System ID: #{xget_id}. System type derived from standards: #{previous_system_type}, overriden to #{system_type}")
|
268
|
+
end
|
269
|
+
|
270
|
+
case system_type
|
271
|
+
when 'Inferred'
|
272
|
+
|
273
|
+
# Get the hvac delivery type enum
|
274
|
+
hvac_delivery = case hvac_delivery_type
|
275
|
+
when 'Forced Air'
|
276
|
+
'air'
|
277
|
+
when 'Hydronic'
|
278
|
+
'hydronic'
|
279
|
+
end
|
280
|
+
|
281
|
+
# Group the zones by occupancy type. Only split out
|
282
|
+
# non-dominant groups if their total area exceeds the limit.
|
283
|
+
sys_groups = standard.model_group_zones_by_type(model, OpenStudio.convert(20_000, 'ft^2', 'm^2').get)
|
284
|
+
|
285
|
+
# For each group, infer the HVAC system type.
|
286
|
+
sys_groups.each do |sys_group|
|
287
|
+
# Infer the principal system type
|
288
|
+
# OpenStudio.logFree(OpenStudio::Info, 'BuildingSync.Facility.create_building_system', "template = #{template}, climate_zone = #{climate_zone}, occ_type = #{sys_group['type']}, hvac_delivery = #{hvac_delivery}, htg_src = #{htg_src}, clg_src = #{clg_src}, area_ft2 = #{sys_group['area_ft2']}, num_stories = #{sys_group['stories']}")
|
289
|
+
sys_type, central_htg_fuel, zone_htg_fuel, clg_fuel = standard.model_typical_hvac_system_type(model,
|
290
|
+
climate_zone,
|
291
|
+
sys_group['type'],
|
292
|
+
hvac_delivery,
|
293
|
+
htg_src,
|
294
|
+
clg_src,
|
295
|
+
OpenStudio.convert(sys_group['area_ft2'], 'ft^2', 'm^2').get,
|
296
|
+
sys_group['stories'])
|
297
|
+
|
298
|
+
# Infer the secondary system type for multizone systems
|
299
|
+
sec_sys_type = case sys_type
|
300
|
+
when 'PVAV Reheat', 'VAV Reheat'
|
301
|
+
'PSZ-AC'
|
302
|
+
when 'PVAV PFP Boxes', 'VAV PFP Boxes'
|
303
|
+
'PSZ-HP'
|
304
|
+
else
|
305
|
+
sys_type # same as primary system type
|
306
|
+
end
|
307
|
+
|
308
|
+
# Group zones by story
|
309
|
+
story_zone_lists = standard.model_group_zones_by_story(model, sys_group['zones'])
|
310
|
+
|
311
|
+
# On each story, add the primary system to the primary zones
|
312
|
+
# and add the secondary system to any zones that are different.
|
313
|
+
story_zone_lists.each do |story_group|
|
314
|
+
# Differentiate primary and secondary zones, based on
|
315
|
+
# operating hours and internal loads (same as 90.1 PRM)
|
316
|
+
pri_sec_zone_lists = standard.model_differentiate_primary_secondary_thermal_zones(model, story_group)
|
317
|
+
# Add the primary system to the primary zones
|
318
|
+
standard.model_add_hvac_system(model, sys_type, central_htg_fuel, zone_htg_fuel, clg_fuel, pri_sec_zone_lists['primary'])
|
319
|
+
# Add the secondary system to the secondary zones (if any)
|
320
|
+
if !pri_sec_zone_lists['secondary'].empty?
|
321
|
+
standard.model_add_hvac_system(model, sec_sys_type, central_htg_fuel, zone_htg_fuel, clg_fuel, pri_sec_zone_lists['secondary'])
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
else
|
326
|
+
# Group the zones by story
|
327
|
+
story_groups = standard.model_group_zones_by_story(model, model.getThermalZones)
|
328
|
+
|
329
|
+
# Add the user specified HVAC system for each story.
|
330
|
+
# Single-zone systems will get one per zone.
|
331
|
+
story_groups.each do |zones|
|
332
|
+
new_system_type = get_system_type_from_zone(zone_hash, zones, system_type)
|
333
|
+
puts "setting system: #{new_system_type} for zone names: #{help_get_zone_name_list(zones)}"
|
334
|
+
model.add_cbecs_hvac_system(standard, new_system_type, zones)
|
335
|
+
end
|
336
|
+
end
|
337
|
+
return true
|
338
|
+
end
|
339
|
+
|
340
|
+
# get system type from zone
|
341
|
+
# @param zone_hash [hash]
|
342
|
+
# @param zones [array<OpenStudio::Model::ThermalZone>]
|
343
|
+
# @param system_type [String]
|
344
|
+
# @return [String]
|
345
|
+
def get_system_type_from_zone(zone_hash, zones, system_type)
|
346
|
+
zone_hash&.each do |id, zone_list|
|
347
|
+
zone_name_list = help_get_zone_name_list(zone_list)
|
348
|
+
zones.each do |zone|
|
349
|
+
if zone_name_list.include? zone.name.get
|
350
|
+
return map_to_cbecs(get_principal_hvac_system_type, system_type)
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
return system_type
|
355
|
+
end
|
356
|
+
|
357
|
+
# apply sizing and assumptions
|
358
|
+
# @param model [OpenStudio::Model]
|
359
|
+
# @param output_path [String]
|
360
|
+
# @param standard [Standard]
|
361
|
+
# @param primary_bldg_type [String]
|
362
|
+
# @param system_type [String]
|
363
|
+
# @param climate_zone [String]
|
364
|
+
# @return [Boolean]
|
365
|
+
def apply_sizing_and_assumptions(model, output_path, standard, primary_bldg_type, system_type, climate_zone)
|
366
|
+
case system_type
|
367
|
+
when 'Ideal Air Loads'
|
368
|
+
|
369
|
+
else
|
370
|
+
# Set the heating and cooling sizing parameters
|
371
|
+
standard.model_apply_prm_sizing_parameters(model)
|
372
|
+
|
373
|
+
# Perform a sizing run
|
374
|
+
if standard.model_run_sizing_run(model, "#{output_path}/SR") == false
|
375
|
+
return false
|
376
|
+
end
|
377
|
+
|
378
|
+
# If there are any multizone systems, reset damper positions
|
379
|
+
# to achieve a 60% ventilation effectiveness minimum for the system
|
380
|
+
# following the ventilation rate procedure from 62.1
|
381
|
+
standard.model_apply_multizone_vav_outdoor_air_sizing(model)
|
382
|
+
|
383
|
+
# Apply the prototype HVAC assumptions
|
384
|
+
standard.model_apply_prototype_hvac_assumptions(model, primary_bldg_type, climate_zone)
|
385
|
+
|
386
|
+
# Apply the HVAC efficiency standard
|
387
|
+
standard.model_apply_hvac_efficiency_standard(model, climate_zone)
|
388
|
+
end
|
389
|
+
return true
|
390
|
+
end
|
391
|
+
|
392
|
+
# principal hvac system type
|
393
|
+
attr_reader :principal_hvac_system_type
|
394
|
+
end
|
395
|
+
end
|