openstudio-workflow 1.0.0.pat1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +16 -68
- data/Rakefile +9 -9
- data/bin/openstudio_cli +786 -0
- data/lib/openstudio/workflow/adapters/input/local.rb +97 -0
- data/lib/openstudio/workflow/adapters/output/local.rb +90 -0
- data/lib/openstudio/workflow/adapters/output/socket.rb +70 -0
- data/lib/openstudio/workflow/{jobs/run_preflight/run_preflight.rb → adapters/output/web.rb} +37 -19
- data/lib/openstudio/workflow/{adapter.rb → adapters/output_adapter.rb} +53 -51
- data/lib/openstudio/workflow/job.rb +22 -0
- data/lib/openstudio/workflow/jobs/{run_energyplus → resources}/monthly_report.idf +0 -0
- data/lib/openstudio/workflow/jobs/run_energyplus.rb +49 -0
- data/lib/openstudio/workflow/jobs/run_ep_measures.rb +55 -0
- data/lib/openstudio/workflow/jobs/run_initialization.rb +136 -0
- data/lib/openstudio/workflow/jobs/run_os_measures.rb +59 -0
- data/lib/openstudio/workflow/jobs/run_postprocess.rb +53 -0
- data/lib/openstudio/workflow/jobs/run_preprocess.rb +81 -0
- data/lib/openstudio/workflow/jobs/run_reporting_measures.rb +86 -0
- data/lib/openstudio/workflow/jobs/run_translation.rb +49 -0
- data/lib/openstudio/workflow/multi_delegator.rb +1 -3
- data/lib/openstudio/workflow/registry.rb +137 -0
- data/lib/openstudio/workflow/run.rb +182 -221
- data/lib/openstudio/workflow/time_logger.rb +1 -1
- data/lib/openstudio/workflow/util/energyplus.rb +564 -0
- data/lib/openstudio/workflow/util/io.rb +33 -0
- data/lib/openstudio/workflow/util/measure.rb +520 -0
- data/lib/openstudio/workflow/util/model.rb +100 -0
- data/lib/openstudio/workflow/util/post_process.rb +177 -0
- data/lib/openstudio/workflow/util/weather_file.rb +108 -0
- data/lib/openstudio/workflow/util.rb +14 -0
- data/lib/openstudio/workflow/version.rb +1 -1
- data/lib/openstudio/workflow_json.rb +399 -0
- data/lib/openstudio/workflow_runner.rb +213 -0
- data/lib/openstudio-workflow.rb +13 -118
- metadata +45 -85
- data/lib/openstudio/extended_runner.rb +0 -105
- data/lib/openstudio/workflow/adapters/local.rb +0 -101
- data/lib/openstudio/workflow/adapters/mongo.rb +0 -227
- data/lib/openstudio/workflow/jobs/lib/apply_measures.rb +0 -253
- data/lib/openstudio/workflow/jobs/run_energyplus/run_energyplus.rb +0 -314
- data/lib/openstudio/workflow/jobs/run_openstudio/run_openstudio.rb +0 -230
- data/lib/openstudio/workflow/jobs/run_postprocess/run_postprocess.rb +0 -110
- data/lib/openstudio/workflow/jobs/run_reporting_measures/run_reporting_measures.rb +0 -471
- data/lib/openstudio/workflow/jobs/run_runmanager/run_runmanager.rb +0 -247
- data/lib/openstudio/workflow/jobs/run_xml/run_xml.rb +0 -279
@@ -1,247 +0,0 @@
|
|
1
|
-
######################################################################
|
2
|
-
# Copyright (c) 2008-2014, Alliance for Sustainable Energy.
|
3
|
-
# All rights reserved.
|
4
|
-
#
|
5
|
-
# This library is free software; you can redistribute it and/or
|
6
|
-
# modify it under the terms of the GNU Lesser General Public
|
7
|
-
# License as published by the Free Software Foundation; either
|
8
|
-
# version 2.1 of the License, or (at your option) any later version.
|
9
|
-
#
|
10
|
-
# This library is distributed in the hope that it will be useful,
|
11
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
-
# Lesser General Public License for more details.
|
14
|
-
#
|
15
|
-
# You should have received a copy of the GNU Lesser General Public
|
16
|
-
# License along with this library; if not, write to the Free Software
|
17
|
-
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
-
######################################################################
|
19
|
-
|
20
|
-
require 'openstudio'
|
21
|
-
|
22
|
-
# TODO: I hear that measures can step on each other if not run in their own directory
|
23
|
-
class RunRunmanager
|
24
|
-
# Mixin the MeasureApplication module to apply measures
|
25
|
-
include OpenStudio::Workflow::ApplyMeasures
|
26
|
-
|
27
|
-
# Initialize
|
28
|
-
# param directory: base directory where the simulation files are prepared
|
29
|
-
# param logger: logger object in which to write log messages
|
30
|
-
def initialize(directory, logger, time_logger, adapter, workflow_arguments, past_results, options = {})
|
31
|
-
@logger = logger
|
32
|
-
|
33
|
-
energyplus_path = find_energyplus
|
34
|
-
defaults = {
|
35
|
-
analysis_root_path: '.',
|
36
|
-
energyplus_path: energyplus_path
|
37
|
-
}
|
38
|
-
@options = defaults.merge(options)
|
39
|
-
|
40
|
-
@analysis_root_path = OpenStudio::Path.new(options[:analysis_root_path])
|
41
|
-
@directory = OpenStudio::Path.new(directory)
|
42
|
-
# TODO: there is a base number of arguments that each job will need including @run_directory. abstract it out.
|
43
|
-
@run_directory = @directory / OpenStudio::Path.new('run')
|
44
|
-
@adapter = adapter
|
45
|
-
@results = {}
|
46
|
-
@logger.info "#{self.class} passed the following options #{@options}"
|
47
|
-
@time_logger = time_logger
|
48
|
-
@workflow_arguments = workflow_arguments
|
49
|
-
@past_results = past_results
|
50
|
-
|
51
|
-
# initialize instance variables that are needed in the perform section
|
52
|
-
@model = nil
|
53
|
-
@model_idf = nil
|
54
|
-
@initial_weather_file = nil
|
55
|
-
@weather_file_path = nil
|
56
|
-
@analysis_json = nil
|
57
|
-
# TODO: rename datapoint_json to just datapoint
|
58
|
-
@datapoint_json = nil
|
59
|
-
@output_attributes = {}
|
60
|
-
@report_measures = []
|
61
|
-
end
|
62
|
-
|
63
|
-
def perform
|
64
|
-
@logger.info "Calling #{__method__} in the #{self.class} class"
|
65
|
-
@logger.info "Current directory is #{@directory}"
|
66
|
-
begin
|
67
|
-
@logger.info 'Retrieving datapoint and problem'
|
68
|
-
@datapoint_json = @adapter.get_datapoint(@directory.to_s, @options)
|
69
|
-
@analysis_json = @adapter.get_problem(@directory.to_s, @options)
|
70
|
-
|
71
|
-
# @results[:weather_filename]
|
72
|
-
# File.open("#{@run_directory}/measure_attributes.json", 'w') do
|
73
|
-
# |f| f << JSON.pretty_generate(@output_attributes)
|
74
|
-
# end
|
75
|
-
|
76
|
-
if @analysis_json && @datapoint_json
|
77
|
-
|
78
|
-
if @analysis_json[:openstudio_version].nil?
|
79
|
-
@logger.info 'analysis_json missing openstudio_version'
|
80
|
-
if @analysis_json[:analysis] && @analysis_json[:analysis][:openstudio_version]
|
81
|
-
version = @analysis_json[:analysis][:openstudio_version]
|
82
|
-
@logger.info "setting analysis_json openstudio_version to '#{version}'"
|
83
|
-
@analysis_json[:openstudio_version] = version
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
if @datapoint_json[:openstudio_version].nil?
|
88
|
-
@logger.info 'datapoint_json missing openstudio_version'
|
89
|
-
if @analysis_json[:analysis] && @analysis_json[:analysis][:openstudio_version]
|
90
|
-
version = @analysis_json[:analysis][:openstudio_version]
|
91
|
-
@logger.info "setting datapoint_json openstudio_version to '#{version}'"
|
92
|
-
@datapoint_json[:openstudio_version] = version
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
# set up log file
|
97
|
-
logSink = OpenStudio::FileLogSink.new(@run_directory / OpenStudio::Path.new('openstudio.log'))
|
98
|
-
# logSink.setLogLevel(OpenStudio::Debug)
|
99
|
-
logSink.setLogLevel(OpenStudio::Trace)
|
100
|
-
OpenStudio::Logger.instance.standardOutLogger.disable
|
101
|
-
|
102
|
-
@logger.info 'Parsing Analysis JSON input'
|
103
|
-
|
104
|
-
# load problem formulation
|
105
|
-
loadResult = OpenStudio::Analysis.loadJSON(JSON.pretty_generate(@analysis_json))
|
106
|
-
if loadResult.analysisObject.empty?
|
107
|
-
loadResult.errors.each do |error|
|
108
|
-
@logger.warn error.logMessage # DLM: is this right?
|
109
|
-
end
|
110
|
-
fail 'Unable to load analysis json.'
|
111
|
-
end
|
112
|
-
|
113
|
-
@logger.info 'Get Analysis From OpenStudio'
|
114
|
-
analysis = loadResult.analysisObject.get.to_Analysis.get
|
115
|
-
|
116
|
-
# fix up paths
|
117
|
-
@logger.info 'Fix Paths'
|
118
|
-
analysis.updateInputPathData(loadResult.projectDir, @analysis_root_path)
|
119
|
-
|
120
|
-
# save for reference only
|
121
|
-
analysis_options = OpenStudio::Analysis::AnalysisSerializationOptions.new(@analysis_root_path)
|
122
|
-
analysis.saveJSON(@run_directory / OpenStudio::Path.new('formulation_final.json'), analysis_options, true)
|
123
|
-
|
124
|
-
@logger.info 'Parsing DataPoint JSON input'
|
125
|
-
|
126
|
-
# load data point to run
|
127
|
-
loadResult = OpenStudio::Analysis.loadJSON(JSON.pretty_generate(@datapoint_json))
|
128
|
-
if loadResult.analysisObject.empty?
|
129
|
-
loadResult.errors.each do |error|
|
130
|
-
@logger.warn error.logMessage
|
131
|
-
end
|
132
|
-
fail 'Unable to load data point json.'
|
133
|
-
end
|
134
|
-
data_point = loadResult.analysisObject.get.to_DataPoint.get
|
135
|
-
analysis.addDataPoint(data_point) # also hooks up real copy of problem
|
136
|
-
|
137
|
-
@logger.info 'Creating RunManager'
|
138
|
-
|
139
|
-
# create a RunManager
|
140
|
-
run_manager_path = @run_directory / OpenStudio::Path.new('run.db')
|
141
|
-
run_manager = OpenStudio::Runmanager::RunManager.new(run_manager_path, true, false, false)
|
142
|
-
|
143
|
-
# have problem create the workflow
|
144
|
-
@logger.info 'Creating Workflow'
|
145
|
-
workflow = analysis.problem.createWorkflow(data_point, OpenStudio::Path.new($OpenStudio_Dir))
|
146
|
-
params = OpenStudio::Runmanager::JobParams.new
|
147
|
-
params.append('cleanoutfiles', 'standard')
|
148
|
-
workflow.add(params)
|
149
|
-
|
150
|
-
tools = OpenStudio::Runmanager::ConfigOptions.makeTools(OpenStudio::Path.new(@options[:energyplus_path]),
|
151
|
-
OpenStudio::Path.new,
|
152
|
-
OpenStudio::Path.new,
|
153
|
-
$OpenStudio_RubyExeDir,
|
154
|
-
OpenStudio::Path.new)
|
155
|
-
workflow.add(tools)
|
156
|
-
# DLM: Elaine somehow we need to add info to data point to avoid this error:
|
157
|
-
# [openstudio.analysis.AnalysisObject] <1> The json string cannot be parsed as an
|
158
|
-
# OpenStudio analysis framework json file, because Unable to find ToolInfo object
|
159
|
-
# at expected location.
|
160
|
-
|
161
|
-
# queue the RunManager job
|
162
|
-
@logger.info 'Queue RunManager Job'
|
163
|
-
url_search_paths = OpenStudio::URLSearchPathVector.new
|
164
|
-
weather_file_path = OpenStudio::Path.new
|
165
|
-
if analysis.weatherFile
|
166
|
-
weather_file_path = analysis.weatherFile.get.path
|
167
|
-
end
|
168
|
-
job = workflow.create(@run_directory, analysis.seed.path, weather_file_path, url_search_paths)
|
169
|
-
OpenStudio::Runmanager::JobFactory.optimizeJobTree(job)
|
170
|
-
analysis.setDataPointRunInformation(data_point, job, OpenStudio::PathVector.new)
|
171
|
-
run_manager.enqueue(job, false)
|
172
|
-
|
173
|
-
@logger.info 'Waiting for simulation to finish'
|
174
|
-
|
175
|
-
if false
|
176
|
-
# Get some introspection on what the current running job is. For now just
|
177
|
-
# look at the directories that are being generated
|
178
|
-
job_dirs = []
|
179
|
-
while run_manager.workPending
|
180
|
-
sleep 1
|
181
|
-
OpenStudio::Application.instance.processEvents
|
182
|
-
|
183
|
-
# check if there are any new folders that were creates
|
184
|
-
temp_dirs = Dir[File.join(@run_directory.to_s, '*/')].map { |d| d.split('/').pop }.sort
|
185
|
-
if (temp_dirs + job_dirs).uniq != job_dirs
|
186
|
-
@logger.info "#{(temp_dirs - job_dirs).join(',')}"
|
187
|
-
job_dirs = temp_dirs
|
188
|
-
end
|
189
|
-
end
|
190
|
-
else
|
191
|
-
run_manager.waitForFinished
|
192
|
-
end
|
193
|
-
|
194
|
-
@logger.info 'Simulation finished'
|
195
|
-
|
196
|
-
# use the completed job to populate data_point with results
|
197
|
-
@logger.info 'Updating OpenStudio DataPoint object'
|
198
|
-
analysis.problem.updateDataPoint(data_point, job)
|
199
|
-
|
200
|
-
@results = { pat_data_point: ::MultiJson.load(data_point.toJSON, symbolize_names: true) }
|
201
|
-
|
202
|
-
# Savet this to the directory for debugging purposes
|
203
|
-
File.open("#{@run_directory}/data_point_result.json", 'w') { |f| f << MultiJson.dump(@results, pretty: true) }
|
204
|
-
|
205
|
-
fail 'Simulation Failed' if data_point.failed
|
206
|
-
else
|
207
|
-
fail 'Could not find analysis_json and datapoint_json'
|
208
|
-
end
|
209
|
-
|
210
|
-
rescue => e
|
211
|
-
log_message = "#{__FILE__} failed with #{e.message}, #{e.backtrace.join("\n")}"
|
212
|
-
@logger.error log_message
|
213
|
-
|
214
|
-
# do not raise as the results will never end up in the datapoint
|
215
|
-
# raise log_message
|
216
|
-
end
|
217
|
-
|
218
|
-
@results
|
219
|
-
end
|
220
|
-
|
221
|
-
private
|
222
|
-
|
223
|
-
# Look for the location of EnergyPlus
|
224
|
-
def find_energyplus
|
225
|
-
if ENV['ENERGYPLUSDIR']
|
226
|
-
return ENV['ENERGYPLUSDIR']
|
227
|
-
# TODO: check if method exists! first
|
228
|
-
elsif OpenStudio.respond_to? :getEnergyPlusDirectory
|
229
|
-
return OpenStudio.getEnergyPlusDirectory.to_s
|
230
|
-
elsif ENV['RUBYLIB'] =~ /OpenStudio/
|
231
|
-
warn 'Finding EnergyPlus by RUBYLIB parsing will not be supported in the near future. Use either ENERGYPLUSDIR'\
|
232
|
-
'env variable or a newer OpenStudio version that has the getEnergyPlusDirectory method'
|
233
|
-
path = ENV['RUBYLIB'].split(':')
|
234
|
-
path = File.dirname(path.find { |p| p =~ /OpenStudio/ })
|
235
|
-
# Grab the version out of the openstudio path
|
236
|
-
path += '/sharedresources/EnergyPlus-8-3-0'
|
237
|
-
|
238
|
-
return path
|
239
|
-
else
|
240
|
-
if /cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM
|
241
|
-
return 'C:/EnergyPlus-8-3-0'
|
242
|
-
else
|
243
|
-
return '/usr/local/EnergyPlus-8-3-0'
|
244
|
-
end
|
245
|
-
end
|
246
|
-
end
|
247
|
-
end
|
@@ -1,279 +0,0 @@
|
|
1
|
-
######################################################################
|
2
|
-
# Copyright (c) 2008-2014, Alliance for Sustainable Energy.
|
3
|
-
# All rights reserved.
|
4
|
-
#
|
5
|
-
# This library is free software; you can redistribute it and/or
|
6
|
-
# modify it under the terms of the GNU Lesser General Public
|
7
|
-
# License as published by the Free Software Foundation; either
|
8
|
-
# version 2.1 of the License, or (at your option) any later version.
|
9
|
-
#
|
10
|
-
# This library is distributed in the hope that it will be useful,
|
11
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
-
# Lesser General Public License for more details.
|
14
|
-
#
|
15
|
-
# You should have received a copy of the GNU Lesser General Public
|
16
|
-
# License along with this library; if not, write to the Free Software
|
17
|
-
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
-
######################################################################
|
19
|
-
|
20
|
-
require 'libxml'
|
21
|
-
|
22
|
-
# This actually belongs as another class that gets added as a state dynamically
|
23
|
-
class RunXml
|
24
|
-
# RunXml
|
25
|
-
def initialize(directory, logger, time_logger, adapter, workflow_arguments, past_results, options = {})
|
26
|
-
defaults = { analysis_root_path: '.', xml_library_file: 'xml_runner.rb' }
|
27
|
-
@options = defaults.merge(options)
|
28
|
-
@directory = directory
|
29
|
-
# TODO: there is a base number of arguments that each job will need including @run_directory. abstract it out.
|
30
|
-
@run_directory = "#{@directory}/run"
|
31
|
-
@adapter = adapter
|
32
|
-
@results = {}
|
33
|
-
@logger = logger
|
34
|
-
@time_logger = time_logger
|
35
|
-
@workflow_arguments = workflow_arguments
|
36
|
-
@past_results = past_results
|
37
|
-
@logger.info "#{self.class} passed the following options #{@options}"
|
38
|
-
|
39
|
-
# initialize instance variables that are needed in the perform section
|
40
|
-
@weather_filename = nil
|
41
|
-
@weather_directory = File.expand_path(File.join(@options[:analysis_root_path], 'weather'))
|
42
|
-
@logger.info "Weather directory is: #{@weather_directory}"
|
43
|
-
@model_xml = nil
|
44
|
-
@model = nil
|
45
|
-
@model_idf = nil
|
46
|
-
@analysis_json = nil
|
47
|
-
# TODO: rename datapoint_json to just datapoint
|
48
|
-
@datapoint_json = nil
|
49
|
-
@output_attributes = {}
|
50
|
-
@report_measures = []
|
51
|
-
@measure_type_lookup = {
|
52
|
-
openstudio_measure: 'RubyMeasure',
|
53
|
-
energyplus_measure: 'EnergyPlusMeasure',
|
54
|
-
reporting_measure: 'ReportingMeasure'
|
55
|
-
}
|
56
|
-
end
|
57
|
-
|
58
|
-
def perform
|
59
|
-
@logger.info "Calling #{__method__} in the #{self.class} class"
|
60
|
-
@logger.info "Current directory is #{@directory}"
|
61
|
-
|
62
|
-
@logger.info 'Retrieving datapoint and problem'
|
63
|
-
@datapoint_json = @adapter.get_datapoint(@directory, @options)
|
64
|
-
@analysis_json = @adapter.get_problem(@directory, @options)
|
65
|
-
|
66
|
-
if @analysis_json && @analysis_json[:analysis]
|
67
|
-
@model_xml = load_xml_model
|
68
|
-
@weather_filename = load_weather_file
|
69
|
-
|
70
|
-
begin
|
71
|
-
apply_xml_measures
|
72
|
-
rescue => e
|
73
|
-
log_message = "Exception during 'apply_xml_measure' with #{e.message}, #{e.backtrace.join("\n")}"
|
74
|
-
raise log_message
|
75
|
-
end
|
76
|
-
|
77
|
-
# @logger.debug "XML measure output attributes JSON is #{@output_attributes}"
|
78
|
-
File.open("#{@run_directory}/measure_attributes_xml.json", 'w') do |f|
|
79
|
-
f << JSON.pretty_generate(@output_attributes)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
create_osm_from_xml
|
84
|
-
|
85
|
-
@results
|
86
|
-
end
|
87
|
-
|
88
|
-
private
|
89
|
-
|
90
|
-
def load_xml_model
|
91
|
-
model = nil
|
92
|
-
@logger.info 'Loading seed model'
|
93
|
-
|
94
|
-
if @analysis_json[:analysis][:seed]
|
95
|
-
@logger.info "Seed model is #{@analysis_json[:analysis][:seed]}"
|
96
|
-
if @analysis_json[:analysis][:seed][:path]
|
97
|
-
|
98
|
-
# assume that the seed model has been placed in the directory
|
99
|
-
baseline_model_path = File.expand_path(
|
100
|
-
File.join(@options[:analysis_root_path], @analysis_json[:analysis][:seed][:path]))
|
101
|
-
|
102
|
-
if File.exist? baseline_model_path
|
103
|
-
@logger.info "Reading in baseline model #{baseline_model_path}"
|
104
|
-
model = LibXML::XML::Document.file(baseline_model_path)
|
105
|
-
fail 'XML model is nil' if model.nil?
|
106
|
-
|
107
|
-
model.save("#{@run_directory}/original.xml")
|
108
|
-
else
|
109
|
-
fail "Seed model '#{baseline_model_path}' did not exist"
|
110
|
-
end
|
111
|
-
else
|
112
|
-
fail 'No seed model path in JSON defined'
|
113
|
-
end
|
114
|
-
else
|
115
|
-
fail 'No seed model block'
|
116
|
-
end
|
117
|
-
|
118
|
-
model
|
119
|
-
end
|
120
|
-
|
121
|
-
# Save the weather file to the instance variable. This can change later after measures run.
|
122
|
-
def load_weather_file
|
123
|
-
weather_filename = nil
|
124
|
-
if @analysis_json[:analysis][:weather_file]
|
125
|
-
if @analysis_json[:analysis][:weather_file][:path]
|
126
|
-
# This last(4) needs to be cleaned up. Why don't we know the path of the file?
|
127
|
-
# assume that the seed model has been placed in the directory
|
128
|
-
weather_filename = File.expand_path(
|
129
|
-
File.join(@options[:analysis_root_path], @analysis_json[:analysis][:weather_file][:path]))
|
130
|
-
unless File.exist?(weather_filename)
|
131
|
-
@logger.warn "Could not find weather file for simulation #{weather_filename}. Will continue because may change"
|
132
|
-
end
|
133
|
-
|
134
|
-
else
|
135
|
-
fail 'No weather file path defined'
|
136
|
-
end
|
137
|
-
else
|
138
|
-
fail 'No weather file block defined'
|
139
|
-
end
|
140
|
-
|
141
|
-
weather_filename
|
142
|
-
end
|
143
|
-
|
144
|
-
def create_osm_from_xml
|
145
|
-
# Save the final state of the XML file
|
146
|
-
xml_filename = "#{@run_directory}/final.xml"
|
147
|
-
@model_xml.save(xml_filename)
|
148
|
-
|
149
|
-
@logger.info 'Starting XML to OSM translation'
|
150
|
-
begin
|
151
|
-
# set the lib path first -- very specific for this application right now
|
152
|
-
@space_lib_path = File.expand_path("#{File.dirname(@options[:xml_library_file])}/space_types")
|
153
|
-
require @options[:xml_library_file]
|
154
|
-
|
155
|
-
@logger.info "The weather file is #{@weather_filename}"
|
156
|
-
|
157
|
-
osxt = Main.new(@weather_directory, @space_lib_path)
|
158
|
-
# def process(as_xml, ideal_loads=false, optimized_model=false, return_objects=false)
|
159
|
-
osm, idf, new_xml, building_name, weather_file = osxt.process(@model_xml.to_s, false, false, true)
|
160
|
-
# return [model, idf_model, zones_xml, building_name, weather_file]
|
161
|
-
rescue => e
|
162
|
-
log_message = "Runner error #{__FILE__} failed with #{e.message}, #{e.backtrace.join("\n")}"
|
163
|
-
raise log_message
|
164
|
-
end
|
165
|
-
|
166
|
-
if osm
|
167
|
-
osm_filename = "#{@run_directory}/xml_out.osm"
|
168
|
-
File.open(osm_filename, 'w') { |f| f << osm }
|
169
|
-
|
170
|
-
@logger.info 'Finished XML to OSM translation'
|
171
|
-
else
|
172
|
-
fail 'No OSM model output from XML translation'
|
173
|
-
end
|
174
|
-
|
175
|
-
@results[:osm_filename] = File.expand_path(osm_filename)
|
176
|
-
@results[:xml_filename] = File.expand_path(xml_filename)
|
177
|
-
@results[:weather_filename] = File.expand_path(File.join(@weather_directory, @weather_filename))
|
178
|
-
end
|
179
|
-
|
180
|
-
def apply_xml_measures
|
181
|
-
# iterate over the workflow and grab the measures
|
182
|
-
if @analysis_json[:analysis][:problem] && @analysis_json[:analysis][:problem][:workflow]
|
183
|
-
@analysis_json[:analysis][:problem][:workflow].each do |wf|
|
184
|
-
if wf[:measure_type] == 'XmlMeasure'
|
185
|
-
# need to map the variables to the XML classes
|
186
|
-
measure_path = wf[:measure_definition_directory]
|
187
|
-
measure_name = wf[:measure_definition_class_name]
|
188
|
-
|
189
|
-
@logger.info "XML Measure path is #{measure_path}"
|
190
|
-
@logger.info "XML Measure name is #{measure_name}"
|
191
|
-
|
192
|
-
@logger.info "Loading measure in relative path #{measure_path}"
|
193
|
-
measure_file_path = File.expand_path(
|
194
|
-
File.join(@options[:analysis_root_path], measure_path, 'measure.rb'))
|
195
|
-
fail "Measure file does not exist #{measure_name} in #{measure_file_path}" unless File.exist? measure_file_path
|
196
|
-
|
197
|
-
require measure_file_path
|
198
|
-
measure = Object.const_get(measure_name).new
|
199
|
-
|
200
|
-
@logger.info "iterate over arguments for workflow item #{wf[:name]}"
|
201
|
-
|
202
|
-
# The Argument hash in the workflow json file looks like the following
|
203
|
-
# {
|
204
|
-
# "display_name": "Set XPath",
|
205
|
-
# "machine_name": "set_xpath",
|
206
|
-
# "name": "xpath",
|
207
|
-
# "value": "/building/blocks/block/envelope/surfaces/window/layout/wwr",
|
208
|
-
# "uuid": "440dcce0-7663-0131-41f1-14109fdf0b37",
|
209
|
-
# "version_uuid": "440e4bd0-7663-0131-41f2-14109fdf0b37"
|
210
|
-
# }
|
211
|
-
args = {}
|
212
|
-
if wf[:arguments]
|
213
|
-
wf[:arguments].each do |wf_arg|
|
214
|
-
if wf_arg[:value]
|
215
|
-
@logger.info "Setting argument value '#{wf_arg[:name]}' to '#{wf_arg[:value]}'"
|
216
|
-
# Note that these measures have symbolized hash keys and not strings. I really want indifferential access here!
|
217
|
-
args[wf_arg[:name].to_sym] = wf_arg[:value]
|
218
|
-
end
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
|
-
@logger.info "iterate over variables for workflow item '#{wf[:name]}'"
|
223
|
-
if wf[:variables]
|
224
|
-
wf[:variables].each do |wf_var|
|
225
|
-
# Argument hash in workflow looks like the following
|
226
|
-
# argument: {
|
227
|
-
# display_name: "Window-To-Wall Ratio",
|
228
|
-
# display_name_short: "Window-To-Wall Ratio",
|
229
|
-
# name: "value",
|
230
|
-
# value_type: "double",
|
231
|
-
# uuid: "27909cb0-f8c9-0131-9b05-14109fdf0b37"
|
232
|
-
# },
|
233
|
-
variable_uuid = wf_var[:uuid].to_sym # this is what the variable value is set to
|
234
|
-
if wf_var[:argument]
|
235
|
-
variable_name = wf_var[:argument][:name]
|
236
|
-
|
237
|
-
# Get the value from the data point json that was set via R / Problem Formulation
|
238
|
-
if @datapoint_json[:data_point]
|
239
|
-
if @datapoint_json[:data_point][:set_variable_values]
|
240
|
-
unless @datapoint_json[:data_point][:set_variable_values][variable_uuid].nil?
|
241
|
-
@logger.info "Setting variable '#{variable_name}' to '#{@datapoint_json[:data_point][:set_variable_values][variable_uuid]}'"
|
242
|
-
|
243
|
-
args[wf_var[:argument][:name].to_sym] = @datapoint_json[:data_point][:set_variable_values][variable_uuid]
|
244
|
-
args["#{wf_var[:argument][:name]}_machine_name".to_sym] = wf_var[:argument][:display_name].to_underscore
|
245
|
-
args["#{wf_var[:argument][:name]}_type".to_sym] = wf_var[:value_type] if wf_var[:value_type]
|
246
|
-
@logger.info "Setting the machine name for argument '#{wf_var[:argument][:name]}' to '#{args["#{wf_var[:argument][:name]}_machine_name".to_sym]}'"
|
247
|
-
|
248
|
-
# Catch a very specific case where the weather file has to be changed
|
249
|
-
if wf[:name] == 'location'
|
250
|
-
@logger.warn "VERY SPECIFIC case to change the location to #{@datapoint_json[:data_point][:set_variable_values][variable_uuid]}"
|
251
|
-
@weather_filename = @datapoint_json[:data_point][:set_variable_values][variable_uuid]
|
252
|
-
end
|
253
|
-
else
|
254
|
-
fail "[ERROR] Value for variable '#{variable_name}:#{variable_uuid}' not set in datapoint object"
|
255
|
-
end
|
256
|
-
else
|
257
|
-
fail 'No block for set_variable_values in data point record'
|
258
|
-
end
|
259
|
-
else
|
260
|
-
fail 'No block for data_point in data_point record'
|
261
|
-
end
|
262
|
-
end
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
# Run the XML Measure
|
267
|
-
xml_changed = measure.run(@model_xml, nil, args)
|
268
|
-
|
269
|
-
# save the JSON with the changed values
|
270
|
-
# the measure has to implement the "results_to_json" method
|
271
|
-
@output_attributes[wf[:name].to_sym] = measure.variable_values
|
272
|
-
measure.results_to_json("#{@run_directory}/#{wf[:name]}_results.json")
|
273
|
-
|
274
|
-
@logger.info "Finished applying measure workflow #{wf[:name]} with change flag set to '#{xml_changed}'"
|
275
|
-
end
|
276
|
-
end
|
277
|
-
end
|
278
|
-
end
|
279
|
-
end
|