buildingsync 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,343 @@
|
|
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 'openstudio'
|
40
|
+
require 'fileutils'
|
41
|
+
require 'json'
|
42
|
+
require 'openstudio/extension/core/os_lib_model_generation'
|
43
|
+
|
44
|
+
require 'buildingsync/helpers/helper'
|
45
|
+
require 'buildingsync/helpers/xml_get_set'
|
46
|
+
|
47
|
+
module BuildingSync
|
48
|
+
# base class for objects that will configure workflows based on building sync files
|
49
|
+
class SpatialElement
|
50
|
+
include OsLib_ModelGeneration
|
51
|
+
include BuildingSync::Helper
|
52
|
+
include BuildingSync::XmlGetSet
|
53
|
+
# initialize SpatialElement class
|
54
|
+
# @param base_xml [REXML::Element] an element corresponding to a spatial element,
|
55
|
+
# either an auc:Site, auc:Building, auc:Section
|
56
|
+
# @param ns [String] namespace, likely 'auc'
|
57
|
+
def initialize(base_xml, ns)
|
58
|
+
@base_xml = base_xml
|
59
|
+
@ns = ns
|
60
|
+
|
61
|
+
@total_floor_area = nil
|
62
|
+
@standards_building_type = nil
|
63
|
+
@system_type = nil
|
64
|
+
@bar_division_method = nil
|
65
|
+
@space_types = {}
|
66
|
+
@fraction_area = nil
|
67
|
+
@space_types_floor_area = nil
|
68
|
+
@conditioned_floor_area_heated_only = nil
|
69
|
+
@conditioned_floor_area_cooled_only = nil
|
70
|
+
@conditioned_floor_area_heated_cooled = nil
|
71
|
+
@custom_conditioned_above_grade_floor_area = nil
|
72
|
+
@custom_conditioned_below_grade_floor_area = nil
|
73
|
+
|
74
|
+
@user_defined_fields = REXML::Element.new("#{@ns}:UserDefinedFields")
|
75
|
+
end
|
76
|
+
|
77
|
+
# read floor areas
|
78
|
+
# @param parent_total_floor_area [Float]
|
79
|
+
def read_floor_areas(parent_total_floor_area)
|
80
|
+
@base_xml.elements.each("#{@ns}:FloorAreas/#{@ns}:FloorArea") do |floor_area_element|
|
81
|
+
next if !floor_area_element.elements["#{@ns}:FloorAreaValue"]
|
82
|
+
floor_area = floor_area_element.elements["#{@ns}:FloorAreaValue"].text.to_f
|
83
|
+
next if floor_area.nil?
|
84
|
+
|
85
|
+
floor_area_type = floor_area_element.elements["#{@ns}:FloorAreaType"].text
|
86
|
+
if floor_area_type == 'Gross'
|
87
|
+
@total_floor_area = OpenStudio.convert(validate_positive_number_excluding_zero('gross_floor_area', floor_area), 'ft^2', 'm^2').get
|
88
|
+
elsif floor_area_type == 'Heated and Cooled'
|
89
|
+
@conditioned_floor_area_heated_cooled = OpenStudio.convert(validate_positive_number_excluding_zero('@heated_and_cooled_floor_area', floor_area), 'ft^2', 'm^2').get
|
90
|
+
elsif floor_area_type == 'Footprint'
|
91
|
+
@footprint_floor_area = OpenStudio.convert(validate_positive_number_excluding_zero('@footprint_floor_area', floor_area), 'ft^2', 'm^2').get
|
92
|
+
elsif floor_area_type == 'Conditioned'
|
93
|
+
@conditioned_floor_area_heated_cooled = OpenStudio.convert(validate_positive_number_excluding_zero('@conditioned_floor_area_heated_cooled', floor_area), 'ft^2', 'm^2').get
|
94
|
+
elsif floor_area_type == 'Heated Only'
|
95
|
+
@conditioned_floor_area_heated_only = OpenStudio.convert(validate_positive_number_excluding_zero('@heated_only_floor_area', floor_area), 'ft^2', 'm^2').get
|
96
|
+
elsif floor_area_type == 'Cooled Only'
|
97
|
+
@conditioned_floor_area_cooled_only = OpenStudio.convert(validate_positive_number_excluding_zero('@cooled_only_floor_area', floor_area), 'ft^2', 'm^2').get
|
98
|
+
elsif floor_area_type == 'Custom'
|
99
|
+
if floor_area_element.elements["#{@ns}:FloorAreaCustomName"].text == 'Conditioned above grade'
|
100
|
+
@custom_conditioned_above_grade_floor_area = OpenStudio.convert(validate_positive_number_excluding_zero('@custom_conditioned_above_grade_floor_area', floor_area), 'ft^2', 'm^2').get
|
101
|
+
elsif floor_area_element.elements["#{@ns}:FloorAreaCustomName"].text == 'Conditioned below grade'
|
102
|
+
@custom_conditioned_below_grade_floor_area = OpenStudio.convert(validate_positive_number_excluding_zero('@custom_conditioned_below_grade_floor_area', floor_area), 'ft^2', 'm^2').get
|
103
|
+
end
|
104
|
+
else
|
105
|
+
OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.SpatialElement.generate_baseline_osm', "Unsupported floor area type found: #{floor_area_type}")
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
if @total_floor_area.nil? || @total_floor_area == 0
|
110
|
+
# if the total floor area is null, we try to calculate the total area, from various conditioned areas
|
111
|
+
running_floor_area = 0
|
112
|
+
if !@conditioned_floor_area_cooled_only.nil? && @conditioned_floor_area_cooled_only > 0
|
113
|
+
running_floor_area += @conditioned_floor_area_cooled_only
|
114
|
+
end
|
115
|
+
if !@conditioned_floor_area_heated_only.nil? && @conditioned_floor_area_heated_only > 0
|
116
|
+
running_floor_area += @conditioned_floor_area_heated_only
|
117
|
+
end
|
118
|
+
if !@conditioned_floor_area_heated_cooled.nil? && @conditioned_floor_area_heated_cooled > 0
|
119
|
+
running_floor_area += @conditioned_floor_area_heated_cooled
|
120
|
+
end
|
121
|
+
if running_floor_area > 0
|
122
|
+
@total_floor_area = running_floor_area
|
123
|
+
else
|
124
|
+
# if the conditions floor areas are null, we look at the conditioned above and below grade areas
|
125
|
+
if !@custom_conditioned_above_grade_floor_area.nil? && @custom_conditioned_above_grade_floor_area > 0
|
126
|
+
running_floor_area += @custom_conditioned_above_grade_floor_area
|
127
|
+
end
|
128
|
+
if !@custom_conditioned_below_grade_floor_area.nil? && @custom_conditioned_below_grade_floor_area > 0
|
129
|
+
running_floor_area += @custom_conditioned_below_grade_floor_area
|
130
|
+
end
|
131
|
+
if running_floor_area > 0
|
132
|
+
@total_floor_area = running_floor_area
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# if we did not find any area we get the parent one
|
138
|
+
if @total_floor_area.nil? || @total_floor_area == 0
|
139
|
+
return parent_total_floor_area
|
140
|
+
else
|
141
|
+
return @total_floor_area
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# set building and system type
|
146
|
+
# @param occupancy_classification [String]
|
147
|
+
# @param total_floor_area [Float]
|
148
|
+
# @param total_number_floors [Integer]
|
149
|
+
# @param raise_exception [Boolean]
|
150
|
+
def set_bldg_and_system_type(occupancy_classification, total_floor_area, total_number_floors, raise_exception)
|
151
|
+
# DOE Prototype building types:from openstudio-standards/lib/openstudio-standards/prototypes/common/prototype_metaprogramming.rb
|
152
|
+
# SmallOffice, MediumOffice, LargeOffice, RetailStandalone, RetailStripmall, PrimarySchool, SecondarySchool, Outpatient
|
153
|
+
# Hospital, SmallHotel, LargeHotel, QuickServiceRestaurant, FullServiceRestaurant, MidriseApartment, HighriseApartment, Warehouse
|
154
|
+
|
155
|
+
if !occupancy_classification.nil? && !total_floor_area.nil?
|
156
|
+
|
157
|
+
building_and_system_types = eval(File.read(BUILDING_AND_SYSTEMS_FILE_PATH))
|
158
|
+
|
159
|
+
process_bldg_and_system_type(building_and_system_types, occupancy_classification, total_floor_area, total_number_floors)
|
160
|
+
|
161
|
+
if @standards_building_type == ''
|
162
|
+
raise "Building type '#{occupancy_classification}' is beyond BuildingSync scope"
|
163
|
+
end
|
164
|
+
elsif raise_exception
|
165
|
+
if occupancy_classification.nil? && !total_floor_area.nil?
|
166
|
+
raise "ID: #{xget_id} occupancy classification '#{occupancy_classification}' is nil"
|
167
|
+
elsif !occupancy_classification.nil? && total_floor_area.nil?
|
168
|
+
raise "ID: #{xget_id} Building total floor area '#{total_floor_area}' is nil"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# gets the standards occupancy type from the building type or the potential overwrite occupancy type
|
174
|
+
# @param occ_type [Hash]
|
175
|
+
# @return [Boolean]
|
176
|
+
def sets_occupancy_bldg_system_types(occ_type)
|
177
|
+
@standards_building_type = occ_type[:standards_building_type]
|
178
|
+
@bar_division_method = occ_type[:bar_division_method]
|
179
|
+
@system_type = occ_type[:system_type]
|
180
|
+
OpenStudio.logFree(OpenStudio::Info, 'BuildingSync.SpatialElement.sets_occupancy_bldg_system_types', "Element ID: #{xget_id} @standards_building_type #{@standards_building_type}, @bar_division_method #{@bar_division_method} and @system_type: #{@system_type}")
|
181
|
+
return true
|
182
|
+
end
|
183
|
+
|
184
|
+
# Determine the standards_building_type, bar_division_method, and system_type given:
|
185
|
+
# - occupancy_classification, total_floor_area, total_number_floors
|
186
|
+
# @param building_and_system_types [Hash] a read in of the building_and_system_types.json file
|
187
|
+
# @param occupancy_classification [String] value of OccupancyClassification element
|
188
|
+
# @param total_floor_area [Float]
|
189
|
+
# @param total_number_floors [Integer]
|
190
|
+
# @return [Boolean]
|
191
|
+
def process_bldg_and_system_type(building_and_system_types, occupancy_classification, total_floor_area, total_number_floors)
|
192
|
+
OpenStudio.logFree(OpenStudio::Info, 'BuildingSync.SpatialElement.process_bldg_and_system_type', "Element ID: #{xget_id} started with occupancy_classification #{occupancy_classification} and total floor area: #{total_floor_area}")
|
193
|
+
puts "Element ID: #{xget_id} started with occupancy_classification #{occupancy_classification} and total floor area: #{total_floor_area}"
|
194
|
+
min_floor_area_correct = false
|
195
|
+
max_floor_area_correct = false
|
196
|
+
building_and_system_types[:"#{occupancy_classification}"]&.each do |occ_type|
|
197
|
+
if !occ_type[:standards_building_type].nil?
|
198
|
+
if occ_type[:min_floor_area] || occ_type[:max_floor_area]
|
199
|
+
if occ_type[:min_floor_area] && occ_type[:min_floor_area].to_f < total_floor_area
|
200
|
+
min_floor_area_correct = true
|
201
|
+
end
|
202
|
+
if occ_type[:max_floor_area] && occ_type[:max_floor_area].to_f > total_floor_area
|
203
|
+
max_floor_area_correct = true
|
204
|
+
end
|
205
|
+
if (min_floor_area_correct && max_floor_area_correct) || (!occ_type[:min_floor_area] && max_floor_area_correct) || (min_floor_area_correct && !occ_type[:max_floor_area])
|
206
|
+
puts "selected the following standards_building_type: #{occ_type[:standards_building_type]}"
|
207
|
+
return sets_occupancy_bldg_system_types(occ_type)
|
208
|
+
end
|
209
|
+
elsif occ_type[:min_number_floors] || occ_type[:max_number_floors]
|
210
|
+
if occ_type[:min_number_floors] && occ_type[:min_number_floors].to_i <= total_number_floors
|
211
|
+
puts "selected the following standards_building_type: #{occ_type[:standards_building_type]}"
|
212
|
+
return sets_occupancy_bldg_system_types(occ_type)
|
213
|
+
elsif occ_type[:max_number_floors] && occ_type[:max_number_floors].to_i > total_number_floors
|
214
|
+
puts "selected the following standards_building_type: #{occ_type[:standards_building_type]}"
|
215
|
+
return sets_occupancy_bldg_system_types(occ_type)
|
216
|
+
end
|
217
|
+
else
|
218
|
+
# otherwise we assume the first one is correct and we select this
|
219
|
+
puts "selected the following standards_building_type: #{occ_type[:standards_building_type]}"
|
220
|
+
return sets_occupancy_bldg_system_types(occ_type)
|
221
|
+
end
|
222
|
+
else
|
223
|
+
# otherwise we assume the first one is correct and we select this
|
224
|
+
return sets_occupancy_bldg_system_types(occ_type)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
raise "BuildingSync Occupancy type #{occupancy_classification} is not available in the building_and_system_types.json dictionary"
|
228
|
+
return false
|
229
|
+
end
|
230
|
+
|
231
|
+
# validate positive number excluding zero
|
232
|
+
# @param name [String]
|
233
|
+
# @param value [Float]
|
234
|
+
# @return float
|
235
|
+
def validate_positive_number_excluding_zero(name, value)
|
236
|
+
puts "Error: parameter #{name} must be positive and not zero." if value <= 0
|
237
|
+
return value
|
238
|
+
end
|
239
|
+
|
240
|
+
# validate positive number including zero
|
241
|
+
# @param name [String]
|
242
|
+
# @param value [Float]
|
243
|
+
# @return float
|
244
|
+
def validate_positive_number_including_zero(name, value)
|
245
|
+
puts "Error: parameter #{name} must be positive or zero." if value < 0
|
246
|
+
return value
|
247
|
+
end
|
248
|
+
|
249
|
+
# create space types
|
250
|
+
# @param model [OpenStudio::Model]
|
251
|
+
# @param total_bldg_floor_area [Float]
|
252
|
+
# @param total_number_floors [Integer]
|
253
|
+
# @param standard_template [String]
|
254
|
+
# @param open_studio_standard [Standard]
|
255
|
+
# @return hash
|
256
|
+
def create_space_types(model, total_bldg_floor_area, total_number_floors, standard_template, open_studio_standard)
|
257
|
+
# create space types from section type
|
258
|
+
# mapping lookup_name name is needed for a few methods
|
259
|
+
set_bldg_and_system_type(xget_text('OccupancyClassification'), total_bldg_floor_area, total_number_floors, false) if @standards_building_type.nil?
|
260
|
+
if open_studio_standard.nil?
|
261
|
+
begin
|
262
|
+
open_studio_standard = Standard.build("#{standard_template}_#{@standards_building_type}")
|
263
|
+
rescue StandardError => e
|
264
|
+
# if the combination of standard type and bldg type fails we try the standard type alone.
|
265
|
+
puts "could not find open studio standard for template #{standard_template} and bldg type: #{@standards_building_type}, trying the standard type alone"
|
266
|
+
open_studio_standard = Standard.build(standard_template)
|
267
|
+
raise(e)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
@space_types = get_space_types_from_building_type(@standards_building_type, standard_template, true)
|
272
|
+
puts "BuildingSync.SpatialElement.create_space_types - Space types: #{@space_types} selected for building type: #{@standards_building_type} and standard template: #{standard_template}"
|
273
|
+
# create space_type_map from array
|
274
|
+
sum_of_ratios = 0.0
|
275
|
+
|
276
|
+
@space_types.each do |space_type_name, hash|
|
277
|
+
# create space type
|
278
|
+
space_type = OpenStudio::Model::SpaceType.new(model)
|
279
|
+
space_type.setStandardsBuildingType(@standards_building_type)
|
280
|
+
space_type.setStandardsSpaceType(space_type_name)
|
281
|
+
space_type.setName("#{@standards_building_type} #{space_type_name}")
|
282
|
+
|
283
|
+
# set color
|
284
|
+
test = open_studio_standard.space_type_apply_rendering_color(space_type) # this uses openstudio-standards
|
285
|
+
OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.SpatialElement.create_space_types', "Warning: Could not find color for #{space_type.name}") if !test
|
286
|
+
# extend hash to hold new space type object
|
287
|
+
hash[:space_type] = space_type
|
288
|
+
|
289
|
+
# add to sum_of_ratios counter for adjustment multiplier
|
290
|
+
sum_of_ratios += hash[:ratio]
|
291
|
+
end
|
292
|
+
|
293
|
+
# store multiplier needed to adjust sum of ratios to equal 1.0
|
294
|
+
@ratio_adjustment_multiplier = 1.0 / sum_of_ratios
|
295
|
+
|
296
|
+
@space_types_floor_area = {}
|
297
|
+
@space_types.each do |space_type_name, hash|
|
298
|
+
ratio_of_bldg_total = hash[:ratio] * @ratio_adjustment_multiplier * @fraction_area
|
299
|
+
final_floor_area = ratio_of_bldg_total * total_bldg_floor_area # I think I can just pass ratio but passing in area is cleaner
|
300
|
+
@space_types_floor_area[hash[:space_type]] = { floor_area: final_floor_area }
|
301
|
+
end
|
302
|
+
puts 'BuildingSync.SpatialElement.create_space_types'
|
303
|
+
return @space_types_floor_area
|
304
|
+
end
|
305
|
+
|
306
|
+
# add user defined field to xml file
|
307
|
+
# @param field_name [String]
|
308
|
+
# @param field_value [String]
|
309
|
+
def add_user_defined_field_to_xml_file(field_name, field_value)
|
310
|
+
user_defined_field = REXML::Element.new("#{@ns}:UserDefinedField")
|
311
|
+
field_name_element = REXML::Element.new("#{@ns}:FieldName")
|
312
|
+
field_value_element = REXML::Element.new("#{@ns}:FieldValue")
|
313
|
+
|
314
|
+
if !field_value.nil?
|
315
|
+
@user_defined_fields.add_element(user_defined_field)
|
316
|
+
user_defined_field.add_element(field_name_element)
|
317
|
+
user_defined_field.add_element(field_value_element)
|
318
|
+
|
319
|
+
field_name_element.text = field_name
|
320
|
+
field_value_element.text = field_value
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
# write parameters to xml for spatial element
|
325
|
+
def prepare_final_xml_for_spatial_element
|
326
|
+
add_user_defined_field_to_xml_file('StandardsBuildingType', @standards_building_type)
|
327
|
+
add_user_defined_field_to_xml_file('SystemType', @system_type)
|
328
|
+
add_user_defined_field_to_xml_file('BarDivisionMethod', @bar_division_method)
|
329
|
+
add_user_defined_field_to_xml_file('FractionArea', @fraction_area)
|
330
|
+
add_user_defined_field_to_xml_file('SpaceTypesFloorArea', @space_types_floor_area)
|
331
|
+
add_user_defined_field_to_xml_file('TotalFloorArea(m^2)', @total_floor_area)
|
332
|
+
add_user_defined_field_to_xml_file('ConditionedFloorArea(m^2)', @conditioned_floor_area_heated_cooled) if !@conditioned_floor_area_heated_cooled.nil?
|
333
|
+
add_user_defined_field_to_xml_file('HeatedFloorArea(m^2)', @conditioned_floor_area_heated_only) if !@conditioned_floor_area_heated_only.nil?
|
334
|
+
add_user_defined_field_to_xml_file('CooledFloorArea(m^2)', @conditioned_floor_area_cooled_only) if !@conditioned_floor_area_cooled_only.nil?
|
335
|
+
add_user_defined_field_to_xml_file('ConditionedAboveGradeFloorArea(m^2)', @custom_conditioned_above_grade_floor_area) if !@custom_conditioned_above_grade_floor_area.nil?
|
336
|
+
add_user_defined_field_to_xml_file('ConditionedBelowGradeFloorArea(m^2)', @custom_conditioned_below_grade_floor_area) if !@custom_conditioned_below_grade_floor_area.nil?
|
337
|
+
|
338
|
+
@base_xml.add_element(@user_defined_fields)
|
339
|
+
end
|
340
|
+
|
341
|
+
attr_reader :total_floor_area, :standards_building_type, :system_type, :space_types
|
342
|
+
end
|
343
|
+
end
|
@@ -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
|
+
# Wall System Type
|
42
|
+
class WallSystemType
|
43
|
+
# initialize a specific floor 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}:WallSystems/#{ns}:WallSystem") do |wall_system|
|
50
|
+
if wall_system.attributes['ID'] == ref
|
51
|
+
read(wall_system, ns)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# read
|
57
|
+
# @param wall_system [REXML:Element]
|
58
|
+
# @param ns [String]
|
59
|
+
def read(wall_system, ns)
|
60
|
+
# ID
|
61
|
+
@id = wall_system.attributes['ID'] if wall_system.attributes['ID']
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,217 @@
|
|
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
|
+
require 'buildingsync/audit_date'
|
41
|
+
require 'buildingsync/scenario'
|
42
|
+
require 'buildingsync/utility'
|
43
|
+
|
44
|
+
module BuildingSync
|
45
|
+
# Report class
|
46
|
+
class Report
|
47
|
+
include BuildingSync::Helper
|
48
|
+
include BuildingSync::XmlGetSet
|
49
|
+
# @param base_xml [REXML::Element]
|
50
|
+
# @param ns [String]
|
51
|
+
def initialize(base_xml, ns)
|
52
|
+
@base_xml = base_xml
|
53
|
+
@ns = ns
|
54
|
+
help_element_class_type_check(base_xml, 'Report')
|
55
|
+
|
56
|
+
@scenarios = []
|
57
|
+
@audit_dates = []
|
58
|
+
@utilities = []
|
59
|
+
|
60
|
+
# Special scenarios
|
61
|
+
@cb_modeled = nil
|
62
|
+
@cb_measured = []
|
63
|
+
@poms = []
|
64
|
+
|
65
|
+
read_xml
|
66
|
+
end
|
67
|
+
|
68
|
+
def read_xml
|
69
|
+
read_scenarios
|
70
|
+
|
71
|
+
# Audit dates
|
72
|
+
@base_xml.elements.each("#{@ns}:AuditDates/#{@ns}:AuditDate") do |audit_date|
|
73
|
+
@audit_dates << BuildingSync::AuditDate.new(audit_date, @ns)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Utilities
|
77
|
+
@base_xml.elements.each("#{@ns}:Utilities/#{@ns}:Utility") do |utility|
|
78
|
+
@utilities << BuildingSync::Utility.new(utility, @ns)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def read_scenarios
|
83
|
+
# Scenarios - create and checks
|
84
|
+
scenarios_xml_temp = @base_xml.get_elements("#{@ns}:Scenarios/#{@ns}:Scenario")
|
85
|
+
cb_modeled = []
|
86
|
+
scenarios_xml_temp&.each do |scenario_xml|
|
87
|
+
if scenario_xml.is_a? REXML::Element
|
88
|
+
sc = BuildingSync::Scenario.new(scenario_xml, @ns)
|
89
|
+
@scenarios.push(sc)
|
90
|
+
cb_modeled << sc if sc.cb_modeled?
|
91
|
+
@cb_measured << sc if sc.cb_measured?
|
92
|
+
@poms << sc if sc.pom?
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# -- Issue warnings for undesirable situations
|
97
|
+
if @scenarios.empty?
|
98
|
+
OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.Facility.read_xml', 'No Scenario elements found')
|
99
|
+
end
|
100
|
+
|
101
|
+
# -- Logging for Scenarios
|
102
|
+
if cb_modeled.empty?
|
103
|
+
OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.Facility.read_xml', 'A Current Building Modeled Scenario is required.')
|
104
|
+
elsif cb_modeled.size > 1
|
105
|
+
@cb_modeled = cb_modeled[0]
|
106
|
+
OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.Facility.read_xml', "Only 1 Current Building Modeled Scenario is supported. Using Scenario with ID: #{@cb_modeled.xget_id}")
|
107
|
+
else
|
108
|
+
@cb_modeled = cb_modeled[0]
|
109
|
+
OpenStudio.logFree(OpenStudio::Info, 'BuildingSync.Facility.read_xml', "Current Building Modeled Scenario has ID: #{@cb_modeled.xget_id}")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def get_all_utility_meter_numbers
|
114
|
+
all = []
|
115
|
+
@utilities.each do |utility|
|
116
|
+
all += utility.get_utility_meter_numbers
|
117
|
+
end
|
118
|
+
return all
|
119
|
+
end
|
120
|
+
|
121
|
+
def get_all_utility_names
|
122
|
+
all = []
|
123
|
+
@utilities.each do |utility|
|
124
|
+
all += utility.get_utility_meter_numbers
|
125
|
+
end
|
126
|
+
return all
|
127
|
+
end
|
128
|
+
|
129
|
+
def get_auditor_contact_id
|
130
|
+
return xget_attribute_for_element('AuditorContactID', 'IDref')
|
131
|
+
end
|
132
|
+
|
133
|
+
def get_newest_audit_date
|
134
|
+
dates = []
|
135
|
+
@audit_dates.each do |date|
|
136
|
+
dates << date.xget_text_as_date('Date')
|
137
|
+
end
|
138
|
+
return dates.max
|
139
|
+
end
|
140
|
+
|
141
|
+
def get_oldest_audit_date
|
142
|
+
dates = []
|
143
|
+
@audit_dates.each do |date|
|
144
|
+
dates << date.xget_text_as_date('Date')
|
145
|
+
end
|
146
|
+
return dates.min
|
147
|
+
end
|
148
|
+
|
149
|
+
# Get the SiteEnergyUseIntensity for the benchmark scenario.
|
150
|
+
# Where multiple benchmark scenarios exist, the value from the first is returned
|
151
|
+
# @see get_scenario_site_eui
|
152
|
+
def get_first_benchmark_site_eui
|
153
|
+
eui = []
|
154
|
+
ids = []
|
155
|
+
@scenarios.each do |scenario|
|
156
|
+
if scenario.benchmark?
|
157
|
+
eui << get_first_scenario_site_eui(scenario)
|
158
|
+
ids << scenario.xget_id
|
159
|
+
end
|
160
|
+
end
|
161
|
+
if eui.size == 1
|
162
|
+
return eui[0]
|
163
|
+
elsif eui.empty?
|
164
|
+
OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.Facility.get_benchmark_site_eui', 'No Benchmark Scenarios exist with SiteEnergyUseIntensity defined')
|
165
|
+
return nil
|
166
|
+
elsif eui.size > 1
|
167
|
+
OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.Facility.get_benchmark_site_eui', "Multiple Benchmark Scenarios exist with SiteEnergyUseIntensity defined. Returning the value for Scenario ID: #{ids[0]}")
|
168
|
+
return eui[0]
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# Get the SiteEnergyUseIntensity for the cb_modeled scenario.
|
173
|
+
# @see get_scenario_site_eui
|
174
|
+
def get_first_cb_modeled_site_eui
|
175
|
+
return get_first_scenario_site_eui(@cb_modeled)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Get the AllResourceTotal/SiteEnergyUseIntensity value as a float.
|
179
|
+
# Where multiple AllResourceTotals exist with the value defined, the first is returned.
|
180
|
+
# @param scenario [BuildingSync::Scenario] the scenario
|
181
|
+
# @return [Float] if atleast one value is found
|
182
|
+
# @return [nil] if no value is found
|
183
|
+
def get_first_scenario_site_eui(scenario)
|
184
|
+
eui = []
|
185
|
+
scenario.get_all_resource_totals.each do |art|
|
186
|
+
eui << art.xget_text_as_float('SiteEnergyUseIntensity')
|
187
|
+
end
|
188
|
+
if eui.size == 1
|
189
|
+
return eui[0]
|
190
|
+
elsif eui.empty?
|
191
|
+
OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.Facility.get_scenario_site_eui', "Scenario ID: #{@cb_modeled.xget_id} does not have a SiteEnergyUseIntensity defined in any of the AllResourceTotal elements.")
|
192
|
+
return nil
|
193
|
+
elsif eui.size > 1
|
194
|
+
OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.Facility.get_scenario_site_eui', "Scenario ID: #{@cb_modeled.xget_id} has more thant 1 (#{eui.size}) SiteEnergyUseIntensity defined in the AllResourceTotal elements. Returning the first.")
|
195
|
+
return eui[0]
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# add a current building modeled scenario and set the @cb_modeled attribute
|
200
|
+
# @param id [String] id to use for the scenario
|
201
|
+
# @return [NilClass]
|
202
|
+
def add_cb_modeled(id = 'Scenario-Baseline')
|
203
|
+
if @cb_modeled.nil? || @cb_modeled.empty?
|
204
|
+
g = BuildingSync::Generator.new
|
205
|
+
scenario_xml = g.add_scenario_to_report(@base_xml, 'CBModeled', id)
|
206
|
+
scenario = BuildingSync::Scenario.new(scenario_xml, @ns)
|
207
|
+
@scenarios.push(scenario)
|
208
|
+
@cb_modeled = scenario
|
209
|
+
OpenStudio.logFree(OpenStudio::Info, 'BuildingSync.WorkflowMaker.add_cb_modeled', "A Current Building Modeled scenario was added (Scenario ID: #{@cb_modeled.xget_id}).")
|
210
|
+
else
|
211
|
+
OpenStudio.logFree(OpenStudio::Warn, 'BuildingSync.WorkflowMaker.add_cb_modeled', "A Current Building Modeled scenario already exists (Scenario ID: #{@cb_modeled.xget_id}). A new one was not added.")
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
attr_reader :scenarios, :cb_modeled, :cb_measured, :poms, :utilities
|
216
|
+
end
|
217
|
+
end
|