openstudio-extension 0.7.1 → 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 +15 -66
  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,129 +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
- # Check the plant loop operational vs. sizing temperatures
8
- # and make sure everything is coordinated. This identifies problems
9
- # caused by sizing to one set of conditions and operating at a different set.
10
- def check_plant_temps(category, target_standard, max_sizing_temp_delta = 0.1, name_only = false)
11
- # summary of the check
12
- check_elems = OpenStudio::AttributeVector.new
13
- check_elems << OpenStudio::Attribute.new('name', 'Plant Loop Temperatures')
14
- check_elems << OpenStudio::Attribute.new('category', category)
15
- check_elems << OpenStudio::Attribute.new('description', 'Check that plant loop sizing and operation temperatures are coordinated.')
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
- std = Standard.build(target_standard)
27
-
28
- begin
29
- # Check each plant loop in the model
30
- @model.getPlantLoops.sort.each do |plant_loop|
31
- loop_name = plant_loop.name.to_s
32
-
33
- # Get the central heating and cooling SAT for sizing
34
- sizing_plant = plant_loop.sizingPlant
35
- loop_siz_f = OpenStudio.convert(sizing_plant.designLoopExitTemperature, 'C', 'F').get
36
-
37
- # Determine the min and max operational temperatures
38
- loop_op_min_f = nil
39
- loop_op_max_f = nil
40
- plant_loop.supplyOutletNode.setpointManagers.each do |spm|
41
- obj_type = spm.iddObjectType.valueName.to_s
42
- case obj_type
43
- when 'OS_SetpointManager_Scheduled'
44
- sch = spm.to_SetpointManagerScheduled.get.schedule
45
- if sch.to_ScheduleRuleset.is_initialized
46
- min_c = std.schedule_ruleset_annual_min_max_value(sch.to_ScheduleRuleset.get)['min']
47
- max_c = std.schedule_ruleset_annual_min_max_value(sch.to_ScheduleRuleset.get)['max']
48
- elsif sch.to_ScheduleConstant.is_initialized
49
- min_c = std.schedule_constant_annual_min_max_value(sch.to_ScheduleConstant.get)['min']
50
- max_c = std.schedule_constant_annual_min_max_value(sch.to_ScheduleConstant.get)['max']
51
- else
52
- next
53
- end
54
- loop_op_min_f = OpenStudio.convert(min_c, 'C', 'F').get
55
- loop_op_max_f = OpenStudio.convert(max_c, 'C', 'F').get
56
- when 'OS_SetpointManager_Scheduled_DualSetpoint'
57
- spm = spm.to_SetpointManagerSingleZoneReheat.get
58
- # Lowest setpoint is minimum of low schedule
59
- low_sch = spm.to_SetpointManagerScheduled.get.lowSetpointSchedule
60
- next if low_sch.empty?
61
- low_sch = low_sch.get
62
- if low_sch.to_ScheduleRuleset.is_initialized
63
- min_c = std.schedule_ruleset_annual_min_max_value(low_sch.to_ScheduleRuleset.get)['min']
64
- max_c = std.schedule_ruleset_annual_min_max_value(low_sch.to_ScheduleRuleset.get)['max']
65
- elsif low_sch.to_ScheduleConstant.is_initialized
66
- min_c = std.schedule_constant_annual_min_max_value(low_sch.to_ScheduleConstant.get)['min']
67
- max_c = std.schedule_constant_annual_min_max_value(low_sch.to_ScheduleConstant.get)['max']
68
- else
69
- next
70
- end
71
- loop_op_min_f = OpenStudio.convert(min_c, 'C', 'F').get
72
- # Highest setpoint it maximum of high schedule
73
- high_sch = spm.to_SetpointManagerScheduled.get.highSetpointSchedule
74
- next if high_sch.empty?
75
- high_sch = high_sch.get
76
- if high_sch.to_ScheduleRuleset.is_initialized
77
- min_c = std.schedule_ruleset_annual_min_max_value(high_sch.to_ScheduleRuleset.get)['min']
78
- max_c = std.schedule_ruleset_annual_min_max_value(high_sch.to_ScheduleRuleset.get)['max']
79
- elsif high_sch.to_ScheduleConstant.is_initialized
80
- min_c = std.schedule_constant_annual_min_max_value(high_sch.to_ScheduleConstant.get)['min']
81
- max_c = std.schedule_constant_annual_min_max_value(high_sch.to_ScheduleConstant.get)['max']
82
- else
83
- next
84
- end
85
- loop_op_max_f = OpenStudio.convert(max_c, 'C', 'F').get
86
- when 'OS_SetpointManager_OutdoorAirReset'
87
- spm = spm.to_SetpointManagerOutdoorAirReset.get
88
- temp_1_f = OpenStudio.convert(spm.setpointatOutdoorHighTemperature, 'C', 'F').get
89
- temp_2_f = OpenStudio.convert(spm.setpointatOutdoorLowTemperature, 'C', 'F').get
90
- loop_op_min_f = [temp_1_f, temp_2_f].min
91
- loop_op_max_f = [temp_1_f, temp_2_f].max
92
- else
93
- next # Only check the commonly used setpoint managers
94
- end
95
- end
96
-
97
- # Compare plant loop sizing temperatures to operational temperatures
98
- case sizing_plant.loopType
99
- when 'Heating'
100
- if loop_op_max_f
101
- if ((loop_op_max_f - loop_siz_f) / loop_op_max_f).abs > max_sizing_temp_delta
102
- check_elems << OpenStudio::Attribute.new('flag', "For #{plant_loop.name}, the sizing is done with a supply water temp of #{loop_siz_f.round(2)}F, but the setpoint manager controlling the loop operates up to #{loop_op_max_f.round(2)}F. These are farther apart than the acceptable #{(max_sizing_temp_delta * 100.0).round(2)}% difference.")
103
- end
104
- end
105
- when 'Cooling'
106
- if loop_op_min_f
107
- if ((loop_op_min_f - loop_siz_f) / loop_op_min_f).abs > max_sizing_temp_delta
108
- check_elems << OpenStudio::Attribute.new('flag', "For #{plant_loop.name}, the sizing is done with a supply water temp of #{loop_siz_f.round(2)}F, but the setpoint manager controlling the loop operates down to #{loop_op_min_f.round(2)}F. These are farther apart than the acceptable #{(max_sizing_temp_delta * 100.0).round(2)}% difference.")
109
- end
110
- end
111
- when 'Condenser'
112
- # Not checking sizing of condenser loops
113
- end
114
- end
115
- rescue StandardError => e
116
- # brief description of ruby error
117
- check_elems << OpenStudio::Attribute.new('flag', "Error prevented QAQC check from running (#{e}).")
118
-
119
- # backtrace of ruby error for diagnostic use
120
- if @error_backtrace then check_elems << OpenStudio::Attribute.new('flag', e.backtrace.join("\n").to_s) end
121
- end
122
-
123
- # add check_elms to new attribute
124
- check_elem = OpenStudio::Attribute.new('check', check_elems)
125
-
126
- return check_elem
127
- # note: registerWarning and registerValue will be added for checks downstream using os_lib_reporting_qaqc.rb
128
- end
129
- end
@@ -1,57 +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
- # Check that there are no people or lights in plenums.
8
- def check_plenum_loads(category, target_standard, name_only = false)
9
- # summary of the check
10
- check_elems = OpenStudio::AttributeVector.new
11
- check_elems << OpenStudio::Attribute.new('name', 'Plenum Loads')
12
- check_elems << OpenStudio::Attribute.new('category', category)
13
- check_elems << OpenStudio::Attribute.new('description', 'Check that the plenums do not have people or lights.')
14
-
15
- # stop here if only name is requested this is used to populate display name for arguments
16
- if name_only == true
17
- results = []
18
- check_elems.each do |elem|
19
- results << elem.valueAsString
20
- end
21
- return results
22
- end
23
-
24
- std = Standard.build(target_standard)
25
-
26
- begin
27
- @model.getThermalZones.each do |zone|
28
- # Only check plenums
29
- next unless std.thermal_zone_plenum?(zone)
30
-
31
- # People
32
- num_people = zone.numberOfPeople
33
- if num_people > 0
34
- check_elems << OpenStudio::Attribute.new('flag', "#{zone.name} is a plenum, but has #{num_people.round(1)} people. Plenums should not contain people.")
35
- end
36
-
37
- # Lights
38
- lights_w = zone.lightingPower
39
- if lights_w > 0
40
- check_elems << OpenStudio::Attribute.new('flag', "#{zone.name} is a plenum, but has #{lights_w.round(1)} W of lights. Plenums should not contain lights.")
41
- end
42
- end
43
- rescue StandardError => e
44
- # brief description of ruby error
45
- check_elems << OpenStudio::Attribute.new('flag', "Error prevented QAQC check from running (#{e}).")
46
-
47
- # backtrace of ruby error for diagnostic use
48
- if @error_backtrace then check_elems << OpenStudio::Attribute.new('flag', e.backtrace.join("\n").to_s) end
49
- end
50
-
51
- # add check_elms to new attribute
52
- check_elem = OpenStudio::Attribute.new('check', check_elems)
53
-
54
- return check_elem
55
- # note: registerWarning and registerValue will be added for checks downstream using os_lib_reporting_qaqc.rb
56
- end
57
- end
@@ -1,78 +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
- # Check the pumping power (W/gpm) for each pump in the model to identify
8
- # unrealistically sized pumps.
9
- def check_pump_pwr(category, target_standard, max_pwr_delta = 0.1, name_only = false)
10
- # summary of the check
11
- check_elems = OpenStudio::AttributeVector.new
12
- check_elems << OpenStudio::Attribute.new('name', 'Pump Power')
13
- check_elems << OpenStudio::Attribute.new('category', category)
14
- check_elems << OpenStudio::Attribute.new('description', 'Check that pump power vs flow makes sense.')
15
-
16
- # stop here if only name is requested this is used to populate display name for arguments
17
- if name_only == true
18
- results = []
19
- check_elems.each do |elem|
20
- results << elem.valueAsString
21
- end
22
- return results
23
- end
24
-
25
- std = Standard.build(target_standard)
26
-
27
- begin
28
- # Check each plant loop
29
- @model.getPlantLoops.each do |plant_loop|
30
- # Set the expected/typical W/gpm
31
- loop_type = plant_loop.sizingPlant.loopType
32
- case loop_type
33
- when 'Heating'
34
- expected_w_per_gpm = 19.0
35
- when 'Cooling'
36
- expected_w_per_gpm = 22.0
37
- when 'Condenser'
38
- expected_w_per_gpm = 19.0
39
- end
40
-
41
- # Check the W/gpm for each pump on each plant loop
42
- plant_loop.supplyComponents.each do |sc|
43
- # Get the W/gpm for the pump
44
- obj_type = sc.iddObjectType.valueName.to_s
45
- case obj_type
46
- when 'OS_Pump_ConstantSpeed'
47
- actual_w_per_gpm = std.pump_rated_w_per_gpm(sc.to_PumpConstantSpeed.get)
48
- when 'OS_Pump_VariableSpeed'
49
- actual_w_per_gpm = std.pump_rated_w_per_gpm(sc.to_PumpVariableSpeed.get)
50
- when 'OS_HeaderedPumps_ConstantSpeed'
51
- actual_w_per_gpm = std.pump_rated_w_per_gpm(sc.to_HeaderedPumpsConstantSpeed.get)
52
- when 'OS_HeaderedPumps_VariableSpeed'
53
- actual_w_per_gpm = std.pump_rated_w_per_gpm(sc.to_HeaderedPumpsVariableSpeed.get)
54
- else
55
- next # Skip non-pump objects
56
- end
57
-
58
- # Compare W/gpm to expected/typical values
59
- if ((expected_w_per_gpm - actual_w_per_gpm) / actual_w_per_gpm).abs > max_pwr_delta
60
- check_elems << OpenStudio::Attribute.new('flag', "For #{sc.name} on #{plant_loop.name}, the actual pumping power of #{actual_w_per_gpm.round(1)} W/gpm is more than #{(max_pwr_delta * 100.0).round(2)}% different from the expected #{expected_w_per_gpm} W/gpm for a #{loop_type} plant loop.")
61
- end
62
- end
63
- end
64
- rescue StandardError => e
65
- # brief description of ruby error
66
- check_elems << OpenStudio::Attribute.new('flag', "Error prevented QAQC check from running (#{e}).")
67
-
68
- # backtrace of ruby error for diagnostic use
69
- if @error_backtrace then check_elems << OpenStudio::Attribute.new('flag', e.backtrace.join("\n").to_s) end
70
- end
71
-
72
- # add check_elms to new attribute
73
- check_elem = OpenStudio::Attribute.new('check', check_elems)
74
-
75
- return check_elem
76
- # note: registerWarning and registerValue will be added for checks downstream using os_lib_reporting_qaqc.rb
77
- end
78
- end
@@ -1,211 +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
- # Determine the hour when the schedule first exceeds the starting value and when
8
- # it goes back down to the ending value at the end of the day.
9
- # This method only works for ScheduleRuleset schedules.
10
- def get_start_and_end_times(schedule_ruleset)
11
- # Ensure that this is a ScheduleRuleset
12
- schedule_ruleset = schedule_ruleset.to_ScheduleRuleset
13
- return [nil, nil] if schedule_ruleset.empty?
14
- schedule_ruleset = schedule_ruleset.get
15
-
16
- # Define the start and end date
17
- year_start_date = nil
18
- year_end_date = nil
19
- if schedule_ruleset.model.yearDescription.is_initialized
20
- year_description = schedule_ruleset.model.yearDescription.get
21
- year = year_description.assumedYear
22
- year_start_date = OpenStudio::Date.new(OpenStudio::MonthOfYear.new('January'), 1, year)
23
- year_end_date = OpenStudio::Date.new(OpenStudio::MonthOfYear.new('December'), 31, year)
24
- else
25
- year_start_date = OpenStudio::Date.new(OpenStudio::MonthOfYear.new('January'), 1, 2009)
26
- year_end_date = OpenStudio::Date.new(OpenStudio::MonthOfYear.new('December'), 31, 2009)
27
- end
28
-
29
- # Get the ordered list of all the day schedules that are used by this schedule ruleset
30
- day_schs = schedule_ruleset.getDaySchedules(year_start_date, year_end_date)
31
-
32
- # Get a 365-value array of which schedule is used on each day of the year,
33
- day_schs_used_each_day = schedule_ruleset.getActiveRuleIndices(year_start_date, year_end_date)
34
-
35
- # Create a map that shows how many days each schedule is used
36
- day_sch_freq = day_schs_used_each_day.group_by { |n| n }
37
- day_sch_freq = day_sch_freq.sort_by { |freq| freq[1].size }
38
- common_day_freq = day_sch_freq.last
39
-
40
- # Build a hash that maps schedule day index to schedule day
41
- schedule_index_to_day = {}
42
- day_schs.each_with_index do |day_sch, i|
43
- schedule_index_to_day[day_schs_used_each_day[i]] = day_sch
44
- end
45
-
46
- # Get the most common day schedule
47
- sch_index = common_day_freq[0]
48
- number_of_days_sch_used = common_day_freq[1].size
49
-
50
- # Get the day schedule at this index
51
- day_sch = if sch_index == -1 # If index = -1, this day uses the default day schedule (not a rule)
52
- schedule_ruleset.defaultDaySchedule
53
- else
54
- schedule_index_to_day[sch_index]
55
- end
56
-
57
- # Determine the full load hours for just one day
58
- values = []
59
- times = []
60
- day_sch.times.each_with_index do |time, i|
61
- times << day_sch.times[i]
62
- values << day_sch.values[i]
63
- end
64
-
65
- # Get the minimum value
66
- start_val = values.first
67
- end_val = values.last
68
-
69
- # Get the start time (first time value goes above minimum)
70
- start_time = nil
71
- values.each_with_index do |val, i|
72
- break if i == values.size - 1 # Stop if we reach end of array
73
- if val == start_val && values[i + 1] > start_val
74
- start_time = times[i + 1]
75
- break
76
- end
77
- end
78
-
79
- # Get the end time (first time value goes back down to minimum)
80
- end_time = nil
81
- values.each_with_index do |val, i|
82
- if i < values.size - 1
83
- if val > end_val && values[i + 1] == end_val
84
- end_time = times[i]
85
- break
86
- end
87
- else
88
- if val > end_val && values[0] == start_val # Check first hour of day for schedules that end at midnight
89
- end_time = OpenStudio::Time.new(0, 24, 0, 0)
90
- break
91
- end
92
- end
93
- end
94
-
95
- return [start_time, end_time]
96
- end
97
-
98
- # Check that the lighting, equipment, and HVAC setpoint schedules
99
- # coordinate with the occupancy schedules. This is defined as having start and end
100
- # times within the specified number of hours away from the occupancy schedule.
101
- def check_sch_coord(category, target_standard, max_hrs, name_only = false)
102
- # summary of the check
103
- check_elems = OpenStudio::AttributeVector.new
104
- check_elems << OpenStudio::Attribute.new('name', 'Conditioned Zones')
105
- check_elems << OpenStudio::Attribute.new('category', category)
106
- check_elems << OpenStudio::Attribute.new('description', 'Check that lighting, equipment, and HVAC schedules coordinate with occupancy.')
107
-
108
- # stop here if only name is requested this is used to populate display name for arguments
109
- if name_only == true
110
- results = []
111
- check_elems.each do |elem|
112
- results << elem.valueAsString
113
- end
114
- return results
115
- end
116
-
117
- std = Standard.build(target_standard)
118
-
119
- begin
120
- # Convert max hr limit to OpenStudio Time
121
- max_hrs = OpenStudio::Time.new(0, max_hrs, 0, 0)
122
-
123
- # Check schedules in each space
124
- @model.getSpaces.each do |space|
125
- # Occupancy, Lighting, and Equipment Schedules
126
- coord_schs = []
127
- occ_schs = []
128
- # Get the space type (optional)
129
- space_type = space.spaceType
130
-
131
- # Occupancy
132
- occs = []
133
- occs += space.people # From space directly
134
- occs += space_type.get.people if space_type.is_initialized # Inherited from space type
135
- occs.each do |occ|
136
- occ_schs << occ.numberofPeopleSchedule.get if occ.numberofPeopleSchedule.is_initialized
137
- end
138
-
139
- # Lights
140
- lts = []
141
- lts += space.lights # From space directly
142
- lts += space_type.get.lights if space_type.is_initialized # Inherited from space type
143
- lts.each do |lt|
144
- coord_schs << lt.schedule.get if lt.schedule.is_initialized
145
- end
146
-
147
- # Equip
148
- plugs = []
149
- plugs += space.electricEquipment # From space directly
150
- plugs += space_type.get.electricEquipment if space_type.is_initialized # Inherited from space type
151
- plugs.each do |plug|
152
- coord_schs << plug.schedule.get if plug.schedule.is_initialized
153
- end
154
-
155
- # HVAC Schedule (airloop-served zones only)
156
- if space.thermalZone.is_initialized
157
- zone = space.thermalZone.get
158
- if zone.airLoopHVAC.is_initialized
159
- coord_schs << zone.airLoopHVAC.get.availabilitySchedule
160
- end
161
- end
162
-
163
- # Cannot check spaces with no occupancy schedule to compare against
164
- next if occ_schs.empty?
165
-
166
- # Get start and end occupancy times from the first occupancy schedule
167
- occ_start_time, occ_end_time = get_start_and_end_times(occ_schs[0])
168
-
169
- # Cannot check a space where the occupancy start time or end time cannot be determined
170
- next if occ_start_time.nil? || occ_end_time.nil?
171
-
172
- # Check all schedules against occupancy
173
-
174
- # Lights should have a start and end within X hrs of the occupancy start and end
175
- coord_schs.each do |coord_sch|
176
- # Get start and end time of load/HVAC schedule
177
- start_time, end_time = get_start_and_end_times(coord_sch)
178
- if start_time.nil?
179
- check_elems << OpenStudio::Attribute.new('flag', "Could not determine start time of a schedule called #{coord_sch.name}, cannot determine if schedule coordinates with occupancy schedule.")
180
- next
181
- elsif end_time.nil?
182
- check_elems << OpenStudio::Attribute.new('flag', "Could not determine end time of a schedule called #{coord_sch.name}, cannot determine if schedule coordinates with occupancy schedule.")
183
- next
184
- end
185
-
186
- # Check start time
187
- if (occ_start_time - start_time) > max_hrs || (start_time - occ_start_time) > max_hrs
188
- check_elems << OpenStudio::Attribute.new('flag', "The start time of #{coord_sch.name} is #{start_time}, which is more than #{max_hrs} away from the occupancy schedule start time of #{occ_start_time} for #{occ_schs[0].name} in #{space.name}. Schedules do not coordinate.")
189
- end
190
-
191
- # Check end time
192
- if (occ_end_time - end_time) > max_hrs || (end_time - occ_end_time) > max_hrs
193
- check_elems << OpenStudio::Attribute.new('flag', "The end time of #{coord_sch.name} is #{end_time}, which is more than #{max_hrs} away from the occupancy schedule end time of #{occ_end_time} for #{occ_schs[0].name} in #{space.name}. Schedules do not coordinate.")
194
- end
195
- end
196
- end
197
- rescue StandardError => e
198
- # brief description of ruby error
199
- check_elems << OpenStudio::Attribute.new('flag', "Error prevented QAQC check from running (#{e}).")
200
-
201
- # backtrace of ruby error for diagnostic use
202
- if @error_backtrace then check_elems << OpenStudio::Attribute.new('flag', e.backtrace.join("\n").to_s) end
203
- end
204
-
205
- # add check_elms to new attribute
206
- check_elem = OpenStudio::Attribute.new('check', check_elems)
207
-
208
- return check_elem
209
- # note: registerWarning and registerValue will be added for checks downstream using os_lib_reporting_qaqc.rb
210
- end
211
- end