openstudio-analysis 1.2.0 → 1.3.1

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