openstudio-extension 0.2.1 → 0.3.0

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.
@@ -148,7 +148,7 @@ module OsLib_ModelSimplification
148
148
  # loop through building type hash to create multiple blends
149
149
  space_type_hash.each do |collection_name, space_types|
150
150
  if collection_name == 'Building'
151
- space_array = model.getSpaces # use all space types, not just space types passed in
151
+ space_array = model.getSpaces.sort # use all space types, not just space types passed in
152
152
  else
153
153
  space_array = []
154
154
  space_types.each do |space_type|
@@ -229,7 +229,7 @@ module OsLib_ModelSimplification
229
229
  if collection_name == 'Building'
230
230
  # count area of spaces that have no space type
231
231
  no_space_type_area_counter = 0
232
- model.getSpaces.each do |space|
232
+ model.getSpaces.sort.each do |space|
233
233
  if space.spaceType.empty?
234
234
  next if !space.partofTotalFloorArea
235
235
  no_space_type_area_counter += space.floorArea * space.multiplier
@@ -400,7 +400,7 @@ module OsLib_ModelSimplification
400
400
  end
401
401
  end
402
402
 
403
- return model.getSpaceTypes
403
+ return model.getSpaceTypes.sort
404
404
  end
405
405
 
406
406
  # blend internal loads used when working from existing model
@@ -788,10 +788,10 @@ module OsLib_ModelSimplification
788
788
  def sort_building_stories_and_get_min_multiplier(model)
789
789
  sorted_building_stories = {}
790
790
  # loop through stories
791
- model.getBuildingStorys.each do |story|
791
+ model.getBuildingStorys.sort.each do |story|
792
792
  story_min_z = nil
793
793
  # loop through spaces in story.
794
- story.spaces.each do |space|
794
+ story.spaces.sort.each do |space|
795
795
  space_z_min = OsLib_Geometry.getSurfaceZValues(space.surfaces.to_a).min + space.zOrigin
796
796
  if story_min_z.nil? || (story_min_z > space_z_min)
797
797
  story_min_z = space_z_min
@@ -829,8 +829,8 @@ module OsLib_ModelSimplification
829
829
 
830
830
  # get bounding_box
831
831
  bounding_box = OpenStudio::BoundingBox.new
832
- model.getSpaces.each do |space|
833
- space.surfaces.each do |spaceSurface|
832
+ model.getSpaces.sort.each do |space|
833
+ space.surfaces.sort.each do |spaceSurface|
834
834
  bounding_box.addPoints(space.transformation * spaceSurface.vertices)
835
835
  end
836
836
  end
@@ -844,7 +844,7 @@ module OsLib_ModelSimplification
844
844
  envelope_data_hash[:building_max_xyz] = [max_x, max_y, max_z]
845
845
 
846
846
  # add orientation specific wwr
847
- ext_surfaces_hash = OsLib_Geometry.getExteriorWindowAndWllAreaByOrientation(model, model.getSpaces.to_a)
847
+ ext_surfaces_hash = OsLib_Geometry.getExteriorWindowAndWllAreaByOrientation(model, model.getSpaces.sort.to_a)
848
848
  envelope_data_hash[:building_wwr_n] = ext_surfaces_hash['northWindow'] / ext_surfaces_hash['northWall']
849
849
  envelope_data_hash[:building_wwr_s] = ext_surfaces_hash['southWindow'] / ext_surfaces_hash['southWall']
850
850
  envelope_data_hash[:building_wwr_e] = ext_surfaces_hash['eastWindow'] / ext_surfaces_hash['eastWall']
@@ -1038,7 +1038,7 @@ module OsLib_ModelSimplification
1038
1038
  envelope_data_hash[:building_overhang_proj_factor_w] = building_overhang_area_w / ext_surfaces_hash['westWindow']
1039
1039
 
1040
1040
  # warn for spaces that are not on a story (in future could infer stories for these)
1041
- model.getSpaces.each do |space|
1041
+ model.getSpaces.sort.each do |space|
1042
1042
  if !space.buildingStory.is_initialized
1043
1043
  runner.registerWarning("#{space.name} is not on a building story, may have unexpected results.")
1044
1044
  end
@@ -37,7 +37,7 @@ module OsLib_OutdoorAirAndInfiltration
37
37
  # delete any infiltration objects used in the model.
38
38
  def self.eraseInfiltrationUsedInModel(model, runner)
39
39
  # get space infiltration objects.
40
- space_infiltration_objects = model.getSpaceInfiltrationDesignFlowRates
40
+ space_infiltration_objects = model.getSpaceInfiltrationDesignFlowRates.sort
41
41
 
42
42
  # hash to hold schedules used for infiltration objects in the model
43
43
  @infiltrationSchedulesHardAssigned = {}
@@ -126,7 +126,7 @@ module OsLib_OutdoorAirAndInfiltration
126
126
 
127
127
  # change objects to be all space types used in the model
128
128
  objects = []
129
- space_types = model.getSpaceTypes
129
+ space_types = model.getSpaceTypes.sort
130
130
  space_types.each do |space_type|
131
131
  if !space_type.spaces.empty?
132
132
  objects << space_type
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  # *******************************************************************************
4
2
  # OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
5
3
  # All rights reserved.
@@ -51,14 +49,17 @@ module OpenStudio
51
49
  setup_subtasks(@name)
52
50
  end
53
51
 
54
- def set_extension_class(extension_class)
52
+ def set_extension_class(extension_class, github_repo = '')
55
53
  @extension_class = extension_class
56
54
  @extension = extension_class.new
57
55
  @root_dir = @extension.root_dir
58
- @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'
59
59
  @core_dir = @extension.core_dir
60
60
  @doc_templates_dir = @extension.doc_templates_dir
61
61
  @files_dir = @extension.files_dir
62
+ @github_repo = github_repo
62
63
  end
63
64
 
64
65
  private
@@ -67,22 +68,20 @@ module OpenStudio
67
68
  namespace name do
68
69
  desc 'Run the CLI task to check for measure updates'
69
70
  task update_measures: ['measures:add_license', 'measures:add_readme', 'measures:copy_resources', 'update_copyright'] do
70
- puts 'updating measures...'
71
+ puts 'updating measures'
71
72
  runner = OpenStudio::Extension::Runner.new(Dir.pwd)
72
73
  runner.update_measures(@measures_dir)
73
74
  end
74
75
 
75
76
  desc 'List measures'
76
77
  task :list_measures do
77
- puts 'Listing measures...'
78
+ puts 'Listing measures'
78
79
  runner = OpenStudio::Extension::Runner.new(Dir.pwd)
79
80
  runner.list_measures(@measures_dir)
80
81
  end
81
82
 
82
83
  desc 'Use openstudio system ruby to run tests'
83
84
  task :test_with_openstudio do
84
- # puts Dir.pwd
85
- # puts Rake.original_dir
86
85
  puts 'testing with openstudio'
87
86
  runner = OpenStudio::Extension::Runner.new(Dir.pwd)
88
87
  result = runner.test_measures_with_cli(@measures_dir)
@@ -92,12 +91,6 @@ module OpenStudio
92
91
  end
93
92
  end
94
93
 
95
- # TODO: Implement this eventually... comment out for now.
96
- # desc 'Use openstudio docker image to run tests'
97
- # task :test_with_docker do
98
- # puts 'testing with docker'
99
- # end
100
-
101
94
  # namespace for measure operations
102
95
  namespace 'measures' do
103
96
  desc 'Copy the resources files to individual measures'
@@ -145,14 +138,233 @@ module OpenStudio
145
138
  runner.update_copyright(@root_dir, @doc_templates_dir)
146
139
  end
147
140
 
148
- desc 'Copy the measures to a location that can be uploaded to BCL'
149
- task :stage_bcl do
150
- 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
151
147
  end
152
148
 
153
- desc 'Upload measures from the specified location.'
154
- task :push_bcl do
155
- 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 options[: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
156
368
  end
157
369
  end
158
370
  end
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  # *******************************************************************************
4
2
  # OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC.
5
3
  # All rights reserved.
@@ -43,6 +41,7 @@ require 'openstudio'
43
41
  require 'yaml'
44
42
  require 'fileutils'
45
43
  require 'parallel'
44
+ require 'bcl'
46
45
 
47
46
  module OpenStudio
48
47
  module Extension
@@ -57,7 +56,7 @@ module OpenStudio
57
56
  # compatible with the OpenStudio CLI.
58
57
  ##
59
58
  # @param [String] dirname Directory to run commands in, defaults to Dir.pwd. If directory includes a Gemfile then create a local bundle.
60
- # @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
61
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.
62
61
  # @option options [String] :max_datapoints Max number of datapoints to run
63
62
  # @option options [String] :num_parallel Number of simulations to run in parallel at a time
@@ -69,20 +68,29 @@ module OpenStudio
69
68
  # in ~/OpenStudio/#{alias} or something like that?
70
69
 
71
70
  # if the dirname contains a runner.conf file, then use the config file to specify the parameters
71
+
72
+ @options = OpenStudio::Extension::RunnerConfig.default_config
73
+ # ORDER of PRECEDENCE: default config < runner.conf file < options passed in directly
72
74
  if File.exist?(File.join(dirname, OpenStudio::Extension::RunnerConfig::FILENAME)) && options.empty?
73
75
  puts 'Using runner options from runner.conf file'
74
76
  runner_config = OpenStudio::Extension::RunnerConfig.new(dirname)
75
- @options = runner_config.options
76
- else
77
- # use the passed values or defaults overriden by passed options
78
- @options = OpenStudio::Extension::RunnerConfig.default_config.merge(options)
77
+ # use the default values overriden with runner.conf values
78
+ @options = @options.merge(runner_config.options)
79
79
  end
80
80
 
81
+ # use the passed values or defaults overriden by passed options
82
+ @options = @options.merge(options)
83
+
81
84
  puts "Initializing runner with dirname: '#{dirname}' and options: #{@options}"
82
85
  @dirname = File.absolute_path(dirname)
83
- @gemfile_path = File.join(@dirname, 'Gemfile')
84
- @bundle_install_path = File.join(@dirname, '.bundle/install/')
86
+
87
+ # use passed options, otherwise assume @dirname
88
+ @gemfile_path = !@options.key?(:gemfile_path) || @options[:gemfile_path] === '' ? File.join(@dirname, 'Gemfile') : @options[:gemfile_path]
89
+ @bundle_install_path = !@options.key?(:bundle_install_path) || @options[:bundle_install_path] === '' ? File.join(@dirname, '.bundle/install/') : @options[:bundle_install_path]
85
90
  @original_dir = Dir.pwd
91
+ # puts "DIRNAME: #{@dirname}"
92
+ # puts "@gemfile_path set to: #{@gemfile_path}"
93
+ # puts "@bundle_install_path set to: #{@bundle_install_path}"
86
94
 
87
95
  @bundle_without = bundle_without || []
88
96
  @bundle_without_string = @bundle_without.join(' ')
@@ -156,7 +164,9 @@ module OpenStudio
156
164
 
157
165
  puts "needs_update = #{needs_update}"
158
166
  if needs_update
159
- run_command('bundle update', get_clean_env)
167
+ # run_command('bundle update', get_clean_env)
168
+ # KAF: updated to include specified gemfile_path...this didn't seem to work before
169
+ run_command("bundle update --gemfile=#{@gemfile_path}", get_clean_env)
160
170
  end
161
171
  ensure
162
172
  Dir.chdir(@original_dir)
@@ -562,12 +572,12 @@ module OpenStudio
562
572
  puts "Encoding.default_internal = #{Encoding.default_internal}"
563
573
 
564
574
  paths.each do |path|
565
- Dir[path[:glob]].each do |file|
566
- puts "Updating license in file #{file}"
567
- f = File.read(file)
575
+ Dir[path[:glob]].each do |dir_file|
576
+ puts "Updating license in file #{dir_file}"
577
+ f = File.read(dir_file)
568
578
  if f.match?(path[:regex])
569
579
  puts ' License found -- updating'
570
- File.open(file, 'w') { |write| write << f.gsub(path[:regex], path[:license]) }
580
+ File.open(dir_file, 'w') { |write| write << f.gsub(path[:regex], path[:license]) }
571
581
  elsif f =~ /\(C\)/i || f =~ /\(Copyright\)/i
572
582
  puts ' File already has copyright -- skipping'
573
583
  else
@@ -576,7 +586,7 @@ module OpenStudio
576
586
  puts ' CANNOT add license to file automatically, add it manually and it will update automatically in the future'
577
587
  next
578
588
  end
579
- File.open(file, 'w') { |write| write << f.insert(0, path[:license] + "\n") }
589
+ File.open(dir_file, 'w') { |write| write << f.insert(0, path[:license] + "\n") }
580
590
  end
581
591
  end
582
592
  end