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.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/continuous_integration.yml +146 -0
  3. data/.gitignore +33 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +10 -0
  6. data/CHANGELOG.md +50 -0
  7. data/Gemfile +31 -0
  8. data/Jenkinsfile +10 -0
  9. data/LICENSE.md +29 -0
  10. data/README.md +105 -0
  11. data/Rakefile +77 -0
  12. data/bin/console +15 -0
  13. data/bin/setup +8 -0
  14. data/buildingsync.gemspec +37 -0
  15. data/config.rb.in +26 -0
  16. data/doc_templates/LICENSE.md +29 -0
  17. data/doc_templates/README.md.erb +42 -0
  18. data/doc_templates/copyright_erb.txt +38 -0
  19. data/doc_templates/copyright_js.txt +5 -0
  20. data/doc_templates/copyright_ruby.txt +36 -0
  21. data/lib/buildingsync.rb +43 -0
  22. data/lib/buildingsync/all_resource_total.rb +54 -0
  23. data/lib/buildingsync/audit_date.rb +54 -0
  24. data/lib/buildingsync/constants.rb +49 -0
  25. data/lib/buildingsync/contact.rb +54 -0
  26. data/lib/buildingsync/extension.rb +57 -0
  27. data/lib/buildingsync/generator.rb +584 -0
  28. data/lib/buildingsync/get_bcl_weather_file.rb +326 -0
  29. data/lib/buildingsync/helpers/Model.hvac.rb +216 -0
  30. data/lib/buildingsync/helpers/helper.rb +494 -0
  31. data/lib/buildingsync/helpers/xml_get_set.rb +215 -0
  32. data/lib/buildingsync/makers/phase_zero_base.osw +178 -0
  33. data/lib/buildingsync/makers/workflow_maker.json +811 -0
  34. data/lib/buildingsync/makers/workflow_maker.rb +581 -0
  35. data/lib/buildingsync/makers/workflow_maker_base.rb +167 -0
  36. data/lib/buildingsync/model_articulation/building.rb +1119 -0
  37. data/lib/buildingsync/model_articulation/building_and_system_types.json +121 -0
  38. data/lib/buildingsync/model_articulation/building_section.rb +190 -0
  39. data/lib/buildingsync/model_articulation/building_system.rb +49 -0
  40. data/lib/buildingsync/model_articulation/envelope_system.rb +102 -0
  41. data/lib/buildingsync/model_articulation/exterior_floor_system_type.rb +64 -0
  42. data/lib/buildingsync/model_articulation/facility.rb +439 -0
  43. data/lib/buildingsync/model_articulation/foundation_system_type.rb +64 -0
  44. data/lib/buildingsync/model_articulation/hvac_system.rb +395 -0
  45. data/lib/buildingsync/model_articulation/lighting_system.rb +102 -0
  46. data/lib/buildingsync/model_articulation/loads_system.rb +287 -0
  47. data/lib/buildingsync/model_articulation/location_element.rb +129 -0
  48. data/lib/buildingsync/model_articulation/measure.rb +57 -0
  49. data/lib/buildingsync/model_articulation/roof_system_type.rb +64 -0
  50. data/lib/buildingsync/model_articulation/service_hot_water_system.rb +87 -0
  51. data/lib/buildingsync/model_articulation/site.rb +242 -0
  52. data/lib/buildingsync/model_articulation/spatial_element.rb +343 -0
  53. data/lib/buildingsync/model_articulation/wall_system_type.rb +64 -0
  54. data/lib/buildingsync/report.rb +217 -0
  55. data/lib/buildingsync/resource_use.rb +55 -0
  56. data/lib/buildingsync/scenario.rb +622 -0
  57. data/lib/buildingsync/selection_tool.rb +98 -0
  58. data/lib/buildingsync/time_series.rb +85 -0
  59. data/lib/buildingsync/translator.rb +167 -0
  60. data/lib/buildingsync/utility.rb +67 -0
  61. data/lib/buildingsync/version.rb +45 -0
  62. 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