buildingsync 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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