openstudio-extension 0.1.6 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -283,7 +283,12 @@ module OsLib_Constructions
283
283
  # create info message
284
284
  if !runner.nil? # todo - need to look for bad visible transmittance here
285
285
  uFactorSiToIpConversion = OpenStudio.convert(material.uFactor, 'W/m^2*K', 'Btu/ft^2*h*R').get
286
- runner.registerInfo("Created #{construction.name} construction. U-factor: #{OpenStudio.toNeatString(uFactorSiToIpConversion, 2, true)}(Btu/ft^2*h*R), SHGC: #{material.getSolarHeatGainCoefficient}, VT: #{material.getVisibleTransmittance.get}.")
286
+ # version check to support 2.x and 3.x
287
+ if Gem::Version.new(OpenStudio::openStudioVersion) > Gem::Version.new("2.9.1")
288
+ runner.registerInfo("Created #{construction.name} construction. U-factor: #{OpenStudio.toNeatString(uFactorSiToIpConversion, 2, true)}(Btu/ft^2*h*R), SHGC: #{material.solarHeatGainCoefficient}, VT: #{material.getVisibleTransmittance.get}.")
289
+ else
290
+ runner.registerInfo("Created #{construction.name} construction. U-factor: #{OpenStudio.toNeatString(uFactorSiToIpConversion, 2, true)}(Btu/ft^2*h*R), SHGC: #{material.getSolarHeatGainCoefficient}, VT: #{material.getVisibleTransmittance.get}.")
291
+ end
287
292
  end
288
293
 
289
294
  result = construction
@@ -606,7 +606,7 @@ module OsLib_ModelGeneration
606
606
  hash['ER_Trauma'] = { ratio: 0.0025, space_type_gen: true, default: false }
607
607
  hash['ER_Triage'] = { ratio: 0.0050, space_type_gen: true, default: false }
608
608
  hash['ICU_NurseStn'] = { ratio: 0.0298, space_type_gen: true, default: false }
609
- hash['ICE_Open'] = { ratio: 0.0275, space_type_gen: true, default: false }
609
+ hash['ICU_Open'] = { ratio: 0.0275, space_type_gen: true, default: false }
610
610
  hash['ICU_PatRm'] = { ratio: 0.0115, space_type_gen: true, default: false }
611
611
  hash['Kitchen'] = { ratio: 0.0414, space_type_gen: true, default: false }
612
612
  hash['Lab'] = { ratio: 0.0236, space_type_gen: true, default: false }
@@ -1641,9 +1641,6 @@ module OsLib_ModelGeneration
1641
1641
  end
1642
1642
  if ! args.has_key?("perim_mult")
1643
1643
  args["perim_mult"] = 1.0 # will not make two bars for extended perimeter
1644
- puts "asdf, doesn't have it I'm adding it"
1645
- else
1646
- puts "asdf, already had it"
1647
1644
  end
1648
1645
 
1649
1646
  # lookup and replace argument values from upstream measures
@@ -2563,6 +2560,19 @@ module OsLib_ModelGeneration
2563
2560
  # Make the standard applier
2564
2561
  standard = Standard.build((args['template']).to_s)
2565
2562
 
2563
+ # validate climate zone
2564
+ if !args.has_key?('climate_zone') || args['climate_zone'] == 'Lookup From Model'
2565
+ climate_zone = standard.model_get_building_climate_zone_and_building_type(model)['climate_zone']
2566
+ runner.registerInfo("Using climate zone #{climate_zone} from model")
2567
+ else
2568
+ climate_zone = args['climate_zone']
2569
+ runner.registerInfo("Using climate zone #{climate_zone} from user arguments")
2570
+ end
2571
+ if climate_zone == ''
2572
+ runner.registerError("Could not determine climate zone from measure arguments or model.")
2573
+ return false
2574
+ end
2575
+
2566
2576
  # make sure daylight savings is turned on up prior to any sizing runs being done.
2567
2577
  if args['enable_dst']
2568
2578
  start_date = '2nd Sunday in March'
@@ -2649,13 +2659,6 @@ module OsLib_ModelGeneration
2649
2659
  else
2650
2660
  is_residential = 'No'
2651
2661
  end
2652
- if !args.has_key?('climate_zone') || args['climate_zone'] == 'Lookup From Model'
2653
- climate_zone = standard.model_get_building_climate_zone_and_building_type(model)['climate_zone']
2654
- runner.registerInfo("Using climate zone #{climate_zone} from model")
2655
- else
2656
- climate_zone = args['climate_zone']
2657
- runner.registerInfo("Using climate zone #{climate_zone} from user arguments")
2658
- end
2659
2662
  bldg_def_const_set = standard.model_add_construction_set(model, climate_zone, lookup_building_type, nil, is_residential)
2660
2663
  if bldg_def_const_set.is_initialized
2661
2664
  bldg_def_const_set = bldg_def_const_set.get
@@ -2800,16 +2803,25 @@ module OsLib_ModelGeneration
2800
2803
  end
2801
2804
  end
2802
2805
 
2803
- # TODO: - when add methods below add bool to enable/disable them with default value to true
2806
+ # add_daylighting_controls (since outdated measure don't have this default to true if arg not found)
2807
+ if !args.has_key?('add_daylighting_controls')
2808
+ args['add_daylighting_controls'] = true
2809
+ end
2810
+ if args['add_daylighting_controls']
2811
+ # remove add_daylighting_controls objects
2812
+ if args['remove_objects']
2813
+ model.getDaylightingControls.each(&:remove)
2814
+ end
2804
2815
 
2805
- # add daylight controls, need to perform a sizing run for 2010
2806
- if args['template'] == '90.1-2010'
2807
- if standard.model_run_sizing_run(model, "#{Dir.pwd}/SRvt") == false
2808
- log_messages_to_runner(runner, debug = true)
2809
- return false
2816
+ # add daylight controls, need to perform a sizing run for 2010
2817
+ if args['template'] == '90.1-2010'
2818
+ if standard.model_run_sizing_run(model, "#{Dir.pwd}/SRvt") == false
2819
+ log_messages_to_runner(runner, debug = true)
2820
+ return false
2821
+ end
2810
2822
  end
2811
- end
2812
2823
  standard.model_add_daylighting_controls(model)
2824
+ end
2813
2825
 
2814
2826
  # add refrigeration
2815
2827
  if args['add_refrigeration']
@@ -3037,20 +3049,6 @@ module OsLib_ModelGeneration
3037
3049
  end
3038
3050
  end
3039
3051
 
3040
- # add internal mass
3041
- if args['add_internal_mass']
3042
-
3043
- if args['remove_objects']
3044
- model.getSpaceLoads.each do |instance|
3045
- next unless instance.to_InternalMass.is_initialized
3046
- instance.remove
3047
- end
3048
- end
3049
-
3050
- # add internal mass to conditioned spaces; needs to happen after thermostats are applied
3051
- standard.model_add_internal_mass(model, primary_bldg_type)
3052
- end
3053
-
3054
3052
  # set unmet hours tolerance
3055
3053
  unmet_hrs_tol_r = args['unmet_hours_tolerance']
3056
3054
  unmet_hrs_tol_k = OpenStudio.convert(unmet_hrs_tol_r, 'R', 'K').get
@@ -49,14 +49,17 @@ module OpenStudio
49
49
  setup_subtasks(@name)
50
50
  end
51
51
 
52
- def set_extension_class(extension_class)
52
+ def set_extension_class(extension_class, github_repo = '')
53
53
  @extension_class = extension_class
54
54
  @extension = extension_class.new
55
55
  @root_dir = @extension.root_dir
56
- @measures_dir = @extension.measures_dir
56
+ # Catch if measures_dir is nil, then just make it an empty string
57
+ @measures_dir = @extension.measures_dir || ''
58
+ @staged_path = @measures_dir + '/staged'
57
59
  @core_dir = @extension.core_dir
58
60
  @doc_templates_dir = @extension.doc_templates_dir
59
61
  @files_dir = @extension.files_dir
62
+ @github_repo = github_repo
60
63
  end
61
64
 
62
65
  private
@@ -65,22 +68,20 @@ module OpenStudio
65
68
  namespace name do
66
69
  desc 'Run the CLI task to check for measure updates'
67
70
  task update_measures: ['measures:add_license', 'measures:add_readme', 'measures:copy_resources', 'update_copyright'] do
68
- puts 'updating measures...'
71
+ puts 'updating measures'
69
72
  runner = OpenStudio::Extension::Runner.new(Dir.pwd)
70
73
  runner.update_measures(@measures_dir)
71
74
  end
72
75
 
73
76
  desc 'List measures'
74
77
  task :list_measures do
75
- puts 'Listing measures...'
78
+ puts 'Listing measures'
76
79
  runner = OpenStudio::Extension::Runner.new(Dir.pwd)
77
80
  runner.list_measures(@measures_dir)
78
81
  end
79
82
 
80
83
  desc 'Use openstudio system ruby to run tests'
81
84
  task :test_with_openstudio do
82
- # puts Dir.pwd
83
- # puts Rake.original_dir
84
85
  puts 'testing with openstudio'
85
86
  runner = OpenStudio::Extension::Runner.new(Dir.pwd)
86
87
  result = runner.test_measures_with_cli(@measures_dir)
@@ -90,12 +91,6 @@ module OpenStudio
90
91
  end
91
92
  end
92
93
 
93
- # TODO: Implement this eventually... comment out for now.
94
- # desc 'Use openstudio docker image to run tests'
95
- # task :test_with_docker do
96
- # puts 'testing with docker'
97
- # end
98
-
99
94
  # namespace for measure operations
100
95
  namespace 'measures' do
101
96
  desc 'Copy the resources files to individual measures'
@@ -143,14 +138,233 @@ module OpenStudio
143
138
  runner.update_copyright(@root_dir, @doc_templates_dir)
144
139
  end
145
140
 
146
- desc 'Copy the measures to a location that can be uploaded to BCL'
147
- task :stage_bcl do
148
- puts 'Staging measures for BCL'
141
+ desc 'Print the change log from GitHub. Date format: yyyy-mm-dd'
142
+ task :change_log, [:start_date, :end_date, :apikey] do |t, args|
143
+ require 'change_log'
144
+ cl = ChangeLog.new(@github_repo, *args)
145
+ cl.process
146
+ cl.print_issues
149
147
  end
150
148
 
151
- desc 'Upload measures from the specified location.'
152
- task :push_bcl do
153
- puts 'Push measures to BCL'
149
+ namespace 'bcl' do
150
+ desc 'Test BCL login'
151
+ task :test_login do
152
+ puts 'test BCL login'
153
+ bcl = ::BCL::ComponentMethods.new
154
+ bcl.login
155
+ end
156
+
157
+ # for custom search, populate env var: bcl_search_keyword
158
+ desc 'Search BCL'
159
+ task :search_measures do
160
+ puts 'test search BCL'
161
+ bcl = ::BCL::ComponentMethods.new
162
+ bcl.login
163
+
164
+ # check for env var specifying keyword first
165
+ if ENV['bcl_search_keyword']
166
+ keyword = ENV['bcl_search_keyword']
167
+ else
168
+ keyword = 'Space'
169
+ end
170
+ num_results = 10
171
+ # bcl.search params: search_string, filter_string, return_all_results?
172
+ puts "searching BCL measures for keyword: #{keyword}"
173
+ results = bcl.search(keyword, "fq[]=bundle:nrel_measure&show_rows=#{num_results}", false)
174
+ puts "there are #{results[:result].count} results"
175
+ results[:result].each do |res|
176
+ puts(res[:measure][:name]).to_s
177
+ end
178
+ end
179
+
180
+ # to call with argument: "openstudio:bcl:stage[true]" (true = remove existing staged content)
181
+ desc 'Copy the measures/components to a location that can be uploaded to BCL'
182
+ task :stage, [:reset] do |t, args|
183
+ puts 'Staging measures for BCL'
184
+ # initialize BCL and login
185
+ bcl = ::BCL::ComponentMethods.new
186
+ bcl.login
187
+
188
+ # process reset options: true to clear out old staged content
189
+ options = { reset: false }
190
+ if args[:reset].to_s == 'true'
191
+ options[:reset] = true
192
+ end
193
+
194
+ # ensure staged dir exists
195
+ FileUtils.mkdir_p(@staged_path)
196
+
197
+ # delete existing tarballs if reset is true
198
+ if options[:reset]
199
+ puts 'Deleting existing staged content'
200
+ FileUtils.rm_rf(Dir.glob("#{@staged_path}/*"))
201
+ end
202
+
203
+ # create new and existing directories
204
+ FileUtils.mkdir_p(@staged_path.to_s + '/update')
205
+ FileUtils.mkdir_p(@staged_path.to_s + '/push/component')
206
+ FileUtils.mkdir_p(@staged_path.to_s + '/push/measure')
207
+
208
+ # keep track of noop, update, push
209
+ noops = 0
210
+ new_ones = 0
211
+ updates = 0
212
+
213
+ # get all content directories to process
214
+ dirs = Dir.glob("#{@measures_dir}/*")
215
+
216
+ dirs.each do |dir|
217
+ next if dir.include?('Rakefile') || File.basename(dir) == 'staged'
218
+ current_d = Dir.pwd
219
+ content_name = File.basename(dir)
220
+ puts '', '---'
221
+ puts "Generating #{content_name}"
222
+
223
+ Dir.chdir(dir)
224
+
225
+ # figure out whether to upload new or update existing
226
+ files = Pathname.glob('**/*')
227
+ uuid = nil
228
+ vid = nil
229
+ content_type = 'measure'
230
+
231
+ paths = []
232
+ files.each do |file|
233
+ # don't tar tests/outputs directory
234
+ next if file.to_s.start_with?('tests/output') # From measure testing process
235
+ next if file.to_s.start_with?('tests/test') # From openstudio-measure-tester-gem
236
+ next if file.to_s.start_with?('tests/coverage') # From openstudio-measure-tester-gem
237
+ next if file.to_s.start_with?('test_results') # From openstudio-measure-tester-gem
238
+ paths << file.to_s
239
+ if file.to_s =~ /^.{0,2}component.xml$/ || file.to_s =~ /^.{0,2}measure.xml$/
240
+ if file.to_s.match?(/^.{0,2}component.xml$/)
241
+ content_type = 'component'
242
+ end
243
+ # extract uuid and vid
244
+ uuid, vid = bcl.uuid_vid_from_xml(file)
245
+ end
246
+ end
247
+ puts "UUID: #{uuid}, VID: #{vid}"
248
+
249
+ # note: if uuid is missing, will assume new content
250
+ action = bcl.search_by_uuid(uuid, vid)
251
+ puts "#{content_name} ACTION TO TAKE: #{action}"
252
+ # new content functionality needs to know if measure or component. update is agnostic.
253
+ if action == 'noop' # ignore up-to-date content
254
+ puts " - WARNING: local #{content_name} uuid and vid match BCL... no update will be performed"
255
+ noops += 1
256
+ next
257
+ elsif action == 'update'
258
+ # puts "#{content_name} labeled as update for BCL"
259
+ destination = @staged_path + '/' + action + '/' + "#{content_name}.tar.gz"
260
+ updates += 1
261
+ elsif action == 'push'
262
+ # puts "#{content_name} labeled as new content for BCL"
263
+ destination = @staged_path + '/' + action + '/' + content_type + "/#{content_name}.tar.gz"
264
+ new_ones += 1
265
+ end
266
+
267
+ puts "destination: #{destination}"
268
+
269
+ # copy over only if 'reset_receipts' is set to TRUE. otherwise ignore if file exists already
270
+ if File.exist?(destination)
271
+ if reset
272
+ FileUtils.rm(destination)
273
+ ::BCL.tarball(destination, paths)
274
+ else
275
+ puts "*** WARNING: File #{content_name}.tar.gz already exists in staged directory... keeping existing file. To overwrite, set reset_receipts arg to true ***"
276
+ end
277
+ else
278
+ ::BCL.tarball(destination, paths)
279
+ end
280
+ Dir.chdir(current_d)
281
+ end
282
+ puts '', "****STAGING DONE**** #{new_ones} new content, #{updates} updates, #{noops} skipped (already up-to-date on BCL)", ''
283
+ end
284
+
285
+ desc 'Upload measures from the specified location.'
286
+ task :push do
287
+ puts 'Push measures to BCL'
288
+
289
+ # initialize BCL and login
290
+ bcl = ::BCL::ComponentMethods.new
291
+ bcl.login
292
+ reset = false
293
+
294
+ total_count = 0
295
+ successes = 0
296
+ errors = 0
297
+ skipped = 0
298
+
299
+ # grab all the new measure and component tar files and push to bcl
300
+ ['measure', 'component'].each do |content_type|
301
+ items = []
302
+ paths = Pathname.glob(@staged_path.to_s + "/push/#{content_type}/*.tar.gz")
303
+ paths.each do |path|
304
+ # puts path
305
+ items << path.to_s
306
+ end
307
+
308
+ items.each do |item|
309
+ puts item.split('/').last
310
+ total_count += 1
311
+
312
+ receipt_file = File.dirname(item) + '/' + File.basename(item, '.tar.gz') + '.receipt'
313
+ if !reset && File.exist?(receipt_file)
314
+ skipped += 1
315
+ puts 'SKIP: receipt file found'
316
+ next
317
+ end
318
+
319
+ valid, res = bcl.push_content(item, true, "nrel_#{content_type}")
320
+ if valid
321
+ successes += 1
322
+ else
323
+ errors += 1
324
+ if res.key?(:error)
325
+ puts " ERROR MESSAGE: #{res[:error]}"
326
+ else
327
+ puts "ERROR: #{res.inspect.chomp}"
328
+ end
329
+ end
330
+ puts '', '---'
331
+ end
332
+ end
333
+
334
+ # grab all the updated content (measures and components) tar files and push to bcl
335
+ items = []
336
+ paths = Pathname.glob(@staged_path.to_s + '/update/*.tar.gz')
337
+ paths.each do |path|
338
+ # puts path
339
+ items << path.to_s
340
+ end
341
+ items.each do |item|
342
+ puts item.split('/').last
343
+ total_count += 1
344
+
345
+ receipt_file = File.dirname(item) + '/' + File.basename(item, '.tar.gz') + '.receipt'
346
+ if !reset && File.exist?(receipt_file)
347
+ skipped += 1
348
+ puts 'SKIP: receipt file found'
349
+ next
350
+ end
351
+
352
+ valid, res = bcl.update_content(item, true)
353
+ if valid
354
+ successes += 1
355
+ else
356
+ errors += 1
357
+ if res.key?(:error)
358
+ puts " ERROR MESSAGE: #{res[:error]}"
359
+ else
360
+ puts "ERROR MESSAGE: #{res.inspect.chomp}"
361
+ end
362
+ end
363
+ puts '', '---'
364
+ end
365
+
366
+ puts "****UPLOAD DONE**** #{total_count} total, #{successes} success, #{errors} failures, #{skipped} skipped"
367
+ end
154
368
  end
155
369
  end
156
370
  end
@@ -41,6 +41,7 @@ require 'openstudio'
41
41
  require 'yaml'
42
42
  require 'fileutils'
43
43
  require 'parallel'
44
+ require 'bcl'
44
45
 
45
46
  module OpenStudio
46
47
  module Extension
@@ -55,7 +56,7 @@ module OpenStudio
55
56
  # compatible with the OpenStudio CLI.
56
57
  ##
57
58
  # @param [String] dirname Directory to run commands in, defaults to Dir.pwd. If directory includes a Gemfile then create a local bundle.
58
- # @param bundle_without [Hash] Hash describing the distribution of the variable.
59
+ # @param bundle_without [Array] List of strings of the groups to exclude when running the bundle command
59
60
  # @param options [Hash] Hash describing options for running the simulation. These are the defaults for all runs unless overriden within the run_* methods. Note if options is used, then a local runner.conf file will not be loaded.
60
61
  # @option options [String] :max_datapoints Max number of datapoints to run
61
62
  # @option options [String] :num_parallel Number of simulations to run in parallel at a time
@@ -560,21 +561,21 @@ module OpenStudio
560
561
  puts "Encoding.default_internal = #{Encoding.default_internal}"
561
562
 
562
563
  paths.each do |path|
563
- Dir[path[:glob]].each do |file|
564
- puts "Updating license in file #{file}"
565
- f = File.read(file)
566
- if f =~ path[:regex]
564
+ Dir[path[:glob]].each do |dir_file|
565
+ puts "Updating license in file #{dir_file}"
566
+ f = File.read(dir_file)
567
+ if f.match?(path[:regex])
567
568
  puts ' License found -- updating'
568
- File.open(file, 'w') { |write| write << f.gsub(path[:regex], path[:license]) }
569
+ File.open(dir_file, 'w') { |write| write << f.gsub(path[:regex], path[:license]) }
569
570
  elsif f =~ /\(C\)/i || f =~ /\(Copyright\)/i
570
571
  puts ' File already has copyright -- skipping'
571
572
  else
572
573
  puts ' No license found -- adding'
573
- if f =~ /#!/
574
+ if f.match?(/#!/)
574
575
  puts ' CANNOT add license to file automatically, add it manually and it will update automatically in the future'
575
576
  next
576
577
  end
577
- File.open(file, 'w') { |write| write << f.insert(0, path[:license] + "\n") }
578
+ File.open(dir_file, 'w') { |write| write << f.insert(0, path[:license] + "\n") }
578
579
  end
579
580
  end
580
581
  end