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