openstudio-extension 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +14 -0
  4. data/LICENSE.md +1 -1
  5. data/README.md +2 -0
  6. data/lib/openstudio/extension/runner.rb +12 -8
  7. data/lib/openstudio/extension/runner_config.rb +33 -6
  8. data/lib/openstudio/extension/version.rb +1 -1
  9. data/openstudio-extension.gemspec +6 -6
  10. metadata +18 -75
  11. data/lib/openstudio/extension/core/CreateResults.rb +0 -1033
  12. data/lib/openstudio/extension/core/check_air_sys_temps.rb +0 -160
  13. data/lib/openstudio/extension/core/check_calibration.rb +0 -125
  14. data/lib/openstudio/extension/core/check_cond_zns.rb +0 -54
  15. data/lib/openstudio/extension/core/check_domestic_hot_water.rb +0 -304
  16. data/lib/openstudio/extension/core/check_envelope_conductance.rb +0 -423
  17. data/lib/openstudio/extension/core/check_eui_by_end_use.rb +0 -132
  18. data/lib/openstudio/extension/core/check_eui_reasonableness.rb +0 -105
  19. data/lib/openstudio/extension/core/check_fan_pwr.rb +0 -68
  20. data/lib/openstudio/extension/core/check_internal_loads.rb +0 -363
  21. data/lib/openstudio/extension/core/check_mech_sys_capacity.rb +0 -196
  22. data/lib/openstudio/extension/core/check_mech_sys_efficiency.rb +0 -296
  23. data/lib/openstudio/extension/core/check_mech_sys_part_load_eff.rb +0 -434
  24. data/lib/openstudio/extension/core/check_mech_sys_type.rb +0 -109
  25. data/lib/openstudio/extension/core/check_part_loads.rb +0 -421
  26. data/lib/openstudio/extension/core/check_placeholder.rb +0 -45
  27. data/lib/openstudio/extension/core/check_plant_cap.rb +0 -93
  28. data/lib/openstudio/extension/core/check_plant_temps.rb +0 -129
  29. data/lib/openstudio/extension/core/check_plenum_loads.rb +0 -57
  30. data/lib/openstudio/extension/core/check_pump_pwr.rb +0 -78
  31. data/lib/openstudio/extension/core/check_sch_coord.rb +0 -211
  32. data/lib/openstudio/extension/core/check_schedules.rb +0 -281
  33. data/lib/openstudio/extension/core/check_simultaneous_heating_and_cooling.rb +0 -128
  34. data/lib/openstudio/extension/core/check_supply_air_and_thermostat_temp_difference.rb +0 -118
  35. data/lib/openstudio/extension/core/check_weather_files.rb +0 -102
  36. data/lib/openstudio/extension/core/deer_vintages.rb +0 -281
  37. data/lib/openstudio/extension/core/os_lib_aedg_measures.rb +0 -461
  38. data/lib/openstudio/extension/core/os_lib_constructions.rb +0 -353
  39. data/lib/openstudio/extension/core/os_lib_geometry.rb +0 -1169
  40. data/lib/openstudio/extension/core/os_lib_helper_methods.rb +0 -383
  41. data/lib/openstudio/extension/core/os_lib_hvac.rb +0 -2163
  42. data/lib/openstudio/extension/core/os_lib_lighting_and_equipment.rb +0 -184
  43. data/lib/openstudio/extension/core/os_lib_model_generation.rb +0 -3584
  44. data/lib/openstudio/extension/core/os_lib_model_simplification.rb +0 -1019
  45. data/lib/openstudio/extension/core/os_lib_outdoorair_and_infiltration.rb +0 -135
  46. data/lib/openstudio/extension/core/os_lib_reporting_qaqc.rb +0 -170
  47. data/lib/openstudio/extension/core/os_lib_schedules.rb +0 -933
@@ -1,423 +0,0 @@
1
- # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
3
- # See also https://openstudio.net/license
4
- # *******************************************************************************
5
-
6
- module OsLib_QAQC
7
- # include any general notes about QAQC method here
8
-
9
- # checks the number of unmet hours in the model
10
- # todo - do I need unique tolerance ranges for conductance, reflectance, and shgc
11
- def check_envelope_conductance(category, target_standard, min_pass, max_pass, name_only = false)
12
- # summary of the check
13
- check_elems = OpenStudio::AttributeVector.new
14
- check_elems << OpenStudio::Attribute.new('name', 'Envelope R-Value')
15
- check_elems << OpenStudio::Attribute.new('category', category)
16
- if target_standard == 'ICC IECC 2015'
17
- dislay_standard = target_standard
18
- check_elems << OpenStudio::Attribute.new('description', "Check envelope against Table R402.1.2 and R402.1.4 in #{dislay_standard} Residential Provisions.")
19
- elsif target_standard.include?('90.1-2013')
20
- display_standard = "ASHRAE #{target_standard}"
21
- check_elems << OpenStudio::Attribute.new('description', "Check envelope against #{display_standard} Table 5.5.2, Table G2.1.5 b,c,d,e, Section 5.5.3.1.1a. Roof reflectance of 55%, wall relfectance of 30%.")
22
- else
23
- # TODO: - could add more elsifs if want to dsiplay tables and sections for additional 90.1 standards
24
- if target_standard.include?('90.1')
25
- display_standard = "ASHRAE #{target_standard}"
26
- else
27
- display_standard = target_standard
28
- end
29
- check_elems << OpenStudio::Attribute.new('description', "Check envelope against #{display_standard}. Roof reflectance of 55%, wall relfectance of 30%.")
30
- end
31
-
32
- # stop here if only name is requested this is used to populate display name for arguments
33
- if name_only == true
34
- results = []
35
- check_elems.each do |elem|
36
- results << elem.valueAsString
37
- end
38
- return results
39
- end
40
-
41
- # list of surface types to identify for each space type for surfaces and sub-surfaces
42
- construction_type_array = []
43
- construction_type_array << ['ExteriorWall', 'SteelFramed']
44
- construction_type_array << ['ExteriorRoof', 'IEAD']
45
- construction_type_array << ['ExteriorFloor', 'Mass']
46
- construction_type_array << ['ExteriorDoor', 'Swinging']
47
- construction_type_array << ['ExteriorWindow', 'Metal framing (all other)']
48
- construction_type_array << ['Skylight', 'Glass with Curb']
49
- # overhead door doesn't show in list, or glass door
50
-
51
- # Versions of OpenStudio greater than 2.4.0 use a modified version of
52
- # openstudio-standards with different method calls. These methods
53
- # require a "Standard" object instead of the standard being passed into method calls.
54
- # This Standard object is used throughout the QAQC check.
55
- if OpenStudio::VersionString.new(OpenStudio.openStudioVersion) < OpenStudio::VersionString.new('2.4.3')
56
- use_old_gem_code = true
57
- else
58
- use_old_gem_code = false
59
- std = Standard.build(target_standard)
60
- end
61
-
62
- begin
63
- # loop through all space types used in the model
64
- @model.getSpaceTypes.each do |space_type|
65
- next if space_type.floorArea <= 0
66
- space_type_const_properties = {}
67
- construction_type_array.each do |const_type|
68
- # gather data for exterior wall
69
- intended_surface_type = const_type[0]
70
- standards_construction_type = const_type[1]
71
- space_type_const_properties[intended_surface_type] = {}
72
- if use_old_gem_code
73
- data = space_type.get_construction_properties(target_standard, intended_surface_type, standards_construction_type)
74
- else
75
- data = std.space_type_get_construction_properties(space_type, intended_surface_type, standards_construction_type)
76
- end
77
- if data.nil?
78
- puts "lookup for #{target_standard},#{intended_surface_type},#{standards_construction_type}"
79
- check_elems << OpenStudio::Attribute.new('flag', "Didn't find construction for #{standards_construction_type} #{intended_surface_type} for #{space_type.name}.")
80
- elsif intended_surface_type.include? 'ExteriorWall' || 'ExteriorFloor' || 'ExteriorDoor'
81
- space_type_const_properties[intended_surface_type]['u_value'] = data['assembly_maximum_u_value']
82
- space_type_const_properties[intended_surface_type]['reflectance'] = 0.30 # hard coded value
83
- elsif intended_surface_type.include? 'ExteriorRoof'
84
- space_type_const_properties[intended_surface_type]['u_value'] = data['assembly_maximum_u_value']
85
- space_type_const_properties[intended_surface_type]['reflectance'] = 0.55 # hard coded value
86
- else
87
- space_type_const_properties[intended_surface_type]['u_value'] = data['assembly_maximum_u_value']
88
- space_type_const_properties[intended_surface_type]['shgc'] = data['assembly_maximum_solar_heat_gain_coefficient']
89
- end
90
- end
91
-
92
- # make array of construction details for surfaces
93
- surface_details = []
94
- missing_surface_constructions = []
95
- sub_surface_details = []
96
- missing_sub_surface_constructions = []
97
-
98
- # loop through spaces
99
- space_type.spaces.each do |space|
100
- space.surfaces.each do |surface|
101
- next if surface.outsideBoundaryCondition != 'Outdoors'
102
- if surface.construction.is_initialized
103
- surface_details << { boundary_condition: surface.outsideBoundaryCondition, surface_type: surface.surfaceType, construction: surface.construction.get }
104
- else
105
- missing_constructions << surface.name.get
106
- end
107
-
108
- # make array of construction details for sub_surfaces
109
- surface.subSurfaces.each do |sub_surface|
110
- if sub_surface.construction.is_initialized
111
- sub_surface_details << { boundary_condition: sub_surface.outsideBoundaryCondition, surface_type: sub_surface.subSurfaceType, construction: sub_surface.construction.get }
112
- else
113
- missing_constructions << sub_surface.name.get
114
- end
115
- end
116
- end
117
- end
118
-
119
- if !missing_surface_constructions.empty?
120
- check_elems << OpenStudio::Attribute.new('flag', "#{missing_constructions.size} surfaces are missing constructions in #{space_type.name}. Spaces and can't be checked.")
121
- end
122
-
123
- if !missing_sub_surface_constructions.empty?
124
- check_elems << OpenStudio::Attribute.new('flag', "#{missing_constructions.size} sub surfaces are missing constructions in #{space_type.name}. Spaces and can't be checked.")
125
- end
126
-
127
- # gather targer values for this space type
128
- # todo - address support for other surface types e.g. overhead door glass door
129
- target_r_value_ip = {}
130
- target_reflectance = {}
131
- target_u_value_ip = {}
132
- target_shgc = {}
133
- target_r_value_ip['Wall'] = 1.0 / space_type_const_properties['ExteriorWall']['u_value'].to_f
134
- target_reflectance['Wall'] = space_type_const_properties['ExteriorWall']['reflectance'].to_f
135
- target_r_value_ip['RoofCeiling'] = 1.0 / space_type_const_properties['ExteriorRoof']['u_value'].to_f
136
- target_reflectance['RoofCeiling'] = space_type_const_properties['ExteriorRoof']['reflectance'].to_f
137
- target_r_value_ip['Floor'] = 1.0 / space_type_const_properties['ExteriorFloor']['u_value'].to_f
138
- target_reflectance['Floor'] = space_type_const_properties['ExteriorFloor']['reflectance'].to_f
139
- target_r_value_ip['Door'] = 1.0 / space_type_const_properties['ExteriorDoor']['u_value'].to_f
140
- target_reflectance['Door'] = space_type_const_properties['ExteriorDoor']['reflectance'].to_f
141
- target_u_value_ip['FixedWindow'] = space_type_const_properties['ExteriorWindow']['u_value'].to_f
142
- target_shgc['FixedWindow'] = space_type_const_properties['ExteriorWindow']['shgc'].to_f
143
- target_u_value_ip['OperableWindow'] = space_type_const_properties['ExteriorWindow']['u_value'].to_f
144
- target_shgc['OperableWindow'] = space_type_const_properties['ExteriorWindow']['shgc'].to_f
145
- target_u_value_ip['Skylight'] = space_type_const_properties['Skylight']['u_value'].to_f
146
- target_shgc['Skylight'] = space_type_const_properties['Skylight']['shgc'].to_f
147
-
148
- # loop through unique construction arary combinations
149
- surface_details.uniq.each do |surface_detail|
150
- if surface_detail[:construction].thermalConductance.is_initialized
151
-
152
- # don't use intened surface type of construction, look map based on surface type and boundary condition
153
- boundary_condition = surface_detail[:boundary_condition]
154
- surface_type = surface_detail[:surface_type]
155
- intended_surface_type = ''
156
- if boundary_condition.to_s == 'Outdoors'
157
- if surface_type.to_s == 'Wall' then intended_surface_type = 'ExteriorWall' end
158
- if surface_type == 'RoofCeiling' then intended_surface_type = 'ExteriorRoof' end
159
- if surface_type == 'Floor' then intended_surface_type = 'ExteriorFloor' end
160
- else
161
- # currently only used for surfaces with outdoor boundary condition
162
- end
163
- if use_old_gem_code
164
- film_coefficients_r_value = surface_detail[:construction].to_LayeredConstruction.get.to_Construction.get.film_coefficients_r_value(intended_surface_type)
165
- else
166
- film_coefficients_r_value = std.film_coefficients_r_value(intended_surface_type, includes_int_film = true, includes_ext_film = true)
167
- end
168
- thermal_conductance = surface_detail[:construction].thermalConductance.get
169
- r_value_with_film = 1 / thermal_conductance + film_coefficients_r_value
170
- source_units = 'm^2*K/W'
171
- target_units = 'ft^2*h*R/Btu'
172
- r_value_ip = OpenStudio.convert(r_value_with_film, source_units, target_units).get
173
- solar_reflectance = surface_detail[:construction].to_LayeredConstruction.get.layers[0].to_OpaqueMaterial.get.solarReflectance .get # TODO: - check optional first does what happens with ext. air wall
174
-
175
- # stop if didn't find values (0 or infinity)
176
- next if target_r_value_ip[surface_detail[:surface_type]] == 0.0
177
- next if target_r_value_ip[surface_detail[:surface_type]] == Float::INFINITY
178
-
179
- # check r avlues
180
- if r_value_ip < target_r_value_ip[surface_detail[:surface_type]] * (1.0 - min_pass)
181
- check_elems << OpenStudio::Attribute.new('flag', "R value of #{r_value_ip.round(2)} (#{target_units}) for #{surface_detail[:construction].name} in #{space_type.name} is more than #{min_pass * 100} % below the expected value of #{target_r_value_ip[surface_detail[:surface_type]].round(2)} (#{target_units}) for #{display_standard}.")
182
- elsif r_value_ip > target_r_value_ip[surface_detail[:surface_type]] * (1.0 + max_pass)
183
- check_elems << OpenStudio::Attribute.new('flag', "R value of #{r_value_ip.round(2)} (#{target_units}) for #{surface_detail[:construction].name} in #{space_type.name} is more than #{max_pass * 100} % above the expected value of #{target_r_value_ip[surface_detail[:surface_type]].round(2)} (#{target_units}) for #{display_standard}.")
184
- end
185
-
186
- # check solar reflectance
187
- if (solar_reflectance < target_reflectance[surface_detail[:surface_type]] * (1.0 - min_pass)) && (target_standard != 'ICC IECC 2015')
188
- check_elems << OpenStudio::Attribute.new('flag', "Solar Reflectance of #{(solar_reflectance * 100).round} % for #{surface_detail[:construction].name} in #{space_type.name} is more than #{min_pass * 100} % below the expected value of #{(target_reflectance[surface_detail[:surface_type]] * 100).round} %.")
189
- elsif (solar_reflectance > target_reflectance[surface_detail[:surface_type]] * (1.0 + max_pass)) && (target_standard != 'ICC IECC 2015')
190
- check_elems << OpenStudio::Attribute.new('flag', "Solar Reflectance of #{(solar_reflectance * 100).round} % for #{surface_detail[:construction].name} in #{space_type.name} is more than #{max_pass * 100} % above the expected value of #{(target_reflectance[surface_detail[:surface_type]] * 100).round} %.")
191
- end
192
-
193
- else
194
- check_elems << OpenStudio::Attribute.new('flag', "Can't calculate R value for #{surface_detail[:construction].name}.")
195
- end
196
- end
197
-
198
- # loop through unique construction arary combinations
199
- sub_surface_details.uniq.each do |sub_surface_detail|
200
- if sub_surface_detail[:surface_type] == 'FixedWindow' || sub_surface_detail[:surface_type] == 'OperableWindow' || sub_surface_detail[:surface_type] == 'Skylight'
201
- # check for non opaque sub surfaces
202
- source_units = 'W/m^2*K'
203
- target_units = 'Btu/ft^2*h*R'
204
-
205
- if use_old_gem_code
206
- u_factor_si = sub_surface_detail[:construction].to_LayeredConstruction.get.to_Construction.get.calculated_u_factor
207
- else
208
- u_factor_si = std.construction_calculated_u_factor(sub_surface_detail[:construction].to_LayeredConstruction.get.to_Construction.get)
209
- end
210
- u_factor_ip = OpenStudio.convert(u_factor_si, source_units, target_units).get
211
- if use_old_gem_code
212
- shgc = sub_surface_detail[:construction].to_LayeredConstruction.get.to_Construction.get.calculated_solar_heat_gain_coefficient
213
- else
214
- shgc = std.construction_calculated_solar_heat_gain_coefficient(sub_surface_detail[:construction].to_LayeredConstruction.get.to_Construction.get)
215
- end
216
-
217
- # stop if didn't find values (0 or infinity)
218
- next if target_u_value_ip[sub_surface_detail[:surface_type]] == 0.0
219
- next if target_u_value_ip[sub_surface_detail[:surface_type]] == Float::INFINITY
220
-
221
- # check u avlues
222
- if u_factor_ip < target_u_value_ip[sub_surface_detail[:surface_type]] * (1.0 - min_pass)
223
- check_elems << OpenStudio::Attribute.new('flag', "U value of #{u_factor_ip.round(2)} (#{target_units}) for #{sub_surface_detail[:construction].name} in #{space_type.name} is more than #{min_pass * 100} % below the expected value of #{target_u_value_ip[sub_surface_detail[:surface_type]].round(2)} (#{target_units}) for #{display_standard}.")
224
- elsif u_factor_ip > target_u_value_ip[sub_surface_detail[:surface_type]] * (1.0 + max_pass)
225
- check_elems << OpenStudio::Attribute.new('flag', "U value of #{u_factor_ip.round(2)} (#{target_units}) for #{sub_surface_detail[:construction].name} in #{space_type.name} is more than #{max_pass * 100} % above the expected value of #{target_u_value_ip[sub_surface_detail[:surface_type]].round(2)} (#{target_units}) for #{display_standard}.")
226
- end
227
-
228
- # check shgc
229
- if shgc < target_shgc[sub_surface_detail[:surface_type]] * (1.0 - min_pass)
230
- check_elems << OpenStudio::Attribute.new('flag', "SHGC of #{shgc.round(2)} % for #{sub_surface_detail[:construction].name} in #{space_type.name} is more than #{min_pass * 100} % below the expected value of #{target_shgc[sub_surface_detail[:surface_type]].round(2)} %.")
231
- elsif shgc > target_shgc[sub_surface_detail[:surface_type]] * (1.0 + max_pass)
232
- check_elems << OpenStudio::Attribute.new('flag', "SHGC of #{shgc.round(2)} % for #{sub_surface_detail[:construction].name} in #{space_type.name} is more than #{max_pass * 100} % above the expected value of #{target_shgc[sub_surface_detail[:surface_type]].round(2)} %.")
233
- end
234
-
235
- else
236
- # check for opaque sub surfaces
237
- if sub_surface_detail[:construction].thermalConductance.is_initialized
238
-
239
- # don't use intened surface type of construction, look map based on surface type and boundary condition
240
- boundary_condition = sub_surface_detail[:boundary_condition]
241
- surface_type = sub_surface_detail[:surface_type]
242
- intended_surface_type = ''
243
- if boundary_condition.to_s == 'Outdoors'
244
- # TODO: add additional intended surface types
245
- if surface_type.to_s == 'Door' then intended_surface_type = 'ExteriorDoor' end
246
- else
247
- # currently only used for surfaces with outdoor boundary condition
248
- end
249
- if use_old_gem_code
250
- film_coefficients_r_value = sub_surface_detail[:construction].to_LayeredConstruction.get.to_Construction.get.film_coefficients_r_value(intended_surface_type)
251
- else
252
- film_coefficients_r_value = std.film_coefficients_r_value(intended_surface_type, includes_int_film = true, includes_ext_film = true)
253
- end
254
-
255
- thermal_conductance = sub_surface_detail[:construction].thermalConductance.get
256
- r_value_with_film = 1 / thermal_conductance + film_coefficients_r_value
257
- source_units = 'm^2*K/W'
258
- target_units = 'ft^2*h*R/Btu'
259
- r_value_ip = OpenStudio.convert(r_value_with_film, source_units, target_units).get
260
- solar_reflectance = sub_surface_detail[:construction].to_LayeredConstruction.get.layers[0].to_OpaqueMaterial.get.solarReflectance .get # TODO: - check optional first does what happens with ext. air wall
261
-
262
- # stop if didn't find values (0 or infinity)
263
- next if target_r_value_ip[sub_surface_detail[:surface_type]] == 0.0
264
- next if target_r_value_ip[sub_surface_detail[:surface_type]] == Float::INFINITY
265
-
266
- # check r avlues
267
- if r_value_ip < target_r_value_ip[sub_surface_detail[:surface_type]] * (1.0 - min_pass)
268
- check_elems << OpenStudio::Attribute.new('flag', "R value of #{r_value_ip.round(2)} (#{target_units}) for #{sub_surface_detail[:construction].name} in #{space_type.name} is more than #{min_pass * 100} % below the expected value of #{target_r_value_ip[sub_surface_detail[:surface_type]].round(2)} (#{target_units}) for #{display_standard}.")
269
- elsif r_value_ip > target_r_value_ip[sub_surface_detail[:surface_type]] * (1.0 + max_pass)
270
- check_elems << OpenStudio::Attribute.new('flag', "R value of #{r_value_ip.round(2)} (#{target_units}) for #{sub_surface_detail[:construction].name} in #{space_type.name} is more than #{max_pass * 100} % above the expected value of #{target_r_value_ip[sub_surface_detail[:surface_type]].round(2)} (#{target_units}) for #{display_standard}.")
271
- end
272
-
273
- # check solar reflectance
274
- if (solar_reflectance < target_reflectance[sub_surface_detail[:surface_type]] * (1.0 - min_pass)) && (target_standard != 'ICC IECC 2015')
275
- check_elems << OpenStudio::Attribute.new('flag', "Solar Reflectance of #{(solar_reflectance * 100).round} % for #{sub_surface_detail[:construction].name} in #{space_type.name} is more than #{min_pass * 100} % below the expected value of #{(target_reflectance[sub_surface_detail[:surface_type]] * 100).round} %.")
276
- elsif (solar_reflectance > target_reflectance[sub_surface_detail[:surface_type]] * (1.0 + max_pass)) && (target_standard != 'ICC IECC 2015')
277
- check_elems << OpenStudio::Attribute.new('flag', "Solar Reflectance of #{(solar_reflectance * 100).round} % for #{sub_surface_detail[:construction].name} in #{space_type.name} is more than #{max_pass * 100} % above the expected value of #{(target_reflectance[sub_surface_detail[:surface_type]] * 100).round} %.")
278
- end
279
-
280
- else
281
- check_elems << OpenStudio::Attribute.new('flag', "Can't calculate R value for #{sub_surface_detail[:construction].name}.")
282
- end
283
-
284
- end
285
- end
286
- end
287
-
288
- # check spaces without space types against Nonresidential for this climate zone
289
- @model.getSpaces.each do |space|
290
- if !space.spaceType.is_initialized
291
-
292
- # make array of construction details for surfaces
293
- surface_details = []
294
- missing_surface_constructions = []
295
- sub_surface_details = []
296
- missing_sub_surface_constructions = []
297
-
298
- space.surfaces.each do |surface|
299
- next if surface.outsideBoundaryCondition != 'Outdoors'
300
- if surface.construction.is_initialized
301
- surface_details << { boundary_condition: surface.outsideBoundaryCondition, surface_type: surface.surfaceType, construction: surface.construction.get }
302
- else
303
- missing_constructions << surface.name.get
304
- end
305
-
306
- # make array of construction details for sub_surfaces
307
- surface.subSurfaces.each do |sub_surface|
308
- if sub_surface.construction.is_initialized
309
- sub_surface_details << { boundary_condition: sub_surface.outsideBoundaryCondition, surface_type: sub_surface.subSurfaceType, construction: sub_surface.construction.get }
310
- else
311
- missing_constructions << sub_surface.name.get
312
- end
313
- end
314
- end
315
-
316
- if !missing_surface_constructions.empty?
317
- check_elems << OpenStudio::Attribute.new('flag', "#{missing_constructions.size} surfaces are missing constructions in #{space_type.name}. Spaces and can't be checked.")
318
- end
319
-
320
- if !missing_sub_surface_constructions.empty?
321
- check_elems << OpenStudio::Attribute.new('flag', "#{missing_constructions.size} sub surfaces are missing constructions in #{space_type.name}. Spaces and can't be checked.")
322
- end
323
-
324
- surface_details.uniq.each do |surface_detail|
325
- if surface_detail[:construction].thermalConductance.is_initialized
326
- # don't use intened surface type of construction, look map based on surface type and boundary condition
327
- boundary_condition = surface_detail[:boundary_condition]
328
- surface_type = surface_detail[:surface_type]
329
- intended_surface_type = ''
330
- if boundary_condition.to_s == 'Outdoors'
331
- if surface_type.to_s == 'Wall'
332
- intended_surface_type = 'ExteriorWall'
333
- standards_construction_type = 'SteelFramed'
334
- elsif surface_type == 'RoofCeiling'
335
- intended_surface_type = 'ExteriorRoof'
336
- standards_construction_type = 'IEAD'
337
- else surface_type == 'Floor'
338
- intended_surface_type = 'ExteriorFloor'
339
- standards_construction_type = 'Mass'
340
- end
341
- else
342
- # currently only used for surfaces with outdoor boundary condition
343
- end
344
- if use_old_gem_code
345
- film_coefficients_r_value = surface_detail[:construction].to_LayeredConstruction.get.to_Construction.get.film_coefficients_r_value(intended_surface_type)
346
- else
347
- film_coefficients_r_value = std.film_coefficients_r_value(intended_surface_type, includes_int_film = true, includes_ext_film = true)
348
- end
349
-
350
- thermal_conductance = surface_detail[:construction].thermalConductance.get
351
- r_value_with_film = 1 / thermal_conductance + film_coefficients_r_value
352
- source_units = 'm^2*K/W'
353
- target_units = 'ft^2*h*R/Btu'
354
- r_value_ip = OpenStudio.convert(r_value_with_film, source_units, target_units).get
355
- solar_reflectance = surface_detail[:construction].to_LayeredConstruction.get.layers[0].to_OpaqueMaterial.get.solarReflectance .get # TODO: - check optional first does what happens with ext. air wall
356
-
357
- # calculate target_r_value_ip
358
- target_reflectance = nil
359
- if use_old_gem_code
360
- data = @model.get_construction_properties(target_standard, intended_surface_type, standards_construction_type)
361
- else
362
- data = std.model_get_construction_properties(@model, intended_surface_type, standards_construction_type)
363
- end
364
-
365
- if data.nil?
366
- check_elems << OpenStudio::Attribute.new('flag', "Didn't find construction for #{standards_construction_type} #{intended_surface_type} for #{space.name}.")
367
- next
368
- elsif intended_surface_type.include? 'ExteriorWall' || 'ExteriorFloor' || 'ExteriorDoor'
369
- assembly_maximum_u_value = data['assembly_maximum_u_value']
370
- target_reflectance = 0.30
371
- elsif intended_surface_type.include? 'ExteriorRoof'
372
- assembly_maximum_u_value = data['assembly_maximum_u_value']
373
- target_reflectance = 0.55
374
- else
375
- assembly_maximum_u_value = data['assembly_maximum_u_value']
376
- assembly_maximum_solar_heat_gain_coefficient = data['assembly_maximum_solar_heat_gain_coefficient']
377
- end
378
- assembly_maximum_r_value_ip = 1 / assembly_maximum_u_value
379
-
380
- # stop if didn't find values (0 or infinity)
381
- next if assembly_maximum_r_value_ip == 0.0
382
- next if assembly_maximum_r_value_ip == Float::INFINITY
383
-
384
- # check r avlues
385
- if r_value_ip < assembly_maximum_r_value_ip * (1.0 - min_pass)
386
- check_elems << OpenStudio::Attribute.new('flag', "R value of #{r_value_ip.round(2)} (#{target_units}) for #{surface_detail[:construction].name} in #{space.name} is more than #{min_pass * 100} % below the expected value of #{assembly_maximum_r_value_ip.round(2)} (#{target_units}) for #{display_standard}.")
387
- elsif r_value_ip > assembly_maximum_r_value_ip * (1.0 + max_pass)
388
- check_elems << OpenStudio::Attribute.new('flag', "R value of #{r_value_ip.round(2)} (#{target_units}) for #{surface_detail[:construction].name} in #{space.name} is more than #{max_pass * 100} % above the expected value of #{assembly_maximum_r_value_ip.round(2)} (#{target_units}) for #{display_standard}.")
389
- end
390
-
391
- # check solar reflectance
392
- if (solar_reflectance < target_reflectance * (1.0 - min_pass)) && (target_standard != 'ICC IECC 2015')
393
- check_elems << OpenStudio::Attribute.new('flag', "Solar Reflectance of #{(solar_reflectance * 100).round} % for #{surface_detail[:construction].name} in #{space.name} is more than #{min_pass * 100} % below the expected value of #{(target_reflectance * 100).round} %.")
394
- elsif (solar_reflectance > target_reflectance * (1.0 + max_pass)) && (target_standard != 'ICC IECC 2015')
395
- check_elems << OpenStudio::Attribute.new('flag', "Solar Reflectance of #{(solar_reflectance * 100).round} % for #{surface_detail[:construction].name} in #{space.name} is more than #{max_pass * 100} % above the expected value of #{(target_reflectance * 100).round} %.")
396
- end
397
- else
398
- check_elems << OpenStudio::Attribute.new('flag', "Can't calculate R value for #{surface_detail[:construction].name}.")
399
- end
400
- end
401
-
402
- sub_surface_details.uniq.each do |sub_surface_detail|
403
- # TODO: update this so it works for doors and windows
404
- check_elems << OpenStudio::Attribute.new('flag', "Not setup to check sub-surfaces of spaces without space types. Can't check properties for #{sub_surface_detail[:construction].name}.")
405
- end
406
-
407
- end
408
- end
409
- rescue StandardError => e
410
- # brief description of ruby error
411
- check_elems << OpenStudio::Attribute.new('flag', "Error prevented QAQC check from running (#{e}).")
412
-
413
- # backtrace of ruby error for diagnostic use
414
- if @error_backtrace then check_elems << OpenStudio::Attribute.new('flag', e.backtrace.join("\n").to_s) end
415
- end
416
-
417
- # add check_elms to new attribute
418
- check_elem = OpenStudio::Attribute.new('check', check_elems)
419
-
420
- return check_elem
421
- # note: registerWarning and registerValue will be added for checks downstream using os_lib_reporting_qaqc.rb
422
- end
423
- end
@@ -1,132 +0,0 @@
1
- # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
3
- # See also https://openstudio.net/license
4
- # *******************************************************************************
5
-
6
- module OsLib_QAQC
7
- # include any general notes about QAQC method here
8
-
9
- # checks the number of unmet hours in the model
10
- def check_eui_by_end_use(category, target_standard, min_pass, max_pass, name_only = false)
11
- # summary of the check
12
- check_elems = OpenStudio::AttributeVector.new
13
- check_elems << OpenStudio::Attribute.new('name', 'End Use by Category')
14
- check_elems << OpenStudio::Attribute.new('category', category)
15
- check_elems << OpenStudio::Attribute.new('description', "Check end use by category against #{target_standard} DOE prototype buildings.")
16
-
17
- # stop here if only name is requested this is used to populate display name for arguments
18
- if name_only == true
19
- results = []
20
- check_elems.each do |elem|
21
- results << elem.valueAsString
22
- end
23
- return results
24
- end
25
-
26
- # Versions of OpenStudio greater than 2.4.0 use a modified version of
27
- # openstudio-standards with different method calls. These methods
28
- # require a "Standard" object instead of the standard being passed into method calls.
29
- # This Standard object is used throughout the QAQC check.
30
- if OpenStudio::VersionString.new(OpenStudio.openStudioVersion) < OpenStudio::VersionString.new('2.4.3')
31
- use_old_gem_code = true
32
- else
33
- use_old_gem_code = false
34
- std = Standard.build(target_standard)
35
- end
36
-
37
- begin
38
- # total building area
39
- query = 'SELECT Value FROM tabulardatawithstrings WHERE '
40
- query << "ReportName='AnnualBuildingUtilityPerformanceSummary' and "
41
- query << "ReportForString='Entire Facility' and "
42
- query << "TableName='Building Area' and "
43
- query << "RowName='Total Building Area' and "
44
- query << "ColumnName='Area' and "
45
- query << "Units='m2';"
46
- query_results = @sql.execAndReturnFirstDouble(query)
47
- if query_results.empty?
48
- check_elems << OpenStudio::Attribute.new('flag', "Can't calculate EUI, SQL query for building area failed.")
49
- return OpenStudio::Attribute.new('check', check_elems)
50
- else
51
- energy_plus_area = query_results.get
52
- end
53
-
54
- # temp code to check OS vs. E+ area
55
- open_studio_area = @model.getBuilding.floorArea
56
- if (energy_plus_area - open_studio_area).abs >= 0.1
57
- check_elems << OpenStudio::Attribute.new('flag', "EnergyPlus reported area is #{energy_plus_area} (m^2). OpenStudio reported area is #{@model.getBuilding.floorArea} (m^2).")
58
- end
59
-
60
- # loop through end uses and gather consumption, normalized by floor area
61
- actual_eui_by_end_use = {}
62
- OpenStudio::EndUseCategoryType.getValues.each do |end_use|
63
- # get end uses
64
- end_use = OpenStudio::EndUseCategoryType.new(end_use).valueDescription
65
- query_elec = "SELECT Value FROM tabulardatawithstrings WHERE ReportName='AnnualBuildingUtilityPerformanceSummary' and TableName='End Uses' and RowName= '#{end_use}' and ColumnName= 'Electricity'"
66
- query_gas = "SELECT Value FROM tabulardatawithstrings WHERE ReportName='AnnualBuildingUtilityPerformanceSummary' and TableName='End Uses' and RowName= '#{end_use}' and ColumnName= 'Natural Gas'"
67
- query_add = "SELECT Value FROM tabulardatawithstrings WHERE ReportName='AnnualBuildingUtilityPerformanceSummary' and TableName='End Uses' and RowName= '#{end_use}' and ColumnName= 'Additional Fuel'"
68
- query_dc = "SELECT Value FROM tabulardatawithstrings WHERE ReportName='AnnualBuildingUtilityPerformanceSummary' and TableName='End Uses' and RowName= '#{end_use}' and ColumnName= 'District Cooling'"
69
- query_dh = "SELECT Value FROM tabulardatawithstrings WHERE ReportName='AnnualBuildingUtilityPerformanceSummary' and TableName='End Uses' and RowName= '#{end_use}' and ColumnName= 'District Heating'"
70
- results_elec = @sql.execAndReturnFirstDouble(query_elec).get
71
- results_gas = @sql.execAndReturnFirstDouble(query_gas).get
72
- results_add = @sql.execAndReturnFirstDouble(query_add).get
73
- results_dc = @sql.execAndReturnFirstDouble(query_dc).get
74
- results_dh = @sql.execAndReturnFirstDouble(query_dh).get
75
- total_end_use = results_elec + results_gas + results_add + results_dc + results_dh
76
-
77
- # populate hash for actual end use normalized by area
78
- actual_eui_by_end_use[end_use] = total_end_use / energy_plus_area
79
- end
80
-
81
- # gather target end uses for given standard as hash
82
- if use_old_gem_code
83
- target_eui_by_end_use = @model.find_target_eui_by_end_use(target_standard)
84
- else
85
- std = Standard.build(target_standard)
86
- target_eui_by_end_use = std.model_find_target_eui_by_end_use(@model)
87
- end
88
-
89
- # units for flag display text and unit conversion
90
- source_units = 'GJ/m^2'
91
- target_units = 'kBtu/ft^2'
92
-
93
- # check acutal vs. target against tolerance
94
- if !target_eui_by_end_use.nil?
95
- actual_eui_by_end_use.each do |end_use, value|
96
- # this should have value of 0 in model. This page change in the future. It doesn't exist in target lookup
97
- next if end_use == 'Exterior Equipment'
98
-
99
- # perform check and issue flags as needed
100
- target_value = target_eui_by_end_use[end_use]
101
- eui_ip_neat = OpenStudio.toNeatString(OpenStudio.convert(value, source_units, target_units).get, 5, true)
102
- target_eui_ip_neat = OpenStudio.toNeatString(OpenStudio.convert(target_value, source_units, target_units).get, 1, true)
103
-
104
- # add in use case specific logic to skip checks when near 0 actual and target
105
- skip = false
106
- if (end_use == 'Heat Recovery') && (value < 0.05) && (target_value < 0.05) then skip = true end
107
- if (end_use == 'Pumps') && (value < 0.05) && (target_value < 0.05) then skip = true end
108
-
109
- if (value < target_value * (1.0 - min_pass)) && !skip
110
- check_elems << OpenStudio::Attribute.new('flag', "#{end_use} EUI of #{eui_ip_neat} (#{target_units}) is less than #{min_pass * 100} % below the expected #{end_use} EUI of #{target_eui_ip_neat} (#{target_units}) for #{target_standard}.")
111
- elsif (value > target_value * (1.0 + max_pass)) && !skip
112
- check_elems << OpenStudio::Attribute.new('flag', "#{end_use} EUI of #{eui_ip_neat} (#{target_units}) is more than #{max_pass * 100} % above the expected #{end_use} EUI of #{target_eui_ip_neat} (#{target_units}) for #{target_standard}.")
113
- end
114
- end
115
- else
116
- check_elems << OpenStudio::Attribute.new('flag', "Can't calculate target end use EUIs. Make sure model has expected climate zone and building type.")
117
- end
118
- rescue StandardError => e
119
- # brief description of ruby error
120
- check_elems << OpenStudio::Attribute.new('flag', "Error prevented QAQC check from running (#{e}).")
121
-
122
- # backtrace of ruby error for diagnostic use
123
- if @error_backtrace then check_elems << OpenStudio::Attribute.new('flag', e.backtrace.join("\n").to_s) end
124
- end
125
-
126
- # add check_elms to new attribute
127
- check_elem = OpenStudio::Attribute.new('check', check_elems)
128
-
129
- return check_elem
130
- # note: registerWarning and registerValue will be added for checks downstream using os_lib_reporting_qaqc.rb
131
- end
132
- end