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,399 +1,399 @@
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_HelperMethods
37
- # populate choice argument from model objects
38
- def self.populateChoiceArgFromModelObjects(model, modelObject_args_hash, includeBuilding = nil)
39
- # populate choice argument for constructions that are applied to surfaces in the model
40
- modelObject_handles = OpenStudio::StringVector.new
41
- modelObject_display_names = OpenStudio::StringVector.new
42
-
43
- # looping through sorted hash of constructions
44
- modelObject_args_hash.sort.map do |key, value|
45
- modelObject_handles << value.handle.to_s
46
- modelObject_display_names << key
47
- end
48
-
49
- unless includeBuilding.nil?
50
- # add building to string vector with space type
51
- building = model.getBuilding
52
- modelObject_handles << building.handle.to_s
53
- modelObject_display_names << includeBuilding
54
- end
55
-
56
- result = { 'modelObject_handles' => modelObject_handles, 'modelObject_display_names' => modelObject_display_names }
57
- return result
58
- end
59
-
60
- # create variables in run from user arguments
61
- def self.createRunVariables(runner, model, user_arguments, arguments)
62
- result = {}
63
-
64
- error = false
65
- # use the built-in error checking
66
- unless runner.validateUserArguments(arguments, user_arguments)
67
- error = true
68
- runner.registerError('Invalid argument values.')
69
- end
70
-
71
- user_arguments.each do |argument|
72
- # get argument info
73
- arg = user_arguments[argument]
74
- arg_type = arg.print.lines($/)[1]
75
-
76
- # create argument variable
77
- if arg_type.include? 'Double, Required'
78
- eval("result[\"#{arg.name}\"] = runner.getDoubleArgumentValue(\"#{arg.name}\", user_arguments)")
79
- elsif arg_type.include? 'Integer, Required'
80
- eval("result[\"#{arg.name}\"] = runner.getIntegerArgumentValue(\"#{arg.name}\", user_arguments)")
81
- elsif arg_type.include? 'String, Required'
82
- eval("result[\"#{arg.name}\"] = runner.getStringArgumentValue(\"#{arg.name}\", user_arguments)")
83
- elsif arg_type.include? 'Boolean, Required'
84
- eval("result[\"#{arg.name}\"] = runner.getBoolArgumentValue(\"#{arg.name}\", user_arguments)")
85
- elsif arg_type.include? 'Choice, Required'
86
- eval("result[\"#{arg.name}\"] = runner.getStringArgumentValue(\"#{arg.name}\", user_arguments)")
87
- else
88
- puts 'not setup to handle all argument types yet, or any optional arguments'
89
- end
90
- end
91
-
92
- if error
93
- return false
94
- else
95
- return result
96
- end
97
- end
98
-
99
- # check choice argument made from model objects
100
- def self.checkChoiceArgFromModelObjects(object, variableName, to_ObjectType, runner, user_arguments)
101
- apply_to_building = false
102
- modelObject = nil
103
- if object.empty?
104
- handle = runner.getStringArgumentValue(variableName, user_arguments)
105
- if handle.empty?
106
- runner.registerError("No #{variableName} was chosen.") # this logic makes this not work on an optional model object argument
107
- else
108
- runner.registerError("The selected #{variableName} with handle '#{handle}' was not found in the model. It may have been removed by another measure.")
109
- end
110
- return false
111
- else
112
- if !eval("object.get.#{to_ObjectType}").empty?
113
- modelObject = eval("object.get.#{to_ObjectType}").get
114
- elsif !object.get.to_Building.empty?
115
- apply_to_building = true
116
- else
117
- runner.registerError("Script Error - argument not showing up as #{variableName}.")
118
- return false
119
- end
120
- end
121
-
122
- result = { 'modelObject' => modelObject, 'apply_to_building' => apply_to_building }
123
- end
124
-
125
- # check choice argument made from model objects
126
- def self.checkOptionalChoiceArgFromModelObjects(object, variableName, to_ObjectType, runner, user_arguments)
127
- apply_to_building = false
128
- modelObject = nil
129
- if object.empty?
130
- handle = runner.getOptionalStringArgumentValue(variableName, user_arguments)
131
- if handle.empty?
132
- # do nothing, this is a valid option
133
- puts 'hello'
134
- modelObject = nil
135
- apply_to_building = false
136
- else
137
- runner.registerError("The selected #{variableName} with handle '#{handle}' was not found in the model. It may have been removed by another measure.")
138
- return false
139
- end
140
- else
141
- if !eval("object.get.#{to_ObjectType}").empty?
142
- modelObject = eval("object.get.#{to_ObjectType}").get
143
- elsif !object.get.to_Building.empty?
144
- apply_to_building = true
145
- else
146
- runner.registerError("Script Error - argument not showing up as #{variableName}.")
147
- return false
148
- end
149
- end
150
-
151
- result = { 'modelObject' => modelObject, 'apply_to_building' => apply_to_building }
152
- end
153
-
154
- # check value of double arguments
155
- def self.checkDoubleAndIntegerArguments(runner, user_arguments, arg_check_hash)
156
- error = false
157
-
158
- # get hash values
159
- min = arg_check_hash['min']
160
- max = arg_check_hash['max']
161
- min_eq_bool = arg_check_hash['min_eq_bool']
162
- max_eq_bool = arg_check_hash['max_eq_bool']
163
-
164
- arg_check_hash['arg_array'].each do |argument|
165
- argument = user_arguments[argument]
166
-
167
- # get arg values
168
- arg_value = nil
169
- if argument.hasValue
170
- arg_value = argument.valueDisplayName.to_f # instead of valueAsDouble so it allows integer arguments as well
171
- elsif argument.hasDefaultValue
172
- arg_value = argument.defaultValueDisplayName.to_f
173
- end
174
- arg_display = argument.displayName
175
-
176
- unless min.nil?
177
- if min_eq_bool
178
- if arg_value < min
179
- runner.registerError("Please enter value greater than or equal to #{min} for #{arg_display}.") # add in argument display name
180
- error = true
181
- end
182
- else
183
- if arg_value <= min
184
- runner.registerError("Please enter value greater than #{min} for #{arg_display}.") # add in argument display name
185
- error = true
186
- end
187
- end
188
- end
189
- unless max.nil?
190
- if max_eq_bool
191
- if arg_value > max
192
- runner.registerError("Please enter value less than or equal to #{max} for #{arg_display}.") # add in argument display name
193
- error = true
194
- end
195
- else
196
- if arg_value >= max
197
- runner.registerError("Please enter value less than #{max} for #{arg_display}.") # add in argument display name
198
- error = true
199
- end
200
- end
201
- end
202
- end
203
-
204
- # check for any errors
205
- if error
206
- return false
207
- else
208
- return true
209
- end
210
- end
211
-
212
- # open channel to log info/warning/error messages
213
- def self.setup_log_msgs(runner, debug = false)
214
- # Open a channel to log info/warning/error messages
215
- @msg_log = OpenStudio::StringStreamLogSink.new
216
- if debug
217
- @msg_log.setLogLevel(OpenStudio::Debug)
218
- else
219
- @msg_log.setLogLevel(OpenStudio::Info)
220
- end
221
- @start_time = Time.new
222
- @runner = runner
223
- end
224
-
225
- # Get all the log messages and put into output
226
- # for users to see.
227
- def self.log_msgs
228
- @msg_log.logMessages.each do |msg|
229
- # DLM: you can filter on log channel here for now
230
- if /openstudio.*/.match(msg.logChannel) # /openstudio\.model\..*/
231
- # Skip certain messages that are irrelevant/misleading
232
- next if msg.logMessage.include?('Skipping layer') || # Annoying/bogus "Skipping layer" warnings
233
- msg.logChannel.include?('runmanager') || # RunManager messages
234
- msg.logChannel.include?('setFileExtension') || # .ddy extension unexpected
235
- msg.logChannel.include?('Translator') || # Forward translator and geometry translator
236
- msg.logMessage.include?('UseWeatherFile') # 'UseWeatherFile' is not yet a supported option for YearDescription
237
-
238
- # Report the message in the correct way
239
- if msg.logLevel == OpenStudio::Info
240
- @runner.registerInfo(msg.logMessage)
241
- elsif msg.logLevel == OpenStudio::Warn
242
- @runner.registerWarning("[#{msg.logChannel}] #{msg.logMessage}")
243
- elsif msg.logLevel == OpenStudio::Error
244
- @runner.registerError("[#{msg.logChannel}] #{msg.logMessage}")
245
- elsif msg.logLevel == OpenStudio::Debug && @debug
246
- @runner.registerInfo("DEBUG - #{msg.logMessage}")
247
- end
248
- end
249
- end
250
- @runner.registerInfo("Total Time = #{(Time.new - @start_time).round}sec.")
251
- end
252
-
253
- def self.check_upstream_measure_for_arg(runner, arg_name)
254
- # 2.x methods (currently setup for measure display name but snake_case arg names)
255
- arg_name_value = {}
256
- runner.workflow.workflowSteps.each do |step|
257
- if step.to_MeasureStep.is_initialized
258
- measure_step = step.to_MeasureStep.get
259
-
260
- measure_name = measure_step.measureDirName
261
- if measure_step.name.is_initialized
262
- measure_name = measure_step.name.get # this is instance name in PAT
263
- end
264
- if measure_step.result.is_initialized
265
- result = measure_step.result.get
266
- result.stepValues.each do |arg|
267
- name = arg.name
268
- value = arg.valueAsVariant.to_s
269
- if name == arg_name
270
- arg_name_value[:value] = value
271
- arg_name_value[:measure_name] = measure_name
272
- return arg_name_value # stop after find first one
273
- end
274
- end
275
- else
276
- # puts "No result for #{measure_name}"
277
- end
278
- else
279
- # puts "This step is not a measure"
280
- end
281
- end
282
-
283
- return arg_name_value
284
- end
285
-
286
- # populate choice argument from model objects. areaType should be string like "floorArea" or "exteriorArea"
287
- # note: it seems like spaceType.floorArea does account for multiplier, so I don't have to call this method unless I have a custom collection of spaces.
288
- def self.getAreaOfSpacesInArray(model, spaceArray, areaType = 'floorArea')
289
- # find selected floor spaces, make array and get floor area.
290
- totalArea = 0
291
- spaceAreaHash = {}
292
- spaceArray.each do |space|
293
- spaceArea = eval("space.#{areaType}*space.multiplier")
294
- spaceAreaHash[space] = spaceArea
295
- totalArea += spaceArea
296
- end
297
-
298
- result = { 'totalArea' => totalArea, 'spaceAreaHash' => spaceAreaHash }
299
- return result
300
- end
301
-
302
- # runs conversion and neat string, and returns value with units in string, optionally before or after the value
303
- def self.neatConvertWithUnitDisplay(double, fromString, toString, digits, unitBefore = false, unitAfter = true, space = true, parentheses = true)
304
- # convert units
305
- doubleConverted = OpenStudio.convert(double, fromString, toString)
306
- if !doubleConverted.nil?
307
- doubleConverted = doubleConverted.get
308
- else
309
- puts "Couldn't convert values, check string choices passed in. From: #{fromString}, To: #{toString}"
310
- end
311
-
312
- # get neat version of converted
313
- neatConverted = OpenStudio.toNeatString(doubleConverted, digits, true)
314
-
315
- # add prefix
316
- if unitBefore
317
- if space == true && parentheses == true
318
- prefix = "(#{toString}) "
319
- elsif space == true && parentheses == false
320
- prefix = "(#{toString})"
321
- elsif space == false && parentheses == true
322
- prefix = "#{toString} "
323
- else
324
- prefix = toString.to_s
325
- end
326
- else
327
- prefix = ''
328
- end
329
-
330
- # add suffix
331
- if unitAfter
332
- if space == true && parentheses == true
333
- suffix = " (#{toString})"
334
- elsif space == true && parentheses == false
335
- suffix = "(#{toString})"
336
- elsif space == false && parentheses == true
337
- suffix = " #{toString}"
338
- else
339
- suffix = toString.to_s
340
- end
341
- else
342
- suffix = ''
343
- end
344
-
345
- finalString = "#{prefix}#{neatConverted}#{suffix}"
346
-
347
- return finalString
348
- end
349
-
350
- # helper that loops through lifecycle costs getting total costs under "Construction" and add to counter if occurs during year 0
351
- def self.getTotalCostForObjects(objectArray, category = 'Construction', onlyYearFromStartZero = true)
352
- counter = 0
353
- objectArray.each do |object|
354
- object_LCCs = object.lifeCycleCosts
355
- object_LCCs.each do |object_LCC|
356
- if object_LCC.category == category
357
- if onlyYearFromStartZero == false || object_LCC.yearsFromStart == 0
358
- counter += object_LCC.totalCost
359
- end
360
- end
361
- end
362
- end
363
-
364
- return counter
365
- end
366
-
367
- # helper that loops through lifecycle costs getting total costs under "Construction" and add to counter if occurs during year 0
368
- def self.getSpaceTypeStandardsInformation(spaceTypeArray)
369
- # hash of space types
370
- spaceTypeStandardsInfoHash = {}
371
-
372
- spaceTypeArray.each do |spaceType|
373
- # get standards building
374
- if !spaceType.standardsBuildingType.empty?
375
- standardsBuilding = spaceType.standardsBuildingType.get
376
- else
377
- standardsBuilding = nil
378
- end
379
-
380
- # get standards space type
381
- if !spaceType.standardsSpaceType.empty?
382
- standardsSpaceType = spaceType.standardsSpaceType.get
383
- else
384
- standardsSpaceType = nil
385
- end
386
-
387
- # populate hash
388
- spaceTypeStandardsInfoHash[spaceType] = [standardsBuilding, standardsSpaceType]
389
- end
390
-
391
- return spaceTypeStandardsInfoHash
392
- end
393
-
394
- # OpenStudio has built in toNeatString method
395
- # OpenStudio::toNeatString(double,2,true)# double,decimals, show commas
396
-
397
- # OpenStudio has built in helper for unit conversion. That can be done using OpenStudio::convert() as shown below.
398
- # OpenStudio::convert(double,"from unit string","to unit string").get
399
- 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_HelperMethods
37
+ # populate choice argument from model objects
38
+ def self.populateChoiceArgFromModelObjects(model, modelObject_args_hash, includeBuilding = nil)
39
+ # populate choice argument for constructions that are applied to surfaces in the model
40
+ modelObject_handles = OpenStudio::StringVector.new
41
+ modelObject_display_names = OpenStudio::StringVector.new
42
+
43
+ # looping through sorted hash of constructions
44
+ modelObject_args_hash.sort.map do |key, value|
45
+ modelObject_handles << value.handle.to_s
46
+ modelObject_display_names << key
47
+ end
48
+
49
+ unless includeBuilding.nil?
50
+ # add building to string vector with space type
51
+ building = model.getBuilding
52
+ modelObject_handles << building.handle.to_s
53
+ modelObject_display_names << includeBuilding
54
+ end
55
+
56
+ result = { 'modelObject_handles' => modelObject_handles, 'modelObject_display_names' => modelObject_display_names }
57
+ return result
58
+ end
59
+
60
+ # create variables in run from user arguments
61
+ def self.createRunVariables(runner, model, user_arguments, arguments)
62
+ result = {}
63
+
64
+ error = false
65
+ # use the built-in error checking
66
+ unless runner.validateUserArguments(arguments, user_arguments)
67
+ error = true
68
+ runner.registerError('Invalid argument values.')
69
+ end
70
+
71
+ user_arguments.each do |argument|
72
+ # get argument info
73
+ arg = user_arguments[argument]
74
+ arg_type = arg.print.lines($/)[1]
75
+
76
+ # create argument variable
77
+ if arg_type.include? 'Double, Required'
78
+ eval("result[\"#{arg.name}\"] = runner.getDoubleArgumentValue(\"#{arg.name}\", user_arguments)")
79
+ elsif arg_type.include? 'Integer, Required'
80
+ eval("result[\"#{arg.name}\"] = runner.getIntegerArgumentValue(\"#{arg.name}\", user_arguments)")
81
+ elsif arg_type.include? 'String, Required'
82
+ eval("result[\"#{arg.name}\"] = runner.getStringArgumentValue(\"#{arg.name}\", user_arguments)")
83
+ elsif arg_type.include? 'Boolean, Required'
84
+ eval("result[\"#{arg.name}\"] = runner.getBoolArgumentValue(\"#{arg.name}\", user_arguments)")
85
+ elsif arg_type.include? 'Choice, Required'
86
+ eval("result[\"#{arg.name}\"] = runner.getStringArgumentValue(\"#{arg.name}\", user_arguments)")
87
+ else
88
+ puts 'not setup to handle all argument types yet, or any optional arguments'
89
+ end
90
+ end
91
+
92
+ if error
93
+ return false
94
+ else
95
+ return result
96
+ end
97
+ end
98
+
99
+ # check choice argument made from model objects
100
+ def self.checkChoiceArgFromModelObjects(object, variableName, to_ObjectType, runner, user_arguments)
101
+ apply_to_building = false
102
+ modelObject = nil
103
+ if object.empty?
104
+ handle = runner.getStringArgumentValue(variableName, user_arguments)
105
+ if handle.empty?
106
+ runner.registerError("No #{variableName} was chosen.") # this logic makes this not work on an optional model object argument
107
+ else
108
+ runner.registerError("The selected #{variableName} with handle '#{handle}' was not found in the model. It may have been removed by another measure.")
109
+ end
110
+ return false
111
+ else
112
+ if !eval("object.get.#{to_ObjectType}").empty?
113
+ modelObject = eval("object.get.#{to_ObjectType}").get
114
+ elsif !object.get.to_Building.empty?
115
+ apply_to_building = true
116
+ else
117
+ runner.registerError("Script Error - argument not showing up as #{variableName}.")
118
+ return false
119
+ end
120
+ end
121
+
122
+ result = { 'modelObject' => modelObject, 'apply_to_building' => apply_to_building }
123
+ end
124
+
125
+ # check choice argument made from model objects
126
+ def self.checkOptionalChoiceArgFromModelObjects(object, variableName, to_ObjectType, runner, user_arguments)
127
+ apply_to_building = false
128
+ modelObject = nil
129
+ if object.empty?
130
+ handle = runner.getOptionalStringArgumentValue(variableName, user_arguments)
131
+ if handle.empty?
132
+ # do nothing, this is a valid option
133
+ puts 'hello'
134
+ modelObject = nil
135
+ apply_to_building = false
136
+ else
137
+ runner.registerError("The selected #{variableName} with handle '#{handle}' was not found in the model. It may have been removed by another measure.")
138
+ return false
139
+ end
140
+ else
141
+ if !eval("object.get.#{to_ObjectType}").empty?
142
+ modelObject = eval("object.get.#{to_ObjectType}").get
143
+ elsif !object.get.to_Building.empty?
144
+ apply_to_building = true
145
+ else
146
+ runner.registerError("Script Error - argument not showing up as #{variableName}.")
147
+ return false
148
+ end
149
+ end
150
+
151
+ result = { 'modelObject' => modelObject, 'apply_to_building' => apply_to_building }
152
+ end
153
+
154
+ # check value of double arguments
155
+ def self.checkDoubleAndIntegerArguments(runner, user_arguments, arg_check_hash)
156
+ error = false
157
+
158
+ # get hash values
159
+ min = arg_check_hash['min']
160
+ max = arg_check_hash['max']
161
+ min_eq_bool = arg_check_hash['min_eq_bool']
162
+ max_eq_bool = arg_check_hash['max_eq_bool']
163
+
164
+ arg_check_hash['arg_array'].each do |argument|
165
+ argument = user_arguments[argument]
166
+
167
+ # get arg values
168
+ arg_value = nil
169
+ if argument.hasValue
170
+ arg_value = argument.valueDisplayName.to_f # instead of valueAsDouble so it allows integer arguments as well
171
+ elsif argument.hasDefaultValue
172
+ arg_value = argument.defaultValueDisplayName.to_f
173
+ end
174
+ arg_display = argument.displayName
175
+
176
+ unless min.nil?
177
+ if min_eq_bool
178
+ if arg_value < min
179
+ runner.registerError("Please enter value greater than or equal to #{min} for #{arg_display}.") # add in argument display name
180
+ error = true
181
+ end
182
+ else
183
+ if arg_value <= min
184
+ runner.registerError("Please enter value greater than #{min} for #{arg_display}.") # add in argument display name
185
+ error = true
186
+ end
187
+ end
188
+ end
189
+ unless max.nil?
190
+ if max_eq_bool
191
+ if arg_value > max
192
+ runner.registerError("Please enter value less than or equal to #{max} for #{arg_display}.") # add in argument display name
193
+ error = true
194
+ end
195
+ else
196
+ if arg_value >= max
197
+ runner.registerError("Please enter value less than #{max} for #{arg_display}.") # add in argument display name
198
+ error = true
199
+ end
200
+ end
201
+ end
202
+ end
203
+
204
+ # check for any errors
205
+ if error
206
+ return false
207
+ else
208
+ return true
209
+ end
210
+ end
211
+
212
+ # open channel to log info/warning/error messages
213
+ def self.setup_log_msgs(runner, debug = false)
214
+ # Open a channel to log info/warning/error messages
215
+ @msg_log = OpenStudio::StringStreamLogSink.new
216
+ if debug
217
+ @msg_log.setLogLevel(OpenStudio::Debug)
218
+ else
219
+ @msg_log.setLogLevel(OpenStudio::Info)
220
+ end
221
+ @start_time = Time.new
222
+ @runner = runner
223
+ end
224
+
225
+ # Get all the log messages and put into output
226
+ # for users to see.
227
+ def self.log_msgs
228
+ @msg_log.logMessages.each do |msg|
229
+ # DLM: you can filter on log channel here for now
230
+ if /openstudio.*/.match(msg.logChannel) # /openstudio\.model\..*/
231
+ # Skip certain messages that are irrelevant/misleading
232
+ next if msg.logMessage.include?('Skipping layer') || # Annoying/bogus "Skipping layer" warnings
233
+ msg.logChannel.include?('runmanager') || # RunManager messages
234
+ msg.logChannel.include?('setFileExtension') || # .ddy extension unexpected
235
+ msg.logChannel.include?('Translator') || # Forward translator and geometry translator
236
+ msg.logMessage.include?('UseWeatherFile') # 'UseWeatherFile' is not yet a supported option for YearDescription
237
+
238
+ # Report the message in the correct way
239
+ if msg.logLevel == OpenStudio::Info
240
+ @runner.registerInfo(msg.logMessage)
241
+ elsif msg.logLevel == OpenStudio::Warn
242
+ @runner.registerWarning("[#{msg.logChannel}] #{msg.logMessage}")
243
+ elsif msg.logLevel == OpenStudio::Error
244
+ @runner.registerError("[#{msg.logChannel}] #{msg.logMessage}")
245
+ elsif msg.logLevel == OpenStudio::Debug && @debug
246
+ @runner.registerInfo("DEBUG - #{msg.logMessage}")
247
+ end
248
+ end
249
+ end
250
+ @runner.registerInfo("Total Time = #{(Time.new - @start_time).round}sec.")
251
+ end
252
+
253
+ def self.check_upstream_measure_for_arg(runner, arg_name)
254
+ # 2.x methods (currently setup for measure display name but snake_case arg names)
255
+ arg_name_value = {}
256
+ runner.workflow.workflowSteps.each do |step|
257
+ if step.to_MeasureStep.is_initialized
258
+ measure_step = step.to_MeasureStep.get
259
+
260
+ measure_name = measure_step.measureDirName
261
+ if measure_step.name.is_initialized
262
+ measure_name = measure_step.name.get # this is instance name in PAT
263
+ end
264
+ if measure_step.result.is_initialized
265
+ result = measure_step.result.get
266
+ result.stepValues.each do |arg|
267
+ name = arg.name
268
+ value = arg.valueAsVariant.to_s
269
+ if name == arg_name
270
+ arg_name_value[:value] = value
271
+ arg_name_value[:measure_name] = measure_name
272
+ return arg_name_value # stop after find first one
273
+ end
274
+ end
275
+ else
276
+ # puts "No result for #{measure_name}"
277
+ end
278
+ else
279
+ # puts "This step is not a measure"
280
+ end
281
+ end
282
+
283
+ return arg_name_value
284
+ end
285
+
286
+ # populate choice argument from model objects. areaType should be string like "floorArea" or "exteriorArea"
287
+ # note: it seems like spaceType.floorArea does account for multiplier, so I don't have to call this method unless I have a custom collection of spaces.
288
+ def self.getAreaOfSpacesInArray(model, spaceArray, areaType = 'floorArea')
289
+ # find selected floor spaces, make array and get floor area.
290
+ totalArea = 0
291
+ spaceAreaHash = {}
292
+ spaceArray.each do |space|
293
+ spaceArea = eval("space.#{areaType}*space.multiplier")
294
+ spaceAreaHash[space] = spaceArea
295
+ totalArea += spaceArea
296
+ end
297
+
298
+ result = { 'totalArea' => totalArea, 'spaceAreaHash' => spaceAreaHash }
299
+ return result
300
+ end
301
+
302
+ # runs conversion and neat string, and returns value with units in string, optionally before or after the value
303
+ def self.neatConvertWithUnitDisplay(double, fromString, toString, digits, unitBefore = false, unitAfter = true, space = true, parentheses = true)
304
+ # convert units
305
+ doubleConverted = OpenStudio.convert(double, fromString, toString)
306
+ if !doubleConverted.nil?
307
+ doubleConverted = doubleConverted.get
308
+ else
309
+ puts "Couldn't convert values, check string choices passed in. From: #{fromString}, To: #{toString}"
310
+ end
311
+
312
+ # get neat version of converted
313
+ neatConverted = OpenStudio.toNeatString(doubleConverted, digits, true)
314
+
315
+ # add prefix
316
+ if unitBefore
317
+ if space == true && parentheses == true
318
+ prefix = "(#{toString}) "
319
+ elsif space == true && parentheses == false
320
+ prefix = "(#{toString})"
321
+ elsif space == false && parentheses == true
322
+ prefix = "#{toString} "
323
+ else
324
+ prefix = toString.to_s
325
+ end
326
+ else
327
+ prefix = ''
328
+ end
329
+
330
+ # add suffix
331
+ if unitAfter
332
+ if space == true && parentheses == true
333
+ suffix = " (#{toString})"
334
+ elsif space == true && parentheses == false
335
+ suffix = "(#{toString})"
336
+ elsif space == false && parentheses == true
337
+ suffix = " #{toString}"
338
+ else
339
+ suffix = toString.to_s
340
+ end
341
+ else
342
+ suffix = ''
343
+ end
344
+
345
+ finalString = "#{prefix}#{neatConverted}#{suffix}"
346
+
347
+ return finalString
348
+ end
349
+
350
+ # helper that loops through lifecycle costs getting total costs under "Construction" and add to counter if occurs during year 0
351
+ def self.getTotalCostForObjects(objectArray, category = 'Construction', onlyYearFromStartZero = true)
352
+ counter = 0
353
+ objectArray.each do |object|
354
+ object_LCCs = object.lifeCycleCosts
355
+ object_LCCs.each do |object_LCC|
356
+ if object_LCC.category == category
357
+ if onlyYearFromStartZero == false || object_LCC.yearsFromStart == 0
358
+ counter += object_LCC.totalCost
359
+ end
360
+ end
361
+ end
362
+ end
363
+
364
+ return counter
365
+ end
366
+
367
+ # helper that loops through lifecycle costs getting total costs under "Construction" and add to counter if occurs during year 0
368
+ def self.getSpaceTypeStandardsInformation(spaceTypeArray)
369
+ # hash of space types
370
+ spaceTypeStandardsInfoHash = {}
371
+
372
+ spaceTypeArray.each do |spaceType|
373
+ # get standards building
374
+ if !spaceType.standardsBuildingType.empty?
375
+ standardsBuilding = spaceType.standardsBuildingType.get
376
+ else
377
+ standardsBuilding = nil
378
+ end
379
+
380
+ # get standards space type
381
+ if !spaceType.standardsSpaceType.empty?
382
+ standardsSpaceType = spaceType.standardsSpaceType.get
383
+ else
384
+ standardsSpaceType = nil
385
+ end
386
+
387
+ # populate hash
388
+ spaceTypeStandardsInfoHash[spaceType] = [standardsBuilding, standardsSpaceType]
389
+ end
390
+
391
+ return spaceTypeStandardsInfoHash
392
+ end
393
+
394
+ # OpenStudio has built in toNeatString method
395
+ # OpenStudio::toNeatString(double,2,true)# double,decimals, show commas
396
+
397
+ # OpenStudio has built in helper for unit conversion. That can be done using OpenStudio::convert() as shown below.
398
+ # OpenStudio::convert(double,"from unit string","to unit string").get
399
+ end