openstudio-extension 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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