openstudio-workflow 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +39 -2
- data/Rakefile +12 -1
- data/lib/openstudio-workflow.rb +31 -4
- data/lib/openstudio/workflow/adapter.rb +8 -9
- data/lib/openstudio/workflow/adapters/local.rb +35 -22
- data/lib/openstudio/workflow/adapters/mongo.rb +82 -92
- data/lib/openstudio/workflow/jobs/lib/apply_measures.rb +229 -0
- data/lib/openstudio/workflow/jobs/run_energyplus/run_energyplus.rb +7 -10
- data/lib/openstudio/workflow/jobs/run_openstudio/run_openstudio.rb +37 -159
- data/lib/openstudio/workflow/jobs/run_postprocess/run_postprocess.rb +53 -492
- data/lib/openstudio/workflow/jobs/run_preflight/run_preflight.rb +1 -5
- data/lib/openstudio/workflow/jobs/{run_postprocess → run_reporting_measures}/packaged_measures/README.md +0 -0
- data/lib/openstudio/workflow/jobs/{run_postprocess → run_reporting_measures}/packaged_measures/StandardReports/measure.rb +81 -87
- data/lib/openstudio/workflow/jobs/{run_postprocess → run_reporting_measures}/packaged_measures/StandardReports/measure.xml +1 -1
- data/lib/openstudio/workflow/jobs/{run_postprocess/packaged_measures/StandardReports/resources/report.html.in → run_reporting_measures/packaged_measures/StandardReports/resources/report.html.erb} +0 -0
- data/lib/openstudio/workflow/jobs/run_reporting_measures/run_reporting_measures.rb +548 -0
- data/lib/openstudio/workflow/jobs/run_runmanager/run_runmanager.rb +226 -0
- data/lib/openstudio/workflow/jobs/run_xml/run_xml.rb +39 -41
- data/lib/openstudio/workflow/multi_delegator.rb +6 -6
- data/lib/openstudio/workflow/run.rb +95 -39
- data/lib/openstudio/workflow/version.rb +1 -1
- metadata +9 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8246584121ca33fc5d5b10e34ff852d0884d6de6
|
4
|
+
data.tar.gz: 979bcb2d5e8445a6cf69cf1e948d091ae1a0cf61
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 843a1e9af4d17e54b28d30d83fe9020502c29ac71e350f3e1625694feea3120a97826dd8ae8c383e3f4bf75ab91ada7b2c67de3d737ed339bdbd099f4ba1517f
|
7
|
+
data.tar.gz: a9463ff16b20e54881097c2fae31ad82f9ed9a1d3398a7fc0987640abaa824fba58923bfd4783c52572d91ca673c967081c0d735e281e7657d30bd193b373773
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,15 @@ OpenStudio::Workflow Change Log
|
|
4
4
|
Unreleased
|
5
5
|
--------------
|
6
6
|
|
7
|
+
Version 0.0.2
|
8
|
+
--------------
|
9
|
+
|
10
|
+
* Support reporting measures
|
11
|
+
* Reduce logging messages
|
12
|
+
* Keep IDF files
|
13
|
+
* Remove mtr and eso files after simulation completes
|
14
|
+
* If measure changes weather file, then use the new weather file with the analysis.json weather path
|
15
|
+
|
7
16
|
Version 0.0.1
|
8
17
|
--------------
|
9
18
|
|
data/README.md
CHANGED
@@ -60,7 +60,7 @@ The workflow manager can also use MongoDB to receive instructions on the workflo
|
|
60
60
|
* Read the analysis.json file to determine the states that are going to run instead of (or inaddition to) passing them into the constructor
|
61
61
|
* Implement better error handling with custom exception classes
|
62
62
|
* Implement a different measure directory, seed model directory, and weather file directory option
|
63
|
-
* Dynamically add other "states" to the workflow
|
63
|
+
* ~Dynamically add other "states" to the workflow~
|
64
64
|
* Create and change into a unique directory when running measures
|
65
65
|
* ~~Implement Error State~~
|
66
66
|
* ~~Implement MongoDB Adapter~~
|
@@ -68,7 +68,6 @@ The workflow manager can also use MongoDB to receive instructions on the workflo
|
|
68
68
|
* Add a results adapter to return a string as the last call based on the source of the call. (e.g. R, command line, C++, etc).
|
69
69
|
* Implement a logger in the Adapters, right now they are unable to log
|
70
70
|
* Hook up the measure groups based workflows
|
71
|
-
* More tests!
|
72
71
|
* ~~Add xml workflow item~~
|
73
72
|
|
74
73
|
## Testing and Development
|
@@ -95,3 +94,41 @@ Run `rspec` or `rake` to execute the tests.
|
|
95
94
|
|
96
95
|
## Development
|
97
96
|
|
97
|
+
If you are testing changes to OpenStudio source code and want to test these on the Vagrant machine you can use the source configuration. This creates a new virtual machine which can be accessed by adding the name 'source' to the end of standard Vagrant commands. To set up this machine, build a custom version of OpenStudio, and install that version for testing follow these steps:
|
98
|
+
|
99
|
+
* vagrant up source
|
100
|
+
* vagrant ssh source
|
101
|
+
* sudo apt-get install dpkg-dev git cmake-curses-gui qt5-default libqt5webkit5-dev libboost1.55-all-dev swig ruby2.0 libssl-dev libxt-dev doxygen graphviz
|
102
|
+
* sudo ln -s /usr/lib/x86_64-linux-gnu/libruby-2.0.so.2.0.0 /usr/lib/x86_64-linux-gnu/libruby.so.2.0
|
103
|
+
** Install clang (OPTIONAL):
|
104
|
+
** wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key|sudo apt-key add -
|
105
|
+
** sudo apt-add-repository 'deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.5 main'
|
106
|
+
** sudo apt-get update
|
107
|
+
** sudo apt-get install clang-3.5
|
108
|
+
** echo 'export CC=/usr/bin/clang-3.5' >> ~/.bashrc
|
109
|
+
** echo 'export CXX=/usr/bin/clang++-3.5' >> ~/.bashrc
|
110
|
+
** source ~/.bashrc
|
111
|
+
** cd /home/vagrant
|
112
|
+
* git clone https://github.com/NREL/OpenStudio.git openstudio
|
113
|
+
* cd openstudio
|
114
|
+
* git checkout your_branch_name
|
115
|
+
* mkdir build
|
116
|
+
* cd build
|
117
|
+
* cmake .. -DBUILD_PACKAGE=TRUE -DCMAKE_INSTALL_PREFIX=$OPENSTUDIO_ROOT -DRUBY_EXECUTABLE=/usr/local/rbenv/versions/2.0.0-p481/bin/ruby
|
118
|
+
* make -j4
|
119
|
+
|
120
|
+
To install do either:
|
121
|
+
* cd OpenStudioCore-prefix/src/OpenStudioCore-build/
|
122
|
+
* sudo make install
|
123
|
+
|
124
|
+
or:
|
125
|
+
* make package
|
126
|
+
* sudo ./OpenStudio-1.5.1.02b7131b4c-Linux.sh --prefix=/usr/local --exclude-subdir --skip-license
|
127
|
+
|
128
|
+
Next you have to do this:
|
129
|
+
* export RUBYLIB=/usr/local/Ruby
|
130
|
+
* export LD_LIBRARY_PATH=/usr/local/lib
|
131
|
+
|
132
|
+
Then you can test that you are using your build by comparing the output of these two commands:
|
133
|
+
* ruby -e "require 'openstudio'" -e "puts OpenStudio::openStudioLongVersion"
|
134
|
+
* git rev-parse --short HEAD
|
data/Rakefile
CHANGED
@@ -12,9 +12,20 @@ require 'rake'
|
|
12
12
|
require 'rspec/core'
|
13
13
|
require 'rspec/core/rake_task'
|
14
14
|
|
15
|
-
#require 'rubocop/rake_task'
|
15
|
+
# require 'rubocop/rake_task'
|
16
16
|
RSpec::Core::RakeTask.new(:spec) do |spec|
|
17
|
+
spec.rspec_opts = %w(--format progress --format CI::Reporter::RSpec)
|
17
18
|
spec.pattern = FileList['spec/**/*_spec.rb']
|
18
19
|
end
|
19
20
|
|
21
|
+
require 'rubocop/rake_task'
|
22
|
+
desc 'Run RuboCop on the lib directory'
|
23
|
+
RuboCop::RakeTask.new(:rubocop) do |task|
|
24
|
+
task.options = ['--no-color', '--out=rubocop-results.xml']
|
25
|
+
task.formatters = ['RuboCop::Formatter::CheckstyleFormatter']
|
26
|
+
task.requires = ['rubocop/formatter/checkstyle_formatter']
|
27
|
+
# don't abort rake on failure
|
28
|
+
task.fail_on_error = false
|
29
|
+
end
|
30
|
+
|
20
31
|
task default: [:spec]
|
data/lib/openstudio-workflow.rb
CHANGED
@@ -23,6 +23,7 @@ require 'multi_json'
|
|
23
23
|
require 'colored'
|
24
24
|
require 'fileutils'
|
25
25
|
require 'json' # needed for a single pretty generate call
|
26
|
+
require 'pathname'
|
26
27
|
|
27
28
|
begin
|
28
29
|
require 'facter'
|
@@ -33,6 +34,7 @@ end
|
|
33
34
|
require 'openstudio/workflow/version'
|
34
35
|
require 'openstudio/workflow/multi_delegator'
|
35
36
|
require 'openstudio/workflow/run'
|
37
|
+
require 'openstudio/workflow/jobs/lib/apply_measures'
|
36
38
|
|
37
39
|
begin
|
38
40
|
require 'openstudio'
|
@@ -42,14 +44,39 @@ rescue LoadError => e
|
|
42
44
|
puts 'OpenStudio did not load, but most functionality is still available. Will try to continue...'.red
|
43
45
|
end
|
44
46
|
|
47
|
+
# some core extensions
|
48
|
+
class String
|
49
|
+
def snake_case
|
50
|
+
gsub(/::/, '/')
|
51
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
52
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
53
|
+
.tr(' -', '__')
|
54
|
+
.downcase
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
45
58
|
module OpenStudio
|
46
59
|
module Workflow
|
47
60
|
extend self
|
48
61
|
|
49
62
|
# Create a new workflow instance using the defined adapter and UUID
|
50
|
-
def load(adapter_name, run_directory, options={})
|
51
|
-
defaults = {adapter_options: {}}
|
63
|
+
def load(adapter_name, run_directory, options = {})
|
64
|
+
defaults = { adapter_options: {} }
|
52
65
|
options = defaults.merge(options)
|
66
|
+
|
67
|
+
# Convert various paths to absolute paths
|
68
|
+
if options[:adapter_options] && options[:adapter_options][:mongoid_path] &&
|
69
|
+
(Pathname.new options[:adapter_options][:mongoid_path]).absolute? == false
|
70
|
+
options[:adapter_options][:mongoid_path] = File.expand_path options[:adapter_options][:mongoid_path]
|
71
|
+
end
|
72
|
+
if options[:analysis_root_path] &&
|
73
|
+
(Pathname.new options[:analysis_root_path]).absolute? == false
|
74
|
+
options[:analysis_root_path] = File.expand_path options[:analysis_root_path]
|
75
|
+
end
|
76
|
+
unless (Pathname.new run_directory).absolute?
|
77
|
+
# relative to wherever you are running the script
|
78
|
+
run_directory = File.expand_path run_directory
|
79
|
+
end
|
53
80
|
adapter = load_adapter adapter_name, options[:adapter_options]
|
54
81
|
run_klass = OpenStudio::Workflow::Run.new(adapter, run_directory, options)
|
55
82
|
# return the run class
|
@@ -58,10 +85,10 @@ module OpenStudio
|
|
58
85
|
|
59
86
|
private
|
60
87
|
|
61
|
-
def load_adapter(name, adapter_options={})
|
88
|
+
def load_adapter(name, adapter_options = {})
|
62
89
|
require "openstudio/workflow/adapters/#{name.downcase}"
|
63
90
|
klass_name = name.to_s.split('_').map(&:capitalize) * ''
|
64
|
-
#pp "#{klass_name} is the adapter class name"
|
91
|
+
# pp "#{klass_name} is the adapter class name"
|
65
92
|
klass = OpenStudio::Workflow::Adapters.const_get(klass_name).new(adapter_options)
|
66
93
|
klass
|
67
94
|
end
|
@@ -21,26 +21,25 @@
|
|
21
21
|
module OpenStudio
|
22
22
|
module Workflow
|
23
23
|
class Adapter
|
24
|
-
|
25
24
|
attr_accessor :options
|
26
25
|
|
27
|
-
def initialize(options={})
|
26
|
+
def initialize(options = {})
|
28
27
|
@options = options
|
29
28
|
@log = nil
|
30
29
|
end
|
31
30
|
|
32
|
-
#class << self
|
33
|
-
#attr_reader :problem
|
31
|
+
# class << self
|
32
|
+
# attr_reader :problem
|
34
33
|
|
35
|
-
def load(filename, options={})
|
34
|
+
def load(filename, options = {})
|
36
35
|
instance.load(filename, options)
|
37
36
|
end
|
38
37
|
|
39
|
-
def communicate_started(id,
|
38
|
+
def communicate_started(id, _options = {})
|
40
39
|
instance.communicate_started id
|
41
40
|
end
|
42
41
|
|
43
|
-
def get_datapoint(id, options={})
|
42
|
+
def get_datapoint(id, options = {})
|
44
43
|
instance.get_datapoint id, options
|
45
44
|
end
|
46
45
|
|
@@ -60,9 +59,9 @@ module OpenStudio
|
|
60
59
|
instance.communicate_failure id
|
61
60
|
end
|
62
61
|
|
63
|
-
def get_logger(file, options={})
|
62
|
+
def get_logger(file, options = {})
|
64
63
|
instance.get_logger file, options
|
65
64
|
end
|
66
65
|
end
|
67
66
|
end
|
68
|
-
end
|
67
|
+
end
|
@@ -24,20 +24,19 @@ module OpenStudio
|
|
24
24
|
module Workflow
|
25
25
|
module Adapters
|
26
26
|
class Local < Adapter
|
27
|
-
def initialize(options={})
|
28
|
-
|
27
|
+
def initialize(options = {})
|
29
28
|
super
|
30
29
|
end
|
31
30
|
|
32
31
|
# Tell the system that the process has started
|
33
|
-
def communicate_started(directory,
|
32
|
+
def communicate_started(directory, _options = {})
|
34
33
|
# Watch out for namespace conflicts (::Time is okay but Time is OpenStudio::Time)
|
35
34
|
File.open("#{directory}/started.job", 'w') { |f| f << "Started Workflow #{::Time.now}" }
|
36
35
|
end
|
37
36
|
|
38
37
|
# Get the data point from the path
|
39
|
-
def get_datapoint(directory, options={})
|
40
|
-
defaults = {datapoint_filename: 'datapoint.json', format: 'json'}
|
38
|
+
def get_datapoint(directory, options = {})
|
39
|
+
defaults = { datapoint_filename: 'datapoint.json', format: 'json' }
|
41
40
|
options = defaults.merge(options)
|
42
41
|
|
43
42
|
# how do we log within this file?
|
@@ -51,7 +50,7 @@ module OpenStudio
|
|
51
50
|
# Get the Problem/Analysis definition from the local file
|
52
51
|
# TODO: rename this to get_analysis_definintion (or something like that)
|
53
52
|
def get_problem(directory, options = {})
|
54
|
-
defaults = {problem_filename: 'problem.json', format: 'json'}
|
53
|
+
defaults = { problem_filename: 'problem.json', format: 'json' }
|
55
54
|
options = defaults.merge(options)
|
56
55
|
|
57
56
|
if File.exist? "#{directory}/#{options[:problem_filename]}"
|
@@ -61,7 +60,7 @@ module OpenStudio
|
|
61
60
|
end
|
62
61
|
end
|
63
62
|
|
64
|
-
def communicate_intermediate_result(
|
63
|
+
def communicate_intermediate_result(_directory)
|
65
64
|
# noop
|
66
65
|
end
|
67
66
|
|
@@ -73,37 +72,51 @@ module OpenStudio
|
|
73
72
|
# zip up the results of the simuation.
|
74
73
|
def communicate_failure(directory)
|
75
74
|
File.open("#{directory}/failed.job", 'w') { |f| f << "Failed Workflow #{::Time.now}" }
|
76
|
-
|
75
|
+
# @communicate_module.communicate_failure(@communicate_object, os_directory)
|
77
76
|
end
|
78
77
|
|
79
78
|
def communicate_results(directory, results)
|
79
|
+
zip_results(directory, 'workflow')
|
80
|
+
|
80
81
|
if results.is_a? Hash
|
81
82
|
File.open("#{directory}/datapoint_out.json", 'w') { |f| f << JSON.pretty_generate(results) }
|
82
83
|
else
|
83
84
|
pp "Unknown datapoint result type. Please handle #{results.class}"
|
84
|
-
#data_point_json_path = OpenStudio::Path.new(run_dir) / OpenStudio::Path.new('data_point_out.json')
|
85
|
-
#os_data_point.saveJSON(data_point_json_path, true)
|
85
|
+
# data_point_json_path = OpenStudio::Path.new(run_dir) / OpenStudio::Path.new('data_point_out.json')
|
86
|
+
# os_data_point.saveJSON(data_point_json_path, true)
|
86
87
|
end
|
87
|
-
#end
|
88
|
-
end
|
89
|
-
|
90
|
-
# TODO: can this be deprecated in favor a checking the class?
|
91
|
-
def communicate_results_json(eplus_json, analysis_dir)
|
92
|
-
# noop
|
93
|
-
end
|
94
|
-
|
95
|
-
def reload
|
96
|
-
# noop
|
88
|
+
# end
|
97
89
|
end
|
98
90
|
|
99
91
|
# For the local adapter send back a handle to a file to append the data. For this adapter
|
100
92
|
# the log messages are likely to be the same as the run.log messages.
|
101
93
|
# TODO: do we really want two local logs from the Local adapter? One is in the run dir and the other is in the root
|
102
|
-
def get_logger(directory,
|
103
|
-
@log ||= File.open("#{directory}/local_adapter.log",
|
94
|
+
def get_logger(directory, _options = {})
|
95
|
+
@log ||= File.open("#{directory}/local_adapter.log", 'w')
|
104
96
|
@log
|
105
97
|
end
|
106
98
|
|
99
|
+
# TODO: this uses a system call to zip results at the moment
|
100
|
+
def zip_results(directory, _analysis_type = 'workflow')
|
101
|
+
current_dir = Dir.pwd
|
102
|
+
begin
|
103
|
+
# create zip file using a system call
|
104
|
+
# @logger.info "Zipping up data point #{analysis_dir}"
|
105
|
+
if File.directory? directory
|
106
|
+
Dir.chdir(directory)
|
107
|
+
`zip -9 -r --exclude=*.rb* data_point.zip .`
|
108
|
+
end
|
109
|
+
|
110
|
+
# zip up only the reports folder
|
111
|
+
report_dir = 'reports'
|
112
|
+
# @logger.info "Zipping up Analysis Reports Directory #{report_dir}/reports"
|
113
|
+
if File.directory? report_dir
|
114
|
+
`zip -9 -r data_point_reports.zip reports`
|
115
|
+
end
|
116
|
+
ensure
|
117
|
+
Dir.chdir(current_dir)
|
118
|
+
end
|
119
|
+
end
|
107
120
|
end
|
108
121
|
end
|
109
122
|
end
|
@@ -37,7 +37,7 @@ module OpenStudio
|
|
37
37
|
class Mongo < Adapter
|
38
38
|
attr_reader :datapoint
|
39
39
|
|
40
|
-
def initialize(options={})
|
40
|
+
def initialize(options = {})
|
41
41
|
super
|
42
42
|
|
43
43
|
require 'mongoid'
|
@@ -52,7 +52,7 @@ module OpenStudio
|
|
52
52
|
end
|
53
53
|
|
54
54
|
# Tell the system that the process has started
|
55
|
-
def communicate_started(directory, options={})
|
55
|
+
def communicate_started(directory, options = {})
|
56
56
|
# Watch out for namespace conflicts (::Time is okay but Time is OpenStudio::Time)
|
57
57
|
File.open("#{directory}/started.job", 'w') { |f| f << "Started Workflow #{::Time.now}" }
|
58
58
|
|
@@ -61,40 +61,52 @@ module OpenStudio
|
|
61
61
|
@datapoint.status_message = ''
|
62
62
|
@datapoint.run_start_time = ::Time.now
|
63
63
|
|
64
|
-
|
65
|
-
# TODO: use a different method to determine if this is an amazon account
|
64
|
+
# TODO: Get Facter to play well on windows and replace 'socket'
|
66
65
|
# TODO: use the ComputeNode model to pull out the information so that we can reuse the methods
|
67
66
|
# Determine what the IP address is of the worker node and save in the data point
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
67
|
+
|
68
|
+
retries = 0
|
69
|
+
begin
|
70
|
+
require 'socket'
|
71
|
+
if Socket.gethostname =~ /os-.*/
|
72
|
+
# Maybe use this in the future: /sbin/ifconfig eth1|grep inet|head -1|sed 's/\:/ /'|awk '{print $3}'
|
73
|
+
# Must be on vagrant and just use the hostname to do a lookup
|
74
|
+
map = {
|
73
75
|
'os-server' => '192.168.33.10',
|
74
76
|
'os-worker-1' => '192.168.33.11',
|
75
77
|
'os-worker-2' => '192.168.33.12'
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
78
|
+
}
|
79
|
+
@datapoint.ip_address = map[Socket.gethostname]
|
80
|
+
@datapoint.internal_ip_address = @datapoint.ip_address
|
81
|
+
else
|
82
|
+
if Gem.loaded_specs['facter']
|
83
|
+
# Check if we are on amazon
|
84
|
+
if Facter.fact(:ec2_metadata)
|
85
|
+
# must be on amazon
|
86
|
+
m = Facter.fact(:ec2_metadata).value
|
87
|
+
|
88
|
+
@datapoint.ip_address = m['public-ipv4'] ? m['public-ipv4'] : 'unknown'
|
89
|
+
@datapoint.internal_ip_address = m['local-ipv4'] ? m['local-ipv4'] : 'unknown'
|
90
|
+
else
|
91
|
+
@datapoint.ip_address = Facter.fact(:ipaddress).value
|
92
|
+
@datapoint.internal_ip_address = Facter.fact(:ipaddress).value
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
rescue => e
|
97
|
+
# catch any exceptions. It appears that if a new instance of amazon starts, then it is likely that
|
98
|
+
# the Facter for AWS may not be initialized yet. Retry after waiting for 15 seconds if this happens.
|
99
|
+
# If this fails out, then the only issue with this is that the data point won't be downloaded because
|
100
|
+
# the worker node is not known
|
101
|
+
|
102
|
+
# retry just in case
|
103
|
+
if retries < 30 # try for up to 5 minutes
|
104
|
+
retries += 1
|
105
|
+
sleep 10
|
106
|
+
retry
|
107
|
+
else
|
108
|
+
raise "could not find Facter based data for worker node after #{retries} retries with message #{e.message}"
|
109
|
+
# just do nothing for now
|
98
110
|
end
|
99
111
|
end
|
100
112
|
|
@@ -102,22 +114,27 @@ module OpenStudio
|
|
102
114
|
end
|
103
115
|
|
104
116
|
# Get the data point from the path
|
105
|
-
def get_datapoint(directory, options={})
|
117
|
+
def get_datapoint(directory, options = {})
|
106
118
|
# TODO : make this a conditional on when to create one vs when to error out.
|
107
119
|
# keep @datapoint as the model instance
|
108
120
|
@datapoint = DataPoint.find_or_create_by(uuid: options[:datapoint_id])
|
109
121
|
|
110
122
|
# convert to JSON for the workflow - and rearrange the version (fix THIS)
|
111
123
|
datapoint_hash = {}
|
112
|
-
|
124
|
+
if @datapoint.nil?
|
125
|
+
fail 'Could not find datapoint'
|
126
|
+
else
|
113
127
|
datapoint_hash[:data_point] = @datapoint.as_document.to_hash
|
114
128
|
# TODO: Can i remove this openstudio_version stuff?
|
115
|
-
#datapoint_hash[:openstudio_version] = datapoint_hash[:openstudio_version]
|
129
|
+
# datapoint_hash[:openstudio_version] = datapoint_hash[:openstudio_version]
|
116
130
|
|
117
131
|
# TODO: need to figure out how to get symbols from mongo.
|
118
|
-
datapoint_hash = MultiJson.load(MultiJson.dump(datapoint_hash
|
119
|
-
|
120
|
-
|
132
|
+
datapoint_hash = MultiJson.load(MultiJson.dump(datapoint_hash), symbolize_keys: true)
|
133
|
+
|
134
|
+
# save to disk for inspection
|
135
|
+
save_dp = File.join(directory, 'data_point.json')
|
136
|
+
FileUtils.rm_f save_dp if File.exist? save_dp
|
137
|
+
File.open(save_dp, 'w') { |f| f << MultiJson.dump(datapoint_hash, pretty: true) }
|
121
138
|
end
|
122
139
|
|
123
140
|
datapoint_hash
|
@@ -125,7 +142,7 @@ module OpenStudio
|
|
125
142
|
|
126
143
|
# TODO: cleanup these options. Make them part of the class. They are just unwieldly here.
|
127
144
|
def get_problem(directory, options = {})
|
128
|
-
defaults = {format: 'json'}
|
145
|
+
defaults = { format: 'json' }
|
129
146
|
options = defaults.merge(options)
|
130
147
|
|
131
148
|
get_datapoint(directory, options) unless @datapoint
|
@@ -133,7 +150,7 @@ module OpenStudio
|
|
133
150
|
if @datapoint
|
134
151
|
analysis = @datapoint.analysis.as_document.to_hash
|
135
152
|
else
|
136
|
-
fail
|
153
|
+
fail 'Cannot retrieve problem because datapoint was nil'
|
137
154
|
end
|
138
155
|
|
139
156
|
analysis_hash = {}
|
@@ -147,11 +164,11 @@ module OpenStudio
|
|
147
164
|
analysis_hash
|
148
165
|
end
|
149
166
|
|
150
|
-
def communicate_intermediate_result(
|
167
|
+
def communicate_intermediate_result(_directory)
|
151
168
|
# noop
|
152
169
|
end
|
153
170
|
|
154
|
-
def communicate_complete(
|
171
|
+
def communicate_complete(_directory)
|
155
172
|
@datapoint.run_end_time = ::Time.now
|
156
173
|
@datapoint.status = 'completed'
|
157
174
|
@datapoint.status_message = 'completed normal'
|
@@ -175,33 +192,25 @@ module OpenStudio
|
|
175
192
|
def communicate_results(directory, results)
|
176
193
|
zip_results(directory, 'workflow')
|
177
194
|
|
178
|
-
|
195
|
+
# @logger.info 'Saving EnergyPlus JSON file'
|
179
196
|
if results
|
180
|
-
@datapoint.results ? @datapoint.results.merge!(
|
197
|
+
@datapoint.results ? @datapoint.results.merge!(results) : @datapoint.results = results
|
181
198
|
end
|
182
199
|
result = @datapoint.save! # redundant because next method calls save too.
|
200
|
+
|
183
201
|
if result
|
184
|
-
|
202
|
+
# @logger.info 'Successfully saved result to database'
|
185
203
|
else
|
186
|
-
|
204
|
+
# @logger.error 'ERROR saving result to database'
|
187
205
|
end
|
188
206
|
end
|
189
207
|
|
190
|
-
# TODO: can this be deprecated in favor a checking the class?
|
191
|
-
def communicate_results_json(eplus_json, analysis_dir)
|
192
|
-
# noop
|
193
|
-
end
|
194
|
-
|
195
|
-
# TODO: not needed anymore i think...
|
196
|
-
def reload
|
197
|
-
# noop
|
198
|
-
end
|
199
|
-
|
200
208
|
# TODO: Implement the writing to the mongo_db for logging
|
201
|
-
def get_logger(directory, options={})
|
209
|
+
def get_logger(directory, options = {})
|
202
210
|
# get the datapoint object
|
203
211
|
get_datapoint(directory, options) unless @datapoint
|
204
212
|
@log = OpenStudio::Workflow::Adapters::MongoLog.new(@datapoint)
|
213
|
+
|
205
214
|
@log
|
206
215
|
end
|
207
216
|
|
@@ -213,47 +222,28 @@ module OpenStudio
|
|
213
222
|
DataPoint.find_or_create_by(uuid: uuid)
|
214
223
|
end
|
215
224
|
|
216
|
-
# TODO: this uses a system call to zip results at the moment
|
217
|
-
def zip_results(
|
218
|
-
eplus_search_path = nil
|
225
|
+
# TODO: this uses a system call to zip results at the moment, replace with rubylib
|
226
|
+
def zip_results(directory, _analysis_type = 'workflow')
|
219
227
|
current_dir = Dir.pwd
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
end
|
227
|
-
|
228
|
-
# copy some files into a report folder
|
229
|
-
eplus_html = Dir.glob(eplus_search_path).last || nil
|
230
|
-
if eplus_html
|
231
|
-
#@logger.info "Checking for HTML Report: #{eplus_html}"
|
232
|
-
if File.exist? eplus_html
|
233
|
-
# do some encoding on the html if possible
|
234
|
-
html = File.read(eplus_html)
|
235
|
-
html = html.force_encoding('ISO-8859-1').encode('utf-8', replace: nil)
|
236
|
-
File.open("#{analysis_dir}/reports/eplustbl.html", 'w') { |f| f << html }
|
228
|
+
begin
|
229
|
+
# create zip file using a system call
|
230
|
+
# @logger.info "Zipping up data point #{analysis_dir}"
|
231
|
+
if File.directory? directory
|
232
|
+
Dir.chdir(directory)
|
233
|
+
`zip -9 -r --exclude=*.rb* data_point_#{@datapoint.uuid}.zip .`
|
237
234
|
end
|
238
|
-
end
|
239
235
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
report_dir = "#{analysis_dir}"
|
249
|
-
#@logger.info "Zipping up Analysis Reports Directory #{report_dir}/reports"
|
250
|
-
if File.directory? report_dir
|
251
|
-
Dir.chdir(report_dir)
|
252
|
-
`zip -r data_point_#{@datapoint.uuid}_reports.zip reports`
|
236
|
+
# zip up only the reports folder
|
237
|
+
report_dir = 'reports'
|
238
|
+
# @logger.info "Zipping up Analysis Reports Directory #{report_dir}/reports"
|
239
|
+
if File.directory? report_dir
|
240
|
+
`zip -9 -r data_point_#{@datapoint.uuid}_reports.zip reports`
|
241
|
+
end
|
242
|
+
ensure
|
243
|
+
Dir.chdir(current_dir)
|
253
244
|
end
|
254
|
-
Dir.chdir(current_dir)
|
255
245
|
end
|
256
246
|
end
|
257
247
|
end
|
258
248
|
end
|
259
|
-
end
|
249
|
+
end
|