openstudio-analysis 1.2.0 → 1.3.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c57c83c75eb61c8b4253907c07d2f4cc1eaa6939aa27c30dc5fdae7bc0bd551f
4
- data.tar.gz: c2299fdd5b78dfc58792c4bf35aa621f2a4e1db862e2e5b3fcd93107ee7f82ae
3
+ metadata.gz: b307b715407bd74c16e687f0acfe025555e232cab093d493ddfec92930208928
4
+ data.tar.gz: b03f1c1c73cbd0c7ec95033e91874d9a4ec6ff267ca038877a04d18ec8772f7d
5
5
  SHA512:
6
- metadata.gz: eac9ee6feee2103b9fe6b9529116f5939145198b8dee8ea9c7094ea5fe0d61e47fb009882c73b0770c152c997f319c5202c56266c6bbd84ca3775a2a98b1074c
7
- data.tar.gz: ac4167112ffa932916d99c765d1486e184ad154f65e49b70b56d99b458bb3a3458371687450e031cc6d0afa92318e647c4756625dd5ef1f097937a50c0d43e88
6
+ metadata.gz: ba82343b9d2bc7e35439d1583ee39b6938459e1fd0f83cd6993ab1e6e71dcf185f2da7fedb62d4b02267664576c42b941e22e3fcf673ac321812998ca60bd07d
7
+ data.tar.gz: 4a8aad3e2348fa63e25c6aa07e496b75a79be7b9aa2af92075c1e63524296e60150169f0c9e732c13cd962b6c701e16a16b50474e7005fb3cbf7e090981ee7df
data/CHANGELOG.md CHANGED
@@ -1,6 +1,14 @@
1
1
  OpenStudio Analysis Gem Change Log
2
2
  ==================================
3
3
 
4
+ Version 1.3.1
5
+ -------------
6
+ * Add method to delete a Variable
7
+
8
+ Version 1.3.0
9
+ -------------
10
+ * Create an OSA from an OSW
11
+
4
12
  Version 1.2.0
5
13
  -------------
6
14
  * master -> main
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC. All rights reserved.
1
+ OpenStudio(R), Copyright (c) 2008-2023, Alliance for Sustainable Energy, LLC. All rights reserved.
2
2
 
3
3
  Redistribution and use in source and binary forms, with or without modification, are permitted provided
4
4
  that the following conditions are met:
data/Rakefile CHANGED
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2023, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2023, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -39,12 +39,20 @@
39
39
  module OpenStudio
40
40
  module Analysis
41
41
  class AlgorithmAttributes
42
- # Create a new instance of an algorithm
42
+ # Create a new instance of the parameters for an algorithm
43
43
  #
44
44
  def initialize
45
- @attributes = {}
45
+ @attributes = {
46
+ "seed": nil,
47
+ "failed_f_value": 1000000000000000000,
48
+ "debug_messages": 1
49
+ }
46
50
  end
47
51
 
52
+ # these are the allowed analysis types
53
+ ANALYSIS_TYPES = ['diag', 'doe', 'fast99', 'ga', 'gaisl', 'lhs', 'morris', 'nsga_nrel', 'optim',
54
+ 'preflight', 'pso', 'repeat_run', 'rgenoud', 'single_run', 'sobol', 'spea_nrel']
55
+
48
56
  def set_attribute(attribute_name, attribute_value)
49
57
  @attributes[attribute_name] = attribute_value
50
58
  begin
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2023, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -58,6 +58,7 @@ module OpenStudio
58
58
  attr_accessor :display_name
59
59
  attr_accessor :workflow
60
60
  attr_accessor :algorithm
61
+ attr_accessor :osw_path
61
62
 
62
63
  # the attributes below are used for packaging data into the analysis zip file
63
64
  attr_reader :weather_files
@@ -65,6 +66,7 @@ module OpenStudio
65
66
  attr_reader :worker_inits
66
67
  attr_reader :worker_finalizes
67
68
  attr_reader :libraries
69
+ attr_reader :server_scripts
68
70
 
69
71
  # Create an instance of the OpenStudio::Analysis::Formulation
70
72
  #
@@ -74,7 +76,7 @@ module OpenStudio
74
76
  @display_name = display_name
75
77
  @analysis_type = nil
76
78
  @outputs = []
77
-
79
+ @workflow = OpenStudio::Analysis::Workflow.new
78
80
  # Initialize child objects (expect workflow)
79
81
  @weather_file = WeatherFile.new
80
82
  @seed_model = SeedModel.new
@@ -86,20 +88,22 @@ module OpenStudio
86
88
  @worker_inits = SupportFiles.new
87
89
  @worker_finalizes = SupportFiles.new
88
90
  @libraries = SupportFiles.new
89
- # @initialization_scripts = SupportFiles.new
90
- end
91
-
92
- # Initialize or return the current workflow object
93
- #
94
- # @return [Object] An OpenStudio::Analysis::Workflow object
95
- def workflow
96
- @workflow ||= OpenStudio::Analysis::Workflow.new
91
+ @server_scripts = ServerScripts.new
97
92
  end
98
-
93
+
99
94
  # Define the type of analysis which is going to be running
100
95
  #
101
96
  # @param name [String] Name of the algorithm/analysis. (e.g. rgenoud, lhs, single_run)
102
- attr_writer :analysis_type
97
+ # allowed values are ANALYSIS_TYPES = ['spea_nrel', 'rgenoud', 'nsga_nrel', 'lhs', 'preflight',
98
+ # 'morris', 'sobol', 'doe', 'fast99', 'ga', 'gaisl',
99
+ # 'single_run', 'repeat_run', 'batch_run']
100
+ def analysis_type=(value)
101
+ if OpenStudio::Analysis::AlgorithmAttributes::ANALYSIS_TYPES.include?(value)
102
+ @analysis_type = value
103
+ else
104
+ raise "Invalid analysis type. Allowed types: #{OpenStudio::Analysis::AlgorithmAttributes::ANALYSIS_TYPES}"
105
+ end
106
+ end
103
107
 
104
108
  # Path to the seed model
105
109
  #
@@ -133,29 +137,43 @@ module OpenStudio
133
137
  # @option output_hash [Float] :scaling_factor How to scale the objective function(s). Default: nil
134
138
  # @option output_hash [Integer] :objective_function_group If grouping objective functions, then group ID. Default: nil
135
139
  def add_output(output_hash)
136
- output_hash = {
137
- units: '',
138
- objective_function: false,
139
- objective_function_index: nil,
140
- objective_function_target: nil,
141
- objective_function_group: nil,
142
- scaling_factor: nil
143
- }.merge(output_hash)
144
-
145
- # Check if the name is already been added. Note that if the name is added again, it will not update any of
146
- # the fields
147
- exist = @outputs.select { |o| o[:name] == output_hash[:name] }
148
- if exist.empty?
140
+ # Check if the name is already been added.
141
+ exist = @outputs.find_index { |o| o[:name] == output_hash[:name] }
142
+ # if so, update the fields but keep objective_function_index the same
143
+ if exist
144
+ original = @outputs[exist]
145
+ if original[:objective_function] && !output_hash[:objective_function]
146
+ return @outputs
147
+ end
148
+ output = original.merge(output_hash)
149
+ output[:objective_function_index] = original[:objective_function_index]
150
+ @outputs[exist] = output
151
+ else
152
+ output = {
153
+ units: '',
154
+ objective_function: false,
155
+ objective_function_index: nil,
156
+ objective_function_target: nil,
157
+ #set default to nil or 1 if objective_function is true and this is not set
158
+ objective_function_group: (output_hash[:objective_function] ? 1 : nil),
159
+ scaling_factor: nil,
160
+ #set default to false or true if objective_function is true and this is not set
161
+ visualize: (output_hash[:objective_function] ? true : false),
162
+ metadata_id: nil,
163
+ export: true,
164
+ }.merge(output_hash)
165
+ #set display_name default to be name if its not set
166
+ output[:display_name] = output_hash[:display_name] ? output_hash[:display_name] : output_hash[:name]
167
+ #set display_name_short default to be display_name if its not set, this can be null if :display_name not set
168
+ output[:display_name_short] = output_hash[:display_name_short] ? output_hash[:display_name_short] : output_hash[:display_name]
149
169
  # if the variable is an objective_function, then increment and
150
170
  # assign and objective function index
151
- if output_hash[:objective_function]
171
+ if output[:objective_function]
152
172
  values = @outputs.select { |o| o[:objective_function] }
153
- output_hash[:objective_function_index] = values.size # size is already +1
154
- else
155
- output_hash[:objective_function] = false
173
+ output[:objective_function_index] = values.size
156
174
  end
157
175
 
158
- @outputs << output_hash
176
+ @outputs << output
159
177
  end
160
178
 
161
179
  @outputs
@@ -215,6 +233,16 @@ module OpenStudio
215
233
  end
216
234
 
217
235
  h[:analysis][:file_format_version] = version
236
+ h[:analysis][:cli_debug] = "--debug"
237
+ h[:analysis][:cli_verbose] = "--verbose"
238
+ h[:analysis][:run_workflow_timeout] = 28800
239
+ h[:analysis][:upload_results_timeout] = 28800
240
+ h[:analysis][:initialize_worker_timeout] = 28800
241
+ #-BLB I dont think this does anything. server_scripts are run if they are in
242
+ #the /scripts/analysis or /scripts/data_point directories
243
+ #but nothing is ever checked in the OSA.
244
+ #
245
+ h[:analysis][:server_scripts] = {}
218
246
 
219
247
  # This is a hack right now, but after the initial hash is created go back and add in the objective functions
220
248
  # to the the algorithm as defined in the output_variables list
@@ -321,9 +349,209 @@ module OpenStudio
321
349
 
322
350
  save_analysis_zip(filename)
323
351
  end
352
+
353
+
354
+ def save_osa_zip(filename)
355
+ filename += '.zip' if File.extname(filename) == ''
356
+
357
+ FileUtils.mkdir_p File.dirname(filename) unless Dir.exist? File.dirname(filename)
358
+
359
+ save_analysis_zip_osa(filename)
360
+ end
361
+
362
+ # convert an OSW to an OSA
363
+ # osw_filename is the full path to the OSW file
364
+ # assumes the associated files and directories are in the same location
365
+ # /example.osw
366
+ # /measures
367
+ # /seeds
368
+ # /weather
369
+ #
370
+ def convert_osw(osw_filename)
371
+ #load OSW so we can loop over [:steps]
372
+ if File.exist? osw_filename #will this work for both rel and abs paths?
373
+ osw = JSON.parse(File.read(osw_filename), symbolize_names: true)
374
+ @osw_path = File.expand_path(osw_filename)
375
+ else
376
+ raise "Could not find workflow file #{osw_filename}"
377
+ end
378
+
379
+ #set the weather and seed files if set in OSW
380
+ self.weather_file = osw[:weather_file] ? osw[:weather_file] : nil
381
+ self.seed_model = osw[:seed_file] ? osw[:seed_file] : nil
382
+
383
+ #set analysis_type default to Single_Run
384
+ self.analysis_type = 'single_run'
385
+
386
+ #loop over OSW 'steps' and map over measures
387
+ #there is no name/display name in the OSW. Just measure directory name
388
+ #read measure.XML from directory to get name / display name
389
+ #increment name by +_1 if there are duplicates
390
+ #add measure
391
+ #change default args to osw arg values
392
+
393
+ osw[:steps].each do |step|
394
+ #get measure directory
395
+ measure_dir = step[:measure_dir_name]
396
+ measure_name = measure_dir.split("measures/").last
397
+ #get XML
398
+ measure_dir_abs_path = File.join(File.dirname(File.expand_path(osw_filename)),measure_dir)
399
+ xml = parse_measure_xml(File.join(measure_dir_abs_path, '/measure.xml'))
400
+ #add check for previous names _+1
401
+ count = 1
402
+ name = xml[:name]
403
+ display_name = xml[:display_name]
404
+ loop do
405
+ measure = @workflow.find_measure(name)
406
+ break if measure.nil?
407
+
408
+ count += 1
409
+ name = "#{xml[:name]}_#{count}"
410
+ display_name = "#{xml[:display_name]} #{count}"
411
+ end
412
+ #Add Measure to workflow
413
+ @workflow.add_measure_from_path(name, display_name, measure_dir_abs_path) #this forces to an absolute path which seems constent with PAT
414
+ #@workflow.add_measure_from_path(name, display_name, measure_dir) #this uses the path in the OSW which could be relative
415
+
416
+ #Change the default argument values to the osw values
417
+ #1. find measure in @workflow
418
+ m = @workflow.find_measure(name)
419
+ #2. loop thru osw args
420
+ step[:arguments].each do |k,v|
421
+ #check if argument is in measure, otherwise setting argument_value will crash
422
+ raise "OSW arg: #{k} is not in Measure: #{name}" if m.arguments.find_all { |a| a[:name] == k.to_s }.empty?
423
+ #set measure arg to match osw arg
424
+ m.argument_value(k.to_s, v)
425
+ end
426
+
427
+ end
428
+ end
324
429
 
325
430
  private
326
431
 
432
+ # New format for OSAs. Package up the seed, weather files, and measures
433
+ # filename is the name of the file to be saved. ex: analysis.zip
434
+ # it will parse the OSA and zip up all the files defined in the workflow
435
+ def save_analysis_zip_osa(filename)
436
+ def add_directory_to_zip_osa(zipfile, local_directory, relative_zip_directory)
437
+ puts "Add Directory #{local_directory}"
438
+ Dir[File.join(local_directory.to_s, '**', '**')].each do |file|
439
+ puts "Adding File #{file}"
440
+
441
+ zipfile.add(file.sub(local_directory, relative_zip_directory), file)
442
+ end
443
+ zipfile
444
+ end
445
+ #delete file if exists
446
+ FileUtils.rm_f(filename) if File.exist?(filename)
447
+ #get the full path to the OSW, since all Files/Dirs should be in same directory as the OSW
448
+ puts "osw_path: #{@osw_path}"
449
+ osw_full_path = File.dirname(File.expand_path(@osw_path))
450
+ puts "osw_full_path: #{osw_full_path}"
451
+
452
+ Zip::File.open(filename, create: true) do |zf|
453
+ ## Weather files
454
+ puts 'Adding Support Files: Weather'
455
+ #check if weather file exists. use abs path. remove leading ./ from @weather_file path if there.
456
+ #check if path is already absolute
457
+ if File.exists?(@weather_file[:file])
458
+ puts " Adding #{@weather_file[:file]}"
459
+ zf.add("weather/#{File.basename(@weather_file[:file])}", @weather_file[:file])
460
+ #make absolute path and check for file
461
+ elsif File.exists?(File.join(osw_full_path,@weather_file[:file].sub(/^\.\//, '')))
462
+ puts " Adding #{File.join(osw_full_path,@weather_file[:file].sub(/^\.\//, ''))}"
463
+ zf.add("weather/#{File.basename(@weather_file[:file])}", File.join(osw_full_path,@weather_file[:file].sub(/^\.\//, '')))
464
+ else
465
+ raise "Weather file does not exist at: #{File.join(osw_full_path,@weather_file[:file].sub(/^\.\//, ''))}"
466
+ end
467
+
468
+ ## Seed files
469
+ puts 'Adding Support Files: Seed Models'
470
+ #check if weather file exists. use abs path. remove leading ./ from @seed_model path if there.
471
+ #check if path is already absolute
472
+ if File.exists?(@seed_model[:file])
473
+ puts " Adding #{@seed_model[:file]}"
474
+ zf.add("seeds/#{File.basename(@seed_model[:file])}", @seed_model[:file])
475
+ #make absolute path and check for file
476
+ elsif File.exists?(File.join(osw_full_path,@seed_model[:file].sub(/^\.\//, '')))
477
+ puts " Adding #{File.join(osw_full_path,@seed_model[:file].sub(/^\.\//, ''))}"
478
+ zf.add("seeds/#{File.basename(@seed_model[:file])}", File.join(osw_full_path,@seed_model[:file].sub(/^\.\//, '')))
479
+ else
480
+ raise "Seed file does not exist at: #{File.join(osw_full_path,@seed_model[:file].sub(/^\.\//, ''))}"
481
+ end
482
+
483
+ puts 'Adding Support Files: Libraries'
484
+ @libraries.each do |lib|
485
+ raise "Libraries must specify their 'library_name' as metadata which becomes the directory upon zip" unless lib[:metadata][:library_name]
486
+
487
+ if File.directory? lib[:file]
488
+ Dir[File.join(lib[:file], '**', '**')].each do |file|
489
+ puts " Adding #{file}"
490
+ zf.add(file.sub(lib[:file], "lib/#{lib[:metadata][:library_name]}"), file)
491
+ end
492
+ else
493
+ # just add the file to the zip
494
+ puts " Adding #{lib[:file]}"
495
+ zf.add(lib[:file], "lib/#{File.basename(lib[:file])}", lib[:file])
496
+ end
497
+ end
498
+
499
+ puts 'Adding Support Files: Server Scripts'
500
+ @server_scripts.each_with_index do |f, index|
501
+ if f[:init_or_final] == 'finalization'
502
+ file_name = 'finalization.sh'
503
+ else
504
+ file_name = 'initialization.sh'
505
+ end
506
+ if f[:server_or_data_point] == 'analysis'
507
+ new_name = "scripts/analysis/#{file_name}"
508
+ else
509
+ new_name = "scripts/data_point/#{file_name}"
510
+ end
511
+ puts " Adding #{f[:file]} as #{new_name}"
512
+ zf.add(new_name, f[:file])
513
+
514
+ if f[:arguments]
515
+ arg_file = "#{(new_name.sub(/\.sh\z/, ''))}.args"
516
+ puts " Adding arguments as #{arg_file}"
517
+ file = Tempfile.new('arg')
518
+ file.write(f[:arguments])
519
+ zf.add(arg_file, file)
520
+ file.close
521
+ end
522
+ end
523
+
524
+ ## Measures
525
+ puts 'Adding Measures'
526
+ added_measures = []
527
+ # The list of the measures should always be there, but make sure they are uniq
528
+ @workflow.each do |measure|
529
+ measure_dir_to_add = measure.measure_definition_directory_local
530
+
531
+ next if added_measures.include? measure_dir_to_add
532
+
533
+ puts " Adding #{File.basename(measure_dir_to_add)}"
534
+ Dir[File.join(measure_dir_to_add, '**')].each do |file|
535
+ if File.directory?(file)
536
+ if File.basename(file) == 'resources' || File.basename(file) == 'lib'
537
+ #remove leading ./ from measure_definition_directory path if there.
538
+ add_directory_to_zip_osa(zf, file, "#{measure.measure_definition_directory.sub(/^\.\//, '')}/#{File.basename(file)}")
539
+ end
540
+ else
541
+ puts " Adding File #{file}"
542
+ #remove leading ./ from measure.measure_definition_directory string with regex .sub(/^\.\//, '')
543
+ zip_path_for_measures = file.sub(measure_dir_to_add, measure.measure_definition_directory.sub(/^\.\//, ''))
544
+ #puts " zip_path_for_measures: #{zip_path_for_measures}"
545
+ zf.add(zip_path_for_measures, file)
546
+ end
547
+ end
548
+
549
+ added_measures << measure_dir_to_add
550
+ end
551
+ end
552
+ end
553
+
554
+ #keep legacy function
327
555
  # Package up the seed, weather files, and measures
328
556
  def save_analysis_zip(filename)
329
557
  def add_directory_to_zip(zipfile, local_directory, relative_zip_directory)
@@ -399,17 +627,17 @@ module OpenStudio
399
627
  @worker_finalizes.each_with_index do |f, index|
400
628
  ordered_file_name = "#{index.to_s.rjust(2, '0')}_#{File.basename(f[:file])}"
401
629
  puts " Adding #{f[:file]} as #{ordered_file_name}"
402
- zf.add(f[:file].sub(f[:file], "./scripts/worker_finalization/#{ordered_file_name}"), f[:file])
630
+ zf.add(f[:file].sub(f[:file], "scripts/worker_finalization/#{ordered_file_name}"), f[:file])
403
631
 
404
632
  if f[:metadata][:args]
405
633
  arg_file = "#{File.basename(ordered_file_name, '.*')}.args"
406
634
  file = Tempfile.new('arg')
407
635
  file.write(f[:metadata][:args])
408
- zf.add("./scripts/worker_finalization/#{arg_file}", file)
636
+ zf.add("scripts/worker_finalization/#{arg_file}", file)
409
637
  file.close
410
638
  end
411
639
  end
412
-
640
+
413
641
  ## Measures
414
642
  puts 'Adding Measures'
415
643
  added_measures = []
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2023, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -0,0 +1,138 @@
1
+ # *******************************************************************************
2
+ # OpenStudio(R), Copyright (c) 2008-2023, 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 HOLDERS AND CONTRIBUTORS "AS IS"
24
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER, THE UNITED STATES
27
+ # GOVERNMENT, OR ANY CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28
+ # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29
+ # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
33
+ # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
+ # *******************************************************************************
35
+
36
+ # OpenStudio::Analysis::ServerScripts is a container to hold the analysis and data_point server scripts.
37
+ module OpenStudio
38
+ module Analysis
39
+ class ServerScripts
40
+ attr_reader :files
41
+
42
+ # Create a new instance of the Server Scripts file class
43
+ # Server scripts are run at either the analysis or data_point level and are either initialization or finalization
44
+ # file: full path to the script
45
+ # arguments: array of arguments for the script
46
+ # init_or_final: specify either 'initialization' or 'finalization'
47
+ # server_or_data_point: specify either 'analysis' or 'data_point'
48
+ #
49
+ def initialize
50
+ @files = []
51
+ end
52
+
53
+ def add(file, arguments, init_or_final = 'initialization', server_or_data_point = 'data_point')
54
+
55
+ file_path = File.expand_path(file)
56
+ if !File.exist?(file_path)
57
+ raise ArgumentError, "File at '#{file_path}' does not exist"
58
+ end
59
+
60
+ if init_or_final != 'initialization' && init_or_final != 'finalization'
61
+ raise ArgumentError, "init_or_final must be 'initialization' or 'finalization'"
62
+ end
63
+
64
+ if server_or_data_point != 'analysis' && server_or_data_point != 'data_point'
65
+ raise ArgumentError, "server_or_data_point must be 'analysis' or 'data_point'"
66
+ end
67
+
68
+ if !arguments.is_a?(Array)
69
+ raise ArgumentError, "arguments must be an array"
70
+ end
71
+
72
+ file = {
73
+ file: file_path,
74
+ arguments: arguments,
75
+ init_or_final: init_or_final,
76
+ server_or_data_point: server_or_data_point
77
+ }
78
+ @files << file
79
+ true
80
+ end
81
+
82
+ # Check if the array is empty
83
+ def empty?
84
+ @files.empty?
85
+ end
86
+
87
+ # Return the first
88
+ def first
89
+ @files.first
90
+ end
91
+
92
+ # Return the last
93
+ def last
94
+ @files.last
95
+ end
96
+
97
+ # Access a file by an index
98
+ def [](index)
99
+ @files[index]
100
+ end
101
+
102
+ # Remove a file from the list
103
+ #
104
+ # @param filename [String] Full name of the file to remove
105
+ def remove(filename)
106
+ @files.delete_if { |f| f[:file] == filename }
107
+ end
108
+
109
+ # Return the number of files
110
+ #
111
+ # @return [Integer] Number of items
112
+ def size
113
+ @files.size
114
+ end
115
+
116
+ # Iterate over the files
117
+ def each
118
+ @files.each { |i| yield i }
119
+ end
120
+
121
+ # Iterate over the files with index
122
+ def each_with_index
123
+ @files.each_with_index { |d, index| yield d, index }
124
+ end
125
+
126
+ # remove all the items
127
+ def clear
128
+ @files.clear
129
+ end
130
+
131
+ # find the first object. There has to be a better way to do this. Can I just inherit an array?
132
+ def find
133
+ @files.find { |i| yield i }
134
+ end
135
+
136
+ end
137
+ end
138
+ end
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2023, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2023, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2023, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2023, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2023, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -37,6 +37,6 @@ module OpenStudio
37
37
  module Analysis
38
38
  # format should be ^.*\-{1}[a-z]+[0-9]+
39
39
  # for example: -rc1, -beta6, -customusecase0
40
- VERSION = '1.2.0'.freeze
40
+ VERSION = '1.3.1'.freeze
41
41
  end
42
42
  end
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2023, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2023, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -50,6 +50,11 @@ module OpenStudio
50
50
  attr_accessor :measure_definition_name_xml
51
51
  attr_accessor :measure_definition_uuid
52
52
  attr_accessor :measure_definition_version_uuid
53
+ attr_accessor :uuid
54
+ attr_accessor :version_uuid
55
+ attr_accessor :description
56
+ attr_accessor :taxonomy
57
+
53
58
  attr_reader :arguments
54
59
  attr_reader :variables
55
60
 
@@ -71,6 +76,10 @@ module OpenStudio
71
76
  @measure_definition_name_xml = nil
72
77
  @measure_definition_uuid = nil
73
78
  @measure_definition_version_uuid = nil
79
+ @uuid = nil
80
+ @version_uuid = nil
81
+ @description = nil
82
+ #@taxonomy = nil #BLB dont do this now
74
83
  @arguments = []
75
84
 
76
85
  @arguments << {
@@ -120,6 +129,16 @@ module OpenStudio
120
129
  v
121
130
  end
122
131
 
132
+ def remove_variable(variable_name)
133
+ v_index = @variables.find_index { |v| v[:argument][:name] == variable_name }
134
+ if v_index
135
+ @variables.delete_at(v_index)
136
+ return true
137
+ else
138
+ return false
139
+ end
140
+ end
141
+
123
142
  # Tag a measure's argument as a variable.
124
143
  #
125
144
  # @param argument_name [String] The instance_name of the measure argument that is to be tagged. This is the same name as the argument's variable in the measure.rb file.
@@ -215,12 +234,18 @@ module OpenStudio
215
234
  end
216
235
 
217
236
  # fix everything to support the legacy version
218
- hash[:variables] = @variables
237
+ # we need to make a deep copy since multiple calls to .to_hash deletes :type, :mode, etc below
238
+ # and we still want those args to be avail for future calls, but not end up in the final OSA hash.
239
+ # without this, the v.delete() below (line ~278-281) will remove :type from @variables.
240
+ # this would be okay if there was only 1 call to .to_hash. but thats not guaranteed
241
+ variables_dup = Marshal.load(Marshal.dump(@variables))
242
+ hash[:variables] = variables_dup
219
243
 
220
244
  # Clean up the variables to match the legacy format
221
245
  hash[:variables].each_with_index do |v, index|
222
246
  v[:variable_type] == 'pivot' ? v[:pivot] = true : v[:variable] = true
223
247
  v[:static_value] = v[:argument][:default_value] unless v[:static_value]
248
+ @variables[index][:static_value] = v[:static_value]
224
249
 
225
250
  v[:uncertainty_description] = {}
226
251
  # In Version 0.5 the _uncertain text will be removed from distribution
@@ -305,6 +330,10 @@ module OpenStudio
305
330
  s.measure_definition_name_xml = hash[:name_xml]
306
331
  s.measure_definition_uuid = hash[:uid]
307
332
  s.measure_definition_version_uuid = hash[:version_id]
333
+ s.uuid = hash[:uid]
334
+ s.version_uuid = hash[:version_id]
335
+ s.description = hash[:description]
336
+ #s.taxonomy = hash[:taxonomy] #BLB dont do this now
308
337
 
309
338
  # do not allow the choice variable_type
310
339
 
@@ -318,13 +347,30 @@ module OpenStudio
318
347
  var_type = 'string'
319
348
  end
320
349
 
350
+
351
+ if var_type.downcase == 'double'
352
+ default_value = arg[:default_value].to_f
353
+ elsif var_type.downcase == 'integer'
354
+ default_value = arg[:default_value].to_i
355
+ elsif var_type.downcase == 'boolean'
356
+ default_value = (arg[:default_value].downcase == "true") #convert the string 'true'/'false' to boolean
357
+ else
358
+ default_value = arg[:default_value]
359
+ end
360
+
361
+ if !arg[:display_name_short].nil?
362
+ display_name_short = arg[:display_name_short]
363
+ else
364
+ display_name_short = arg[:display_name]
365
+ end
366
+
321
367
  s.arguments << {
322
368
  display_name: arg[:display_name],
323
- display_name_short: arg[:display_name_short],
369
+ display_name_short: display_name_short,
324
370
  name: arg[:name],
325
371
  value_type: var_type,
326
- default_value: arg[:default_value],
327
- value: arg[:default_value]
372
+ default_value: default_value,
373
+ value: default_value
328
374
  }
329
375
  end
330
376
 
@@ -389,6 +435,10 @@ module OpenStudio
389
435
  s.measure_definition_name_xml = hash[:measure_definition_name_xml]
390
436
  s.measure_definition_uuid = hash[:measure_definition_uuid]
391
437
  s.measure_definition_version_uuid = hash[:measure_definition_version_uuid]
438
+ s.uuid = hash[:uuid] if hash[:uuid]
439
+ s.version_uuid = hash[:version_uuid] if hash[:version_uuid]
440
+ s.description = hash[:description] if hash[:description]
441
+ #s.taxonomy = hash[:taxonomy] if hash[:taxonomy] #BLB dont do this, its a Tags array of Tag
392
442
 
393
443
  s.type = hash[:measure_type] # this is actually the measure type
394
444
  hash[:arguments]&.each do |arg|
@@ -400,13 +450,33 @@ module OpenStudio
400
450
  var_type = 'string'
401
451
  end
402
452
 
453
+ if var_type.downcase == 'double'
454
+ default_value = arg[:default_value].to_f
455
+ value = arg[:value].to_f
456
+ elsif var_type.downcase == 'integer'
457
+ default_value = arg[:default_value].to_i
458
+ value = arg[:value].to_i
459
+ elsif var_type.downcase == 'boolean'
460
+ default_value = (arg[:default_value].downcase == "true") #convert the string 'true'/'false' to boolean
461
+ value = (arg[:value].downcase == "true") #convert the string 'true'/'false' to boolean
462
+ else
463
+ default_value = arg[:default_value]
464
+ value = arg[:value]
465
+ end
466
+
467
+ if !arg[:display_name_short].nil?
468
+ display_name_short = arg[:display_name_short]
469
+ else
470
+ display_name_short = arg[:display_name]
471
+ end
472
+
403
473
  s.arguments << {
404
474
  display_name: arg[:display_name],
405
- display_name_short: arg[:display_name_short],
475
+ display_name_short: display_name_short,
406
476
  name: arg[:name],
407
477
  value_type: var_type,
408
- default_value: arg[:default_value],
409
- value: arg[:value]
478
+ default_value: default_value,
479
+ value: value
410
480
  }
411
481
  end
412
482
 
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2023, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2023, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2023, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2023, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2023, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -1,5 +1,5 @@
1
1
  # *******************************************************************************
2
- # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
2
+ # OpenStudio(R), Copyright (c) 2008-2023, Alliance for Sustainable Energy, LLC.
3
3
  # All rights reserved.
4
4
  # Redistribution and use in source and binary forms, with or without
5
5
  # modification, are permitted provided that the following conditions are met:
@@ -61,6 +61,7 @@ require 'openstudio/analysis/formulation'
61
61
  require 'openstudio/analysis/workflow'
62
62
  require 'openstudio/analysis/workflow_step'
63
63
  require 'openstudio/analysis/algorithm_attributes'
64
+ require 'openstudio/analysis/server_scripts'
64
65
 
65
66
  # translators
66
67
  require 'openstudio/analysis/translator/excel'
@@ -30,6 +30,7 @@ Gem::Specification.new do |s|
30
30
  s.add_dependency 'rubyzip', '~> 2.3.0'
31
31
  s.add_dependency 'semantic', '~> 1.4'
32
32
 
33
+ s.add_development_dependency 'json-schema', '~> 2.8.0'
33
34
  s.add_development_dependency 'rake', '~> 13.0'
34
35
  s.add_development_dependency 'rspec', '~> 3.9'
35
36
  s.add_development_dependency 'rubocop', '~> 0.54.0'
data/update_license.rb CHANGED
@@ -6,7 +6,7 @@ js_regex = /^\/\* @preserve.*Copyright.*license.{2}\*\//m
6
6
 
7
7
  ruby_header_text = <<EOT
8
8
  # *******************************************************************************
9
- # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
9
+ # OpenStudio(R), Copyright (c) 2008-2023, Alliance for Sustainable Energy, LLC.
10
10
  # All rights reserved.
11
11
  # Redistribution and use in source and binary forms, with or without
12
12
  # modification, are permitted provided that the following conditions are met:
@@ -45,7 +45,7 @@ ruby_header_text.strip!
45
45
  erb_header_text = <<EOT
46
46
  <%
47
47
  # *******************************************************************************
48
- # OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC.
48
+ # OpenStudio(R), Copyright (c) 2008-2023, Alliance for Sustainable Energy, LLC.
49
49
  # All rights reserved.
50
50
  # Redistribution and use in source and binary forms, with or without
51
51
  # modification, are permitted provided that the following conditions are met:
@@ -84,7 +84,7 @@ erb_header_text.strip!
84
84
 
85
85
  js_header_text = <<EOT
86
86
  /* @preserve
87
- * OpenStudio(R), Copyright (c) 2008-2021, Alliance for Sustainable Energy, LLC. All rights reserved.
87
+ * OpenStudio(R), Copyright (c) 2008-2023, Alliance for Sustainable Energy, LLC. All rights reserved.
88
88
  * Use of this source code is governed by a BSD-style license that can be found at openstudio.net/license.
89
89
  */
90
90
  EOT
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openstudio-analysis
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nicholas Long
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-04-05 00:00:00.000000000 Z
11
+ date: 2023-03-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bcl
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '1.4'
97
+ - !ruby/object:Gem::Dependency
98
+ name: json-schema
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 2.8.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 2.8.0
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: rake
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -170,6 +184,7 @@ files:
170
184
  - lib/openstudio/analysis/algorithm_attributes.rb
171
185
  - lib/openstudio/analysis/formulation.rb
172
186
  - lib/openstudio/analysis/server_api.rb
187
+ - lib/openstudio/analysis/server_scripts.rb
173
188
  - lib/openstudio/analysis/support_files.rb
174
189
  - lib/openstudio/analysis/translator/datapoints.rb
175
190
  - lib/openstudio/analysis/translator/excel.rb
@@ -187,7 +202,7 @@ homepage: http://openstudio.nrel.gov
187
202
  licenses:
188
203
  - BSD
189
204
  metadata: {}
190
- post_install_message:
205
+ post_install_message:
191
206
  rdoc_options: []
192
207
  require_paths:
193
208
  - lib
@@ -203,7 +218,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
203
218
  version: '0'
204
219
  requirements: []
205
220
  rubygems_version: 3.1.4
206
- signing_key:
221
+ signing_key:
207
222
  specification_version: 4
208
223
  summary: Create JSON, ZIP to communicate with OpenStudio Distributed Analysis in the
209
224
  Cloud