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,281 +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_schedules(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', 'Schedules')
14
- check_elems << OpenStudio::Attribute.new('category', category)
15
- check_elems << OpenStudio::Attribute.new('description', 'Check schedules for lighting, ventilation, occupant density, plug loads, and equipment based on DOE reference building schedules in terms of full load hours per year.')
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
- # loop through all space types used in the model
39
- @model.getSpaceTypes.each do |space_type|
40
- next if space_type.floorArea <= 0
41
-
42
- # load in standard info for this space type
43
- if use_old_gem_code
44
- data = space_type.get_standards_data(target_standard)
45
- else
46
- data = std.space_type_get_standards_data(space_type)
47
- end
48
-
49
- if data.nil? || data.empty?
50
-
51
- # skip if all spaces using this space type are plenums
52
- all_spaces_plenums = true
53
- space_type.spaces.each do |space|
54
- if use_old_gem_code
55
- if !space.plenum?
56
- all_spaces_plenums = false
57
- next
58
- end
59
- else
60
- if !std.space_plenum?(space)
61
- all_spaces_plenums = false
62
- next
63
- end
64
- end
65
- end
66
-
67
- if !all_spaces_plenums
68
- check_elems << OpenStudio::Attribute.new('flag', "Unexpected standards type for #{space_type.name}, can't validate schedules.")
69
- end
70
-
71
- next
72
- end
73
-
74
- # temp model to hold schedules to check
75
- model_temp = OpenStudio::Model::Model.new
76
-
77
- # check lighting schedules
78
- data['lighting_per_area'].nil? ? (target_ip = 0.0) : (target_ip = data['lighting_per_area'])
79
- if target_ip.to_f > 0
80
- if use_old_gem_code
81
- schedule_target = model_temp.add_schedule(data['lighting_schedule'])
82
- else
83
- schedule_target = std.model_add_schedule(model_temp, data['lighting_schedule'])
84
- end
85
- if !schedule_target
86
- check_elems << OpenStudio::Attribute.new('flag', "Didn't find schedule named #{data['lighting_schedule']} in standards json.")
87
- else
88
- # loop through and test individual load instances
89
- if use_old_gem_code
90
- target_hrs = schedule_target.annual_equivalent_full_load_hrs
91
- else
92
- target_hrs = std.schedule_ruleset_annual_equivalent_full_load_hrs(schedule_target)
93
- end
94
- space_type.lights.each do |load_inst|
95
- inst_sch_check = generate_load_insc_sch_check_attribute(target_hrs, load_inst, space_type, check_elems, min_pass, max_pass)
96
- if inst_sch_check then check_elems << inst_sch_check end
97
- end
98
-
99
- end
100
- end
101
-
102
- # check electric equipment schedules
103
- data['electric_equipment_per_area'].nil? ? (target_ip = 0.0) : (target_ip = data['electric_equipment_per_area'])
104
- if target_ip.to_f > 0
105
- if use_old_gem_code
106
- schedule_target = model_temp.add_schedule(data['electric_equipment_schedule'])
107
- else
108
- schedule_target = std.model_add_schedule(model_temp, data['electric_equipment_schedule'])
109
- end
110
- if !schedule_target
111
- check_elems << OpenStudio::Attribute.new('flag', "Didn't find schedule named #{data['electric_equipment_schedule']} in standards json.")
112
- else
113
- # loop through and test individual load instances
114
- if use_old_gem_code
115
- target_hrs = schedule_target.annual_equivalent_full_load_hrs
116
- else
117
- target_hrs = std.schedule_ruleset_annual_equivalent_full_load_hrs(schedule_target)
118
- end
119
-
120
- space_type.electricEquipment.each do |load_inst|
121
- inst_sch_check = generate_load_insc_sch_check_attribute(target_hrs, load_inst, space_type, check_elems, min_pass, max_pass)
122
- if inst_sch_check then check_elems << inst_sch_check end
123
- end
124
- end
125
- end
126
-
127
- # check gas equipment schedules
128
- # todo - update measure test to with space type to check this
129
- data['gas_equipment_per_area'].nil? ? (target_ip = 0.0) : (target_ip = data['gas_equipment_per_area'])
130
- if target_ip.to_f > 0
131
- if use_old_gem_code
132
- schedule_target = model_temp.add_schedule(data['gas_equipment_schedule'])
133
- else
134
- schedule_target = std.model_add_schedule(model_temp, data['gas_equipment_schedule'])
135
- end
136
- if !schedule_target
137
- check_elems << OpenStudio::Attribute.new('flag', "Didn't find schedule named #{data['gas_equipment_schedule']} in standards json.")
138
- else
139
- # loop through and test individual load instances
140
- if use_old_gem_code
141
- target_hrs = schedule_target.annual_equivalent_full_load_hrs
142
- else
143
- target_hrs = std.schedule_ruleset_annual_equivalent_full_load_hrs(schedule_target)
144
- end
145
- space_type.gasEquipment.each do |load_inst|
146
- inst_sch_check = generate_load_insc_sch_check_attribute(target_hrs, load_inst, space_type, check_elems, min_pass, max_pass)
147
- if inst_sch_check then check_elems << inst_sch_check end
148
- end
149
- end
150
- end
151
-
152
- # check occupancy schedules
153
- data['occupancy_per_area'].nil? ? (target_ip = 0.0) : (target_ip = data['occupancy_per_area'])
154
- if target_ip.to_f > 0
155
- if use_old_gem_code
156
- schedule_target = model_temp.add_schedule(data['occupancy_schedule'])
157
- else
158
- schedule_target = std.model_add_schedule(model_temp, data['occupancy_schedule'])
159
- end
160
- if !schedule_target
161
- check_elems << OpenStudio::Attribute.new('flag', "Didn't find schedule named #{data['occupancy_schedule']} in standards json.")
162
- else
163
- # loop through and test individual load instances
164
- if use_old_gem_code
165
- target_hrs = schedule_target.annual_equivalent_full_load_hrs
166
- else
167
- target_hrs = std.schedule_ruleset_annual_equivalent_full_load_hrs(schedule_target)
168
- end
169
- space_type.people.each do |load_inst|
170
- inst_sch_check = generate_load_insc_sch_check_attribute(target_hrs, load_inst, space_type, check_elems, min_pass, max_pass)
171
- if inst_sch_check then check_elems << inst_sch_check end
172
- end
173
-
174
- end
175
- end
176
-
177
- # TODO: - check ventilation schedules
178
- # if objects are in the model should they just be always on schedule, or have a 8760 annual equiv value
179
- # oa_schedule should not exist, or if it does shoudl be always on or have 8760 annual equiv value
180
- if space_type.designSpecificationOutdoorAir.is_initialized
181
- oa = space_type.designSpecificationOutdoorAir.get
182
- if oa.outdoorAirFlowRateFractionSchedule.is_initialized
183
- # TODO: - update measure test to check this
184
- target_hrs = 8760
185
- inst_sch_check = generate_load_insc_sch_check_attribute(target_hrs, oa, space_type, check_elems, min_pass, max_pass)
186
- if inst_sch_check then check_elems << inst_sch_check end
187
- end
188
- end
189
-
190
- # notes
191
- # current logic only looks at 8760 values and not design days
192
- # when multiple instances of a type currently check every schedule by itself. In future could do weighted avg. merge
193
- # not looking at infiltration schedules
194
- # not looking at luminaires
195
- # not looking at space loads, only loads at space type
196
- # only checking schedules where standard shows non zero load value
197
- # model load for space type where standards doesn't have one wont throw flag about mis-matched schedules
198
- end
199
-
200
- # warn if there are spaces in model that don't use space type unless they appear to be plenums
201
- @model.getSpaces.each do |space|
202
- if use_old_gem_code
203
- next if space.plenum?
204
- else
205
- next if std.space_plenum?(space)
206
- end
207
- if !space.spaceType.is_initialized
208
- check_elems << OpenStudio::Attribute.new('flag', "#{space.name} doesn't have a space type assigned, can't validate schedules.")
209
- end
210
- end
211
- rescue StandardError => e
212
- # brief description of ruby error
213
- check_elems << OpenStudio::Attribute.new('flag', "Error prevented QAQC check from running (#{e}).")
214
-
215
- # backtrace of ruby error for diagnostic use
216
- if @error_backtrace then check_elems << OpenStudio::Attribute.new('flag', e.backtrace.join("\n").to_s) end
217
- end
218
-
219
- # add check_elms to new attribute
220
- check_elem = OpenStudio::Attribute.new('check', check_elems)
221
-
222
- return check_elem
223
- # note: registerWarning and registerValue will be added for checks downstream using os_lib_reporting_qaqc.rb
224
- end
225
-
226
- # code for each load instance for different load types will pass through here
227
- # will return nill or a single attribute
228
- def generate_load_insc_sch_check_attribute(target_hrs, load_inst, space_type, check_elems, min_pass, max_pass)
229
- # Versions of OpenStudio greater than 2.4.0 use a modified version of
230
- # openstudio-standards with different method calls. These methods
231
- # require a "Standard" object instead of the standard being passed into method calls.
232
- # This Standard object is used throughout the QAQC check.
233
- if OpenStudio::VersionString.new(OpenStudio.openStudioVersion) < OpenStudio::VersionString.new('2.4.3')
234
- use_old_gem_code = true
235
- else
236
- use_old_gem_code = false
237
- std = Standard.build('90.1-2013')
238
- end
239
-
240
- schedule_inst = nil
241
- inst_hrs = nil
242
-
243
- # get schedule
244
- if (load_inst.class.to_s == 'OpenStudio::Model::People') && load_inst.numberofPeopleSchedule.is_initialized
245
- schedule_inst = load_inst.numberofPeopleSchedule.get
246
- elsif (load_inst.class.to_s == 'OpenStudio::Model::DesignSpecificationOutdoorAir') && load_inst.outdoorAirFlowRateFractionSchedule.is_initialized
247
- schedule_inst = load_inst.outdoorAirFlowRateFractionSchedule .get
248
- elsif load_inst.schedule.is_initialized
249
- schedule_inst = load_inst.schedule.get
250
- else
251
- return OpenStudio::Attribute.new('flag', "#{load_inst.name} in #{space_type.name} doesn't have a schedule assigned.")
252
- end
253
-
254
- # get annual equiv for model schedule
255
- if schedule_inst.to_ScheduleRuleset.is_initialized
256
- if use_old_gem_code
257
- inst_hrs = schedule_inst.to_ScheduleRuleset.get.annual_equivalent_full_load_hrs
258
- else
259
- inst_hrs = std.schedule_ruleset_annual_equivalent_full_load_hrs(schedule_inst.to_ScheduleRuleset.get)
260
- end
261
- elsif schedule_inst.to_ScheduleConstant.is_initialized
262
- if use_old_gem_code
263
- inst_hrs = schedule_inst.to_ScheduleConstant.get.annual_equivalent_full_load_hrs
264
- else
265
- inst_hrs = std.schedule_constant_annual_equivalent_full_load_hrs(schedule_inst.to_ScheduleConstant.get)
266
- end
267
- else
268
- return OpenStudio::Attribute.new('flag', "#{schedule_inst.name} isn't a Ruleset or Constant schedule. Can't calculate annual equivalent full load hours.")
269
- end
270
-
271
- # check instance against target
272
- if inst_hrs < target_hrs * (1.0 - min_pass)
273
- return OpenStudio::Attribute.new('flag', "#{inst_hrs.round} annual equivalent full load hours for #{schedule_inst.name} in #{space_type.name} is more than #{min_pass * 100} (%) below the typical value of #{target_hrs.round} hours from the DOE Prototype building.")
274
- elsif inst_hrs > target_hrs * (1.0 + max_pass)
275
- return OpenStudio::Attribute.new('flag', "#{inst_hrs.round} annual equivalent full load hours for #{schedule_inst.name} in #{space_type.name} is more than #{max_pass * 100} (%) above the typical value of #{target_hrs.round} hours DOE Prototype building.")
276
- end
277
-
278
- # will get to this if no flag was thrown
279
- return false
280
- end
281
- end
@@ -1,128 +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_simultaneous_heating_and_cooling(category, max_pass, name_only = false)
11
- # summary of the check
12
- check_elems = OpenStudio::AttributeVector.new
13
- check_elems << OpenStudio::Attribute.new('name', 'Simultaneous Heating and Cooling')
14
- check_elems << OpenStudio::Attribute.new('category', category)
15
- check_elems << OpenStudio::Attribute.new('description', 'Check for simultaneous heating and cooling by looping through all Single Duct VAV Reheat Air Terminals and analyzing hourly data when there is a cooling load. ')
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
- begin
27
- # get the weather file run period (as opposed to design day run period)
28
- ann_env_pd = nil
29
- @sql.availableEnvPeriods.each do |env_pd|
30
- env_type = @sql.environmentType(env_pd)
31
- if env_type.is_initialized
32
- if env_type.get == OpenStudio::EnvironmentType.new('WeatherRunPeriod')
33
- ann_env_pd = env_pd
34
- break
35
- end
36
- end
37
- end
38
-
39
- # only try to get the annual timeseries if an annual simulation was run
40
- if ann_env_pd.nil?
41
- check_elems << OpenStudio::Attribute.new('flag', 'Cannot find the annual simulation run period, cannot determine simultaneous heating and cooling.')
42
- return check_elem
43
- end
44
-
45
- # For each VAV reheat terminal, calculate
46
- # the annual total % reheat hours.
47
- @model.getAirTerminalSingleDuctVAVReheats.each do |term|
48
- # Reheat coil heating rate
49
- rht_coil = term.reheatCoil
50
- key_value = rht_coil.name.get.to_s.upcase # must be in all caps.
51
- time_step = 'Hourly' # "Zone Timestep", "Hourly", "HVAC System Timestep"
52
- variable_name = 'Heating Coil Heating Rate'
53
- variable_name_alt = 'Heating Coil Air Heating Rate'
54
- rht_rate_ts = @sql.timeSeries(ann_env_pd, time_step, variable_name, key_value) # key value would go at the end if we used it.
55
-
56
- # try and alternate variable name
57
- if rht_rate_ts.empty?
58
- rht_rate_ts = @sql.timeSeries(ann_env_pd, time_step, variable_name_alt, key_value) # key value would go at the end if we used it.
59
- end
60
-
61
- if rht_rate_ts.empty?
62
- check_elems << OpenStudio::Attribute.new('flag', "Heating Coil (Air) Heating Rate Timeseries not found for #{key_value}.")
63
- else
64
-
65
- rht_rate_ts = rht_rate_ts.get.values
66
- # Put timeseries into array
67
- rht_rate_vals = []
68
- for i in 0..(rht_rate_ts.size - 1)
69
- rht_rate_vals << rht_rate_ts[i]
70
- end
71
-
72
- # Zone Air Terminal Sensible Heating Rate
73
- key_value = "ADU #{term.name.get.to_s.upcase}" # must be in all caps.
74
- time_step = 'Hourly' # "Zone Timestep", "Hourly", "HVAC System Timestep"
75
- variable_name = 'Zone Air Terminal Sensible Cooling Rate'
76
- clg_rate_ts = @sql.timeSeries(ann_env_pd, time_step, variable_name, key_value) # key value would go at the end if we used it.
77
- if clg_rate_ts.empty?
78
- check_elems << OpenStudio::Attribute.new('flag', "Zone Air Terminal Sensible Cooling Rate Timeseries not found for #{key_value}.")
79
- else
80
-
81
- clg_rate_ts = clg_rate_ts.get.values
82
- # Put timeseries into array
83
- clg_rate_vals = []
84
- for i in 0..(clg_rate_ts.size - 1)
85
- clg_rate_vals << clg_rate_ts[i]
86
- end
87
-
88
- # Loop through each timestep and calculate the hourly
89
- # % reheat value.
90
- ann_rht_hrs = 0
91
- ann_clg_hrs = 0
92
- ann_pcts = []
93
- rht_rate_vals.zip(clg_rate_vals).each do |rht_w, clg_w|
94
- # Skip hours with no cooling (in heating mode)
95
- next if clg_w == 0
96
- pct_overcool_rht = rht_w / (rht_w + clg_w)
97
- ann_rht_hrs += pct_overcool_rht # implied * 1hr b/c hrly results
98
- ann_clg_hrs += 1
99
- ann_pcts << pct_overcool_rht.round(3)
100
- end
101
-
102
- # Calculate annual % reheat hours
103
- ann_pct_reheat = ((ann_rht_hrs / ann_clg_hrs) * 100).round(1)
104
-
105
- # Compare to limit
106
- if ann_pct_reheat > max_pass * 100.0
107
- check_elems << OpenStudio::Attribute.new('flag', "#{term.name} has #{ann_pct_reheat}% overcool-reheat, which is greater than the limit of #{max_pass * 100.0}%. This terminal is in cooling mode for #{ann_clg_hrs} hours of the year.")
108
- end
109
-
110
- end
111
-
112
- end
113
- end
114
- rescue StandardError => e
115
- # brief description of ruby error
116
- check_elems << OpenStudio::Attribute.new('flag', "Error prevented QAQC check from running (#{e}).")
117
-
118
- # backtrace of ruby error for diagnostic use
119
- if @error_backtrace then check_elems << OpenStudio::Attribute.new('flag', e.backtrace.join("\n").to_s) end
120
- end
121
-
122
- # add check_elms to new attribute
123
- check_elem = OpenStudio::Attribute.new('check', check_elems)
124
-
125
- return check_elem
126
- # note: registerWarning and registerValue will be added for checks downstream using os_lib_reporting_qaqc.rb
127
- end
128
- end
@@ -1,118 +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_supply_air_and_thermostat_temp_difference(category, target_standard, max_delta, name_only = false)
11
- # G3.1.2.9 requires a 20 degree F delta between supply air temperature and zone temperature.
12
- target_clg_delta = 20.0
13
-
14
- # summary of the check
15
- check_elems = OpenStudio::AttributeVector.new
16
- check_elems << OpenStudio::Attribute.new('name', 'Supply and Zone Air Temperature')
17
- check_elems << OpenStudio::Attribute.new('category', category)
18
- if @utility_name.nil?
19
- check_elems << OpenStudio::Attribute.new('description', "Check if fans modeled to ASHRAE 90.1 2013 Section G3.1.2.9 requirements. Compare the supply air temperature for each thermal zone against the thermostat setpoints. Throw flag if temperature difference excedes threshold of #{target_clg_delta}F plus the selected tolerance.")
20
- else
21
- check_elems << OpenStudio::Attribute.new('description', "Check if fans modeled to ASHRAE 90.1 2013 Section G3.1.2.9 requirements. Compare the supply air temperature for each thermal zone against the thermostat setpoints. Throw flag if temperature difference excedes threshold set by #{@utility_name}.")
22
- end
23
-
24
- # stop here if only name is requested this is used to populate display name for arguments
25
- if name_only == true
26
- results = []
27
- check_elems.each do |elem|
28
- results << elem.valueAsString
29
- end
30
- return results
31
- end
32
-
33
- # Versions of OpenStudio greater than 2.4.0 use a modified version of
34
- # openstudio-standards with different method calls. These methods
35
- # require a "Standard" object instead of the standard being passed into method calls.
36
- # This Standard object is used throughout the QAQC check.
37
- if OpenStudio::VersionString.new(OpenStudio.openStudioVersion) < OpenStudio::VersionString.new('2.4.3')
38
- use_old_gem_code = true
39
- else
40
- use_old_gem_code = false
41
- std = Standard.build(target_standard)
42
- end
43
-
44
- begin
45
- # loop through thermal zones
46
- @model.getThermalZones.sort.each do |thermal_zone|
47
- model_clg_min = nil
48
-
49
- # populate thermostat ranges
50
- if thermal_zone.thermostatSetpointDualSetpoint.is_initialized
51
-
52
- thermostat = thermal_zone.thermostatSetpointDualSetpoint.get
53
- if thermostat.coolingSetpointTemperatureSchedule.is_initialized
54
-
55
- clg_sch = thermostat.coolingSetpointTemperatureSchedule.get
56
- schedule_values = nil
57
- if clg_sch.to_ScheduleRuleset.is_initialized
58
- if use_old_gem_code
59
- schedule_values = clg_sch.to_ScheduleRuleset.get.annual_min_max_value
60
- else
61
- schedule_values = std.schedule_ruleset_annual_min_max_value(clg_sch.to_ScheduleRuleset.get)
62
- end
63
- elsif clg_sch.to_ScheduleConstant.is_initialized
64
- if use_old_gem_code
65
- schedule_values = clg_sch.to_ScheduleConstant.get.annual_min_max_value
66
- else
67
- schedule_values = std.schedule_constant_annual_min_max_value(clg_sch.to_ScheduleConstant.get)
68
- end
69
- end
70
-
71
- unless schedule_values.nil?
72
- model_clg_min = schedule_values['min']
73
- end
74
- end
75
-
76
- else
77
- # go to next zone if not conditioned
78
- next
79
-
80
- end
81
-
82
- # flag if there is setpoint schedule can't be inspected (isn't ruleset)
83
- if model_clg_min.nil?
84
- check_elems << OpenStudio::Attribute.new('flag', "Can't inspect thermostat schedules for #{thermal_zone.name}")
85
- else
86
-
87
- # get supply air temps from thermal zone sizing
88
- sizing_zone = thermal_zone.sizingZone
89
- clg_supply_air_temp = sizing_zone.zoneCoolingDesignSupplyAirTemperature
90
-
91
- # convert model values to IP
92
- model_clg_min_ip = OpenStudio.convert(model_clg_min, 'C', 'F').get
93
- clg_supply_air_temp_ip = OpenStudio.convert(clg_supply_air_temp, 'C', 'F').get
94
-
95
- # check supply air against zone temperature (only check against min setpoint, assume max is night setback)
96
- if model_clg_min_ip - clg_supply_air_temp_ip > target_clg_delta + max_delta
97
- check_elems << OpenStudio::Attribute.new('flag', "For #{thermal_zone.name} the delta temp between the cooling supply air temp of #{clg_supply_air_temp_ip.round(2)} (F) and the minimum thermostat cooling temp of #{model_clg_min_ip.round(2)} (F) is more than #{max_delta} (F) larger than the expected delta of #{target_clg_delta} (F)")
98
- elsif model_clg_min_ip - clg_supply_air_temp_ip < target_clg_delta - max_delta
99
- check_elems << OpenStudio::Attribute.new('flag', "For #{thermal_zone.name} the delta temp between the cooling supply air temp of #{clg_supply_air_temp_ip.round(2)} (F) and the minimum thermostat cooling temp of #{model_clg_min_ip.round(2)} (F) is more than #{max_delta} (F) smaller than the expected delta of #{target_clg_delta} (F)")
100
- end
101
-
102
- end
103
- end
104
- rescue StandardError => e
105
- # brief description of ruby error
106
- check_elems << OpenStudio::Attribute.new('flag', "Error prevented QAQC check from running (#{e}).")
107
-
108
- # backtrace of ruby error for diagnostic use
109
- if @error_backtrace then check_elems << OpenStudio::Attribute.new('flag', e.backtrace.join("\n").to_s) end
110
- end
111
-
112
- # add check_elms to new attribute
113
- check_elem = OpenStudio::Attribute.new('check', check_elems)
114
-
115
- return check_elem
116
- # note: registerWarning and registerValue will be added for checks downstream using os_lib_reporting_qaqc.rb
117
- end
118
- end
@@ -1,102 +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_weather_files(category, options, name_only = false)
11
- # summary of the check
12
- check_elems = OpenStudio::AttributeVector.new
13
- check_elems << OpenStudio::Attribute.new('name', 'Weather Files')
14
- check_elems << OpenStudio::Attribute.new('category', category)
15
- check_elems << OpenStudio::Attribute.new('description', "Check weather file, design days, and climate zone against #{@utility_name} list of allowable options.")
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
- begin
27
- # get weather file
28
- model_epw = nil
29
- if @model.getWeatherFile.url.is_initialized
30
- raw_epw = @model.getWeatherFile.url.get
31
- end_path_index = raw_epw.rindex('/')
32
- model_epw = raw_epw.slice!(end_path_index + 1, raw_epw.length) # everything right of last forward slash
33
- end
34
-
35
- # check design days (model must have one or more of the required summer and winter design days)
36
- # get design days names from model
37
- model_summer_dd_names = []
38
- model_winter_dd_names = []
39
- @model.getDesignDays.each do |design_day|
40
- if design_day.dayType == 'SummerDesignDay'
41
- model_summer_dd_names << design_day.name.to_s
42
- elsif design_day.dayType == 'WinterDesignDay'
43
- model_winter_dd_names << design_day.name.to_s
44
- else
45
- puts "unexpected day type of #{design_day.dayType} wont' be included in check"
46
- end
47
- end
48
-
49
- # find matching weather file from options, as well as design days and climate zone
50
- if options.key?(model_epw)
51
- required_summer_dd = options[model_epw]['summer']
52
- required_winter_dd = options[model_epw]['winter']
53
- valid_climate_zones = [options[model_epw]['climate_zone']]
54
-
55
- # check for intersection betwen model valid design days
56
- summer_intersection = (required_summer_dd & model_summer_dd_names)
57
- winter_intersection = (required_winter_dd & model_winter_dd_names)
58
- if summer_intersection.empty? && !required_summer_dd.empty?
59
- check_elems << OpenStudio::Attribute.new('flag', "Didn't find any of the expected summer design days for #{model_epw}")
60
- end
61
- if winter_intersection.empty? && !required_winter_dd.empty?
62
- check_elems << OpenStudio::Attribute.new('flag', "Didn't find any of the expected winter design days for #{model_epw}")
63
- end
64
-
65
- else
66
- check_elems << OpenStudio::Attribute.new('flag', "#{model_epw} is not a an expected weather file.")
67
- check_elems << OpenStudio::Attribute.new('flag', "Model doesn't have expected epw file, as a result can't validate design days.")
68
- valid_climate_zones = []
69
- options.each do |lookup_epw, value|
70
- valid_climate_zones << value['climate_zone']
71
- end
72
- end
73
-
74
- # get ashrae climate zone from model
75
- model_climate_zone = nil
76
- climateZones = @model.getClimateZones
77
- climateZones.climateZones.each do |climateZone|
78
- if climateZone.institution == 'ASHRAE'
79
- model_climate_zone = climateZone.value
80
- next
81
- end
82
- end
83
- if model_climate_zone == ''
84
- check_elems << OpenStudio::Attribute.new('flag', "The model's ASHRAE climate zone has not been defined. Expected climate zone was #{valid_climate_zones.uniq.join(',')}.")
85
- elsif !valid_climate_zones.include?(model_climate_zone)
86
- check_elems << OpenStudio::Attribute.new('flag', "The model's ASHRAE climate zone was #{model_climate_zone}. Expected climate zone was #{valid_climate_zones.uniq.join(',')}.")
87
- end
88
- rescue StandardError => e
89
- # brief description of ruby error
90
- check_elems << OpenStudio::Attribute.new('flag', "Error prevented QAQC check from running (#{e}).")
91
-
92
- # backtrace of ruby error for diagnostic use
93
- if @error_backtrace then check_elems << OpenStudio::Attribute.new('flag', e.backtrace.join("\n").to_s) end
94
- end
95
-
96
- # add check_elms to new attribute
97
- check_elem = OpenStudio::Attribute.new('check', check_elems)
98
-
99
- return check_elem
100
- # note: registerWarning and registerValue will be added for checks downstream using os_lib_reporting_qaqc.rb
101
- end
102
- end