openstudio-analysis 1.3.6 → 1.3.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/openstudio-analysis.yml +40 -40
- data/.gitignore +21 -21
- data/.rubocop.yml +9 -9
- data/CHANGELOG.md +274 -269
- data/Gemfile +14 -14
- data/README.md +102 -102
- data/Rakefile +40 -40
- data/lib/openstudio/analysis/algorithm_attributes.rb +47 -47
- data/lib/openstudio/analysis/formulation.rb +881 -857
- data/lib/openstudio/analysis/server_api.rb +862 -862
- data/lib/openstudio/analysis/server_scripts.rb +108 -108
- data/lib/openstudio/analysis/support_files.rb +104 -104
- data/lib/openstudio/analysis/translator/datapoints.rb +454 -454
- data/lib/openstudio/analysis/translator/excel.rb +893 -893
- data/lib/openstudio/analysis/translator/workflow.rb +143 -143
- data/lib/openstudio/analysis/version.rb +12 -12
- data/lib/openstudio/analysis/workflow.rb +302 -279
- data/lib/openstudio/analysis/workflow_step.rb +523 -523
- data/lib/openstudio/analysis.rb +144 -144
- data/lib/openstudio/helpers/hash.rb +10 -10
- data/lib/openstudio/helpers/string.rb +36 -36
- data/lib/openstudio/helpers/utils.rb +36 -36
- data/lib/openstudio/weather/epw.rb +178 -178
- data/lib/openstudio-analysis.rb +47 -47
- data/openstudio-analysis.gemspec +38 -38
- data/update_license.rb +60 -60
- metadata +2 -2
data/lib/openstudio/analysis.rb
CHANGED
@@ -1,144 +1,144 @@
|
|
1
|
-
# *******************************************************************************
|
2
|
-
# OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
|
3
|
-
# See also https://openstudio.net/license
|
4
|
-
# *******************************************************************************
|
5
|
-
|
6
|
-
# OpenStudio::Analysis Module instantiates versions of formulations
|
7
|
-
module OpenStudio
|
8
|
-
module Analysis
|
9
|
-
# Create a new analysis
|
10
|
-
def self.create(display_name)
|
11
|
-
OpenStudio::Analysis::Formulation.new(display_name)
|
12
|
-
end
|
13
|
-
|
14
|
-
# Load the analysis json or from a file. If this is a json then it must have
|
15
|
-
# symbolized keys
|
16
|
-
def self.load(h)
|
17
|
-
h = MultiJson.load(h, symbolize_keys: true) unless h.is_a? Hash
|
18
|
-
OpenStudio::Analysis::Formulation.from_hash h
|
19
|
-
end
|
20
|
-
|
21
|
-
# Load an analysis from excel. This will create an array of analyses because
|
22
|
-
# excel can create more than one analyses
|
23
|
-
def self.from_excel(filename)
|
24
|
-
excel = OpenStudio::Analysis::Translator::Excel.new(filename)
|
25
|
-
excel.process
|
26
|
-
excel.analyses
|
27
|
-
end
|
28
|
-
|
29
|
-
# Load an set of batch datapoints from a csv. This will create a analysis
|
30
|
-
# of type 'batch_datapoints' which requires 'batch_run'
|
31
|
-
def self.from_csv(filename)
|
32
|
-
csv = OpenStudio::Analysis::Translator::Datapoints.new(filename)
|
33
|
-
csv.process
|
34
|
-
csv.analysis
|
35
|
-
end
|
36
|
-
|
37
|
-
# Process an OSA with a set of OSDs into OSWs
|
38
|
-
def self.make_osws(osa_filename, osd_array)
|
39
|
-
translator = OpenStudio::Analysis::Translator::Workflow.new(osa_filename)
|
40
|
-
osd_array.each { |osd| translator.process_datapoints osd }
|
41
|
-
end
|
42
|
-
|
43
|
-
# Retrieve aws instance options from a project. This will return a hash
|
44
|
-
def self.aws_instance_options(filename)
|
45
|
-
if File.extname(filename) == '.xlsx'
|
46
|
-
excel = OpenStudio::Analysis::Translator::Excel.new(filename)
|
47
|
-
excel.process
|
48
|
-
options = {
|
49
|
-
os_server_version: excel.settings['openstudio_server_version'],
|
50
|
-
server_instance_type: excel.settings['server_instance_type'],
|
51
|
-
worker_instance_type: excel.settings['worker_instance_type'],
|
52
|
-
worker_node_number: excel.settings['worker_nodes'].to_i,
|
53
|
-
user_id: excel.settings['user_id'],
|
54
|
-
aws_tags: excel.aws_tags,
|
55
|
-
analysis_type: excel.analyses.first.analysis_type,
|
56
|
-
cluster_name: excel.cluster_name
|
57
|
-
}
|
58
|
-
elsif File.extname(filename) == '.csv'
|
59
|
-
csv = OpenStudio::Analysis::Translator::Datapoints.new(filename)
|
60
|
-
csv.process
|
61
|
-
options = csv.settings
|
62
|
-
else
|
63
|
-
raise 'Invalid file extension'
|
64
|
-
end
|
65
|
-
|
66
|
-
return options
|
67
|
-
end
|
68
|
-
|
69
|
-
# Generate a DEnCity complient hash for uploading from the analysis hash
|
70
|
-
# TODO make this work off of the analysis object, not the hash.
|
71
|
-
def self.to_dencity_analysis(analysis_hash, analysis_uuid)
|
72
|
-
dencity_hash = {}
|
73
|
-
a = analysis_hash[:analysis]
|
74
|
-
provenance = {}
|
75
|
-
provenance[:user_defined_id] = analysis_uuid
|
76
|
-
provenance[:user_created_date] = ::Time.now
|
77
|
-
provenance[:analysis_types] = [a[:problem][:analysis_type]]
|
78
|
-
provenance[:name] = a[:name]
|
79
|
-
provenance[:display_name] = a[:display_name]
|
80
|
-
provenance[:description] = 'Auto-generated DEnCity analysis hash using the OpenStudio Analysis Gem'
|
81
|
-
measure_metadata = []
|
82
|
-
if a[:problem]
|
83
|
-
if a[:problem][:algorithm]
|
84
|
-
provenance[:analysis_information] = a[:problem][:algorithm]
|
85
|
-
else
|
86
|
-
raise 'No algorithm found in the analysis.json.'
|
87
|
-
end
|
88
|
-
|
89
|
-
if a[:problem][:workflow]
|
90
|
-
a[:problem][:workflow].each do |wf|
|
91
|
-
new_wfi = {}
|
92
|
-
new_wfi[:id] = wf[:measure_definition_uuid]
|
93
|
-
new_wfi[:version_id] = wf[:measure_definition_version_uuid]
|
94
|
-
|
95
|
-
# Eventually all of this could be pulled directly from BCL
|
96
|
-
new_wfi[:name] = wf[:measure_definition_class_name] if wf[:measure_definition_class_name]
|
97
|
-
new_wfi[:display_name] = wf[:measure_definition_display_name] if wf[:measure_definition_display_name]
|
98
|
-
new_wfi[:type] = wf[:measure_type] if wf[:measure_type]
|
99
|
-
new_wfi[:modeler_description] = wf[:modeler_description] if wf[:modeler_description]
|
100
|
-
new_wfi[:description] = wf[:description] if wf[:description]
|
101
|
-
new_wfi[:arguments] = []
|
102
|
-
|
103
|
-
wf[:arguments]&.each do |arg|
|
104
|
-
wfi_arg = {}
|
105
|
-
wfi_arg[:display_name] = arg[:display_name] if arg[:display_name]
|
106
|
-
wfi_arg[:display_name_short] = arg[:display_name_short] if arg[:display_name_short]
|
107
|
-
wfi_arg[:name] = arg[:name] if arg[:name]
|
108
|
-
wfi_arg[:data_type] = arg[:value_type] if arg[:value_type]
|
109
|
-
wfi_arg[:default_value] = nil
|
110
|
-
wfi_arg[:description] = ''
|
111
|
-
wfi_arg[:display_units] = '' # should be haystack compatible unit strings
|
112
|
-
wfi_arg[:units] = '' # should be haystack compatible unit strings
|
113
|
-
|
114
|
-
new_wfi[:arguments] << wfi_arg
|
115
|
-
end
|
116
|
-
|
117
|
-
wf[:variables]&.each do |arg|
|
118
|
-
wfi_var = {}
|
119
|
-
wfi_var[:display_name] = arg[:argument][:display_name] if arg[:argument][:display_name]
|
120
|
-
wfi_var[:display_name_short] = arg[:argument][:display_name_short] if arg[:argument][:display_name_short]
|
121
|
-
wfi_var[:name] = arg[:argument][:name] if arg[:argument][:name]
|
122
|
-
wfi_var[:default_value] = nil
|
123
|
-
wfi_var[:data_type] = arg[:argument][:value_type] if arg[:argument][:value_type]
|
124
|
-
wfi_var[:description] = ''
|
125
|
-
wfi_var[:display_units] = arg[:units] if arg[:units]
|
126
|
-
wfi_var[:units] = '' # should be haystack compatible unit strings
|
127
|
-
new_wfi[:arguments] << wfi_var
|
128
|
-
end
|
129
|
-
|
130
|
-
measure_metadata << new_wfi
|
131
|
-
end
|
132
|
-
else
|
133
|
-
raise 'No workflow found in the analysis.json'
|
134
|
-
end
|
135
|
-
|
136
|
-
dencity_hash[:analysis] = provenance
|
137
|
-
dencity_hash[:measure_definitions] = measure_metadata
|
138
|
-
else
|
139
|
-
raise 'No problem found in the analysis.json'
|
140
|
-
end
|
141
|
-
return dencity_hash
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
1
|
+
# *******************************************************************************
|
2
|
+
# OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
|
3
|
+
# See also https://openstudio.net/license
|
4
|
+
# *******************************************************************************
|
5
|
+
|
6
|
+
# OpenStudio::Analysis Module instantiates versions of formulations
|
7
|
+
module OpenStudio
|
8
|
+
module Analysis
|
9
|
+
# Create a new analysis
|
10
|
+
def self.create(display_name)
|
11
|
+
OpenStudio::Analysis::Formulation.new(display_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Load the analysis json or from a file. If this is a json then it must have
|
15
|
+
# symbolized keys
|
16
|
+
def self.load(h)
|
17
|
+
h = MultiJson.load(h, symbolize_keys: true) unless h.is_a? Hash
|
18
|
+
OpenStudio::Analysis::Formulation.from_hash h
|
19
|
+
end
|
20
|
+
|
21
|
+
# Load an analysis from excel. This will create an array of analyses because
|
22
|
+
# excel can create more than one analyses
|
23
|
+
def self.from_excel(filename)
|
24
|
+
excel = OpenStudio::Analysis::Translator::Excel.new(filename)
|
25
|
+
excel.process
|
26
|
+
excel.analyses
|
27
|
+
end
|
28
|
+
|
29
|
+
# Load an set of batch datapoints from a csv. This will create a analysis
|
30
|
+
# of type 'batch_datapoints' which requires 'batch_run'
|
31
|
+
def self.from_csv(filename)
|
32
|
+
csv = OpenStudio::Analysis::Translator::Datapoints.new(filename)
|
33
|
+
csv.process
|
34
|
+
csv.analysis
|
35
|
+
end
|
36
|
+
|
37
|
+
# Process an OSA with a set of OSDs into OSWs
|
38
|
+
def self.make_osws(osa_filename, osd_array)
|
39
|
+
translator = OpenStudio::Analysis::Translator::Workflow.new(osa_filename)
|
40
|
+
osd_array.each { |osd| translator.process_datapoints osd }
|
41
|
+
end
|
42
|
+
|
43
|
+
# Retrieve aws instance options from a project. This will return a hash
|
44
|
+
def self.aws_instance_options(filename)
|
45
|
+
if File.extname(filename) == '.xlsx'
|
46
|
+
excel = OpenStudio::Analysis::Translator::Excel.new(filename)
|
47
|
+
excel.process
|
48
|
+
options = {
|
49
|
+
os_server_version: excel.settings['openstudio_server_version'],
|
50
|
+
server_instance_type: excel.settings['server_instance_type'],
|
51
|
+
worker_instance_type: excel.settings['worker_instance_type'],
|
52
|
+
worker_node_number: excel.settings['worker_nodes'].to_i,
|
53
|
+
user_id: excel.settings['user_id'],
|
54
|
+
aws_tags: excel.aws_tags,
|
55
|
+
analysis_type: excel.analyses.first.analysis_type,
|
56
|
+
cluster_name: excel.cluster_name
|
57
|
+
}
|
58
|
+
elsif File.extname(filename) == '.csv'
|
59
|
+
csv = OpenStudio::Analysis::Translator::Datapoints.new(filename)
|
60
|
+
csv.process
|
61
|
+
options = csv.settings
|
62
|
+
else
|
63
|
+
raise 'Invalid file extension'
|
64
|
+
end
|
65
|
+
|
66
|
+
return options
|
67
|
+
end
|
68
|
+
|
69
|
+
# Generate a DEnCity complient hash for uploading from the analysis hash
|
70
|
+
# TODO make this work off of the analysis object, not the hash.
|
71
|
+
def self.to_dencity_analysis(analysis_hash, analysis_uuid)
|
72
|
+
dencity_hash = {}
|
73
|
+
a = analysis_hash[:analysis]
|
74
|
+
provenance = {}
|
75
|
+
provenance[:user_defined_id] = analysis_uuid
|
76
|
+
provenance[:user_created_date] = ::Time.now
|
77
|
+
provenance[:analysis_types] = [a[:problem][:analysis_type]]
|
78
|
+
provenance[:name] = a[:name]
|
79
|
+
provenance[:display_name] = a[:display_name]
|
80
|
+
provenance[:description] = 'Auto-generated DEnCity analysis hash using the OpenStudio Analysis Gem'
|
81
|
+
measure_metadata = []
|
82
|
+
if a[:problem]
|
83
|
+
if a[:problem][:algorithm]
|
84
|
+
provenance[:analysis_information] = a[:problem][:algorithm]
|
85
|
+
else
|
86
|
+
raise 'No algorithm found in the analysis.json.'
|
87
|
+
end
|
88
|
+
|
89
|
+
if a[:problem][:workflow]
|
90
|
+
a[:problem][:workflow].each do |wf|
|
91
|
+
new_wfi = {}
|
92
|
+
new_wfi[:id] = wf[:measure_definition_uuid]
|
93
|
+
new_wfi[:version_id] = wf[:measure_definition_version_uuid]
|
94
|
+
|
95
|
+
# Eventually all of this could be pulled directly from BCL
|
96
|
+
new_wfi[:name] = wf[:measure_definition_class_name] if wf[:measure_definition_class_name]
|
97
|
+
new_wfi[:display_name] = wf[:measure_definition_display_name] if wf[:measure_definition_display_name]
|
98
|
+
new_wfi[:type] = wf[:measure_type] if wf[:measure_type]
|
99
|
+
new_wfi[:modeler_description] = wf[:modeler_description] if wf[:modeler_description]
|
100
|
+
new_wfi[:description] = wf[:description] if wf[:description]
|
101
|
+
new_wfi[:arguments] = []
|
102
|
+
|
103
|
+
wf[:arguments]&.each do |arg|
|
104
|
+
wfi_arg = {}
|
105
|
+
wfi_arg[:display_name] = arg[:display_name] if arg[:display_name]
|
106
|
+
wfi_arg[:display_name_short] = arg[:display_name_short] if arg[:display_name_short]
|
107
|
+
wfi_arg[:name] = arg[:name] if arg[:name]
|
108
|
+
wfi_arg[:data_type] = arg[:value_type] if arg[:value_type]
|
109
|
+
wfi_arg[:default_value] = nil
|
110
|
+
wfi_arg[:description] = ''
|
111
|
+
wfi_arg[:display_units] = '' # should be haystack compatible unit strings
|
112
|
+
wfi_arg[:units] = '' # should be haystack compatible unit strings
|
113
|
+
|
114
|
+
new_wfi[:arguments] << wfi_arg
|
115
|
+
end
|
116
|
+
|
117
|
+
wf[:variables]&.each do |arg|
|
118
|
+
wfi_var = {}
|
119
|
+
wfi_var[:display_name] = arg[:argument][:display_name] if arg[:argument][:display_name]
|
120
|
+
wfi_var[:display_name_short] = arg[:argument][:display_name_short] if arg[:argument][:display_name_short]
|
121
|
+
wfi_var[:name] = arg[:argument][:name] if arg[:argument][:name]
|
122
|
+
wfi_var[:default_value] = nil
|
123
|
+
wfi_var[:data_type] = arg[:argument][:value_type] if arg[:argument][:value_type]
|
124
|
+
wfi_var[:description] = ''
|
125
|
+
wfi_var[:display_units] = arg[:units] if arg[:units]
|
126
|
+
wfi_var[:units] = '' # should be haystack compatible unit strings
|
127
|
+
new_wfi[:arguments] << wfi_var
|
128
|
+
end
|
129
|
+
|
130
|
+
measure_metadata << new_wfi
|
131
|
+
end
|
132
|
+
else
|
133
|
+
raise 'No workflow found in the analysis.json'
|
134
|
+
end
|
135
|
+
|
136
|
+
dencity_hash[:analysis] = provenance
|
137
|
+
dencity_hash[:measure_definitions] = measure_metadata
|
138
|
+
else
|
139
|
+
raise 'No problem found in the analysis.json'
|
140
|
+
end
|
141
|
+
return dencity_hash
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -1,10 +1,10 @@
|
|
1
|
-
# *******************************************************************************
|
2
|
-
# OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
|
3
|
-
# See also https://openstudio.net/license
|
4
|
-
# *******************************************************************************
|
5
|
-
|
6
|
-
class Hash
|
7
|
-
def deep_find(key)
|
8
|
-
key?(key) ? self[key] : values.reduce(nil) { |memo, v| memo ||= v.deep_find(key) if v.respond_to?(:deep_find) }
|
9
|
-
end
|
10
|
-
end
|
1
|
+
# *******************************************************************************
|
2
|
+
# OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
|
3
|
+
# See also https://openstudio.net/license
|
4
|
+
# *******************************************************************************
|
5
|
+
|
6
|
+
class Hash
|
7
|
+
def deep_find(key)
|
8
|
+
key?(key) ? self[key] : values.reduce(nil) { |memo, v| memo ||= v.deep_find(key) if v.respond_to?(:deep_find) }
|
9
|
+
end
|
10
|
+
end
|
@@ -1,36 +1,36 @@
|
|
1
|
-
# *******************************************************************************
|
2
|
-
# OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
|
3
|
-
# See also https://openstudio.net/license
|
4
|
-
# *******************************************************************************
|
5
|
-
|
6
|
-
# Typecast Variable Values by a string.
|
7
|
-
def typecast_value(variable_type, value, inspect_string = false)
|
8
|
-
out_value = nil
|
9
|
-
unless value.nil?
|
10
|
-
case variable_type.downcase
|
11
|
-
when 'double'
|
12
|
-
out_value = value.to_f
|
13
|
-
when 'integer'
|
14
|
-
out_value = value.to_i
|
15
|
-
when 'string', 'choice'
|
16
|
-
out_value = inspect_string ? value.inspect : value.to_s
|
17
|
-
when 'bool', 'boolean'
|
18
|
-
# Check if the value is already a boolean
|
19
|
-
if !!value == value
|
20
|
-
out_value = value
|
21
|
-
else
|
22
|
-
if value.casecmp('true').zero?
|
23
|
-
out_value = true
|
24
|
-
elsif value.casecmp('false').zero?
|
25
|
-
out_value = false
|
26
|
-
else
|
27
|
-
raise "Can't cast to a bool from a value of '#{value}' of class '#{value.class}'"
|
28
|
-
end
|
29
|
-
end
|
30
|
-
else
|
31
|
-
raise "Unknown variable type of '#{@variable['type']}'"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
out_value
|
36
|
-
end
|
1
|
+
# *******************************************************************************
|
2
|
+
# OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
|
3
|
+
# See also https://openstudio.net/license
|
4
|
+
# *******************************************************************************
|
5
|
+
|
6
|
+
# Typecast Variable Values by a string.
|
7
|
+
def typecast_value(variable_type, value, inspect_string = false)
|
8
|
+
out_value = nil
|
9
|
+
unless value.nil?
|
10
|
+
case variable_type.downcase
|
11
|
+
when 'double'
|
12
|
+
out_value = value.to_f
|
13
|
+
when 'integer'
|
14
|
+
out_value = value.to_i
|
15
|
+
when 'string', 'choice'
|
16
|
+
out_value = inspect_string ? value.inspect : value.to_s
|
17
|
+
when 'bool', 'boolean'
|
18
|
+
# Check if the value is already a boolean
|
19
|
+
if !!value == value
|
20
|
+
out_value = value
|
21
|
+
else
|
22
|
+
if value.casecmp('true').zero?
|
23
|
+
out_value = true
|
24
|
+
elsif value.casecmp('false').zero?
|
25
|
+
out_value = false
|
26
|
+
else
|
27
|
+
raise "Can't cast to a bool from a value of '#{value}' of class '#{value.class}'"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
else
|
31
|
+
raise "Unknown variable type of '#{@variable['type']}'"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
out_value
|
36
|
+
end
|
@@ -1,36 +1,36 @@
|
|
1
|
-
# *******************************************************************************
|
2
|
-
# OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
|
3
|
-
# See also https://openstudio.net/license
|
4
|
-
# *******************************************************************************
|
5
|
-
|
6
|
-
require 'rexml/document'
|
7
|
-
|
8
|
-
def parse_measure_xml(measure_xml_filename)
|
9
|
-
measure_hash = {}
|
10
|
-
xml_to_parse = File.open(measure_xml_filename)
|
11
|
-
xml_root = REXML::Document.new(xml_to_parse).root
|
12
|
-
|
13
|
-
# pull out some information
|
14
|
-
measure_hash[:classname] = xml_root.elements['//measure/class_name'].text
|
15
|
-
measure_hash[:name] = xml_root.elements['//measure/name'].text
|
16
|
-
measure_hash[:display_name] = xml_root.elements['//measure/display_name'].text
|
17
|
-
measure_hash[:display_name_titleized] = measure_hash[:name].titleize
|
18
|
-
measure_hash[:measure_type] = xml_root.elements['//measure/attributes/attribute[name="Measure Type"]/value'].text
|
19
|
-
measure_hash[:description] = xml_root.elements['//measure/description'].text
|
20
|
-
measure_hash[:modeler_description] = xml_root.elements['//measure/modeler_description'].text
|
21
|
-
measure_hash[:uid] = xml_root.elements['//measure/uid'].text
|
22
|
-
measure_hash[:version_id] = xml_root.elements['//measure/version_id'].text
|
23
|
-
measure_hash[:arguments] = []
|
24
|
-
|
25
|
-
REXML::XPath.each(xml_root, '//measure/arguments/argument') do |arg|
|
26
|
-
measure_hash[:arguments] << {
|
27
|
-
name: arg.elements['name']&.text,
|
28
|
-
display_name: arg.elements['display_name']&.text,
|
29
|
-
variable_type: arg.elements['type']&.text.downcase,
|
30
|
-
default_value: arg.elements['default_value']&.text,
|
31
|
-
units: arg.elements['units']&.text || ''
|
32
|
-
}
|
33
|
-
end
|
34
|
-
|
35
|
-
measure_hash
|
36
|
-
end
|
1
|
+
# *******************************************************************************
|
2
|
+
# OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
|
3
|
+
# See also https://openstudio.net/license
|
4
|
+
# *******************************************************************************
|
5
|
+
|
6
|
+
require 'rexml/document'
|
7
|
+
|
8
|
+
def parse_measure_xml(measure_xml_filename)
|
9
|
+
measure_hash = {}
|
10
|
+
xml_to_parse = File.open(measure_xml_filename)
|
11
|
+
xml_root = REXML::Document.new(xml_to_parse).root
|
12
|
+
|
13
|
+
# pull out some information
|
14
|
+
measure_hash[:classname] = xml_root.elements['//measure/class_name'].text
|
15
|
+
measure_hash[:name] = xml_root.elements['//measure/name'].text
|
16
|
+
measure_hash[:display_name] = xml_root.elements['//measure/display_name'].text
|
17
|
+
measure_hash[:display_name_titleized] = measure_hash[:name].titleize
|
18
|
+
measure_hash[:measure_type] = xml_root.elements['//measure/attributes/attribute[name="Measure Type"]/value'].text
|
19
|
+
measure_hash[:description] = xml_root.elements['//measure/description'].text
|
20
|
+
measure_hash[:modeler_description] = xml_root.elements['//measure/modeler_description'].text
|
21
|
+
measure_hash[:uid] = xml_root.elements['//measure/uid'].text
|
22
|
+
measure_hash[:version_id] = xml_root.elements['//measure/version_id'].text
|
23
|
+
measure_hash[:arguments] = []
|
24
|
+
|
25
|
+
REXML::XPath.each(xml_root, '//measure/arguments/argument') do |arg|
|
26
|
+
measure_hash[:arguments] << {
|
27
|
+
name: arg.elements['name']&.text,
|
28
|
+
display_name: arg.elements['display_name']&.text,
|
29
|
+
variable_type: arg.elements['type']&.text.downcase,
|
30
|
+
default_value: arg.elements['default_value']&.text,
|
31
|
+
units: arg.elements['units']&.text || ''
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
measure_hash
|
36
|
+
end
|