lib/openstudio/analysis/translator/excel.rb in openstudio-analysis-0.2.3 vs lib/openstudio/analysis/translator/excel.rb in openstudio-analysis-0.3.0
- old
+ new
@@ -15,11 +15,11 @@
attr_reader :algorithm
attr_reader :problem
attr_reader :run_setup
# remove these once we have classes to construct the JSON file
- attr_reader :name
+ attr_accessor :name
attr_reader :machine_name
attr_reader :template_json
# methods to override instance variables
@@ -101,51 +101,52 @@
FileUtils.mkdir_p(@export_path)
# verify that all continuous variables have all the data needed and create a name maps
variable_names = []
@variables['data'].each do |measure|
- if measure['enabled'] && measure['name'] != 'baseline'
+ if measure['enabled']
measure['variables'].each do |variable|
# Determine if row is suppose to be an argument or a variable to be perturbed.
if variable['variable_type'] == 'variable'
variable_names << variable['display_name']
- if variable['method'] == 'static'
- # add this as an argument
+
+ # make sure that the variable has a static value
+ if variable['distribution']['static_value'].nil? || variable['distribution']['static_value'] == ''
+ fail "Variable #{measure['name']}:#{variable['name']} needs a static value"
+ end
+
+ if variable['type'] == 'enum' || variable['type'] == 'Choice'
# check something
- elsif variable['method'] == 'lhs'
- if variable['type'] == 'enum' || variable['type'] == 'Choice'
- # check something
- else # must be an integer or double
- if variable['distribution']['type'] == 'discrete_uncertain'
- if variable['distribution']['discrete_values'].nil? || variable['distribution']['discrete_values'] == ''
- fail "Variable #{measure['name']}:#{variable['name']} needs discrete values"
- end
- else
- if variable['distribution']['mean'].nil? || variable['distribution']['mean'] == ''
- fail "Variable #{measure['name']}:#{variable['name']} must have a mean"
- end
- if variable['distribution']['stddev'].nil? || variable['distribution']['stddev'] == ''
- fail "Variable #{measure['name']}:#{variable['name']} must have a stddev"
- end
+ else # must be an integer or double
+ if variable['distribution']['type'] == 'discrete_uncertain'
+ if variable['distribution']['discrete_values'].nil? || variable['distribution']['discrete_values'] == ''
+ fail "Variable #{measure['name']}:#{variable['name']} needs discrete values"
end
-
+ else
if variable['distribution']['mean'].nil? || variable['distribution']['mean'] == ''
- fail "Variable #{measure['name']}:#{variable['name']} must have a mean/mode"
+ fail "Variable #{measure['name']}:#{variable['name']} must have a mean"
end
- if variable['distribution']['min'].nil? || variable['distribution']['min'] == ''
- fail "Variable #{measure['name']}:#{variable['name']} must have a minimum"
+ if variable['distribution']['stddev'].nil? || variable['distribution']['stddev'] == ''
+ fail "Variable #{measure['name']}:#{variable['name']} must have a stddev"
end
- if variable['distribution']['max'].nil? || variable['distribution']['max'] == ''
- fail "Variable #{measure['name']}:#{variable['name']} must have a maximum"
- end
+ end
+
+ if variable['distribution']['mean'].nil? || variable['distribution']['mean'] == ''
+ fail "Variable #{measure['name']}:#{variable['name']} must have a mean/mode"
+ end
+ if variable['distribution']['min'].nil? || variable['distribution']['min'] == ''
+ fail "Variable #{measure['name']}:#{variable['name']} must have a minimum"
+ end
+ if variable['distribution']['max'].nil? || variable['distribution']['max'] == ''
+ fail "Variable #{measure['name']}:#{variable['name']} must have a maximum"
+ end
+ unless variable['type'] == 'string'
if variable['distribution']['min'] > variable['distribution']['max']
fail "Variable min is greater than variable max for #{measure['name']}:#{variable['name']}"
end
-
end
- elsif variable['method'] == 'pivot'
- # check something
+
end
end
end
end
end
@@ -187,11 +188,10 @@
template_root = File.join(File.dirname(__FILE__), '../../templates')
analysis_template = ERB.new(File.open("#{template_root}/analysis.json.erb", 'r').read)
workflow_template = ERB.new(File.open("#{template_root}/workflow_item.json.erb", 'r').read)
uncertain_variable_template = ERB.new(File.open("#{template_root}/uncertain_variable.json.erb", 'r').read)
discrete_uncertain_variable_template = ERB.new(File.open("#{template_root}/discrete_uncertain_variable.json.erb", 'r').read)
- static_variable_template = ERB.new(File.open("#{template_root}/static_variable.json.erb", 'r').read)
pivot_variable_template = ERB.new(File.open("#{template_root}/pivot_variable.json.erb", 'r').read)
argument_template = ERB.new(File.open("#{template_root}/argument.json.erb", 'r').read)
# Templated analysis json file (this is what is returned)
puts "Analysis name is #{@name}"
@@ -202,11 +202,11 @@
openstudio_analysis_json['analysis'].merge!(@outputs)
@measure_index = -1
@variables['data'].each do |measure|
# With OpenStudio server we need to create the workflow with all the measure instances
- if measure['enabled'] && measure['name'] != 'baseline'
+ if measure['enabled']
@measure_index += 1
puts " Adding measure item '#{measure['name']}'"
@measure = measure
@measure['measure_file_name_dir'] = @measure['measure_file_name'].underscore
@@ -215,25 +215,20 @@
wf = JSON.parse(workflow_template.result(get_binding))
# add in the variables
measure['variables'].each do |variable|
@variable = variable
-
# Determine if row is suppose to be an argument or a variable to be perturbed.
if @variable['variable_type'] == 'argument'
ag = nil
- if @variable['method'] == 'static'
- if @variable['distribution']['static_value'].nil? || @variable['distribution']['static_value'] == 'null'
- puts " Warning: '#{measure['name']}:#{@variable['name']}' static value was empty or null, assuming optional and skipping"
- next
- end
- # unless @variable['distribution']['static_value']
- # fail 'Cannot have an argument that is not a static value defined in which to set the argument'
- # end
+ if @variable['distribution']['static_value'].nil? || @variable['distribution']['static_value'] == 'null'
+ puts " Warning: '#{measure['name']}:#{@variable['name']}' static value was empty or null, assuming optional and skipping"
+ next
+ end
- # add this as an argument
- case @variable['type'].downcase
+ # add this as an argument
+ case @variable['type'].downcase
when 'double'
@static_value = @variable['distribution']['static_value'].to_f
when 'integer'
@static_value = @variable['distribution']['static_value'].to_i
# TODO: update openstudio export to write only Strings
@@ -245,59 +240,74 @@
else
@static_value = false
end
else
fail "Unknown variable type of '#{@variable['type']}'"
- end
- ag = JSON.parse(argument_template.result(get_binding))
end
+ ag = JSON.parse(argument_template.result(get_binding))
fail "Argument '#{@variable['name']}' did not process. Most likely it did not have all parameters defined." if ag.nil?
wf['arguments'] << ag
else # must be a variable [either pivot or normal variable]
vr = nil
- if @variable['method'] == 'static'
- # add this as an argument
- vr = JSON.parse(static_variable_template.result(get_binding))
- elsif @variable['method'] == 'lhs'
- # TODO: remove enum and choice as this is not the variable type
- if @variable['type'] == 'enum' || @variable['type'].downcase == 'choice'
- @values_and_weights = @variable['distribution']['enumerations'].map { |v| { value: v } }.to_json
- vr = JSON.parse(discrete_uncertain_variable_template.result(get_binding))
- elsif @variable['distribution']['type'] == 'discrete_uncertain'
- # puts @variable.inspect
- weights = nil
- if @variable['distribution']['discrete_weights'] && @variable['distribution']['discrete_weights'] != ''
- weights = eval(@variable['distribution']['discrete_weights'])
- end
-
- values = nil
- if variable['type'].downcase == 'bool'
- values = eval(@variable['distribution']['discrete_values'])
- values.map! { |v| v.downcase == 'true' }
+ # add this as an argument
+ case @variable['type'].downcase
+ when 'double'
+ @static_value = @variable['distribution']['static_value'].to_f
+ when 'integer'
+ @static_value = @variable['distribution']['static_value'].to_i
+ # TODO: update openstudio export to write only Strings
+ when 'string', 'choice'
+ @static_value = @variable['distribution']['static_value'].inspect
+ when 'bool'
+ if @variable['distribution']['static_value'].downcase == 'true'
+ @static_value = true
else
- values = eval(@variable['distribution']['discrete_values'])
+ @static_value = false
end
+ else
+ fail "Unknown variable type of '#{@variable['type']}'"
+ end
- if weights
- fail "Discrete variable '#{@variable['name']}' does not have equal length of values and weights" if values.size != weights.size
- @values_and_weights = values.zip(weights).map { |v, w| { value: v, weight: w } }.to_json
- else
- @values_and_weights = values.map { |v| { value: v } }.to_json
- end
+ # TODO: remove enum and choice as this is not the variable type
+ if @variable['type'] == 'enum' || @variable['type'].downcase == 'choice'
+ @values_and_weights = @variable['distribution']['enumerations'].map { |v| {value: v} }.to_json
+ vr = JSON.parse(discrete_uncertain_variable_template.result(get_binding))
+ elsif @variable['distribution']['type'] == 'discrete_uncertain'
+ # puts @variable.inspect
+ weights = nil
+ if @variable['distribution']['discrete_weights'] && @variable['distribution']['discrete_weights'] != ''
+ weights = eval(@variable['distribution']['discrete_weights'])
+ end
- if @variable['variable_type'] == 'pivot'
- vr = JSON.parse(pivot_variable_template.result(get_binding))
- else
- vr = JSON.parse(discrete_uncertain_variable_template.result(get_binding))
- end
+ values = nil
+ if variable['type'].downcase == 'bool'
+ values = eval(@variable['distribution']['discrete_values'])
+ values.map! { |v| v.to_s == 'true' }
else
- if @variable['variable_type'] == 'pivot'
- fail 'Currently unable to pivot on continuous variables... stay tuned.'
- else
- vr = JSON.parse(uncertain_variable_template.result(get_binding))
- end
+ values = eval(@variable['distribution']['discrete_values'])
end
+
+ if weights
+ fail "Discrete variable '#{@variable['name']}' does not have equal length of values and weights" if values.size != weights.size
+ @values_and_weights = values.zip(weights).map { |v, w| {value: v, weight: w} }.to_json
+ else
+ @values_and_weights = values.map { |v| {value: v} }.to_json
+ end
+
+
+ if @variable['variable_type'] == 'pivot'
+
+ vr = JSON.parse(pivot_variable_template.result(get_binding))
+ else
+ vr = JSON.parse(discrete_uncertain_variable_template.result(get_binding))
+ end
+ else
+ if @variable['variable_type'] == 'pivot'
+ fail 'Currently unable to pivot on continuous variables... stay tuned.'
+ else
+ vr = JSON.parse(uncertain_variable_template.result(get_binding))
+ end
end
fail 'variable was nil after processing' if vr.nil?
wf['variables'] << vr
end
end
@@ -350,15 +360,10 @@
# pp "Measure to save is #{measure}"
break
end
end
- if v['measure_file_name_directory'] =~ /baseline/i
- puts ' Skipping baseline measure'
- next
- end
-
if measure_to_save && !added_measures.include?(measure_to_save)
# pp "Attempting to add measure #{measure_to_save}"
if File.exist?(measure_to_save)
# pp "Adding measure directory to zip #{measure_to_save}"
Dir[File.join(measure_to_save, '**')].each do |file|
@@ -395,10 +400,11 @@
def create_analysis_json(analysis_json, model, append_model_name)
def deep_copy(o)
Marshal.load(Marshal.dump(o))
end
+
# append the model name to the analysis name if requested (normally if there are more than
# 1 models in the spreadsheet)
new_analysis_json = deep_copy(analysis_json)
if append_model_name
new_analysis_json['analysis']['display_name'] = new_analysis_json['analysis']['display_name'] + ' - ' + model[:display_name]
@@ -508,15 +514,27 @@
@cluster_name = @settings['cluster_name'].snake_case if @settings['cluster_name']
# type some of the values that we know
@settings['proxy_port'] = @settings['proxy_port'].to_i if @settings['proxy_port']
elsif b_run_setup
- @name = row[1].chomp if row[0] == 'Analysis Name'
- @machine_name = @name.snake_case
+ if row[0] == 'Analysis Name'
+ if row[1]
+ @name = row[1]
+ else
+ @name = UUID.new.generate
+ end
+ @machine_name = @name.snake_case
+ end
@export_path = File.expand_path(File.join(@root_path, row[1])) if row[0] == 'Export Directory'
- @measure_path = File.expand_path(File.join(@root_path, row[1])) if row[0] == 'Measure Directory'
-
+ if row[0] == 'Measure Directory'
+ tmp_filepath = row[1]
+ if (Pathname.new tmp_filepath).absolute?
+ @measure_path = tmp_filepath
+ else
+ @measure_path = File.expand_path(File.join(@root_path, tmp_filepath))
+ end
+ end
@run_setup["#{row[0].snake_case}"] = row[1] if row[0]
# type cast
@run_setup['allow_multiple_jobs'] = @run_setup['allow_multiple_jobs'].to_s.to_bool if @run_setup['allow_multiple_jobs']
@run_setup['use_server_as_worker'] = @run_setup['use_server_as_worker'].to_s.to_bool if @run_setup['use_server_as_worker']
@@ -537,13 +555,18 @@
elsif b_weather_files
if row[0] == 'Weather File'
@weather_files += Dir.glob(File.expand_path(File.join(@root_path, row[1])))
end
elsif b_models
- @models << { name: row[1].snake_case, display_name: row[1], type: row[2], path: File.expand_path(File.join(@root_path, row[3])) }
+ if row[1]
+ tmp_m_name = row[1]
+ else
+ tmp_m_name = UUID.new.generate
+ end
+ @models << {name: tmp_m_name.snake_case, display_name: tmp_m_name, type: row[2], path: File.expand_path(File.join(@root_path, row[3]))}
elsif b_other_libs
- @other_files << { lib_zip_name: row[1], path: row[2] }
+ @other_files << {lib_zip_name: row[1], path: row[2]}
end
end
end
# parse_variables will parse the XLS spreadsheet and save the data into
@@ -555,16 +578,39 @@
# If you add a new column and you want that variable in the hash, then you must add it here.
# rows = @xls.sheet('Variables').parse(:enabled => "# variable")
# puts rows.inspect
rows = nil
begin
- if @version >= '0.2.0'
+ if @version >= '0.3.0'.to_version
rows = @xls.sheet('Variables').parse(enabled: '# variable',
measure_name_or_var_type: 'type',
measure_file_name_or_var_display_name: 'parameter display name.*',
measure_file_name_directory: 'measure directory',
measure_type_or_parameter_name_in_measure: 'parameter name in measure',
+ #sampling_method: 'sampling method',
+ variable_type: 'Variable Type',
+ units: 'units',
+ default_value: 'static.default value',
+ enums: 'enumerations',
+ min: 'min',
+ max: 'max',
+ mode: 'mean|mode',
+ stddev: 'std dev',
+ delta_x: 'delta.x',
+ discrete_values: 'discrete values',
+ discrete_weights: 'discrete weights',
+ distribution: 'distribution',
+ source: 'data source',
+ notes: 'notes',
+ relation_to_eui: 'typical var to eui relationship',
+ clean: true)
+ elsif @version >= '0.2.0'.to_version
+ rows = @xls.sheet('Variables').parse(enabled: '# variable',
+ measure_name_or_var_type: 'type',
+ measure_file_name_or_var_display_name: 'parameter display name.*',
+ measure_file_name_directory: 'measure directory',
+ measure_type_or_parameter_name_in_measure: 'parameter name in measure',
sampling_method: 'sampling method',
variable_type: 'Variable Type',
units: 'units',
default_value: 'static.default value',
enums: 'enumerations',
@@ -578,11 +624,11 @@
distribution: 'distribution',
source: 'data source',
notes: 'notes',
relation_to_eui: 'typical var to eui relationship',
clean: true)
- elsif @version >= '0.1.12' # add delta x
+ elsif @version >= '0.1.12'.to_version
rows = @xls.sheet('Variables').parse(enabled: '# variable',
measure_name_or_var_type: 'type',
measure_file_name_or_var_display_name: 'parameter display name.*',
measure_type_or_parameter_name_in_measure: 'parameter name in measure',
sampling_method: 'sampling method',
@@ -600,11 +646,11 @@
distribution: 'distribution',
source: 'data source',
notes: 'notes',
relation_to_eui: 'typical var to eui relationship',
clean: true)
- elsif @version >= '0.1.11' # add discrete variables
+ elsif @version >= '0.1.11'.to_version
rows = @xls.sheet('Variables').parse(enabled: '# variable',
measure_name_or_var_type: 'type',
measure_file_name_or_var_display_name: 'parameter display name.*',
measure_type_or_parameter_name_in_measure: 'parameter name in measure',
sampling_method: 'sampling method',
@@ -655,17 +701,15 @@
# map the data to another hash that is more easily processed
data = {}
data['data'] = []
- icnt = 0
measure_index = -1
variable_index = -1
measure_name = nil
- rows.each do |row|
- icnt += 1
- next if icnt <= 1 # skip the first line after the header
+ rows.each_with_index do |row, icnt|
+ next if icnt < 1 # skip the first line after the header
# puts "Parsing line: #{icnt}:#{row}"
# check if we are a measure - nil means that the cell was blank
if row[:enabled].nil?
unless measure_name.nil?
@@ -676,11 +720,10 @@
var['display_name'] = row[:measure_file_name_or_var_display_name]
var['machine_name'] = row[:measure_file_name_or_var_display_name].downcase.strip.gsub('-', '_').gsub(' ', '_').strip
var['name'] = row[:measure_type_or_parameter_name_in_measure]
var['index'] = variable_index # order of the variable (not sure of its need)
- var['method'] = row[:sampling_method]
var['type'] = row[:variable_type] ? row[:variable_type].downcase : row[:variable_type]
var['units'] = row[:units]
var['distribution'] = {}
@@ -691,21 +734,18 @@
var['distribution']['enumerations'] = []
var['distribution']['enumerations'] << 'true' # TODO: should this be a real bool?
var['distribution']['enumerations'] << 'false'
end
- if var['method'] == 'lhs'
- var['distribution']['min'] = row[:min]
- var['distribution']['max'] = row[:max]
- var['distribution']['mean'] = row[:mode]
- var['distribution']['stddev'] = row[:stddev]
- var['distribution']['discrete_values'] = row[:discrete_values]
- var['distribution']['discrete_weights'] = row[:discrete_weights]
- var['distribution']['type'] = row[:distribution]
- elsif var['method'] == 'static'
- var['distribution']['static_value'] = row[:default_value]
- end
+ var['distribution']['min'] = row[:min]
+ var['distribution']['max'] = row[:max]
+ var['distribution']['mean'] = row[:mode]
+ var['distribution']['stddev'] = row[:stddev]
+ var['distribution']['discrete_values'] = row[:discrete_values]
+ var['distribution']['discrete_weights'] = row[:discrete_weights]
+ var['distribution']['type'] = row[:distribution]
+ var['distribution']['static_value'] = row[:default_value]
var['distribution']['source'] = row[:source]
var['notes'] = row[:notes]
var['relation_to_eui'] = row[:relation_to_eui]
@@ -722,11 +762,11 @@
measure_name = display_name.downcase.strip.gsub('-', '_').gsub(' ', '_')
data['data'][measure_index]['display_name'] = display_name
data['data'][measure_index]['name'] = measure_name
data['data'][measure_index]['enabled'] = row[:enabled] == 'TRUE' ? true : false
data['data'][measure_index]['measure_file_name'] = row[:measure_file_name_or_var_display_name]
- if row[:measure_file_name_directory]
+ if row[:measure_file_name_directory]
data['data'][measure_index]['measure_file_name_directory'] = row[:measure_file_name_directory]
else
data['data'][measure_index]['measure_file_name_directory'] = row[:measure_file_name_or_var_display_name].underscore
end
data['data'][measure_index]['measure_type'] = row[:measure_type_or_parameter_name_in_measure]
@@ -739,47 +779,72 @@
# puts data.inspect
data
end
def parse_outputs
- rows = @xls.sheet('Outputs').parse
+ rows = nil
+ if @version >= '0.3.0'.to_version
+ rows = @xls.sheet('Outputs').parse(display_name: 'Variable Display Name',
+ metadata_id: 'Taxonomy Identifier',
+ name: '^Name$',
+ units: 'Units',
+ visualize: 'Visualize',
+ export: 'Export',
+ variable_type: 'Variable Type',
+ objective_function: 'Objective Function',
+ objective_function_target: 'Objective Function Target',
+ scaling_factor: 'Scale',
+ objective_function_group: 'Objective Function Group')
+ else
+ rows = @xls.sheet('Outputs').parse(display_name: 'Variable Display Name',
+ name: '^Name$',
+ units: 'units',
+ objective_function: 'objective function',
+ objective_function_target: 'objective function target',
+ scaling_factor: 'scale',
+ objective_function_group: 'objective')
+ end
unless rows
fail "Could not find the sheet name 'Outputs' in excel file #{@root_path}"
end
data = {}
data['output_variables'] = []
- icnt = 0
variable_index = -1
group_index = 1
@algorithm['objective_functions'] = []
- rows.each do |row|
- icnt += 1
- # puts "Parsing line: #{icnt}"
- next if icnt <= 3 # skip the first 3 lines of the file
+ rows.each_with_index do |row, icnt|
+ next if icnt < 2 # skip the first 3 lines of the file
var = {}
- var['display_name'] = row[0].strip
- var['name'] = row[1]
- var['units'] = row[2]
- var['objective_function'] = row[3].downcase == 'true' ? true : false
- if var['objective_function'] == true
+ var['display_name'] = row[:display_name]
+ var['metadata_id'] = row[:metadata_id]
+ var['name'] = row[:name]
+ var['units'] = row[:units]
+ var['visualize'] = row[:visualize].downcase == 'true' ? true : false if row[:visualize]
+ var['export'] = row[:export].downcase == 'true' ? true : false if row[:export]
+ var['variable_type'] = row[:variable_type] if row[:variable_type]
+ var['objective_function'] = row[:objective_function].downcase == 'true' ? true : false
+ if var['objective_function']
@algorithm['objective_functions'] << var['name']
variable_index += 1
var['objective_function_index'] = variable_index
else
var['objective_function_index'] = nil
end
- var['objective_function_target'] = row[4]
- var['scaling_factor'] = row[5]
- if row[6].nil?
- var['objective_function_group'] = group_index
- group_index += 1
- else
- var['objective_function_group'] = row[6]
+ var['objective_function_target'] = row[:objective_function_target]
+ var['scaling_factor'] = row[:scaling_factor]
+
+ if var['objective_function']
+ if row[:objective_function_group].nil?
+ var['objective_function_group'] = group_index
+ group_index += 1
+ else
+ var['objective_function_group'] = row[:objective_function_group]
+ end
end
data['output_variables'] << var
end
data