openstudio-extension 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +29 -26
  3. data/.rspec +3 -3
  4. data/.rubocop.yml +10 -9
  5. data/CHANGELOG.md +16 -0
  6. data/Gemfile +6 -6
  7. data/Jenkinsfile +10 -10
  8. data/README.md +251 -250
  9. data/Rakefile +119 -119
  10. data/bin/console +14 -14
  11. data/bin/setup +8 -8
  12. data/doc_templates/LICENSE.md +26 -26
  13. data/doc_templates/README.md.erb +41 -41
  14. data/doc_templates/copyright_erb.txt +35 -35
  15. data/doc_templates/copyright_js.txt +3 -3
  16. data/doc_templates/copyright_ruby.txt +33 -33
  17. data/init_templates/README.md +37 -37
  18. data/init_templates/gemspec.txt +32 -32
  19. data/init_templates/openstudio_module.rb +50 -50
  20. data/init_templates/spec.rb +47 -47
  21. data/init_templates/spec_helper.rb +49 -49
  22. data/init_templates/template_gemfile.txt +17 -17
  23. data/init_templates/template_rakefile.txt +15 -15
  24. data/init_templates/version.rb +40 -40
  25. data/lib/files/openstudio-extension-gem-test.ddy +536 -536
  26. data/lib/files/openstudio-extension-gem-test.epw +8768 -8768
  27. data/lib/files/openstudio-extension-gem-test.stat +554 -554
  28. data/lib/measures/openstudio_extension_test_measure/LICENSE.md +26 -26
  29. data/lib/measures/openstudio_extension_test_measure/README.md +26 -26
  30. data/lib/measures/openstudio_extension_test_measure/README.md.erb +41 -41
  31. data/lib/measures/openstudio_extension_test_measure/measure.rb +72 -72
  32. data/lib/measures/openstudio_extension_test_measure/measure.xml +83 -83
  33. data/lib/measures/openstudio_extension_test_measure/resources/os_lib_helper_methods.rb +399 -399
  34. data/lib/measures/openstudio_extension_test_measure/tests/{OpenStudioExtensionTestMeasure_Test.rb → openstudio_extension_test_measure_test.rb} +74 -75
  35. data/lib/openstudio-extension.rb +1 -1
  36. data/lib/openstudio/extension.rb +234 -229
  37. data/lib/openstudio/extension/core/CreateResults.rb +886 -886
  38. data/lib/openstudio/extension/core/check_air_sys_temps.rb +190 -190
  39. data/lib/openstudio/extension/core/check_calibration.rb +155 -155
  40. data/lib/openstudio/extension/core/check_cond_zns.rb +84 -84
  41. data/lib/openstudio/extension/core/check_domestic_hot_water.rb +334 -334
  42. data/lib/openstudio/extension/core/check_envelope_conductance.rb +453 -453
  43. data/lib/openstudio/extension/core/check_eui_by_end_use.rb +162 -162
  44. data/lib/openstudio/extension/core/check_eui_reasonableness.rb +135 -135
  45. data/lib/openstudio/extension/core/check_fan_pwr.rb +98 -98
  46. data/lib/openstudio/extension/core/check_internal_loads.rb +393 -393
  47. data/lib/openstudio/extension/core/check_mech_sys_capacity.rb +226 -226
  48. data/lib/openstudio/extension/core/check_mech_sys_efficiency.rb +326 -326
  49. data/lib/openstudio/extension/core/check_mech_sys_part_load_eff.rb +464 -464
  50. data/lib/openstudio/extension/core/check_mech_sys_type.rb +139 -139
  51. data/lib/openstudio/extension/core/check_part_loads.rb +451 -451
  52. data/lib/openstudio/extension/core/check_placeholder.rb +75 -75
  53. data/lib/openstudio/extension/core/check_plant_cap.rb +123 -123
  54. data/lib/openstudio/extension/core/check_plant_temps.rb +159 -159
  55. data/lib/openstudio/extension/core/check_plenum_loads.rb +87 -87
  56. data/lib/openstudio/extension/core/check_pump_pwr.rb +108 -108
  57. data/lib/openstudio/extension/core/check_sch_coord.rb +241 -241
  58. data/lib/openstudio/extension/core/check_schedules.rb +311 -311
  59. data/lib/openstudio/extension/core/check_simultaneous_heating_and_cooling.rb +158 -158
  60. data/lib/openstudio/extension/core/check_supply_air_and_thermostat_temp_difference.rb +148 -148
  61. data/lib/openstudio/extension/core/check_weather_files.rb +132 -132
  62. data/lib/openstudio/extension/core/deer_vintages.rb +311 -311
  63. data/lib/openstudio/extension/core/os_lib_aedg_measures.rb +491 -491
  64. data/lib/openstudio/extension/core/os_lib_cofee.rb +258 -258
  65. data/lib/openstudio/extension/core/os_lib_constructions.rb +378 -378
  66. data/lib/openstudio/extension/core/os_lib_geometry.rb +1022 -1022
  67. data/lib/openstudio/extension/core/os_lib_helper_methods.rb +399 -399
  68. data/lib/openstudio/extension/core/os_lib_hvac.rb +2171 -2171
  69. data/lib/openstudio/extension/core/os_lib_lighting_and_equipment.rb +214 -214
  70. data/lib/openstudio/extension/core/os_lib_model_generation.rb +817 -817
  71. data/lib/openstudio/extension/core/os_lib_model_simplification.rb +1049 -1049
  72. data/lib/openstudio/extension/core/os_lib_outdoorair_and_infiltration.rb +165 -165
  73. data/lib/openstudio/extension/core/os_lib_reporting.rb +4651 -4651
  74. data/lib/openstudio/extension/core/os_lib_reporting_qaqc.rb +200 -200
  75. data/lib/openstudio/extension/core/os_lib_schedules.rb +963 -963
  76. data/lib/openstudio/extension/rake_task.rb +159 -149
  77. data/lib/openstudio/extension/runner.rb +667 -644
  78. data/lib/openstudio/extension/runner_config.rb +114 -0
  79. data/lib/openstudio/extension/version.rb +40 -40
  80. data/openstudio-extension.gemspec +34 -33
  81. metadata +39 -37
@@ -1,87 +1,87 @@
1
- # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2019, Alliance for Sustainable Energy, LLC.
3
- # All rights reserved.
4
- # Redistribution and use in source and binary forms, with or without
5
- # modification, are permitted provided that the following conditions are met:
6
- #
7
- # (1) Redistributions of source code must retain the above copyright notice,
8
- # this list of conditions and the following disclaimer.
9
- #
10
- # (2) Redistributions in binary form must reproduce the above copyright notice,
11
- # this list of conditions and the following disclaimer in the documentation
12
- # and/or other materials provided with the distribution.
13
- #
14
- # (3) Neither the name of the copyright holder nor the names of any contributors
15
- # may be used to endorse or promote products derived from this software without
16
- # specific prior written permission from the respective party.
17
- #
18
- # (4) Other than as required in clauses (1) and (2), distributions in any form
19
- # of modifications or other derivative works may not use the "OpenStudio"
20
- # trademark, "OS", "os", or any other confusingly similar designation without
21
- # specific prior written permission from Alliance for Sustainable Energy, LLC.
22
- #
23
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS
24
- # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
25
- # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
- # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE
27
- # UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF
28
- # THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29
- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
30
- # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31
- # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32
- # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33
- # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
- # *******************************************************************************
35
-
36
- module OsLib_QAQC
37
- # Check that there are no people or lights in plenums.
38
- def check_plenum_loads(category, target_standard, name_only = false)
39
- # summary of the check
40
- check_elems = OpenStudio::AttributeVector.new
41
- check_elems << OpenStudio::Attribute.new('name', 'Plenum Loads')
42
- check_elems << OpenStudio::Attribute.new('category', category)
43
- check_elems << OpenStudio::Attribute.new('description', 'Check that the plenums do not have people or lights.')
44
-
45
- # stop here if only name is requested this is used to populate display name for arguments
46
- if name_only == true
47
- results = []
48
- check_elems.each do |elem|
49
- results << elem.valueAsString
50
- end
51
- return results
52
- end
53
-
54
- std = Standard.build(target_standard)
55
-
56
- begin
57
- @model.getThermalZones.each do |zone|
58
- # Only check plenums
59
- next unless std.thermal_zone_plenum?(zone)
60
-
61
- # People
62
- num_people = zone.numberOfPeople
63
- if num_people > 0
64
- check_elems << OpenStudio::Attribute.new('flag', "#{zone.name} is a plenum, but has #{num_people.round(1)} people. Plenums should not contain people.")
65
- end
66
-
67
- # Lights
68
- lights_w = zone.lightingPower
69
- if lights_w > 0
70
- 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.")
71
- end
72
- end
73
- rescue StandardError => e
74
- # brief description of ruby error
75
- check_elems << OpenStudio::Attribute.new('flag', "Error prevented QAQC check from running (#{e}).")
76
-
77
- # backtrace of ruby error for diagnostic use
78
- if @error_backtrace then check_elems << OpenStudio::Attribute.new('flag', e.backtrace.join("\n").to_s) end
79
- end
80
-
81
- # add check_elms to new attribute
82
- check_elem = OpenStudio::Attribute.new('check', check_elems)
83
-
84
- return check_elem
85
- # note: registerWarning and registerValue will be added for checks downstream using os_lib_reporting_qaqc.rb
86
- end
87
- end
1
+ # *******************************************************************************
2
+ # OpenStudio(R), Copyright (c) 2008-2019, Alliance for Sustainable Energy, LLC.
3
+ # All rights reserved.
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # (1) Redistributions of source code must retain the above copyright notice,
8
+ # this list of conditions and the following disclaimer.
9
+ #
10
+ # (2) Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # (3) Neither the name of the copyright holder nor the names of any contributors
15
+ # may be used to endorse or promote products derived from this software without
16
+ # specific prior written permission from the respective party.
17
+ #
18
+ # (4) Other than as required in clauses (1) and (2), distributions in any form
19
+ # of modifications or other derivative works may not use the "OpenStudio"
20
+ # trademark, "OS", "os", or any other confusingly similar designation without
21
+ # specific prior written permission from Alliance for Sustainable Energy, LLC.
22
+ #
23
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS
24
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
25
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE
27
+ # UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF
28
+ # THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
30
+ # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32
+ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33
+ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
+ # *******************************************************************************
35
+
36
+ module OsLib_QAQC
37
+ # Check that there are no people or lights in plenums.
38
+ def check_plenum_loads(category, target_standard, name_only = false)
39
+ # summary of the check
40
+ check_elems = OpenStudio::AttributeVector.new
41
+ check_elems << OpenStudio::Attribute.new('name', 'Plenum Loads')
42
+ check_elems << OpenStudio::Attribute.new('category', category)
43
+ check_elems << OpenStudio::Attribute.new('description', 'Check that the plenums do not have people or lights.')
44
+
45
+ # stop here if only name is requested this is used to populate display name for arguments
46
+ if name_only == true
47
+ results = []
48
+ check_elems.each do |elem|
49
+ results << elem.valueAsString
50
+ end
51
+ return results
52
+ end
53
+
54
+ std = Standard.build(target_standard)
55
+
56
+ begin
57
+ @model.getThermalZones.each do |zone|
58
+ # Only check plenums
59
+ next unless std.thermal_zone_plenum?(zone)
60
+
61
+ # People
62
+ num_people = zone.numberOfPeople
63
+ if num_people > 0
64
+ check_elems << OpenStudio::Attribute.new('flag', "#{zone.name} is a plenum, but has #{num_people.round(1)} people. Plenums should not contain people.")
65
+ end
66
+
67
+ # Lights
68
+ lights_w = zone.lightingPower
69
+ if lights_w > 0
70
+ 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.")
71
+ end
72
+ end
73
+ rescue StandardError => e
74
+ # brief description of ruby error
75
+ check_elems << OpenStudio::Attribute.new('flag', "Error prevented QAQC check from running (#{e}).")
76
+
77
+ # backtrace of ruby error for diagnostic use
78
+ if @error_backtrace then check_elems << OpenStudio::Attribute.new('flag', e.backtrace.join("\n").to_s) end
79
+ end
80
+
81
+ # add check_elms to new attribute
82
+ check_elem = OpenStudio::Attribute.new('check', check_elems)
83
+
84
+ return check_elem
85
+ # note: registerWarning and registerValue will be added for checks downstream using os_lib_reporting_qaqc.rb
86
+ end
87
+ end
@@ -1,108 +1,108 @@
1
- # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2019, Alliance for Sustainable Energy, LLC.
3
- # All rights reserved.
4
- # Redistribution and use in source and binary forms, with or without
5
- # modification, are permitted provided that the following conditions are met:
6
- #
7
- # (1) Redistributions of source code must retain the above copyright notice,
8
- # this list of conditions and the following disclaimer.
9
- #
10
- # (2) Redistributions in binary form must reproduce the above copyright notice,
11
- # this list of conditions and the following disclaimer in the documentation
12
- # and/or other materials provided with the distribution.
13
- #
14
- # (3) Neither the name of the copyright holder nor the names of any contributors
15
- # may be used to endorse or promote products derived from this software without
16
- # specific prior written permission from the respective party.
17
- #
18
- # (4) Other than as required in clauses (1) and (2), distributions in any form
19
- # of modifications or other derivative works may not use the "OpenStudio"
20
- # trademark, "OS", "os", or any other confusingly similar designation without
21
- # specific prior written permission from Alliance for Sustainable Energy, LLC.
22
- #
23
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS
24
- # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
25
- # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
- # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE
27
- # UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF
28
- # THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29
- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
30
- # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31
- # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32
- # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33
- # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
- # *******************************************************************************
35
-
36
- module OsLib_QAQC
37
- # Check the pumping power (W/gpm) for each pump in the model to identify
38
- # unrealistically sized pumps.
39
- def check_pump_pwr(category, target_standard, max_pwr_delta = 0.1, name_only = false)
40
- # summary of the check
41
- check_elems = OpenStudio::AttributeVector.new
42
- check_elems << OpenStudio::Attribute.new('name', 'Pump Power')
43
- check_elems << OpenStudio::Attribute.new('category', category)
44
- check_elems << OpenStudio::Attribute.new('description', 'Check that pump power vs flow makes sense.')
45
-
46
- # stop here if only name is requested this is used to populate display name for arguments
47
- if name_only == true
48
- results = []
49
- check_elems.each do |elem|
50
- results << elem.valueAsString
51
- end
52
- return results
53
- end
54
-
55
- std = Standard.build(target_standard)
56
-
57
- begin
58
- # Check each plant loop
59
- @model.getPlantLoops.each do |plant_loop|
60
- # Set the expected/typical W/gpm
61
- loop_type = plant_loop.sizingPlant.loopType
62
- case loop_type
63
- when 'Heating'
64
- expected_w_per_gpm = 19.0
65
- when 'Cooling'
66
- expected_w_per_gpm = 22.0
67
- when 'Condenser'
68
- expected_w_per_gpm = 19.0
69
- end
70
-
71
- # Check the W/gpm for each pump on each plant loop
72
- plant_loop.supplyComponents.each do |sc|
73
- # Get the W/gpm for the pump
74
- obj_type = sc.iddObjectType.valueName.to_s
75
- case obj_type
76
- when 'OS_Pump_ConstantSpeed'
77
- actual_w_per_gpm = std.pump_rated_w_per_gpm(sc.to_PumpConstantSpeed.get)
78
- when 'OS_Pump_VariableSpeed'
79
- actual_w_per_gpm = std.pump_rated_w_per_gpm(sc.to_PumpVariableSpeed.get)
80
- when 'OS_HeaderedPumps_ConstantSpeed'
81
- actual_w_per_gpm = std.pump_rated_w_per_gpm(sc.to_HeaderedPumpsConstantSpeed.get)
82
- when 'OS_HeaderedPumps_VariableSpeed'
83
- actual_w_per_gpm = std.pump_rated_w_per_gpm(sc.to_HeaderedPumpsVariableSpeed.get)
84
- else
85
- next # Skip non-pump objects
86
- end
87
-
88
- # Compare W/gpm to expected/typical values
89
- if ((expected_w_per_gpm - actual_w_per_gpm) / actual_w_per_gpm).abs > max_pwr_delta
90
- 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.")
91
- end
92
- end
93
- end
94
- rescue StandardError => e
95
- # brief description of ruby error
96
- check_elems << OpenStudio::Attribute.new('flag', "Error prevented QAQC check from running (#{e}).")
97
-
98
- # backtrace of ruby error for diagnostic use
99
- if @error_backtrace then check_elems << OpenStudio::Attribute.new('flag', e.backtrace.join("\n").to_s) end
100
- end
101
-
102
- # add check_elms to new attribute
103
- check_elem = OpenStudio::Attribute.new('check', check_elems)
104
-
105
- return check_elem
106
- # note: registerWarning and registerValue will be added for checks downstream using os_lib_reporting_qaqc.rb
107
- end
108
- end
1
+ # *******************************************************************************
2
+ # OpenStudio(R), Copyright (c) 2008-2019, Alliance for Sustainable Energy, LLC.
3
+ # All rights reserved.
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # (1) Redistributions of source code must retain the above copyright notice,
8
+ # this list of conditions and the following disclaimer.
9
+ #
10
+ # (2) Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # (3) Neither the name of the copyright holder nor the names of any contributors
15
+ # may be used to endorse or promote products derived from this software without
16
+ # specific prior written permission from the respective party.
17
+ #
18
+ # (4) Other than as required in clauses (1) and (2), distributions in any form
19
+ # of modifications or other derivative works may not use the "OpenStudio"
20
+ # trademark, "OS", "os", or any other confusingly similar designation without
21
+ # specific prior written permission from Alliance for Sustainable Energy, LLC.
22
+ #
23
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS
24
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
25
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE
27
+ # UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF
28
+ # THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
30
+ # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32
+ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33
+ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
+ # *******************************************************************************
35
+
36
+ module OsLib_QAQC
37
+ # Check the pumping power (W/gpm) for each pump in the model to identify
38
+ # unrealistically sized pumps.
39
+ def check_pump_pwr(category, target_standard, max_pwr_delta = 0.1, name_only = false)
40
+ # summary of the check
41
+ check_elems = OpenStudio::AttributeVector.new
42
+ check_elems << OpenStudio::Attribute.new('name', 'Pump Power')
43
+ check_elems << OpenStudio::Attribute.new('category', category)
44
+ check_elems << OpenStudio::Attribute.new('description', 'Check that pump power vs flow makes sense.')
45
+
46
+ # stop here if only name is requested this is used to populate display name for arguments
47
+ if name_only == true
48
+ results = []
49
+ check_elems.each do |elem|
50
+ results << elem.valueAsString
51
+ end
52
+ return results
53
+ end
54
+
55
+ std = Standard.build(target_standard)
56
+
57
+ begin
58
+ # Check each plant loop
59
+ @model.getPlantLoops.each do |plant_loop|
60
+ # Set the expected/typical W/gpm
61
+ loop_type = plant_loop.sizingPlant.loopType
62
+ case loop_type
63
+ when 'Heating'
64
+ expected_w_per_gpm = 19.0
65
+ when 'Cooling'
66
+ expected_w_per_gpm = 22.0
67
+ when 'Condenser'
68
+ expected_w_per_gpm = 19.0
69
+ end
70
+
71
+ # Check the W/gpm for each pump on each plant loop
72
+ plant_loop.supplyComponents.each do |sc|
73
+ # Get the W/gpm for the pump
74
+ obj_type = sc.iddObjectType.valueName.to_s
75
+ case obj_type
76
+ when 'OS_Pump_ConstantSpeed'
77
+ actual_w_per_gpm = std.pump_rated_w_per_gpm(sc.to_PumpConstantSpeed.get)
78
+ when 'OS_Pump_VariableSpeed'
79
+ actual_w_per_gpm = std.pump_rated_w_per_gpm(sc.to_PumpVariableSpeed.get)
80
+ when 'OS_HeaderedPumps_ConstantSpeed'
81
+ actual_w_per_gpm = std.pump_rated_w_per_gpm(sc.to_HeaderedPumpsConstantSpeed.get)
82
+ when 'OS_HeaderedPumps_VariableSpeed'
83
+ actual_w_per_gpm = std.pump_rated_w_per_gpm(sc.to_HeaderedPumpsVariableSpeed.get)
84
+ else
85
+ next # Skip non-pump objects
86
+ end
87
+
88
+ # Compare W/gpm to expected/typical values
89
+ if ((expected_w_per_gpm - actual_w_per_gpm) / actual_w_per_gpm).abs > max_pwr_delta
90
+ 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.")
91
+ end
92
+ end
93
+ end
94
+ rescue StandardError => e
95
+ # brief description of ruby error
96
+ check_elems << OpenStudio::Attribute.new('flag', "Error prevented QAQC check from running (#{e}).")
97
+
98
+ # backtrace of ruby error for diagnostic use
99
+ if @error_backtrace then check_elems << OpenStudio::Attribute.new('flag', e.backtrace.join("\n").to_s) end
100
+ end
101
+
102
+ # add check_elms to new attribute
103
+ check_elem = OpenStudio::Attribute.new('check', check_elems)
104
+
105
+ return check_elem
106
+ # note: registerWarning and registerValue will be added for checks downstream using os_lib_reporting_qaqc.rb
107
+ end
108
+ end
@@ -1,241 +1,241 @@
1
- # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2019, Alliance for Sustainable Energy, LLC.
3
- # All rights reserved.
4
- # Redistribution and use in source and binary forms, with or without
5
- # modification, are permitted provided that the following conditions are met:
6
- #
7
- # (1) Redistributions of source code must retain the above copyright notice,
8
- # this list of conditions and the following disclaimer.
9
- #
10
- # (2) Redistributions in binary form must reproduce the above copyright notice,
11
- # this list of conditions and the following disclaimer in the documentation
12
- # and/or other materials provided with the distribution.
13
- #
14
- # (3) Neither the name of the copyright holder nor the names of any contributors
15
- # may be used to endorse or promote products derived from this software without
16
- # specific prior written permission from the respective party.
17
- #
18
- # (4) Other than as required in clauses (1) and (2), distributions in any form
19
- # of modifications or other derivative works may not use the "OpenStudio"
20
- # trademark, "OS", "os", or any other confusingly similar designation without
21
- # specific prior written permission from Alliance for Sustainable Energy, LLC.
22
- #
23
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS
24
- # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
25
- # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
- # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE
27
- # UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF
28
- # THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29
- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
30
- # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31
- # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32
- # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33
- # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
- # *******************************************************************************
35
-
36
- module OsLib_QAQC
37
- # Determine the hour when the schedule first exceeds the starting value and when
38
- # it goes back down to the ending value at the end of the day.
39
- # This method only works for ScheduleRuleset schedules.
40
- def get_start_and_end_times(schedule_ruleset)
41
- # Ensure that this is a ScheduleRuleset
42
- schedule_ruleset = schedule_ruleset.to_ScheduleRuleset
43
- return [nil, nil] if schedule_ruleset.empty?
44
- schedule_ruleset = schedule_ruleset.get
45
-
46
- # Define the start and end date
47
- year_start_date = nil
48
- year_end_date = nil
49
- if schedule_ruleset.model.yearDescription.is_initialized
50
- year_description = schedule_ruleset.model.yearDescription.get
51
- year = year_description.assumedYear
52
- year_start_date = OpenStudio::Date.new(OpenStudio::MonthOfYear.new('January'), 1, year)
53
- year_end_date = OpenStudio::Date.new(OpenStudio::MonthOfYear.new('December'), 31, year)
54
- else
55
- year_start_date = OpenStudio::Date.new(OpenStudio::MonthOfYear.new('January'), 1, 2009)
56
- year_end_date = OpenStudio::Date.new(OpenStudio::MonthOfYear.new('December'), 31, 2009)
57
- end
58
-
59
- # Get the ordered list of all the day schedules that are used by this schedule ruleset
60
- day_schs = schedule_ruleset.getDaySchedules(year_start_date, year_end_date)
61
-
62
- # Get a 365-value array of which schedule is used on each day of the year,
63
- day_schs_used_each_day = schedule_ruleset.getActiveRuleIndices(year_start_date, year_end_date)
64
-
65
- # Create a map that shows how many days each schedule is used
66
- day_sch_freq = day_schs_used_each_day.group_by { |n| n }
67
- day_sch_freq = day_sch_freq.sort_by { |freq| freq[1].size }
68
- common_day_freq = day_sch_freq.last
69
-
70
- # Build a hash that maps schedule day index to schedule day
71
- schedule_index_to_day = {}
72
- day_schs.each_with_index do |day_sch, i|
73
- schedule_index_to_day[day_schs_used_each_day[i]] = day_sch
74
- end
75
-
76
- # Get the most common day schedule
77
- sch_index = common_day_freq[0]
78
- number_of_days_sch_used = common_day_freq[1].size
79
-
80
- # Get the day schedule at this index
81
- day_sch = if sch_index == -1 # If index = -1, this day uses the default day schedule (not a rule)
82
- schedule_ruleset.defaultDaySchedule
83
- else
84
- schedule_index_to_day[sch_index]
85
- end
86
-
87
- # Determine the full load hours for just one day
88
- values = []
89
- times = []
90
- day_sch.times.each_with_index do |time, i|
91
- times << day_sch.times[i]
92
- values << day_sch.values[i]
93
- end
94
-
95
- # Get the minimum value
96
- start_val = values.first
97
- end_val = values.last
98
-
99
- # Get the start time (first time value goes above minimum)
100
- start_time = nil
101
- values.each_with_index do |val, i|
102
- break if i == values.size - 1 # Stop if we reach end of array
103
- if val == start_val && values[i + 1] > start_val
104
- start_time = times[i + 1]
105
- break
106
- end
107
- end
108
-
109
- # Get the end time (first time value goes back down to minimum)
110
- end_time = nil
111
- values.each_with_index do |val, i|
112
- if i < values.size - 1
113
- if val > end_val && values[i + 1] == end_val
114
- end_time = times[i]
115
- break
116
- end
117
- else
118
- if val > end_val && values[0] == start_val # Check first hour of day for schedules that end at midnight
119
- end_time = OpenStudio::Time.new(0, 24, 0, 0)
120
- break
121
- end
122
- end
123
- end
124
-
125
- return [start_time, end_time]
126
- end
127
-
128
- # Check that the lighting, equipment, and HVAC setpoint schedules
129
- # coordinate with the occupancy schedules. This is defined as having start and end
130
- # times within the specified number of hours away from the occupancy schedule.
131
- def check_sch_coord(category, target_standard, max_hrs, name_only = false)
132
- # summary of the check
133
- check_elems = OpenStudio::AttributeVector.new
134
- check_elems << OpenStudio::Attribute.new('name', 'Conditioned Zones')
135
- check_elems << OpenStudio::Attribute.new('category', category)
136
- check_elems << OpenStudio::Attribute.new('description', 'Check that lighting, equipment, and HVAC schedules coordinate with occupancy.')
137
-
138
- # stop here if only name is requested this is used to populate display name for arguments
139
- if name_only == true
140
- results = []
141
- check_elems.each do |elem|
142
- results << elem.valueAsString
143
- end
144
- return results
145
- end
146
-
147
- std = Standard.build(target_standard)
148
-
149
- begin
150
- # Convert max hr limit to OpenStudio Time
151
- max_hrs = OpenStudio::Time.new(0, max_hrs, 0, 0)
152
-
153
- # Check schedules in each space
154
- @model.getSpaces.each do |space|
155
- # Occupancy, Lighting, and Equipment Schedules
156
- coord_schs = []
157
- occ_schs = []
158
- # Get the space type (optional)
159
- space_type = space.spaceType
160
-
161
- # Occupancy
162
- occs = []
163
- occs += space.people # From space directly
164
- occs += space_type.get.people if space_type.is_initialized # Inherited from space type
165
- occs.each do |occ|
166
- occ_schs << occ.numberofPeopleSchedule.get if occ.numberofPeopleSchedule.is_initialized
167
- end
168
-
169
- # Lights
170
- lts = []
171
- lts += space.lights # From space directly
172
- lts += space_type.get.lights if space_type.is_initialized # Inherited from space type
173
- lts.each do |lt|
174
- coord_schs << lt.schedule.get if lt.schedule.is_initialized
175
- end
176
-
177
- # Equip
178
- plugs = []
179
- plugs += space.electricEquipment # From space directly
180
- plugs += space_type.get.electricEquipment if space_type.is_initialized # Inherited from space type
181
- plugs.each do |plug|
182
- coord_schs << plug.schedule.get if plug.schedule.is_initialized
183
- end
184
-
185
- # HVAC Schedule (airloop-served zones only)
186
- if space.thermalZone.is_initialized
187
- zone = space.thermalZone.get
188
- if zone.airLoopHVAC.is_initialized
189
- coord_schs << zone.airLoopHVAC.get.availabilitySchedule
190
- end
191
- end
192
-
193
- # Cannot check spaces with no occupancy schedule to compare against
194
- next if occ_schs.empty?
195
-
196
- # Get start and end occupancy times from the first occupancy schedule
197
- occ_start_time, occ_end_time = get_start_and_end_times(occ_schs[0])
198
-
199
- # Cannot check a space where the occupancy start time or end time cannot be determined
200
- next if occ_start_time.nil? || occ_end_time.nil?
201
-
202
- # Check all schedules against occupancy
203
-
204
- # Lights should have a start and end within X hrs of the occupancy start and end
205
- coord_schs.each do |coord_sch|
206
- # Get start and end time of load/HVAC schedule
207
- start_time, end_time = get_start_and_end_times(coord_sch)
208
- if start_time.nil?
209
- 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.")
210
- next
211
- elsif end_time.nil?
212
- 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.")
213
- next
214
- end
215
-
216
- # Check start time
217
- if (occ_start_time - start_time) > max_hrs || (start_time - occ_start_time) > max_hrs
218
- 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.")
219
- end
220
-
221
- # Check end time
222
- if (occ_end_time - end_time) > max_hrs || (end_time - occ_end_time) > max_hrs
223
- 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.")
224
- end
225
- end
226
- end
227
- rescue StandardError => e
228
- # brief description of ruby error
229
- check_elems << OpenStudio::Attribute.new('flag', "Error prevented QAQC check from running (#{e}).")
230
-
231
- # backtrace of ruby error for diagnostic use
232
- if @error_backtrace then check_elems << OpenStudio::Attribute.new('flag', e.backtrace.join("\n").to_s) end
233
- end
234
-
235
- # add check_elms to new attribute
236
- check_elem = OpenStudio::Attribute.new('check', check_elems)
237
-
238
- return check_elem
239
- # note: registerWarning and registerValue will be added for checks downstream using os_lib_reporting_qaqc.rb
240
- end
241
- end
1
+ # *******************************************************************************
2
+ # OpenStudio(R), Copyright (c) 2008-2019, Alliance for Sustainable Energy, LLC.
3
+ # All rights reserved.
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # (1) Redistributions of source code must retain the above copyright notice,
8
+ # this list of conditions and the following disclaimer.
9
+ #
10
+ # (2) Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # (3) Neither the name of the copyright holder nor the names of any contributors
15
+ # may be used to endorse or promote products derived from this software without
16
+ # specific prior written permission from the respective party.
17
+ #
18
+ # (4) Other than as required in clauses (1) and (2), distributions in any form
19
+ # of modifications or other derivative works may not use the "OpenStudio"
20
+ # trademark, "OS", "os", or any other confusingly similar designation without
21
+ # specific prior written permission from Alliance for Sustainable Energy, LLC.
22
+ #
23
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS
24
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
25
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE
27
+ # UNITED STATES GOVERNMENT, OR THE UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF
28
+ # THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
30
+ # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32
+ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33
+ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
+ # *******************************************************************************
35
+
36
+ module OsLib_QAQC
37
+ # Determine the hour when the schedule first exceeds the starting value and when
38
+ # it goes back down to the ending value at the end of the day.
39
+ # This method only works for ScheduleRuleset schedules.
40
+ def get_start_and_end_times(schedule_ruleset)
41
+ # Ensure that this is a ScheduleRuleset
42
+ schedule_ruleset = schedule_ruleset.to_ScheduleRuleset
43
+ return [nil, nil] if schedule_ruleset.empty?
44
+ schedule_ruleset = schedule_ruleset.get
45
+
46
+ # Define the start and end date
47
+ year_start_date = nil
48
+ year_end_date = nil
49
+ if schedule_ruleset.model.yearDescription.is_initialized
50
+ year_description = schedule_ruleset.model.yearDescription.get
51
+ year = year_description.assumedYear
52
+ year_start_date = OpenStudio::Date.new(OpenStudio::MonthOfYear.new('January'), 1, year)
53
+ year_end_date = OpenStudio::Date.new(OpenStudio::MonthOfYear.new('December'), 31, year)
54
+ else
55
+ year_start_date = OpenStudio::Date.new(OpenStudio::MonthOfYear.new('January'), 1, 2009)
56
+ year_end_date = OpenStudio::Date.new(OpenStudio::MonthOfYear.new('December'), 31, 2009)
57
+ end
58
+
59
+ # Get the ordered list of all the day schedules that are used by this schedule ruleset
60
+ day_schs = schedule_ruleset.getDaySchedules(year_start_date, year_end_date)
61
+
62
+ # Get a 365-value array of which schedule is used on each day of the year,
63
+ day_schs_used_each_day = schedule_ruleset.getActiveRuleIndices(year_start_date, year_end_date)
64
+
65
+ # Create a map that shows how many days each schedule is used
66
+ day_sch_freq = day_schs_used_each_day.group_by { |n| n }
67
+ day_sch_freq = day_sch_freq.sort_by { |freq| freq[1].size }
68
+ common_day_freq = day_sch_freq.last
69
+
70
+ # Build a hash that maps schedule day index to schedule day
71
+ schedule_index_to_day = {}
72
+ day_schs.each_with_index do |day_sch, i|
73
+ schedule_index_to_day[day_schs_used_each_day[i]] = day_sch
74
+ end
75
+
76
+ # Get the most common day schedule
77
+ sch_index = common_day_freq[0]
78
+ number_of_days_sch_used = common_day_freq[1].size
79
+
80
+ # Get the day schedule at this index
81
+ day_sch = if sch_index == -1 # If index = -1, this day uses the default day schedule (not a rule)
82
+ schedule_ruleset.defaultDaySchedule
83
+ else
84
+ schedule_index_to_day[sch_index]
85
+ end
86
+
87
+ # Determine the full load hours for just one day
88
+ values = []
89
+ times = []
90
+ day_sch.times.each_with_index do |time, i|
91
+ times << day_sch.times[i]
92
+ values << day_sch.values[i]
93
+ end
94
+
95
+ # Get the minimum value
96
+ start_val = values.first
97
+ end_val = values.last
98
+
99
+ # Get the start time (first time value goes above minimum)
100
+ start_time = nil
101
+ values.each_with_index do |val, i|
102
+ break if i == values.size - 1 # Stop if we reach end of array
103
+ if val == start_val && values[i + 1] > start_val
104
+ start_time = times[i + 1]
105
+ break
106
+ end
107
+ end
108
+
109
+ # Get the end time (first time value goes back down to minimum)
110
+ end_time = nil
111
+ values.each_with_index do |val, i|
112
+ if i < values.size - 1
113
+ if val > end_val && values[i + 1] == end_val
114
+ end_time = times[i]
115
+ break
116
+ end
117
+ else
118
+ if val > end_val && values[0] == start_val # Check first hour of day for schedules that end at midnight
119
+ end_time = OpenStudio::Time.new(0, 24, 0, 0)
120
+ break
121
+ end
122
+ end
123
+ end
124
+
125
+ return [start_time, end_time]
126
+ end
127
+
128
+ # Check that the lighting, equipment, and HVAC setpoint schedules
129
+ # coordinate with the occupancy schedules. This is defined as having start and end
130
+ # times within the specified number of hours away from the occupancy schedule.
131
+ def check_sch_coord(category, target_standard, max_hrs, name_only = false)
132
+ # summary of the check
133
+ check_elems = OpenStudio::AttributeVector.new
134
+ check_elems << OpenStudio::Attribute.new('name', 'Conditioned Zones')
135
+ check_elems << OpenStudio::Attribute.new('category', category)
136
+ check_elems << OpenStudio::Attribute.new('description', 'Check that lighting, equipment, and HVAC schedules coordinate with occupancy.')
137
+
138
+ # stop here if only name is requested this is used to populate display name for arguments
139
+ if name_only == true
140
+ results = []
141
+ check_elems.each do |elem|
142
+ results << elem.valueAsString
143
+ end
144
+ return results
145
+ end
146
+
147
+ std = Standard.build(target_standard)
148
+
149
+ begin
150
+ # Convert max hr limit to OpenStudio Time
151
+ max_hrs = OpenStudio::Time.new(0, max_hrs, 0, 0)
152
+
153
+ # Check schedules in each space
154
+ @model.getSpaces.each do |space|
155
+ # Occupancy, Lighting, and Equipment Schedules
156
+ coord_schs = []
157
+ occ_schs = []
158
+ # Get the space type (optional)
159
+ space_type = space.spaceType
160
+
161
+ # Occupancy
162
+ occs = []
163
+ occs += space.people # From space directly
164
+ occs += space_type.get.people if space_type.is_initialized # Inherited from space type
165
+ occs.each do |occ|
166
+ occ_schs << occ.numberofPeopleSchedule.get if occ.numberofPeopleSchedule.is_initialized
167
+ end
168
+
169
+ # Lights
170
+ lts = []
171
+ lts += space.lights # From space directly
172
+ lts += space_type.get.lights if space_type.is_initialized # Inherited from space type
173
+ lts.each do |lt|
174
+ coord_schs << lt.schedule.get if lt.schedule.is_initialized
175
+ end
176
+
177
+ # Equip
178
+ plugs = []
179
+ plugs += space.electricEquipment # From space directly
180
+ plugs += space_type.get.electricEquipment if space_type.is_initialized # Inherited from space type
181
+ plugs.each do |plug|
182
+ coord_schs << plug.schedule.get if plug.schedule.is_initialized
183
+ end
184
+
185
+ # HVAC Schedule (airloop-served zones only)
186
+ if space.thermalZone.is_initialized
187
+ zone = space.thermalZone.get
188
+ if zone.airLoopHVAC.is_initialized
189
+ coord_schs << zone.airLoopHVAC.get.availabilitySchedule
190
+ end
191
+ end
192
+
193
+ # Cannot check spaces with no occupancy schedule to compare against
194
+ next if occ_schs.empty?
195
+
196
+ # Get start and end occupancy times from the first occupancy schedule
197
+ occ_start_time, occ_end_time = get_start_and_end_times(occ_schs[0])
198
+
199
+ # Cannot check a space where the occupancy start time or end time cannot be determined
200
+ next if occ_start_time.nil? || occ_end_time.nil?
201
+
202
+ # Check all schedules against occupancy
203
+
204
+ # Lights should have a start and end within X hrs of the occupancy start and end
205
+ coord_schs.each do |coord_sch|
206
+ # Get start and end time of load/HVAC schedule
207
+ start_time, end_time = get_start_and_end_times(coord_sch)
208
+ if start_time.nil?
209
+ 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.")
210
+ next
211
+ elsif end_time.nil?
212
+ 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.")
213
+ next
214
+ end
215
+
216
+ # Check start time
217
+ if (occ_start_time - start_time) > max_hrs || (start_time - occ_start_time) > max_hrs
218
+ 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.")
219
+ end
220
+
221
+ # Check end time
222
+ if (occ_end_time - end_time) > max_hrs || (end_time - occ_end_time) > max_hrs
223
+ 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.")
224
+ end
225
+ end
226
+ end
227
+ rescue StandardError => e
228
+ # brief description of ruby error
229
+ check_elems << OpenStudio::Attribute.new('flag', "Error prevented QAQC check from running (#{e}).")
230
+
231
+ # backtrace of ruby error for diagnostic use
232
+ if @error_backtrace then check_elems << OpenStudio::Attribute.new('flag', e.backtrace.join("\n").to_s) end
233
+ end
234
+
235
+ # add check_elms to new attribute
236
+ check_elem = OpenStudio::Attribute.new('check', check_elems)
237
+
238
+ return check_elem
239
+ # note: registerWarning and registerValue will be added for checks downstream using os_lib_reporting_qaqc.rb
240
+ end
241
+ end