openstudio-analysis 0.4.2 → 0.4.3

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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/README.md +6 -1
  4. data/lib/openstudio-analysis.rb +4 -0
  5. data/lib/openstudio/analysis.rb +16 -0
  6. data/lib/openstudio/analysis/algorithm_attributes.rb +4 -0
  7. data/lib/openstudio/analysis/formulation.rb +115 -49
  8. data/lib/openstudio/analysis/server_api.rb +151 -12
  9. data/lib/openstudio/analysis/support_files.rb +21 -3
  10. data/lib/openstudio/analysis/translator/excel.rb +84 -299
  11. data/lib/openstudio/analysis/version.rb +1 -1
  12. data/lib/openstudio/analysis/workflow.rb +79 -33
  13. data/lib/openstudio/analysis/workflow_step.rb +165 -39
  14. data/lib/openstudio/helpers/string.rb +1 -1
  15. data/lib/openstudio/weather/epw.rb +193 -0
  16. data/spec/files/0_1_09_outputvars.xlsx +0 -0
  17. data/spec/files/0_1_09_setup_version_2.xlsx +0 -0
  18. data/spec/files/0_3_0_dynamic_uuids.xlsx +0 -0
  19. data/spec/files/0_3_0_outputs.xlsx +0 -0
  20. data/spec/files/0_3_3_short_names.xlsx +0 -0
  21. data/spec/files/0_3_5_multiple_measure_paths.xlsx +0 -0
  22. data/spec/files/0_3_7_unique_measure_names.xlsx +0 -0
  23. data/spec/files/0_3_7_worker_init_final.xlsx +0 -0
  24. data/spec/files/0_4_0_multiple_seeds.xlsx +0 -0
  25. data/spec/files/0_4_0_pivot_test.xlsx +0 -0
  26. data/spec/files/analysis/examples/medium_office_workflow.json +1298 -0
  27. data/spec/files/analysis/medium_office.json +666 -603
  28. data/spec/files/analysis/medium_office.zip +0 -0
  29. data/spec/files/analysis/name_goes_here.json +1752 -0
  30. data/spec/files/{export/analysis/small_seed.zip → analysis/name_goes_here.zip} +0 -0
  31. data/spec/files/export/analysis/0_1_09_outputvars.json +265 -230
  32. data/spec/files/export/analysis/0_1_09_outputvars.zip +0 -0
  33. data/spec/files/export/analysis/{71bebb0a-34b7-404b-b430-0ee7dab962ff.json → 0_3_0_dynamic_uuids.json} +684 -590
  34. data/spec/files/export/analysis/{67e3ba4a-2660-41b6-a7c5-d4457a4275c4.zip → 0_3_0_dynamic_uuids.zip} +0 -0
  35. data/spec/files/export/analysis/0_3_0_outputs.json +684 -590
  36. data/spec/files/export/analysis/0_3_0_outputs.zip +0 -0
  37. data/spec/files/export/analysis/{5b5264db-a31e-4bab-931b-94101bd23b80.json → 0_3_3_short_names.json} +697 -622
  38. data/spec/files/export/analysis/{1d8d62bb-f058-4c38-893b-8eaa7ceea254.zip → 0_3_3_short_names.zip} +0 -0
  39. data/spec/files/export/analysis/{1d8d62bb-f058-4c38-893b-8eaa7ceea254.json → 0_3_5_multiple_measure_paths.json} +717 -602
  40. data/spec/files/export/analysis/{5b5264db-a31e-4bab-931b-94101bd23b80.zip → 0_3_5_multiple_measure_paths.zip} +0 -0
  41. data/spec/files/export/analysis/{67e3ba4a-2660-41b6-a7c5-d4457a4275c4.json → 0_3_7_worker_init_final.json} +708 -613
  42. data/spec/files/export/analysis/{71bebb0a-34b7-404b-b430-0ee7dab962ff.zip → 0_3_7_worker_init_final.zip} +0 -0
  43. data/spec/files/export/analysis/{0_1_11_discrete_variables.json → example_analysis.json} +279 -214
  44. data/spec/files/export/analysis/{0_1_11_discrete_variables.zip → example_analysis.zip} +0 -0
  45. data/spec/files/export/analysis/{discrete_lhs_example.json → lhs_discrete_and_continuous_variables.json} +549 -436
  46. data/spec/files/export/analysis/{discrete_lhs_example.zip → lhs_discrete_and_continuous_variables.zip} +0 -0
  47. data/spec/files/export/analysis/lhs_discrete_and_continuous_variables_f4a73fc4-0514-4033-b54d-d1c58c77c724.json +1298 -0
  48. data/spec/files/export/analysis/lhs_discrete_and_continuous_variables_f4a73fc4-0514-4033-b54d-d1c58c77c724.zip +0 -0
  49. data/spec/files/export/analysis/lhs_discrete_and_continuous_variables_model_-_1.json +1298 -0
  50. data/spec/files/export/analysis/lhs_discrete_and_continuous_variables_model_-_1.zip +0 -0
  51. data/spec/files/export/analysis/lhs_discrete_and_continuous_variables_something_else.json +1298 -0
  52. data/spec/files/export/analysis/lhs_discrete_and_continuous_variables_something_else.zip +0 -0
  53. data/spec/files/export/analysis/pivot_test.json +1323 -0
  54. data/spec/files/export/analysis/pivot_test.zip +0 -0
  55. data/spec/files/export/analysis/{0_2_0_template_simpletest.json → simple_test.json} +201 -178
  56. data/spec/files/export/analysis/{0_2_0_template_simpletest.zip → simple_test.zip} +0 -0
  57. data/spec/files/export/analysis/{0_1_12_discrete_dynamic_columns.json → test_model.json} +189 -167
  58. data/spec/files/export/analysis/{0_1_12_discrete_dynamic_columns.zip → test_model.zip} +0 -0
  59. data/spec/files/export/weather/weather_out.epw +32 -0
  60. data/spec/files/export/weather/weather_out_appended.epw +56 -0
  61. data/spec/files/export/workflow/analysis.json +0 -1
  62. data/spec/files/measures/reduce_space_infiltration_by_percentage/measure.rb +5 -0
  63. data/spec/files/measures/reduce_space_infiltration_by_percentage/measure.xml +1 -0
  64. data/spec/files/measures/rotate_building/measure.rb +5 -0
  65. data/spec/files/measures/rotate_building/measure.xml +1 -0
  66. data/spec/files/measures/set_window_to_wall_ratio_by_facade/measure.rb +5 -0
  67. data/spec/files/measures/set_window_to_wall_ratio_by_facade/measure.xml +1 -0
  68. data/spec/files/partial_weather.epw +32 -32
  69. data/spec/openstudio/excel_spec.rb +103 -69
  70. data/spec/openstudio/formulation_spec.rb +28 -14
  71. data/spec/openstudio/support_files_spec.rb +2 -2
  72. data/spec/openstudio/weather_spec.rb +45 -0
  73. data/spec/openstudio/workflow_spec.rb +2 -1
  74. data/spec/openstudio/workflow_step_spec.rb +24 -22
  75. data/spec/reports/SPEC-OpenStudio-Analysis-Formulation.xml +59 -10
  76. data/spec/reports/SPEC-OpenStudio-Analysis-ServerApi-create-a-new-object-instance.xml +2 -2
  77. data/spec/reports/SPEC-OpenStudio-Analysis-ServerApi-test-not-localhost.xml +2 -2
  78. data/spec/reports/SPEC-OpenStudio-Analysis-ServerApi.xml +1 -1
  79. data/spec/reports/SPEC-OpenStudio-Analysis-SupportFiles.xml +6 -6
  80. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-discrete-variables.xml +25 -7
  81. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-discrete-with-dynamic-columns.xml +18 -5
  82. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-no-variables-defined.xml +5 -8
  83. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-proxy-setup-with-user.xml +2 -2
  84. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-proxy-setup.xml +2 -2
  85. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-setup-output-variables.xml +29 -12
  86. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-setup-version-0-1-9.xml +5 -5
  87. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-small-list-of-incomplete-variables.xml +2 -2
  88. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-small-list-of-variables-should-not-validate.xml +2 -2
  89. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-small-list-of-variables.xml +26 -9
  90. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-small-list-with-with-repeated-variable-names.xml +2 -2
  91. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-version-0-1-10.xml +3 -7
  92. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-version-0-2-0-simple.xml +20 -9
  93. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-version-0-2-0.xml +35 -10
  94. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-version-0-3-0-dynamic-uuid-assignments.xml +47 -5
  95. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-version-0-3-0-measure-existence-checks.xml +3 -6
  96. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-version-0-3-0-objective-functions.xml +48 -10
  97. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-version-0-3-3-and-short-display-names.xml +48 -6
  98. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-version-0-3-5-and-measure-paths.xml +48 -8
  99. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-version-0-3-7-and-worker-init-final-scripts.0.xml +55 -6
  100. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-version-0-3-7-and-worker-init-final-scripts.xml +51 -8
  101. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-version-0-4-0-multiple-seed-models.xml +165 -0
  102. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel-version-0-4-0-pivot-test.xml +60 -0
  103. data/spec/reports/SPEC-OpenStudio-Analysis-Translator-Excel.xml +1 -1
  104. data/spec/reports/SPEC-OpenStudio-Analysis-Workflow.xml +7 -7
  105. data/spec/reports/SPEC-OpenStudio-Analysis-WorkflowStep.xml +8 -14
  106. data/spec/reports/SPEC-OpenStudio-Weather-Epw.xml +9 -0
  107. metadata +97 -50
  108. data/spec/files/export/analysis/small_seed.json +0 -593
@@ -4,7 +4,6 @@
4
4
  module OpenStudio
5
5
  module Analysis
6
6
  class SupportFiles
7
-
8
7
  attr_reader :files
9
8
 
10
9
  # Create a new instance of the support file class
@@ -24,7 +23,7 @@ module OpenStudio
24
23
 
25
24
  # only add if it isn't allready in the list
26
25
  if @files.find_all { |f| f[:file] == path_or_filename }.empty?
27
- @files << {file: path_or_filename, metadata: metadata}
26
+ @files << { file: path_or_filename, metadata: metadata }
28
27
  end
29
28
 
30
29
  true
@@ -33,7 +32,7 @@ module OpenStudio
33
32
  # Add a glob path with the same metadata for all the items
34
33
  #
35
34
  # @param pattern [String] Pattern to glob. example: /home/user1/files/**/*.rb
36
- # @return [Boolean] Returns false if the file does not exist
35
+ # @return [Boolean] Always returns true
37
36
  def add_files(pattern, metadata = {})
38
37
  Dir[pattern].each do |f|
39
38
  add(f, metadata)
@@ -42,6 +41,16 @@ module OpenStudio
42
41
  true
43
42
  end
44
43
 
44
+ # Return the first
45
+ def first
46
+ @files.first
47
+ end
48
+
49
+ # Return the last
50
+ def last
51
+ @files.last
52
+ end
53
+
45
54
  # Access a file by an index
46
55
  def [](index)
47
56
  @files[index]
@@ -66,11 +75,20 @@ module OpenStudio
66
75
  @files.each { |i| yield i }
67
76
  end
68
77
 
78
+ # Iterate over the files with index
79
+ def each_with_index
80
+ @files.each_with_index { |d, index| yield d, index }
81
+ end
82
+
69
83
  # remove all the items
70
84
  def clear
71
85
  @files.clear
72
86
  end
73
87
 
88
+ # find the first object. There has to be a better way to do this. Can I just inherit an array?
89
+ def find
90
+ @files.find { |i| yield i }
91
+ end
74
92
  end
75
93
  end
76
94
  end
@@ -9,6 +9,7 @@ module OpenStudio
9
9
  attr_reader :models
10
10
  attr_reader :weather_files
11
11
  attr_reader :measure_paths
12
+ attr_reader :weather_paths
12
13
  attr_reader :worker_inits
13
14
  attr_reader :worker_finals
14
15
  attr_reader :export_path
@@ -22,7 +23,6 @@ module OpenStudio
22
23
  # remove these once we have classes to construct the JSON file
23
24
  attr_accessor :name
24
25
  attr_reader :analysis_name
25
- attr_reader :template_json
26
26
 
27
27
  # methods to override instance variables
28
28
 
@@ -41,11 +41,13 @@ module OpenStudio
41
41
 
42
42
  # Initialize some other instance variables
43
43
  @version = '0.0.1'
44
+ @analyses = [] # Array o OpenStudio::Analysis. Use method to access
44
45
  @name = nil
45
46
  @analysis_name = nil
46
47
  @cluster_name = nil
47
48
  @settings = {}
48
- @weather_files = []
49
+ @weather_files = [] # remove this from excel!
50
+ @weather_paths = []
49
51
  @models = []
50
52
  @other_files = []
51
53
  @worker_inits = []
@@ -55,7 +57,6 @@ module OpenStudio
55
57
  @number_of_samples = 0 # todo: remove this
56
58
  @problem = {}
57
59
  @algorithm = {}
58
- @template_json = nil
59
60
  @outputs = {}
60
61
  @run_setup = {}
61
62
  @aws_tags = []
@@ -90,12 +91,6 @@ module OpenStudio
90
91
  }
91
92
  end
92
93
 
93
- # Save off the legacy format of the JSON file
94
- def save_variable_json(filename)
95
- FileUtils.rm_f(filename) if File.exist?(filename)
96
- File.open(filename, 'w') { |f| f << JSON.pretty_generate(@variables) }
97
- end
98
-
99
94
  def validate_analysis
100
95
  # Setup the paths and do some error checking
101
96
  @measure_paths.each do |mp|
@@ -199,309 +194,103 @@ module OpenStudio
199
194
  true
200
195
  end
201
196
 
202
- def create_analysis_hash
203
- # save the format in the OpenStudio analysis json format template without
204
- # the correct weather files or models
205
- @template_json = translate_to_analysis_json_template
206
-
207
- # save the other format for now
208
- translate_to_analysis
209
-
210
- @template_json
211
- end
212
-
213
- # save_analysis will iterate over each model that is defined in the spreadsheet and save the
214
- # zip and json file.
215
- def save_analysis
216
- @template_json = create_analysis_hash
197
+ # convert the data in excel's parsed data into an OpenStudio Analysis Object
198
+ # @seed_model [Hash] Seed model to set the new analysis to
199
+ # @append_model_name [Boolean] Append the name of the seed model to the display name
200
+ # @return [Object] An OpenStudio::Analysis
201
+ def analysis(seed_model = nil, append_model_name = false)
202
+ fail 'There are no seed models defined in the excel file. Please add one.' if @models.size == 0
203
+ fail "There are more than one seed models defined in the excel file. Call 'analyses' to return the array" if @models.size > 1 && seed_model.nil?
217
204
 
218
- # validate_template_json
205
+ seed_model = @models.first if seed_model.nil?
219
206
 
220
- # iterate over each model and save the zip and json
221
- @models.each do |model|
222
- puts "Creating JSON and ZIP file for #{@name}:#{model[:display_name]}"
223
- save_analysis_zip(model)
224
- analysis_json = create_analysis_json(@template_json, model, @models.count > 1)
225
- end
226
- end
207
+ # Use the programmatic interface to make the analysis
208
+ # append the model name to the analysis name if requested (normally if there are more than 1 models in the spreadsheet)
209
+ display_name = append_model_name ? @name + ' ' + seed_model[:display_name] : @name
227
210
 
228
- # New method that uses the objects to hold the analysis
229
- def translate_to_analysis
230
- # Use the programmatic interface to make the analysis json now
231
- analysis = OpenStudio::Analysis.create(@analysis_name)
211
+ a = OpenStudio::Analysis.create(display_name)
232
212
 
233
213
  @variables['data'].each do |measure|
234
214
  next unless measure['enabled']
235
215
 
236
- # TODO: make this read the measure.rb file, then override any of the differences. That is call workflow.add_from_measure_path
237
- analysis.workflow.add_measure_from_excel(measure)
238
- end
239
-
240
- # Add in the outputs
241
-
242
- @outputs['output_variables'].each do |o|
243
- o = Hash[o.map { |k, v| [k.to_sym, v] }]
244
- analysis.add_output(o)
245
- end
246
-
247
- # Temp save of the json file
248
- # analysis.save("#{analysis.display_name}_api.json")
249
-
250
- analysis
251
- end
252
-
253
- def translate_to_analysis_json_template
254
- # Load in the templates for constructing the JSON file
255
- template_root = File.join(File.dirname(__FILE__), '../../templates')
256
- analysis_template = ERB.new(File.open("#{template_root}/analysis.json.erb", 'r').read)
257
- workflow_template = ERB.new(File.open("#{template_root}/workflow_item.json.erb", 'r').read)
258
- uncertain_variable_template = ERB.new(File.open("#{template_root}/uncertain_variable.json.erb", 'r').read)
259
- discrete_uncertain_variable_template = ERB.new(File.open("#{template_root}/discrete_uncertain_variable.json.erb", 'r').read)
260
- pivot_variable_template = ERB.new(File.open("#{template_root}/pivot_variable.json.erb", 'r').read)
261
- argument_template = ERB.new(File.read("#{template_root}/argument.json.erb"))
262
-
263
- # Templated analysis json file (this is what is returned)
264
- openstudio_analysis_json = JSON.parse(analysis_template.result(get_binding))
265
-
266
- openstudio_analysis_json['analysis']['problem'].merge!(@problem)
267
- openstudio_analysis_json['analysis']['problem']['algorithm'].merge!(@algorithm)
268
- openstudio_analysis_json['analysis'].merge!(@outputs)
269
-
270
- @measure_index = -1
271
- @variables['data'].each do |measure|
272
- # With OpenStudio server we need to create the workflow with all the measure instances
273
- if measure['enabled']
274
- @measure_index += 1
275
-
276
- # puts " Adding measure item '#{measure['name']}' to analysis.json"
277
- @measure = measure
278
- @measure['measure_file_name_dir'] = @measure['measure_file_name'].underscore
279
-
280
- # Grab the measure json file out of the right directory
281
- wf = JSON.parse(workflow_template.result(get_binding))
282
-
283
- # add in the variables
284
- measure['variables'].each do |variable|
285
- @variable = variable
286
- # Determine if row is suppose to be an argument or a variable to be perturbed.
287
- if @variable['variable_type'] == 'argument'
288
- ag = nil
289
- if @variable['distribution']['static_value'].nil? || @variable['distribution']['static_value'] == 'null'
290
- puts " Warning: '#{measure['name']}:#{@variable['name']}' static value was empty or null, assuming optional and skipping"
291
- next
292
- end
293
-
294
- # add this as an argument
295
- case @variable['type'].downcase
296
- when 'string', 'choice'
297
- @static_value = @variable['distribution']['static_value'].inspect
298
- else
299
- @static_value = @variable['distribution']['static_value']
300
- end
301
- ag = JSON.parse(argument_template.result(get_binding))
302
- fail "Argument '#{@variable['name']}' did not process. Most likely it did not have all parameters defined." if ag.nil?
303
- wf['arguments'] << ag
304
- else # must be a variable [either pivot or normal variable]
305
- vr = nil
306
- # add this as an argument
307
- case @variable['type'].downcase
308
- when 'string', 'choice'
309
- @static_value = @variable['distribution']['static_value'].inspect
310
- else
311
- @static_value = @variable['distribution']['static_value']
312
- end
313
-
314
- # TODO: remove enum and choice as this is not the variable type
315
- if @variable['type'] == 'enum' || @variable['type'].downcase == 'choice'
316
- @values_and_weights = @variable['distribution']['enumerations'].map { |v| { value: v } }.to_json
317
- vr = JSON.parse(discrete_uncertain_variable_template.result(get_binding))
318
- elsif @variable['distribution']['type'] == 'discrete_uncertain'
319
- # puts @variable.inspect
320
- if @variable['distribution']['discrete_weights']
321
- fail "Discrete variable '#{@variable['name']}' does not have equal length of values and weights" if @variable['distribution']['discrete_values'].size != @variable['distribution']['discrete_weights'].size
322
- @values_and_weights = @variable['distribution']['discrete_values'].zip(@variable['distribution']['discrete_weights']).map { |v, w| { value: v, weight: w } }.to_json
323
- else
324
- @values_and_weights = @variable['distribution']['discrete_values'].map { |v| { value: v } }.to_json
325
- end
326
-
327
- if @variable['variable_type'] == 'pivot'
328
-
329
- vr = JSON.parse(pivot_variable_template.result(get_binding))
330
- else
331
- vr = JSON.parse(discrete_uncertain_variable_template.result(get_binding))
332
- end
333
- else
334
- if @variable['variable_type'] == 'pivot'
335
- fail 'Currently unable to pivot on continuous variables... stay tuned.'
336
- else
337
- vr = JSON.parse(uncertain_variable_template.result(get_binding))
338
- end
339
- end
340
- fail 'variable was nil after processing' if vr.nil?
341
- wf['variables'] << vr
216
+ @measure_paths.each do |measure_path|
217
+ measure_dir_to_add = "#{measure_path}/#{measure['measure_file_name_directory']}"
218
+ if Dir.exist? measure_dir_to_add
219
+ if File.exist? "#{measure_dir_to_add}/measure.rb"
220
+ measure['local_path_to_measure'] = "#{measure_dir_to_add}/measure.rb"
221
+ break
222
+ else
223
+ fail "Measure in directory '#{measure_dir_to_add}' did not contain a measure.rb file"
342
224
  end
343
225
  end
344
-
345
- openstudio_analysis_json['analysis']['problem']['workflow'] << wf
346
226
  end
347
- end
348
227
 
349
- openstudio_analysis_json
350
- end
228
+ fail "Could not find measure '#{measure['name']}' in directory named '#{measure['measure_file_name_directory']}' in the measure paths '#{@measure_paths.join(', ')}'" unless measure['local_path_to_measure']
351
229
 
352
- protected
353
-
354
- # helper method for ERB
355
- def get_binding
356
- binding
357
- end
358
-
359
- # Package up the seed, weather files, and measures
360
- def save_analysis_zip(model)
361
- def add_directory_to_zip(zipfile, local_directory, relative_zip_directory)
362
- # puts "Add Directory #{local_directory}"
363
- Dir[File.join("#{local_directory}", '**', '**')].each do |file|
364
- # puts "Adding File #{file}"
365
- zipfile.add(file.sub(local_directory, relative_zip_directory), file)
366
- end
367
- zipfile
230
+ a.workflow.add_measure_from_excel(measure)
368
231
  end
369
232
 
370
- zipfile_name = "#{@export_path}/#{model[:name]}.zip"
371
- FileUtils.rm_f(zipfile_name) if File.exist?(zipfile_name)
372
-
373
- Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile|
374
- @weather_files.each do |filename|
375
- # puts " Adding #{filename}"
376
- zipfile.add("./weather/#{File.basename(filename)}", filename)
377
- end
378
-
379
- # Add only the measures that are defined in the spreadsheet
380
- required_measures = @variables['data'].map { |v| v['measure_file_name_directory'] if v['enabled'] }.compact.uniq
381
-
382
- # Convert this into a hash which looks like {name: measure_name}. This will allow us to add more
383
- # fields to the measure, such as which directory is the measure.
384
- required_measures = required_measures.map { |value| { name: value } }
385
-
386
- # first validate that all the measures exist
387
- errors = []
388
- required_measures.each do |measure|
389
- next if measure.key? :path
390
-
391
- @measure_paths.each do |measure_path|
392
- measure_dir_to_add = "#{measure_path}/#{measure[:name]}"
393
- if Dir.exist? measure_dir_to_add
394
- if File.exist? "#{measure_dir_to_add}/measure.rb"
395
- measure[:path] = measure_path
396
- break
397
- else
398
- errors << "Measure in directory '#{@measure_path}/#{measure}' did not contain a measure.rb file"
399
- end
400
- end
401
- end
402
- end
403
-
404
- # validate that all measures were found
405
- required_measures.each do |measure|
406
- unless measure.key? :path
407
- errors << "Could not find measure '#{measure}' in directory '#{@measure_path}'"
408
- end
409
- end
233
+ @other_files.each do |library|
234
+ a.libraries.add(library[:path], library_name: library[:lib_zip_name])
235
+ end
410
236
 
411
- fail errors.join("\n") unless errors.empty?
237
+ @worker_inits.each do |w|
238
+ a.worker_inits.add(w[:path], args: w[:args])
239
+ end
412
240
 
413
- required_measures.each do |measure|
414
- measure_dir_to_add = "#{measure[:path]}/#{measure[:name]}"
415
- puts " Adding measure #{measure_dir_to_add} to zip file"
416
- Dir[File.join(measure_dir_to_add, '**')].each do |file|
417
- if File.directory?(file)
418
- if File.basename(file) == 'resources' || File.basename(file) == 'lib'
419
- add_directory_to_zip(zipfile, file, "./measures/#{measure[:name]}/#{File.basename(file)}")
420
- else
421
- # puts "Skipping Directory #{File.basename(file)}"
422
- end
423
- else
424
- # puts "Adding File #{file}"
425
- # added_measures << measure_dir unless added_measures.include? measure_dir
426
- zipfile.add(file.sub(measure_dir_to_add, "./measures/#{measure[:name]}/"), file)
427
- end
428
- end
429
- end
241
+ @worker_finals.each do |w|
242
+ a.worker_finalizes.add(w[:path], args: w[:args])
243
+ end
430
244
 
431
- # puts "Adding #{model[:path]}"
432
- zipfile.add("./seed/#{File.basename(model[:path])}", model[:path])
245
+ # Add in the outputs
246
+ @outputs['output_variables'].each do |o|
247
+ o = Hash[o.map { |k, v| [k.to_sym, v] }]
248
+ a.add_output(o)
249
+ end
433
250
 
434
- # puts "Adding in other files #{@other_files.inspect}"
435
- @other_files.each do |others|
436
- Dir[File.join(others[:path], '**', '**')].each do |file|
437
- zipfile.add(file.sub(others[:path], "./lib/#{others[:lib_zip_name]}/"), file)
438
- end
439
- end
251
+ a.analysis_type = @problem['analysis_type']
252
+ @algorithm.each do |k, v|
253
+ a.algorithm.set_attribute(k, v)
254
+ end
440
255
 
441
- # puts "Adding in Worker initialize scripts #{@worker_inits}"
442
- @worker_inits.each_with_index do |f, index|
443
- # this is ordered
444
- f[:ordered_file_name] = "#{index.to_s.rjust(2, '0')}_#{File.basename(f[:path])}"
445
- f[:index] = index
446
-
447
- zipfile.add(f[:path].sub(f[:path], "./lib/worker_initialize/#{f[:ordered_file_name]}"), f[:path])
448
- arg_file = "#{File.basename(f[:ordered_file_name], '.*')}.args"
449
- file = Tempfile.new('arg')
450
- file.write(f[:args])
451
- zipfile.add("./lib/worker_initialize/#{arg_file}", file)
452
- file.close
453
- end
256
+ # clear out the seed files before adding new ones
257
+ a.seed_model = seed_model[:path]
454
258
 
455
- # puts "Adding in Worker finalize scripts #{@worker_finals}"
456
- @worker_finals.each_with_index do |f, index|
457
- # this is ordered
458
- f[:ordered_file_name] = "#{index.to_s.rjust(2, '0')}_#{File.basename(f[:path])}"
459
- f[:index] = index
460
-
461
- zipfile.add(f[:path].sub(f[:path], "./lib/worker_finalize/#{f[:ordered_file_name]}"), f[:path])
462
- arg_file = "#{File.basename(f[:ordered_file_name], '.*')}.args"
463
- file = Tempfile.new('arg')
464
- file.write(f[:args])
465
- zipfile.add("./lib/worker_finalize/#{arg_file}", file)
466
- file.close
467
- end
259
+ # clear out the weather files before adding new ones
260
+ a.weather_files.clear
261
+ @weather_paths.each do |wp|
262
+ a.weather_files.add_files(wp)
468
263
  end
469
- end
470
264
 
471
- def create_analysis_json(analysis_json, model, append_model_name)
472
- def deep_copy(o)
473
- Marshal.load(Marshal.dump(o))
474
- end
265
+ a
266
+ end
475
267
 
476
- # append the model name to the analysis name if requested (normally if there are more than
477
- # 1 models in the spreadsheet)
478
- new_analysis_json = deep_copy(analysis_json)
479
- if append_model_name
480
- new_analysis_json['analysis']['display_name'] = new_analysis_json['analysis']['display_name'] + ' - ' + model[:display_name]
481
- new_analysis_json['analysis']['name'] = new_analysis_json['analysis']['name'] + '_' + model[:name]
268
+ # Return an array of analyses objects of OpenStudio::Analysis::Formulation
269
+ def analyses
270
+ as = []
271
+ @models.map do |model|
272
+ as << analysis(model, @models.count > 1)
482
273
  end
483
274
 
484
- # Set the seed model in the analysis_json
485
- new_analysis_json['analysis']['seed']['file_type'] = model[:type]
486
- # This is the path that will be seen on the server when this runs
487
- new_analysis_json['analysis']['seed']['path'] = "./seed/#{File.basename(model[:path])}"
275
+ as
276
+ end
488
277
 
489
- # Set the weather file as the first in the list -- this is optional
490
- new_analysis_json['analysis']['weather_file']['file_type'].downcase == 'epw'
491
- if File.extname(@weather_files.first) =~ /.zip/i
492
- new_analysis_json['analysis']['weather_file']['path'] = "./weather/#{File.basename(@weather_files.first, '.zip')}.epw"
493
- else
494
- # get the first EPW file (not the first file)
495
- weather = @weather_files.find { |w| File.extname(w).downcase == '.epw' }
496
- fail "Could not find a weather file (*.epw) in weather directory #{File.dirname(@weather_files.first)}" unless weather
497
- new_analysis_json['analysis']['weather_file']['path'] = "./weather/#{File.basename(weather)}"
278
+ # save_analysis will iterate over each model that is defined in the spreadsheet and save the
279
+ # zip and json file.
280
+ def save_analysis
281
+ analyses.each do |a|
282
+ puts "Saving JSON and ZIP file for #{@name}:#{a.display_name}"
283
+ json_file_name = "#{@export_path}/#{a.name}.json"
284
+ FileUtils.rm_f(json_file_name) if File.exist?(json_file_name)
285
+ # File.open(json_file_name, 'w') { |f| f << JSON.pretty_generate(new_analysis_json) }
286
+
287
+ a.save json_file_name
288
+ a.save_zip "#{File.dirname(json_file_name)}/#{File.basename(json_file_name, '.*')}.zip"
498
289
  end
499
-
500
- json_file_name = "#{@export_path}/#{model[:name]}.json"
501
- FileUtils.rm_f(json_file_name) if File.exist?(json_file_name)
502
- File.open(json_file_name, 'w') { |f| f << JSON.pretty_generate(new_analysis_json) }
503
290
  end
504
291
 
292
+ protected
293
+
505
294
  # parse_setup will pull out the data on the "setup" tab and store it in memory for later use
506
295
  def parse_setup
507
296
  rows = @xls.sheet('Setup').parse
@@ -680,6 +469,7 @@ module OpenStudio
680
469
  unless (Pathname.new weather_path).absolute?
681
470
  weather_path = File.expand_path(File.join(@root_path, weather_path))
682
471
  end
472
+ @weather_paths << weather_path
683
473
  @weather_files += Dir.glob(weather_path)
684
474
  end
685
475
  elsif b_models
@@ -736,12 +526,13 @@ module OpenStudio
736
526
  # If you add a new column and you want that variable in the hash, then you must add it here.
737
527
  # rows = @xls.sheet('Variables').parse(:enabled => "# variable")
738
528
  # puts rows.inspect
529
+
739
530
  rows = nil
740
531
  begin
741
532
  if @version >= '0.3.3'.to_version
742
533
  rows = @xls.sheet('Variables').parse(enabled: '# variable',
743
534
  measure_name_or_var_type: 'type',
744
- measure_file_name_or_var_display_name: 'parameter display name.*',
535
+ measure_file_name_or_var_display_name: 'parameter display name*',
745
536
  measure_file_name_directory: 'measure directory',
746
537
  measure_type_or_parameter_name_in_measure: 'parameter name in measure',
747
538
  display_name_short: 'parameter short display name',
@@ -765,7 +556,7 @@ module OpenStudio
765
556
  elsif @version >= '0.3.0'.to_version
766
557
  rows = @xls.sheet('Variables').parse(enabled: '# variable',
767
558
  measure_name_or_var_type: 'type',
768
- measure_file_name_or_var_display_name: 'parameter display name.*',
559
+ measure_file_name_or_var_display_name: 'parameter display name*',
769
560
  measure_file_name_directory: 'measure directory',
770
561
  measure_type_or_parameter_name_in_measure: 'parameter name in measure',
771
562
  # sampling_method: 'sampling method',
@@ -788,7 +579,7 @@ module OpenStudio
788
579
  elsif @version >= '0.2.0'.to_version
789
580
  rows = @xls.sheet('Variables').parse(enabled: '# variable',
790
581
  measure_name_or_var_type: 'type',
791
- measure_file_name_or_var_display_name: 'parameter display name.*',
582
+ measure_file_name_or_var_display_name: 'parameter display name*',
792
583
  measure_file_name_directory: 'measure directory',
793
584
  measure_type_or_parameter_name_in_measure: 'parameter name in measure',
794
585
  sampling_method: 'sampling method',
@@ -811,7 +602,7 @@ module OpenStudio
811
602
  elsif @version >= '0.1.12'.to_version
812
603
  rows = @xls.sheet('Variables').parse(enabled: '# variable',
813
604
  measure_name_or_var_type: 'type',
814
- measure_file_name_or_var_display_name: 'parameter display name.*',
605
+ measure_file_name_or_var_display_name: 'parameter display name*',
815
606
  measure_type_or_parameter_name_in_measure: 'parameter name in measure',
816
607
  sampling_method: 'sampling method',
817
608
  variable_type: 'Variable Type',
@@ -833,7 +624,7 @@ module OpenStudio
833
624
  elsif @version >= '0.1.11'.to_version
834
625
  rows = @xls.sheet('Variables').parse(enabled: '# variable',
835
626
  measure_name_or_var_type: 'type',
836
- measure_file_name_or_var_display_name: 'parameter display name.*',
627
+ measure_file_name_or_var_display_name: 'parameter display name*',
837
628
  measure_type_or_parameter_name_in_measure: 'parameter name in measure',
838
629
  sampling_method: 'sampling method',
839
630
  variable_type: 'Variable Type',
@@ -855,7 +646,7 @@ module OpenStudio
855
646
  else
856
647
  rows = @xls.sheet('Variables').parse(enabled: '# variable',
857
648
  measure_name_or_var_type: 'type',
858
- measure_file_name_or_var_display_name: 'parameter display name.*',
649
+ measure_file_name_or_var_display_name: 'parameter display name*',
859
650
  measure_type_or_parameter_name_in_measure: 'parameter name in measure',
860
651
  sampling_method: 'sampling method',
861
652
  variable_type: 'Variable Type',
@@ -876,7 +667,7 @@ module OpenStudio
876
667
  clean: true)
877
668
  end
878
669
  rescue => e
879
- raise "#{e.message} with Spreadsheet #{@xls_filename} with Version #{@version} "
670
+ raise "Unable to parse spreadsheet #{@xls_filename} with version #{@version} due to error: #{e.message}"
880
671
  end
881
672
 
882
673
  fail "Could not find the sheet name 'Variables' in excel file #{@root_path}" unless rows
@@ -909,7 +700,9 @@ module OpenStudio
909
700
 
910
701
  # parse the choices/enums
911
702
  if var['type'] == 'enum' || var['type'] == 'choice' # this is now a choice
912
- var['distribution']['enumerations'] = row[:enums].gsub('|', '').split(',').map(&:strip)
703
+ if row[:enums]
704
+ var['distribution']['enumerations'] = row[:enums].gsub('|', '').split(',').map(&:strip)
705
+ end
913
706
  elsif var['type'] == 'bool'
914
707
  var['distribution']['enumerations'] = []
915
708
  var['distribution']['enumerations'] << 'true' # TODO: should this be a real bool?
@@ -1032,7 +825,6 @@ module OpenStudio
1032
825
 
1033
826
  variable_index = -1
1034
827
  group_index = 1
1035
- @algorithm['objective_functions'] = []
1036
828
 
1037
829
  rows.each_with_index do |row, icnt|
1038
830
  next if icnt < 2 # skip the first 3 lines of the file
@@ -1047,13 +839,6 @@ module OpenStudio
1047
839
  var['export'] = row[:export].downcase == 'true' ? true : false if row[:export]
1048
840
  var['variable_type'] = row[:variable_type].downcase if row[:variable_type]
1049
841
  var['objective_function'] = row[:objective_function].downcase == 'true' ? true : false
1050
- if var['objective_function']
1051
- @algorithm['objective_functions'] << var['name']
1052
- variable_index += 1
1053
- var['objective_function_index'] = variable_index
1054
- else
1055
- var['objective_function_index'] = nil
1056
- end
1057
842
  var['objective_function_target'] = row[:objective_function_target]
1058
843
  var['scaling_factor'] = row[:scaling_factor]
1059
844