openstudio-extension 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +9 -0
  3. data/.rubocop.yml +9 -0
  4. data/Gemfile +3 -1
  5. data/Jenkinsfile +10 -0
  6. data/README.md +230 -12
  7. data/Rakefile +88 -3
  8. data/bin/console +3 -3
  9. data/doc_templates/LICENSE.md +27 -0
  10. data/doc_templates/README.md.erb +42 -0
  11. data/doc_templates/copyright_erb.txt +36 -0
  12. data/doc_templates/copyright_js.txt +4 -0
  13. data/doc_templates/copyright_ruby.txt +34 -0
  14. data/init_templates/README.md +37 -0
  15. data/init_templates/gemspec.txt +32 -0
  16. data/init_templates/openstudio_module.rb +50 -0
  17. data/init_templates/spec.rb +47 -0
  18. data/init_templates/spec_helper.rb +49 -0
  19. data/init_templates/template_gemfile.txt +17 -0
  20. data/init_templates/template_rakefile.txt +15 -0
  21. data/init_templates/version.rb +40 -0
  22. data/lib/files/openstudio-extension-gem-test.ddy +536 -0
  23. data/lib/files/openstudio-extension-gem-test.epw +8768 -0
  24. data/lib/files/openstudio-extension-gem-test.stat +554 -0
  25. data/lib/measures/openstudio_extension_test_measure/LICENSE.md +27 -0
  26. data/lib/measures/openstudio_extension_test_measure/README.md +26 -0
  27. data/lib/measures/openstudio_extension_test_measure/README.md.erb +42 -0
  28. data/lib/measures/openstudio_extension_test_measure/measure.rb +72 -0
  29. data/lib/measures/openstudio_extension_test_measure/measure.xml +83 -0
  30. data/lib/measures/openstudio_extension_test_measure/resources/os_lib_helper_methods.rb +399 -0
  31. data/lib/measures/openstudio_extension_test_measure/tests/OpenStudioExtensionTestMeasure_Test.rb +75 -0
  32. data/lib/openstudio/extension.rb +220 -0
  33. data/lib/openstudio/extension/core/CreateResults.rb +879 -0
  34. data/lib/openstudio/extension/core/check_air_sys_temps.rb +190 -0
  35. data/lib/openstudio/extension/core/check_calibration.rb +155 -0
  36. data/lib/openstudio/extension/core/check_cond_zns.rb +84 -0
  37. data/lib/openstudio/extension/core/check_domestic_hot_water.rb +334 -0
  38. data/lib/openstudio/extension/core/check_envelope_conductance.rb +453 -0
  39. data/lib/openstudio/extension/core/check_eui_by_end_use.rb +162 -0
  40. data/lib/openstudio/extension/core/check_eui_reasonableness.rb +135 -0
  41. data/lib/openstudio/extension/core/check_fan_pwr.rb +98 -0
  42. data/lib/openstudio/extension/core/check_internal_loads.rb +393 -0
  43. data/lib/openstudio/extension/core/check_mech_sys_capacity.rb +226 -0
  44. data/lib/openstudio/extension/core/check_mech_sys_efficiency.rb +326 -0
  45. data/lib/openstudio/extension/core/check_mech_sys_part_load_eff.rb +464 -0
  46. data/lib/openstudio/extension/core/check_mech_sys_type.rb +139 -0
  47. data/lib/openstudio/extension/core/check_part_loads.rb +451 -0
  48. data/lib/openstudio/extension/core/check_placeholder.rb +75 -0
  49. data/lib/openstudio/extension/core/check_plant_cap.rb +123 -0
  50. data/lib/openstudio/extension/core/check_plant_temps.rb +159 -0
  51. data/lib/openstudio/extension/core/check_plenum_loads.rb +87 -0
  52. data/lib/openstudio/extension/core/check_pump_pwr.rb +108 -0
  53. data/lib/openstudio/extension/core/check_sch_coord.rb +241 -0
  54. data/lib/openstudio/extension/core/check_schedules.rb +311 -0
  55. data/lib/openstudio/extension/core/check_simultaneous_heating_and_cooling.rb +158 -0
  56. data/lib/openstudio/extension/core/check_supply_air_and_thermostat_temp_difference.rb +148 -0
  57. data/lib/openstudio/extension/core/check_weather_files.rb +132 -0
  58. data/lib/openstudio/extension/core/deer_vintages.rb +311 -0
  59. data/lib/openstudio/extension/core/os_lib_aedg_measures.rb +491 -0
  60. data/lib/openstudio/extension/core/os_lib_cofee.rb +259 -0
  61. data/lib/openstudio/extension/core/os_lib_constructions.rb +378 -0
  62. data/lib/openstudio/extension/core/os_lib_geometry.rb +1022 -0
  63. data/lib/openstudio/extension/core/os_lib_helper_methods.rb +399 -0
  64. data/lib/openstudio/extension/core/os_lib_hvac.rb +2171 -0
  65. data/lib/openstudio/extension/core/os_lib_lighting_and_equipment.rb +214 -0
  66. data/lib/openstudio/extension/core/os_lib_model_generation.rb +817 -0
  67. data/lib/openstudio/extension/core/os_lib_model_simplification.rb +1049 -0
  68. data/lib/openstudio/extension/core/os_lib_outdoorair_and_infiltration.rb +165 -0
  69. data/lib/openstudio/extension/core/os_lib_reporting.rb +4652 -0
  70. data/lib/openstudio/extension/core/os_lib_reporting_qaqc.rb +200 -0
  71. data/lib/openstudio/extension/core/os_lib_schedules.rb +963 -0
  72. data/lib/openstudio/extension/rake_task.rb +149 -0
  73. data/lib/openstudio/extension/runner.rb +644 -0
  74. data/lib/openstudio/extension/version.rb +40 -0
  75. data/openstudio-extension.gemspec +20 -15
  76. metadata +150 -14
  77. data/.travis.yml +0 -7
  78. data/lib/OpenStudio/Extension/rake_task.rb +0 -84
  79. data/lib/OpenStudio/Extension/version.rb +0 -33
  80. data/lib/OpenStudio/extension.rb +0 -65
@@ -0,0 +1,158 @@
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
+ # include any general notes about QAQC method here
38
+
39
+ # checks the number of unmet hours in the model
40
+ def check_simultaneous_heating_and_cooling(category, max_pass, name_only = false)
41
+ # summary of the check
42
+ check_elems = OpenStudio::AttributeVector.new
43
+ check_elems << OpenStudio::Attribute.new('name', 'Simultaneous Heating and Cooling')
44
+ check_elems << OpenStudio::Attribute.new('category', category)
45
+ 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. ')
46
+
47
+ # stop here if only name is requested this is used to populate display name for arguments
48
+ if name_only == true
49
+ results = []
50
+ check_elems.each do |elem|
51
+ results << elem.valueAsString
52
+ end
53
+ return results
54
+ end
55
+
56
+ begin
57
+ # get the weather file run period (as opposed to design day run period)
58
+ ann_env_pd = nil
59
+ @sql.availableEnvPeriods.each do |env_pd|
60
+ env_type = @sql.environmentType(env_pd)
61
+ if env_type.is_initialized
62
+ if env_type.get == OpenStudio::EnvironmentType.new('WeatherRunPeriod')
63
+ ann_env_pd = env_pd
64
+ break
65
+ end
66
+ end
67
+ end
68
+
69
+ # only try to get the annual timeseries if an annual simulation was run
70
+ if ann_env_pd.nil?
71
+ check_elems << OpenStudio::Attribute.new('flag', 'Cannot find the annual simulation run period, cannot determine simultaneous heating and cooling.')
72
+ return check_elem
73
+ end
74
+
75
+ # For each VAV reheat terminal, calculate
76
+ # the annual total % reheat hours.
77
+ @model.getAirTerminalSingleDuctVAVReheats.each do |term|
78
+ # Reheat coil heating rate
79
+ rht_coil = term.reheatCoil
80
+ key_value = rht_coil.name.get.to_s.upcase # must be in all caps.
81
+ time_step = 'Hourly' # "Zone Timestep", "Hourly", "HVAC System Timestep"
82
+ variable_name = 'Heating Coil Heating Rate'
83
+ variable_name_alt = 'Heating Coil Air Heating Rate'
84
+ 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.
85
+
86
+ # try and alternate variable name
87
+ if rht_rate_ts.empty?
88
+ 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.
89
+ end
90
+
91
+ if rht_rate_ts.empty?
92
+ check_elems << OpenStudio::Attribute.new('flag', "Heating Coil (Air) Heating Rate Timeseries not found for #{key_value}.")
93
+ else
94
+
95
+ rht_rate_ts = rht_rate_ts.get.values
96
+ # Put timeseries into array
97
+ rht_rate_vals = []
98
+ for i in 0..(rht_rate_ts.size - 1)
99
+ rht_rate_vals << rht_rate_ts[i]
100
+ end
101
+
102
+ # Zone Air Terminal Sensible Heating Rate
103
+ key_value = "ADU #{term.name.get.to_s.upcase}" # must be in all caps.
104
+ time_step = 'Hourly' # "Zone Timestep", "Hourly", "HVAC System Timestep"
105
+ variable_name = 'Zone Air Terminal Sensible Cooling Rate'
106
+ 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.
107
+ if clg_rate_ts.empty?
108
+ check_elems << OpenStudio::Attribute.new('flag', "Zone Air Terminal Sensible Cooling Rate Timeseries not found for #{key_value}.")
109
+ else
110
+
111
+ clg_rate_ts = clg_rate_ts.get.values
112
+ # Put timeseries into array
113
+ clg_rate_vals = []
114
+ for i in 0..(clg_rate_ts.size - 1)
115
+ clg_rate_vals << clg_rate_ts[i]
116
+ end
117
+
118
+ # Loop through each timestep and calculate the hourly
119
+ # % reheat value.
120
+ ann_rht_hrs = 0
121
+ ann_clg_hrs = 0
122
+ ann_pcts = []
123
+ rht_rate_vals.zip(clg_rate_vals).each do |rht_w, clg_w|
124
+ # Skip hours with no cooling (in heating mode)
125
+ next if clg_w == 0
126
+ pct_overcool_rht = rht_w / (rht_w + clg_w)
127
+ ann_rht_hrs += pct_overcool_rht # implied * 1hr b/c hrly results
128
+ ann_clg_hrs += 1
129
+ ann_pcts << pct_overcool_rht.round(3)
130
+ end
131
+
132
+ # Calculate annual % reheat hours
133
+ ann_pct_reheat = ((ann_rht_hrs / ann_clg_hrs) * 100).round(1)
134
+
135
+ # Compare to limit
136
+ if ann_pct_reheat > max_pass * 100.0
137
+ 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.")
138
+ end
139
+
140
+ end
141
+
142
+ end
143
+ end
144
+ rescue StandardError => e
145
+ # brief description of ruby error
146
+ check_elems << OpenStudio::Attribute.new('flag', "Error prevented QAQC check from running (#{e}).")
147
+
148
+ # backtrace of ruby error for diagnostic use
149
+ if @error_backtrace then check_elems << OpenStudio::Attribute.new('flag', e.backtrace.join("\n").to_s) end
150
+ end
151
+
152
+ # add check_elms to new attribute
153
+ check_elem = OpenStudio::Attribute.new('check', check_elems)
154
+
155
+ return check_elem
156
+ # note: registerWarning and registerValue will be added for checks downstream using os_lib_reporting_qaqc.rb
157
+ end
158
+ end
@@ -0,0 +1,148 @@
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
+ # include any general notes about QAQC method here
38
+
39
+ # checks the number of unmet hours in the model
40
+ def check_supply_air_and_thermostat_temp_difference(category, target_standard, max_delta, name_only = false)
41
+ # G3.1.2.9 requires a 20 degree F delta between supply air temperature and zone temperature.
42
+ target_clg_delta = 20.0
43
+
44
+ # summary of the check
45
+ check_elems = OpenStudio::AttributeVector.new
46
+ check_elems << OpenStudio::Attribute.new('name', 'Supply and Zone Air Temperature')
47
+ check_elems << OpenStudio::Attribute.new('category', category)
48
+ if @utility_name.nil?
49
+ 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.")
50
+ else
51
+ 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}.")
52
+ end
53
+
54
+ # stop here if only name is requested this is used to populate display name for arguments
55
+ if name_only == true
56
+ results = []
57
+ check_elems.each do |elem|
58
+ results << elem.valueAsString
59
+ end
60
+ return results
61
+ end
62
+
63
+ # Versions of OpenStudio greater than 2.4.0 use a modified version of
64
+ # openstudio-standards with different method calls. These methods
65
+ # require a "Standard" object instead of the standard being passed into method calls.
66
+ # This Standard object is used throughout the QAQC check.
67
+ if OpenStudio::VersionString.new(OpenStudio.openStudioVersion) < OpenStudio::VersionString.new('2.4.3')
68
+ use_old_gem_code = true
69
+ else
70
+ use_old_gem_code = false
71
+ std = Standard.build(target_standard)
72
+ end
73
+
74
+ begin
75
+ # loop through thermal zones
76
+ @model.getThermalZones.sort.each do |thermal_zone|
77
+ model_clg_min = nil
78
+
79
+ # populate thermostat ranges
80
+ if thermal_zone.thermostatSetpointDualSetpoint.is_initialized
81
+
82
+ thermostat = thermal_zone.thermostatSetpointDualSetpoint.get
83
+ if thermostat.coolingSetpointTemperatureSchedule.is_initialized
84
+
85
+ clg_sch = thermostat.coolingSetpointTemperatureSchedule.get
86
+ schedule_values = nil
87
+ if clg_sch.to_ScheduleRuleset.is_initialized
88
+ if use_old_gem_code
89
+ schedule_values = clg_sch.to_ScheduleRuleset.get.annual_min_max_value
90
+ else
91
+ schedule_values = std.schedule_ruleset_annual_min_max_value(clg_sch.to_ScheduleRuleset.get)
92
+ end
93
+ elsif clg_sch.to_ScheduleConstant.is_initialized
94
+ if use_old_gem_code
95
+ schedule_values = clg_sch.to_ScheduleConstant.get.annual_min_max_value
96
+ else
97
+ schedule_values = std.schedule_constant_annual_min_max_value(clg_sch.to_ScheduleConstant.get)
98
+ end
99
+ end
100
+
101
+ unless schedule_values.nil?
102
+ model_clg_min = schedule_values['min']
103
+ end
104
+ end
105
+
106
+ else
107
+ # go to next zone if not conditioned
108
+ next
109
+
110
+ end
111
+
112
+ # flag if there is setpoint schedule can't be inspected (isn't ruleset)
113
+ if model_clg_min.nil?
114
+ check_elems << OpenStudio::Attribute.new('flag', "Can't inspect thermostat schedules for #{thermal_zone.name}")
115
+ else
116
+
117
+ # get supply air temps from thermal zone sizing
118
+ sizing_zone = thermal_zone.sizingZone
119
+ clg_supply_air_temp = sizing_zone.zoneCoolingDesignSupplyAirTemperature
120
+
121
+ # convert model values to IP
122
+ model_clg_min_ip = OpenStudio.convert(model_clg_min, 'C', 'F').get
123
+ clg_supply_air_temp_ip = OpenStudio.convert(clg_supply_air_temp, 'C', 'F').get
124
+
125
+ # check supply air against zone temperature (only check against min setpoint, assume max is night setback)
126
+ if model_clg_min_ip - clg_supply_air_temp_ip > target_clg_delta + max_delta
127
+ 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)")
128
+ elsif model_clg_min_ip - clg_supply_air_temp_ip < target_clg_delta - max_delta
129
+ 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)")
130
+ end
131
+
132
+ end
133
+ end
134
+ rescue StandardError => e
135
+ # brief description of ruby error
136
+ check_elems << OpenStudio::Attribute.new('flag', "Error prevented QAQC check from running (#{e}).")
137
+
138
+ # backtrace of ruby error for diagnostic use
139
+ if @error_backtrace then check_elems << OpenStudio::Attribute.new('flag', e.backtrace.join("\n").to_s) end
140
+ end
141
+
142
+ # add check_elms to new attribute
143
+ check_elem = OpenStudio::Attribute.new('check', check_elems)
144
+
145
+ return check_elem
146
+ # note: registerWarning and registerValue will be added for checks downstream using os_lib_reporting_qaqc.rb
147
+ end
148
+ end
@@ -0,0 +1,132 @@
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
+ # include any general notes about QAQC method here
38
+
39
+ # checks the number of unmet hours in the model
40
+ def check_weather_files(category, options, name_only = false)
41
+ # summary of the check
42
+ check_elems = OpenStudio::AttributeVector.new
43
+ check_elems << OpenStudio::Attribute.new('name', 'Weather Files')
44
+ check_elems << OpenStudio::Attribute.new('category', category)
45
+ check_elems << OpenStudio::Attribute.new('description', "Check weather file, design days, and climate zone against #{@utility_name} list of allowable options.")
46
+
47
+ # stop here if only name is requested this is used to populate display name for arguments
48
+ if name_only == true
49
+ results = []
50
+ check_elems.each do |elem|
51
+ results << elem.valueAsString
52
+ end
53
+ return results
54
+ end
55
+
56
+ begin
57
+ # get weather file
58
+ model_epw = nil
59
+ if @model.getWeatherFile.url.is_initialized
60
+ raw_epw = @model.getWeatherFile.url.get
61
+ end_path_index = raw_epw.rindex('/')
62
+ model_epw = raw_epw.slice!(end_path_index + 1, raw_epw.length) # everything right of last forward slash
63
+ end
64
+
65
+ # check design days (model must have one or more of the required summer and winter design days)
66
+ # get design days names from model
67
+ model_summer_dd_names = []
68
+ model_winter_dd_names = []
69
+ @model.getDesignDays.each do |design_day|
70
+ if design_day.dayType == 'SummerDesignDay'
71
+ model_summer_dd_names << design_day.name.to_s
72
+ elsif design_day.dayType == 'WinterDesignDay'
73
+ model_winter_dd_names << design_day.name.to_s
74
+ else
75
+ puts "unexpected day type of #{design_day.dayType} wont' be included in check"
76
+ end
77
+ end
78
+
79
+ # find matching weather file from options, as well as design days and climate zone
80
+ if options.key?(model_epw)
81
+ required_summer_dd = options[model_epw]['summer']
82
+ required_winter_dd = options[model_epw]['winter']
83
+ valid_climate_zones = [options[model_epw]['climate_zone']]
84
+
85
+ # check for intersection betwen model valid design days
86
+ summer_intersection = (required_summer_dd & model_summer_dd_names)
87
+ winter_intersection = (required_winter_dd & model_winter_dd_names)
88
+ if summer_intersection.empty? && !required_summer_dd.empty?
89
+ check_elems << OpenStudio::Attribute.new('flag', "Didn't find any of the expected summer design days for #{model_epw}")
90
+ end
91
+ if winter_intersection.empty? && !required_winter_dd.empty?
92
+ check_elems << OpenStudio::Attribute.new('flag', "Didn't find any of the expected winter design days for #{model_epw}")
93
+ end
94
+
95
+ else
96
+ check_elems << OpenStudio::Attribute.new('flag', "#{model_epw} is not a an expected weather file.")
97
+ check_elems << OpenStudio::Attribute.new('flag', "Model doesn't have expected epw file, as a result can't validate design days.")
98
+ valid_climate_zones = []
99
+ options.each do |lookup_epw, value|
100
+ valid_climate_zones << value['climate_zone']
101
+ end
102
+ end
103
+
104
+ # get ashrae climate zone from model
105
+ model_climate_zone = nil
106
+ climateZones = @model.getClimateZones
107
+ climateZones.climateZones.each do |climateZone|
108
+ if climateZone.institution == 'ASHRAE'
109
+ model_climate_zone = climateZone.value
110
+ next
111
+ end
112
+ end
113
+ if model_climate_zone == ''
114
+ 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(',')}.")
115
+ elsif !valid_climate_zones.include?(model_climate_zone)
116
+ 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(',')}.")
117
+ end
118
+ rescue StandardError => e
119
+ # brief description of ruby error
120
+ check_elems << OpenStudio::Attribute.new('flag', "Error prevented QAQC check from running (#{e}).")
121
+
122
+ # backtrace of ruby error for diagnostic use
123
+ if @error_backtrace then check_elems << OpenStudio::Attribute.new('flag', e.backtrace.join("\n").to_s) end
124
+ end
125
+
126
+ # add check_elms to new attribute
127
+ check_elem = OpenStudio::Attribute.new('check', check_elems)
128
+
129
+ return check_elem
130
+ # note: registerWarning and registerValue will be added for checks downstream using os_lib_reporting_qaqc.rb
131
+ end
132
+ end
@@ -0,0 +1,311 @@
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
+ # Maps the DEER vintages to year ranges
37
+ module DEERVintages
38
+ # Building type abbreviation to long name map
39
+ def building_type_to_long
40
+ return {
41
+ 'Asm' => 'Assembly',
42
+ 'DMo' => 'Residential Mobile Home',
43
+ 'ECC' => 'Education - Community College',
44
+ 'EPr' => 'Education - Primary School',
45
+ 'ERC' => 'Education - Relocatable Classroom',
46
+ 'ESe' => 'Education - Secondary School',
47
+ 'EUn' => 'Education - University',
48
+ 'GHs' => 'Greenhouse',
49
+ 'Gro' => 'Grocery',
50
+ 'Hsp' => 'Health/Medical - Hospital',
51
+ 'Htl' => 'Lodging - Hotel',
52
+ 'MBT' => 'Manufacturing Biotech',
53
+ 'MFm' => 'Residential Multi-family',
54
+ 'MLI' => 'Manufacturing Light Industrial',
55
+ 'Mtl' => 'Lodging - Motel',
56
+ 'Nrs' => 'Health/Medical - Nursing Home',
57
+ 'OfL' => 'Office - Large',
58
+ 'OfS' => 'Office - Small',
59
+ 'RFF' => 'Restaurant - Fast-Food',
60
+ 'RSD' => 'Restaurant - Sit-Down',
61
+ 'Rt3' => 'Retail - Multistory Large',
62
+ 'RtL' => 'Retail - Single-Story Large',
63
+ 'RtS' => 'Retail - Small',
64
+ 'SCn' => 'Storage - Conditioned',
65
+ 'SFm' => 'Residential Single Family',
66
+ 'SUn' => 'Storage - Unconditioned',
67
+ 'WRf' => 'Warehouse - Refrigerated'
68
+ }
69
+ end
70
+
71
+ # HVAC type abbreviation to long name map
72
+ def hvac_sys_to_long
73
+ return {
74
+ 'DXGF' => 'Split or Packaged DX Unit with Gas Furnace',
75
+ 'DXEH' => 'Split or Packaged DX Unit with Electric Heat',
76
+ 'DXHP' => 'Split or Packaged DX Unit with Heat Pump',
77
+ 'WLHP' => 'Water Loop Heat Pump',
78
+ 'NCEH' => 'No Cooling with Electric Heat',
79
+ 'NCGF' => 'No Cooling with Gas Furnace',
80
+ 'PVVG' => 'Packaged VAV System with Gas Boiler',
81
+ 'PVVE' => 'Packaged VAV System with Electric Heat',
82
+ 'SVVG' => 'Built-Up VAV System with Gas Boiler',
83
+ 'SVVE' => 'Built-Up VAV System with Electric Reheat',
84
+ 'Unc' => 'No HVAC (Unconditioned)',
85
+ 'PTAC' => 'Packaged Terminal Air Conditioner',
86
+ 'PTHP' => 'Packaged Terminal Heat Pump',
87
+ 'FPFC' => 'Four Pipe Fan Coil',
88
+ 'DDCT' => 'Dual Duct System',
89
+ 'EVAP' => 'Evaporative Cooling with Separate Gas Furnace'
90
+ }
91
+ end
92
+
93
+ # Valid building type/hvac type combos
94
+ def building_type_to_hvac_systems
95
+ return {
96
+ 'Asm' => [
97
+ 'DXEH',
98
+ 'DXGF',
99
+ 'DXHP',
100
+ 'NCEH',
101
+ 'NCGF'
102
+ ],
103
+ 'ECC' => [
104
+ 'DXEH',
105
+ 'DXGF',
106
+ 'DXHP',
107
+ 'NCEH',
108
+ 'NCGF',
109
+ 'PVVE',
110
+ 'PVVG',
111
+ 'SVVE',
112
+ 'SVVG',
113
+ 'WLHP'
114
+ ],
115
+ 'EPr' => [
116
+ 'DXEH',
117
+ 'DXGF',
118
+ 'DXHP',
119
+ 'NCEH',
120
+ 'NCGF',
121
+ 'WLHP'
122
+ ],
123
+ 'ERC' => [
124
+ 'DXEH',
125
+ 'DXGF',
126
+ 'DXHP',
127
+ 'NCEH',
128
+ 'NCGF'
129
+ ],
130
+ 'ESe' => [
131
+ 'DXEH',
132
+ 'DXGF',
133
+ 'DXHP',
134
+ 'NCEH',
135
+ 'NCGF',
136
+ 'PVVE',
137
+ 'PVVG',
138
+ 'SVVE',
139
+ 'SVVG',
140
+ 'WLHP'
141
+ ],
142
+ 'EUn' => [
143
+ 'DXEH',
144
+ 'DXGF',
145
+ 'DXHP',
146
+ 'NCEH',
147
+ 'NCGF',
148
+ 'PVVE',
149
+ 'PVVG',
150
+ 'SVVE',
151
+ 'SVVG'
152
+ ],
153
+ 'Gro' => [
154
+ 'DXEH',
155
+ 'DXGF',
156
+ 'DXHP',
157
+ 'NCEH',
158
+ 'NCGF'
159
+ ],
160
+ 'Hsp' => [
161
+ 'DXEH',
162
+ 'DXGF',
163
+ 'DXHP',
164
+ 'NCEH',
165
+ 'NCGF',
166
+ 'PVVE',
167
+ 'PVVG',
168
+ 'SVVE',
169
+ 'SVVG'
170
+ ],
171
+ 'Nrs' => [
172
+ 'DXEH',
173
+ 'DXGF',
174
+ 'DXHP',
175
+ 'FPFC',
176
+ 'NCEH',
177
+ 'NCGF',
178
+ 'PVVE',
179
+ 'PVVG',
180
+ 'SVVE',
181
+ 'SVVG'
182
+ ],
183
+ 'Htl' => [
184
+ 'DXEH',
185
+ 'DXGF',
186
+ 'DXHP',
187
+ 'NCEH',
188
+ 'NCGF',
189
+ 'PVVE',
190
+ 'PVVG',
191
+ 'SVVE',
192
+ 'SVVG',
193
+ 'WLHP'
194
+ ],
195
+ 'Mtl' => [
196
+ 'DXEH',
197
+ 'DXGF',
198
+ 'DXHP',
199
+ 'NCEH',
200
+ 'NCGF'
201
+ ],
202
+ 'MBT' => [
203
+ 'DXEH',
204
+ 'DXGF',
205
+ 'DXHP',
206
+ 'NCEH',
207
+ 'NCGF',
208
+ 'PVVE',
209
+ 'PVVG',
210
+ 'SVVE',
211
+ 'SVVG',
212
+ 'WLHP'
213
+ ],
214
+ 'MLI' => [
215
+ 'DXEH',
216
+ 'DXGF',
217
+ 'DXHP',
218
+ 'NCEH',
219
+ 'NCGF'
220
+ ],
221
+ 'OfL' => [
222
+ 'DXEH',
223
+ 'DXGF',
224
+ 'DXHP',
225
+ 'NCEH',
226
+ 'NCGF',
227
+ 'PVVE',
228
+ 'PVVG',
229
+ 'SVVE',
230
+ 'SVVG',
231
+ 'WLHP'
232
+ ],
233
+ 'OfS' => [
234
+ 'DXEH',
235
+ 'DXGF',
236
+ 'DXHP',
237
+ 'NCEH',
238
+ 'NCGF',
239
+ 'PVVE',
240
+ 'PVVG',
241
+ 'SVVE',
242
+ 'SVVG',
243
+ 'WLHP'
244
+ ],
245
+ 'RFF' => [
246
+ 'DXEH',
247
+ 'DXGF',
248
+ 'DXHP',
249
+ 'NCEH',
250
+ 'NCGF'
251
+ ],
252
+ 'RSD' => [
253
+ 'DXEH',
254
+ 'DXGF',
255
+ 'DXHP',
256
+ 'NCEH',
257
+ 'NCGF'
258
+ ],
259
+ 'Rt3' => [
260
+ 'DXEH',
261
+ 'DXGF',
262
+ 'DXHP',
263
+ 'NCEH',
264
+ 'NCGF',
265
+ 'PVVE',
266
+ 'PVVG',
267
+ 'SVVE',
268
+ 'SVVG',
269
+ 'WLHP'
270
+ ],
271
+ 'RtL' => [
272
+ 'DXEH',
273
+ 'DXGF',
274
+ 'DXHP',
275
+ 'NCEH',
276
+ 'NCGF'
277
+ ],
278
+ 'RtS' => [
279
+ 'DXEH',
280
+ 'DXGF',
281
+ 'DXHP',
282
+ 'NCEH',
283
+ 'NCGF'
284
+ ],
285
+ 'SCn' => [
286
+ 'DXEH',
287
+ 'DXGF',
288
+ 'DXHP',
289
+ 'NCEH',
290
+ 'NCGF'
291
+ ],
292
+ 'SUn' => ['Unc'],
293
+ 'WRf' => ['DXGF']
294
+ }
295
+ end
296
+
297
+ # Age range to DEER template
298
+ def template_to_age_range
299
+ return {
300
+ 'DEER Pre-1975' => 'Before 1978',
301
+ 'DEER 1985' => '1978-1992',
302
+ 'DEER 1996' => '1993-2001',
303
+ 'DEER 2003' => '2002-2005',
304
+ 'DEER 2007' => '2006-2009',
305
+ 'DEER 2011' => '2010-2013',
306
+ 'DEER 2014' => '2014',
307
+ 'DEER 2015' => '2015-2016',
308
+ 'DEER 2017' => '2017 or Later'
309
+ }
310
+ end
311
+ end