openstudio-workflow 0.0.4 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0530685f749da9f5112920053f26b8934ab4861e
4
- data.tar.gz: 312ebc0a8b2844f94796214054605e414fc5606f
3
+ metadata.gz: e81fcf5450aa2cf5f13bc03f0a253f14b95d74e9
4
+ data.tar.gz: 90a64f53393b213e23b9961a3096895de4fe4f4b
5
5
  SHA512:
6
- metadata.gz: eebca1c2eac830150a5c8cace44e77724d12090109bd34b224a228645930f85ca7f3bb068bbc254e0437719e9e8a5a23aaf5850aad18fdf45fe439cfe5b29f23
7
- data.tar.gz: 6eb722576d2142d9de21aa193703783ee4115ffa203a4d5f99c38438524cfa974e9972dc7485289790fc83736bf1fc97be1aba0bf4c099ac9eb4bf41a036bab8
6
+ metadata.gz: 6d95bdac9f31a85775003125291db53cabf63be1bf2a054fe79def4a1281f05f422b68cd23d4cc2f37132d286288ed0cdcf610b790ea7c92103f42ae20499dd2
7
+ data.tar.gz: 22491f3a0392364381028ef6287cf0dc2a4a837388da2a62013caa981799cb797f98a2150176b05b6055f87fb350230609e99c95c7ca7ccfc301435111758636
data/CHANGELOG.md CHANGED
@@ -1,7 +1,25 @@
1
1
  OpenStudio::Workflow Change Log
2
2
  ==================================
3
3
 
4
- Version 0.0.4 (Unreleased)
4
+ Version 0.1.1
5
+ ------------------
6
+ * Catch exception when loading a measure file.
7
+ * Enable running simulations on windows and mac
8
+ * Use rubyzip gem instead of system call
9
+ * Fix the double directory which caused the zip files to behave strangely on windows
10
+ * New find_energyplus method which tries to use OpenStudio's version of EnergyPlus
11
+ * Copy all EnergyPlus files into run directory
12
+ * Better cleanup after EnergyPlus simulation
13
+ * Read machine information from /etc/openstudio-server directory, if available
14
+
15
+
16
+ Version 0.1.0
17
+ -------------
18
+ * Tests for programmatically creating the analysis.json files from the OpenStudio-analysis-gem
19
+ * Upgrade to EnergyPlus 8.2. Right now the run energyplus and run runmanager job hard code these paths.
20
+ * Upgrade and fix Facter facts to grab the correct ip address when running on EC2
21
+
22
+ Version 0.0.4
5
23
  -------------
6
24
  * Include rubyXL gem for reading/writing MS Excel files
7
25
  * Remove invalid characters from OpenStudio Measure Attributes. /[|!@#\$%^&\*\(\)\{\}\\\[\]|;:'",<.>\/?\+=]+/
data/README.md CHANGED
@@ -1,19 +1,19 @@
1
1
  # OpenStudio::Workflow
2
+ [![Dependency Status](https://www.versioneye.com/user/projects/5531fb7b10e714121100102e/badge.svg?style=flat)](https://www.versioneye.com/user/projects/5531fb7b10e714121100102e)
2
3
 
3
4
  Run an EnergyPlus simulation using a file-based workflow that is read from a Local or MongoDB adapter.
4
5
 
5
6
  ## Installation
6
7
 
7
- This applications has the following dependencies
8
+ The OpenStudio Workflow Gem has the following dependencies:
8
9
 
9
10
  * Ruby 2.0
10
11
  * OpenStudio with Ruby 2.0 bindings
11
- * EnergyPlus 8.1 (assuming OpenStudio ~> 1.3.1)
12
+ * EnergyPlus 8.2 (assuming OpenStudio >= 1.5.4)
12
13
  * MongoDB if using MongoDB Adapter (or when running rspec)
13
14
 
14
15
  [OpenStudio](http://developer.nrel.gov/downloads/buildings/openstudio/builds/) needs to be installed
15
- and in your path. On Mac/Linux it is easiest to add the following to your .bash_profile or /etc/profile.d in order
16
- to make sure that OpenStudio can be loaded.
16
+ and in your path. On Mac/Linux it is easiest to add the following to your .bash_profile or /etc/profile.d/<file>.sh to ensure OpenStudio can be loaded.
17
17
 
18
18
  export OPENSTUDIO_ROOT=/usr/local
19
19
  export RUBYLIB=$OPENSTUDIO_ROOT/lib/ruby/site_ruby/2.0.0
@@ -24,18 +24,27 @@ Add this line to your application's Gemfile:
24
24
 
25
25
  Use this line if you want the bleeding edge:
26
26
 
27
- gem 'OpenStudio-workflow', :git => 'git@github.com:NREL/OpenStudio-workflow-gem.git'
27
+ gem 'OpenStudio-workflow', github: 'NREL/OpenStudio-workflow-gem', branch: 'EnergyPlus-8.2.0'
28
28
 
29
29
  And then execute:
30
+
31
+ Mac/Linux:
30
32
 
31
- $ bundle
33
+ $ bundle
34
+
35
+ Windows (avoids native extensions):
36
+
37
+ $ bundle install --without xml profile
32
38
 
33
39
  Or install it yourself as:
34
-
40
+
35
41
  $ gem install OpenStudio-workflow
36
-
42
+
37
43
  ## Usage
38
44
 
45
+ Note that the branches of the Workflow Gem depict which version of EnergyPlus is in use. The develop branch at the
46
+ moment should not be used.
47
+
39
48
  There are currently two adapters to run OpenStudio workflow. The first is a simple Local adapter
40
49
  allowing the user to pass in the directory to simulation. The directory must have an
41
50
  [analysis/problem JSON file](spec/files/local_ex1/analysis_1.json) and a [datapoint JSON file](spec/files/local_ex1/datapoint_1.json).
@@ -57,11 +66,11 @@ The workflow manager can also use MongoDB to receive instructions on the workflo
57
66
 
58
67
  ### Todos
59
68
 
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
69
+ * Read the analysis.json file to determine the states that are going to run instead of (or in addition to) passing them into the constructor
61
70
  * Implement better error handling with custom exception classes
62
- * Implement a different measure directory, seed model directory, and weather file directory option
71
+ * ~Implement a different measure directory, seed model directory, and weather file directory option~
63
72
  * ~Dynamically add other "states" to the workflow~
64
- * Create and change into a unique directory when running measures
73
+ * ~~Create and change into a unique directory when running measures~~
65
74
  * ~~Implement Error State~~
66
75
  * ~~Implement MongoDB Adapter~~
67
76
  * ~~Implement remaining Adapter states (i.e. communicate success, communicate failure etc~~
@@ -108,7 +117,7 @@ If you are testing changes to OpenStudio source code and want to test these on t
108
117
  ** echo 'export CC=/usr/bin/clang-3.5' >> ~/.bashrc
109
118
  ** echo 'export CXX=/usr/bin/clang++-3.5' >> ~/.bashrc
110
119
  ** source ~/.bashrc
111
- ** cd /home/vagrant
120
+ * cd /home/vagrant
112
121
  * git clone https://github.com/NREL/OpenStudio.git openstudio
113
122
  * cd openstudio
114
123
  * git checkout your_branch_name
data/Rakefile CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'bundler'
2
- require 'bundler/gem_tasks'
2
+
3
3
  begin
4
4
  Bundler.setup
5
5
  rescue Bundler::BundlerError => e
@@ -8,16 +8,21 @@ rescue Bundler::BundlerError => e
8
8
  exit e.status_code
9
9
  end
10
10
 
11
- require 'rake'
12
- require 'rspec/core'
13
11
  require 'rspec/core/rake_task'
14
12
 
15
- # require 'rubocop/rake_task'
16
- RSpec::Core::RakeTask.new(:spec) do |spec|
13
+ # Always create spec reports
14
+ require 'ci/reporter/rake/rspec'
15
+
16
+ # Gem tasks
17
+ require 'bundler/gem_tasks'
18
+
19
+ RSpec::Core::RakeTask.new('spec:unit') do |spec|
17
20
  spec.rspec_opts = %w(--format progress --format CI::Reporter::RSpec)
18
21
  spec.pattern = FileList['spec/**/*_spec.rb']
19
22
  end
20
23
 
24
+ task 'spec:unit' => 'ci:setup:rspec'
25
+
21
26
  require 'rubocop/rake_task'
22
27
  desc 'Run RuboCop on the lib directory'
23
28
  RuboCop::RakeTask.new(:rubocop) do |task|
@@ -28,4 +33,4 @@ RuboCop::RakeTask.new(:rubocop) do |task|
28
33
  task.fail_on_error = false
29
34
  end
30
35
 
31
- task default: [:spec]
36
+ task default: 'spec:unit'
@@ -22,14 +22,15 @@ require 'rubyXL'
22
22
  require 'multi_json'
23
23
  require 'colored'
24
24
  require 'fileutils'
25
- require 'securerandom'
25
+ require 'securerandom' # uuids
26
26
  require 'json' # needed for a single pretty generate call
27
27
  require 'pathname'
28
+ require 'mkmf' # for finding files
28
29
 
29
30
  begin
30
31
  require 'facter'
31
32
  rescue LoadError => e
32
- puts 'Could not load Facter. Will not be able to save the IP address to the log'.red
33
+ warn 'Could not load Facter. Will not be able to save the IP address to the log'.red
33
34
  end
34
35
 
35
36
  require 'openstudio/workflow/version'
@@ -86,8 +87,12 @@ module OpenStudio
86
87
  end
87
88
 
88
89
  # predefined method that simply runs EnergyPlus in the specified directory. It does not apply any workflow steps
89
- # such as preprocessing / postprocessing.
90
- # The directory must have the IDF and EPW file in the folder. The simulations will run in the directory/run path
90
+ # such as preprocessing / postprocessing. The directory must have the IDF and EPW file in the folder. The
91
+ # simulations will run in the directory/run path
92
+ #
93
+ # @param adapter_name [String] Type of adapter, local or mongo.
94
+ # @param run_directory [String] Path to where the simulation is to run
95
+ # @param options [Hash] List of options for the adapter
91
96
  def run_energyplus(adapter_name, run_directory, options = {})
92
97
  unless (Pathname.new run_directory).absolute?
93
98
  # relative to wherever you are running the script
@@ -114,9 +119,30 @@ module OpenStudio
114
119
 
115
120
  adapter = load_adapter adapter_name, options[:adapter_options]
116
121
  run_klass = OpenStudio::Workflow::Run.new(adapter, run_directory, options)
122
+
117
123
  run_klass
118
124
  end
119
125
 
126
+ # Extract an archive to a specific location
127
+ # @param archive_filename [String] Path and name of the file to extract
128
+ # @param destination [String] Path to extract to
129
+ # @param overwrite [Boolean] If true, will overwrite any extracted file that may already exist
130
+ def extract_archive(archive_filename, destination, overwrite = true)
131
+ Zip::File.open(archive_filename) do |zf|
132
+ zf.each do |f|
133
+ f_path = File.join(destination, f.name)
134
+ FileUtils.mkdir_p(File.dirname(f_path))
135
+
136
+ if File.exist?(f_path) && overwrite
137
+ FileUtils.rm_rf(f_path)
138
+ zf.extract(f, f_path)
139
+ elsif !File.exist? f_path
140
+ zf.extract(f, f_path)
141
+ end
142
+ end
143
+ end
144
+ end
145
+
120
146
  private
121
147
 
122
148
  def load_adapter(name, adapter_options = {})
@@ -26,6 +26,7 @@ module OpenStudio
26
26
  def initialize(options = {})
27
27
  @options = options
28
28
  @log = nil
29
+ @datapoint = nil
29
30
  end
30
31
 
31
32
  # class << self
@@ -62,6 +63,69 @@ module OpenStudio
62
63
  def get_logger(file, options = {})
63
64
  instance.get_logger file, options
64
65
  end
66
+
67
+ protected
68
+
69
+ # Zip up a folder and it's contents
70
+ def zip_directory(directory, zip_filename, pattern = '*')
71
+ # Submethod for adding the directory to the zip folder.
72
+ def add_directory_to_zip(zip_file, local_directory, root_directory)
73
+ Dir[File.join("#{local_directory}", '**', '**')].each do |file|
74
+ # remove the base directory from the zip file
75
+ rel_dir = local_directory.sub("#{root_directory}/", '')
76
+ zip_file_to_add = file.gsub("#{local_directory}", "#{rel_dir}")
77
+ zip_file.add(zip_file_to_add, file)
78
+ end
79
+
80
+ zip_file
81
+ end
82
+
83
+ FileUtils.rm_f(zip_filename) if File.exist?(zip_filename)
84
+
85
+ Zip.default_compression = Zlib::BEST_COMPRESSION
86
+ Zip::File.open(zip_filename, Zip::File::CREATE) do |zf|
87
+ Dir[File.join(directory, pattern)].each do |file|
88
+ if File.directory?(file)
89
+ # skip a few directory that should not be zipped as they are inputs
90
+ if File.basename(file) =~ /seed|measures|weather/
91
+ next
92
+ end
93
+ add_directory_to_zip(zf, file, directory)
94
+ else
95
+ next if File.extname(file) =~ /\.rb.*/
96
+ next if File.extname(file) =~ /\.zip.*/
97
+
98
+ zip_file_to_add = file.gsub("#{directory}/", '')
99
+ zf.add(zip_file_to_add, file)
100
+ end
101
+ end
102
+ end
103
+
104
+ File.chmod(0664, zip_filename)
105
+ end
106
+
107
+ # Main method to zip up the results of the simulation results. This will append the UUID of the data point
108
+ # if it exists. This method will create two zip files. One for the reports and one for the entire data point. The
109
+ # Data Point ZIP will also contain the reports.
110
+ #
111
+ # @param directory [String] The data point directory to zip up.
112
+ # @return nil
113
+ def zip_results(directory)
114
+ # create zip file using a system call
115
+ if Dir.exist?(directory) && File.directory?(directory)
116
+ zip_filename = @datapoint ? "data_point_#{@datapoint.uuid}.zip" : 'data_point.zip'
117
+ zip_filename = File.join(directory, zip_filename)
118
+ zip_directory directory, zip_filename
119
+ end
120
+
121
+ # zip up only the reports folder
122
+ report_dir = File.join(directory, 'reports')
123
+ if Dir.exist?(report_dir) && File.directory?(report_dir)
124
+ zip_filename = @datapoint ? "data_point_#{@datapoint.uuid}_reports.zip" : 'data_point_reports.zip'
125
+ zip_filename = File.join(directory, zip_filename)
126
+ zip_directory directory, zip_filename, 'reports'
127
+ end
128
+ end
65
129
  end
66
130
  end
67
131
  end
@@ -76,10 +76,10 @@ module OpenStudio
76
76
  end
77
77
 
78
78
  def communicate_results(directory, results)
79
- zip_results(directory, 'workflow')
79
+ zip_results(directory)
80
80
 
81
81
  if results.is_a? Hash
82
- File.open("#{directory}/datapoint_out.json", 'w') { |f| f << JSON.pretty_generate(results) }
82
+ File.open("#{directory}/data_point_out.json", 'w') { |f| f << JSON.pretty_generate(results) }
83
83
  else
84
84
  pp "Unknown datapoint result type. Please handle #{results.class}"
85
85
  # data_point_json_path = OpenStudio::Path.new(run_dir) / OpenStudio::Path.new('data_point_out.json')
@@ -90,33 +90,11 @@ module OpenStudio
90
90
 
91
91
  # For the local adapter send back a handle to a file to append the data. For this adapter
92
92
  # the log messages are likely to be the same as the run.log messages.
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
93
+ # ?: do we really want two local logs from the Local adapter? One is in the run dir and the other is in the root
94
94
  def get_logger(directory, _options = {})
95
95
  @log ||= File.open("#{directory}/local_adapter.log", 'w')
96
96
  @log
97
97
  end
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
120
98
  end
121
99
  end
122
100
  end
@@ -47,8 +47,6 @@ module OpenStudio
47
47
 
48
48
  Dir["#{base_path}/models/*.rb"].each { |f| require f }
49
49
  Mongoid.load!("#{base_path}/mongoid.yml", :development)
50
-
51
- @datapoint = nil
52
50
  end
53
51
 
54
52
  # Tell the system that the process has started
@@ -61,52 +59,60 @@ module OpenStudio
61
59
  @datapoint.status_message = ''
62
60
  @datapoint.run_start_time = ::Time.now
63
61
 
64
- # TODO: Get Facter to play well on windows and replace 'socket'
65
62
  # TODO: use the ComputeNode model to pull out the information so that we can reuse the methods
66
63
  # Determine what the IP address is of the worker node and save in the data point
67
64
 
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 = {
75
- 'os-server' => '192.168.33.10',
76
- 'os-worker-1' => '192.168.33.11',
77
- 'os-worker-2' => '192.168.33.12'
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
65
+ # ami-id: ami-7c7e4e14
66
+ # instance-id: i-c52e0412
67
+ # instance-type: m3.medium
68
+ # local-hostname: ip-10-99-169-57.ec2.internal
69
+ # local-ipv4: 10.99.169.57
70
+ # placement: us-east-1a
71
+ # public-hostname: ec2-54-161-221-129.compute-1.amazonaws.com
72
+ # public-ipv4: 54.161.221.129
73
+ # number_of_cores: 1
74
+ if File.exist? '/etc/openstudio-server/instance.yml'
75
+ y = YAML.load_file('/etc/openstudio-server/instance.yml')
76
+ @datapoint.ip_address = y['public-ipv4'] if y['public-ipv4']
77
+ @datapoint.internal_ip_address = y['local-ipv4'] if y['local-ipv4']
78
+ else
79
+ # try to infer it from the socket/facter information
80
+ # note, facter will be deprecated in the future, so don't extend it!
81
+ retries = 0
82
+ begin
83
+ require 'socket'
84
+ if Socket.gethostname =~ /os-.*/
85
+ # Maybe use this in the future: /sbin/ifconfig eth1|grep inet|head -1|sed 's/\:/ /'|awk '{print $3}'
86
+ # Must be on vagrant and just use the hostname to do a lookup
87
+ map = {
88
+ 'os-server' => '192.168.33.10',
89
+ 'os-worker-1' => '192.168.33.11',
90
+ 'os-worker-2' => '192.168.33.12'
91
+ }
92
+ @datapoint.ip_address = map[Socket.gethostname]
93
+ @datapoint.internal_ip_address = @datapoint.ip_address
94
+ else
95
+ if Gem.loaded_specs['facter']
96
+ # Use EC2 public to check if we are on AWS.
97
+ @datapoint.ip_address = Facter.fact(:ec2_public_ipv4) ? Facter.fact(:ec2_public_ipv4).value : Facter.fact(:ipaddress).value
92
98
  @datapoint.internal_ip_address = Facter.fact(:ipaddress).value
93
99
  end
94
100
  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
101
+ rescue => e
102
+ # catch any exceptions. It appears that if a new instance of amazon starts, then it is likely that
103
+ # the Facter for AWS may not be initialized yet. Retry after waiting for 15 seconds if this happens.
104
+ # If this fails out, then the only issue with this is that the data point won't be downloaded because
105
+ # the worker node is not known
106
+
107
+ # retry just in case
108
+ if retries < 30 # try for up to 5 minutes
109
+ retries += 1
110
+ sleep 10
111
+ retry
112
+ else
113
+ raise "could not find Facter based data for worker node after #{retries} retries with message #{e.message}"
114
+ # just do nothing for now
115
+ end
110
116
  end
111
117
  end
112
118
 
@@ -190,19 +196,13 @@ module OpenStudio
190
196
  end
191
197
 
192
198
  def communicate_results(directory, results)
193
- zip_results(directory, 'workflow')
199
+ zip_results(directory)
194
200
 
195
201
  # @logger.info 'Saving EnergyPlus JSON file'
196
202
  if results
197
203
  @datapoint.results ? @datapoint.results.merge!(results) : @datapoint.results = results
198
204
  end
199
205
  result = @datapoint.save! # redundant because next method calls save too.
200
-
201
- if result
202
- # @logger.info 'Successfully saved result to database'
203
- else
204
- # @logger.error 'ERROR saving result to database'
205
- end
206
206
  end
207
207
 
208
208
  # TODO: Implement the writing to the mongo_db for logging
@@ -221,28 +221,6 @@ module OpenStudio
221
221
  # keep @datapoint as the model instance
222
222
  DataPoint.find_or_create_by(uuid: uuid)
223
223
  end
224
-
225
- # TODO: this uses a system call to zip results at the moment, replace with rubylib
226
- def zip_results(directory, _analysis_type = 'workflow')
227
- current_dir = Dir.pwd
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 .`
234
- end
235
-
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)
244
- end
245
- end
246
224
  end
247
225
  end
248
226
  end
@@ -39,12 +39,12 @@ module OpenStudio
39
39
  success = true
40
40
 
41
41
  unless argument[:value].nil?
42
- @logger.info "Setting argument value #{argument[:name]} to #{argument[:value]}"
42
+ @logger.info "Setting argument value '#{argument[:name]}' to '#{argument[:value]}'"
43
43
 
44
44
  v = argument_map[argument[:name]]
45
45
  fail "Could not find argument map in measure for '#{argument[:name]}' with value '#{argument[:value]}'" unless v
46
46
  value_set = v.setValue(argument[:value])
47
- fail "Could not set argument #{argument[:name]} of value #{argument[:value]} on model" unless value_set
47
+ fail "Could not set argument '#{argument[:name]}' of value '#{argument[:value]}' on model" unless value_set
48
48
  argument_map[argument[:name]] = v.clone
49
49
  else
50
50
  @logger.warn "Value for argument '#{argument[:name]}' not set in argument list therefore will use default"
@@ -97,7 +97,7 @@ module OpenStudio
97
97
  def apply_measure(workflow_item)
98
98
  @logger.info "Starting #{__method__} for #{workflow_item[:name]}"
99
99
  @time_logger.start("Measure:#{workflow_item[:name]}")
100
- #start_time = ::Time.now
100
+ # start_time = ::Time.now
101
101
  current_dir = Dir.pwd
102
102
  begin
103
103
  measure_working_directory = "#{@run_directory}/#{workflow_item[:measure_definition_class_name]}"
@@ -120,41 +120,56 @@ module OpenStudio
120
120
  @logger.info "Loading Measure from #{measure_file_path}"
121
121
  fail "Measure file does not exist #{measure_name} in #{measure_file_path}" unless File.exist? measure_file_path
122
122
 
123
- require measure_file_path
124
- measure = Object.const_get(measure_name).new
125
- runner = OpenStudio::Ruleset::OSRunner.new
123
+ measure = nil
124
+ runner = nil
126
125
  result = nil
126
+ begin
127
+ require measure_file_path
128
+ measure = Object.const_get(measure_name).new
129
+ runner = OpenStudio::Ruleset::OSRunner.new
130
+ rescue => e
131
+ log_message = "Error requiring measure #{__FILE__}. Failed with #{e.message}, #{e.backtrace.join("\n")}"
132
+ raise log_message
133
+ end
127
134
 
128
135
  arguments = nil
129
- if workflow_item[:measure_type] == 'RubyMeasure'
130
- arguments = measure.arguments(@model)
131
- elsif workflow_item[:measure_type] == 'EnergyPlusMeasure'
132
- arguments = measure.arguments(@model)
133
- elsif workflow_item[:measure_type] == 'ReportingMeasure'
134
- arguments = measure.arguments
135
- end
136
136
 
137
- # Create argument map and initialize all the arguments
138
- argument_map = OpenStudio::Ruleset::OSArgumentMap.new
139
- arguments.each do |v|
140
- argument_map[v.name] = v.clone
141
- end
142
- # @logger.info "Argument map for measure is #{argument_map}"
137
+ begin
138
+ if workflow_item[:measure_type] == 'RubyMeasure'
139
+ arguments = measure.arguments(@model)
140
+ elsif workflow_item[:measure_type] == 'EnergyPlusMeasure'
141
+ arguments = measure.arguments(@model)
142
+ elsif workflow_item[:measure_type] == 'ReportingMeasure'
143
+ arguments = measure.arguments
144
+ end
145
+
146
+ @logger.info "Extracted the following arguments: #{arguments}"
143
147
 
144
- @logger.info "Iterating over arguments for workflow item '#{workflow_item[:name]}'"
145
- if workflow_item[:arguments]
146
- workflow_item[:arguments].each do |argument|
147
- success = apply_arguments(argument_map, argument)
148
- fail 'Could not set arguments' unless success
148
+ # Create argument map and initialize all the arguments
149
+ argument_map = OpenStudio::Ruleset::OSArgumentMap.new
150
+ arguments.each do |v|
151
+ argument_map[v.name] = v.clone
149
152
  end
150
- end
153
+ # @logger.info "Argument map for measure is #{argument_map}"
151
154
 
152
- @logger.info "Iterating over variables for workflow item '#{workflow_item[:name]}'"
153
- if workflow_item[:variables]
154
- workflow_item[:variables].each do |variable|
155
- success = apply_variables(argument_map, variable)
156
- fail 'Could not set variables' unless success
155
+ @logger.info "Iterating over arguments for workflow item '#{workflow_item[:name]}'"
156
+ if workflow_item[:arguments]
157
+ workflow_item[:arguments].each do |argument|
158
+ success = apply_arguments(argument_map, argument)
159
+ fail 'Could not set arguments' unless success
160
+ end
157
161
  end
162
+
163
+ @logger.info "Iterating over variables for workflow item '#{workflow_item[:name]}'"
164
+ if workflow_item[:variables]
165
+ workflow_item[:variables].each do |variable|
166
+ success = apply_variables(argument_map, variable)
167
+ fail 'Could not set variables' unless success
168
+ end
169
+ end
170
+ rescue => e
171
+ log_message = "Error assigning argument in measure #{__FILE__}. Failed with #{e.message}, #{e.backtrace.join("\n")}"
172
+ raise log_message
158
173
  end
159
174
 
160
175
  begin
@@ -200,9 +215,13 @@ module OpenStudio
200
215
  measure_attributes = JSON.parse(OpenStudio.toJSON(result.attributes), symbolize_names: true)
201
216
  @output_attributes[workflow_item[:name].to_sym] = measure_attributes[:attributes]
202
217
  rescue => e
203
- log_message = "TODO: #{__FILE__} failed with #{e.message}, #{e.backtrace.join("\n")}"
204
- @logger.warn log_message
218
+ log_message = "#{__FILE__} failed with #{e.message}, #{e.backtrace.join("\n")}"
219
+ @logger.error log_message
205
220
  end
221
+ rescue => e
222
+ log_message = "#{__FILE__} failed with message #{e.message} in #{e.backtrace.join("\n")}"
223
+ @logger.error log_message
224
+ raise log_message
206
225
  ensure
207
226
  Dir.chdir current_dir
208
227
  @time_logger.stop("Measure:#{workflow_item[:name]}")
@@ -17,18 +17,19 @@
17
17
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
18
  ######################################################################
19
19
 
20
+ # Force the MakeMakefile logger write file output to null.
21
+ module MakeMakefile::Logging
22
+ @logfile = File::NULL
23
+ end
24
+
20
25
  class RunEnergyplus
21
26
  # Initialize
22
27
  # param directory: base directory where the simulation files are prepared
23
28
  # param logger: logger object in which to write log messages
24
29
  def initialize(directory, logger, time_logger, adapter, options = {})
25
- energyplus_path = nil
26
- if /cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM
27
- energyplus_path = 'C:/EnergyPlus-8-1-0'
28
- else
29
- energyplus_path = '/usr/local/EnergyPlus-8-1-0'
30
- end
30
+ @logger = logger
31
31
 
32
+ energyplus_path = find_energyplus
32
33
  defaults = {
33
34
  energyplus_path: energyplus_path
34
35
  }
@@ -38,10 +39,15 @@ class RunEnergyplus
38
39
  @directory = directory
39
40
  @run_directory = "#{@directory}/run"
40
41
  @adapter = adapter
41
- @logger = logger
42
42
  @time_logger = time_logger
43
43
  @results = {}
44
44
 
45
+ # container for storing the energyplus files there were copied into the local directory. These will be
46
+ # removed at the end of the simulation.
47
+ @energyplus_files = []
48
+ @energyplus_exe = nil
49
+ @expand_objects_exe = nil
50
+
45
51
  @logger.info "#{self.class} passed the following options #{@options}"
46
52
  end
47
53
 
@@ -98,35 +104,90 @@ class RunEnergyplus
98
104
  end
99
105
 
100
106
  # can't create symlinks because the /vagrant mount is actually a windows mount
101
- @logger.info "Copying EnergyPlus files to run directory: #{@run_directory}"
102
- @time_logger.start("Copying EnergyPlus files")
103
- FileUtils.copy("#{@options[:energyplus_path]}/libbcvtb.so", "#{@run_directory}/libbcvtb.so")
104
- FileUtils.copy("#{@options[:energyplus_path]}/libepexpat.so", "#{@run_directory}/libepexpat.so")
105
- FileUtils.copy("#{@options[:energyplus_path]}/libepfmiimport.so", "#{@run_directory}/libepfmiimport.so")
106
- FileUtils.copy("#{@options[:energyplus_path]}/libDElight.so", "#{@run_directory}/libDElight.so")
107
- FileUtils.copy("#{@options[:energyplus_path]}/libDElight.so", "#{@run_directory}/libDElight.so")
108
- FileUtils.copy("#{@options[:energyplus_path]}/ExpandObjects", "#{@run_directory}/ExpandObjects")
109
- FileUtils.copy("#{@options[:energyplus_path]}/EnergyPlus", "#{@run_directory}/EnergyPlus")
110
- FileUtils.copy("#{@options[:energyplus_path]}/Energy+.idd", "#{@run_directory}/Energy+.idd")
111
- @time_logger.stop("Copying EnergyPlus files")
112
-
113
- @time_logger.start("Running EnergyPlus")
107
+ @time_logger.start('Copying EnergyPlus files')
108
+ prepare_energyplus_dir
109
+ @time_logger.stop('Copying EnergyPlus files')
110
+
111
+ @time_logger.start('Running EnergyPlus')
114
112
  @results = call_energyplus
115
- @time_logger.stop("Running EnergyPlus")
113
+ @time_logger.stop('Running EnergyPlus')
116
114
 
117
115
  @results
118
116
  end
119
117
 
120
118
  private
121
119
 
120
+ # Look for the location of EnergyPlus
121
+ def find_energyplus
122
+ if ENV['ENERGYPLUSDIR']
123
+ return ENV['ENERGYPLUSDIR']
124
+ elsif ENV['RUBYLIB'] =~ /OpenStudio/
125
+ path = ENV['RUBYLIB'].split(':')
126
+ path = File.dirname(path.find { |p| p =~ /OpenStudio/ })
127
+ # Grab the version out of the openstudio path
128
+ path += '/sharedresources/EnergyPlus-8-2-0'
129
+ @logger.info "found EnergyPlus path of #{path}"
130
+ return path
131
+ else
132
+ if /cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM
133
+ energyplus_path = 'C:/EnergyPlus-8-2-0'
134
+ else
135
+ energyplus_path = '/usr/local/EnergyPlus-8-2-0'
136
+ end
137
+
138
+ end
139
+ end
140
+
141
+ def clean_directory
142
+ @logger.info 'Removing any copied EnergyPlus files'
143
+ @energyplus_files.each do |file|
144
+ if File.exist? file
145
+ FileUtils.rm_f file
146
+ end
147
+ end
148
+
149
+ paths_to_rm = []
150
+ paths_to_rm << "#{@run_directory}/packaged_measures"
151
+ paths_to_rm << "#{@run_directory}/Energy+.ini"
152
+ paths_to_rm.each { |p| FileUtils.rm_rf(p) if File.exist?(p) }
153
+ end
154
+
155
+ # Prepare the directory to run EnergyPlus. In EnergyPlus < 8.2, we have to copy all the files into the directory.
156
+ #
157
+ # @return [Boolean] Returns true is there is more than one file copied
158
+ def prepare_energyplus_dir
159
+ @logger.info "Copying EnergyPlus files to run directory: #{@run_directory}"
160
+ Dir["#{@options[:energyplus_path]}/*"].each do |file|
161
+ next if File.directory? file
162
+ next if File.extname(file).downcase =~ /.pdf|.app|.html|.gif|.txt|.xlsx/
163
+
164
+ dest_file = "#{@run_directory}/#{File.basename(file)}"
165
+ @energyplus_files << dest_file
166
+
167
+ @energyplus_exe = File.basename(dest_file) if File.basename(dest_file) =~ /^energyplus.{0,4}$/i
168
+ @expand_objects_exe = File.basename(dest_file) if File.basename(dest_file) =~ /^ExpandObjects.{0,4}$/i
169
+ FileUtils.copy file, dest_file
170
+ end
171
+
172
+ fail "Could not find EnergyPlus Executable in #{@options[:energyplus_path]}" unless @energyplus_exe
173
+ fail "Could not find ExpandObjects Executable in #{@options[:energyplus_path]}" unless @expand_objects_exe
174
+
175
+ @energyplus_files.size > 0
176
+ end
177
+
122
178
  def call_energyplus
123
179
  begin
124
180
  current_dir = Dir.pwd
125
181
  Dir.chdir(@run_directory)
126
182
  @logger.info "Starting simulation in run directory: #{Dir.pwd}"
127
183
 
184
+ # @logger.info "Contents of: #{Dir.pwd}"
185
+ # Dir.glob("*").each do |f|
186
+ # @logger.info " #{f}"
187
+ # end
188
+
128
189
  File.open('stdout-expandobject', 'w') do |file|
129
- IO.popen('./ExpandObjects') do |io|
190
+ IO.popen("./#{@expand_objects_exe}") do |io|
130
191
  while (line = io.gets)
131
192
  file << line
132
193
  end
@@ -141,7 +202,7 @@ class RunEnergyplus
141
202
 
142
203
  # create stdout
143
204
  File.open('stdout-energyplus', 'w') do |file|
144
- IO.popen('./EnergyPlus + 2>&1') do |io|
205
+ IO.popen("./#{@energyplus_exe} 2>&1") do |io|
145
206
  while (line = io.gets)
146
207
  file << line
147
208
  end
@@ -149,25 +210,25 @@ class RunEnergyplus
149
210
  end
150
211
  r = $?
151
212
 
152
- @logger.info "System call to EnergyPlus returned #{r}"
153
-
154
- paths_to_rm = []
155
- paths_to_rm << Pathname.glob("#{@run_directory}/*.ini")
156
- paths_to_rm << Pathname.glob("#{@run_directory}/*.so")
157
- paths_to_rm << Pathname.glob("#{@run_directory}/*.idd")
158
- paths_to_rm << Pathname.glob("#{@run_directory}/ExpandObjects")
159
- paths_to_rm << Pathname.glob("#{@run_directory}/EnergyPlus")
160
- paths_to_rm << Pathname.glob("#{@run_directory}/packaged_measures")
161
- paths_to_rm.each { |p| FileUtils.rm_rf(p) }
162
-
213
+ @logger.info "EnergyPlus returned '#{r}'"
163
214
  unless r == 0
164
- fail 'EnergyPlus returned a non-zero exit code. Check the stdout-energyplus log.'
215
+ @logger.warn 'EnergyPlus returned a non-zero exit code. Check the stdout-energyplus log.'
216
+ end
217
+
218
+ if File.exist? 'eplusout.end'
219
+ f = File.read('eplusout.end').force_encoding('ISO-8859-1').encode('utf-8', replace: nil)
220
+ warnings_count = f[/(\d*).Warning/, 1]
221
+ error_count = f[/(\d*).Severe.Errors/, 1]
222
+ @logger.info "EnergyPlus finished with #{warnings_count} warnings and #{error_count} severe errors"
223
+ if f =~ /EnergyPlus Terminated--Fatal Error Detected/
224
+ fail 'EnergyPlus Terminated with a Fatal Error. Check eplusout.err log.'
225
+ end
226
+ else
227
+ fail 'EnergyPlus failed and did not create an eplusout.end file. Check the stdout-energyplus log.'
165
228
  end
166
229
 
167
- # TODO: check the end or err file
168
230
  if File.exist? 'eplusout.err'
169
- eplus_err = File.read('eplusout.err')
170
- eplus_err = eplus_err.force_encoding('ISO-8859-1').encode('utf-8', replace: nil)
231
+ eplus_err = File.read('eplusout.err').force_encoding('ISO-8859-1').encode('utf-8', replace: nil)
171
232
  if eplus_err =~ /EnergyPlus Terminated--Fatal Error Detected/
172
233
  fail 'EnergyPlus Terminated with a Fatal Error. Check eplusout.err log.'
173
234
  end
@@ -177,11 +238,13 @@ class RunEnergyplus
177
238
  @logger.error log_message
178
239
  raise log_message
179
240
  ensure
241
+ @logger.info "Ensuring 'clean' directory"
242
+ clean_directory
243
+
180
244
  Dir.chdir(current_dir)
181
245
  @logger.info 'EnergyPlus Completed'
182
246
  end
183
247
 
184
- # TODO: get list of all the files that are generated and return
185
248
  {}
186
249
  end
187
250
  end
@@ -64,9 +64,9 @@ class RunOpenstudio
64
64
 
65
65
  apply_measures(:openstudio_measure)
66
66
 
67
- @time_logger.start("Translating to EnergyPlus")
67
+ @time_logger.start('Translating to EnergyPlus')
68
68
  translate_to_energyplus
69
- @time_logger.stop("Translating to EnergyPlus")
69
+ @time_logger.stop('Translating to EnergyPlus')
70
70
 
71
71
  apply_measures(:energyplus_measure)
72
72
 
@@ -84,14 +84,14 @@ class RunOpenstudio
84
84
  end
85
85
 
86
86
  @logger.info 'Saving measure output attributes JSON'
87
- File.open("#{@run_directory}/measure_attributes.json", 'w') do
88
- |f| f << JSON.pretty_generate(@output_attributes)
87
+ File.open("#{@run_directory}/measure_attributes.json", 'w') do |f|
88
+ f << JSON.pretty_generate(@output_attributes)
89
89
  end
90
90
  end
91
91
 
92
- @time_logger.start("Saving OSM and IDF")
92
+ @time_logger.start('Saving OSM and IDF')
93
93
  save_osm_and_idf
94
- @time_logger.stop("Saving OSM and IDF")
94
+ @time_logger.stop('Saving OSM and IDF')
95
95
 
96
96
  @results
97
97
  end
@@ -135,7 +135,7 @@ class RunOpenstudio
135
135
 
136
136
  # assume that the seed model has been placed in the directory
137
137
  baseline_model_path = File.expand_path(
138
- File.join(@options[:analysis_root_path], @analysis_json[:analysis][:seed][:path]))
138
+ File.join(@options[:analysis_root_path], @analysis_json[:analysis][:seed][:path]))
139
139
  else
140
140
  fail 'No seed model path in JSON defined'
141
141
  end
@@ -173,7 +173,7 @@ class RunOpenstudio
173
173
  elsif @analysis_json[:analysis][:weather_file]
174
174
  if @analysis_json[:analysis][:weather_file][:path]
175
175
  weather_filename = File.expand_path(
176
- File.join(@options[:analysis_root_path], @analysis_json[:analysis][:weather_file][:path])
176
+ File.join(@options[:analysis_root_path], @analysis_json[:analysis][:weather_file][:path])
177
177
  )
178
178
  @weather_file_path = File.dirname(weather_filename)
179
179
  else
@@ -88,7 +88,10 @@ class RunPostprocess
88
88
  end
89
89
 
90
90
  # Remove empty directories in run folder
91
- Dir["#{@run_directory}/*"].select { |d| File.directory? d }.select { |d| (Dir.entries(d) - %w(. ..)).empty? }.each { |d| Dir.rmdir d }
91
+ Dir["#{@run_directory}/*"].select { |d| File.directory? d }.select { |d| (Dir.entries(d) - %w(. ..)).empty? }.each do |d|
92
+ @logger.info "Removing empty directory #{d}"
93
+ Dir.rmdir d
94
+ end
92
95
 
93
96
  paths_to_rm = []
94
97
  # paths_to_rm << Pathname.glob("#{@run_directory}/*.osm")
@@ -60,13 +60,13 @@ class RunReportingMeasures
60
60
  @datapoint_json = @adapter.get_datapoint(@directory, @options)
61
61
  @analysis_json = @adapter.get_problem(@directory, @options)
62
62
 
63
- @time_logger.start("Running standard post process")
63
+ @time_logger.start('Running standard post process')
64
64
  if @options[:use_monthly_reports]
65
65
  run_monthly_postprocess
66
66
  else
67
67
  run_standard_postprocess
68
68
  end
69
- @time_logger.stop("Running standard post process")
69
+ @time_logger.stop('Running standard post process')
70
70
 
71
71
  translate_csv_to_json
72
72
 
@@ -77,8 +77,7 @@ class RunReportingMeasures
77
77
  end
78
78
 
79
79
  @logger.info 'Saving reporting measures output attributes JSON'
80
- File.open("#{@run_directory}/reporting_measure_attributes.json", 'w') do
81
- |f|
80
+ File.open("#{@run_directory}/reporting_measure_attributes.json", 'w') do |f|
82
81
  f << JSON.pretty_generate(@output_attributes)
83
82
  end
84
83
 
@@ -371,7 +370,6 @@ class RunReportingMeasures
371
370
  ['INTERIORLIGHTS:ELECTRICITY', 'EXTERIORLIGHTS:ELECTRICITY', 'INTERIOREQUIPMENT:ELECTRICITY', 'EXTERIOREQUIPMENT:ELECTRICITY',
372
371
  'FANS:ELECTRICITY', 'PUMPS:ELECTRICITY', 'HEATING:ELECTRICITY', 'COOLING:ELECTRICITY', 'HEATREJECTION:ELECTRICITY',
373
372
  'HUMIDIFIER:ELECTRICITY', 'HEATRECOVERY:ELECTRICITY', 'WATERSYSTEMS:ELECTRICITY', 'COGENERATION:ELECTRICITY', 'REFRIGERATION:ELECTRICITY'].each do |end_use|
374
-
375
373
  tmp_query = query + " AND ColumnName='#{end_use}'"
376
374
  tmp_val = sql_query(sql, 'BUILDING ENERGY PERFORMANCE - ELECTRICITY', tmp_query)
377
375
  val += tmp_val unless tmp_val.nil?
@@ -30,9 +30,9 @@ class RunRunmanager
30
30
  def initialize(directory, logger, time_logger, adapter, options = {})
31
31
  energyplus_path = nil
32
32
  if /cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM
33
- energyplus_path = 'C:/EnergyPlus-8-1-0'
33
+ energyplus_path = 'C:/EnergyPlus-8-2-0'
34
34
  else
35
- energyplus_path = '/usr/local/EnergyPlus-8-1-0'
35
+ energyplus_path = '/usr/local/EnergyPlus-8-2-0'
36
36
  end
37
37
 
38
38
  defaults = {
@@ -73,8 +73,7 @@ class RunXml
73
73
  end
74
74
 
75
75
  # @logger.debug "XML measure output attributes JSON is #{@output_attributes}"
76
- File.open("#{@run_directory}/measure_attributes_xml.json", 'w') do
77
- |f|
76
+ File.open("#{@run_directory}/measure_attributes_xml.json", 'w') do |f|
78
77
  f << JSON.pretty_generate(@output_attributes)
79
78
  end
80
79
  end
@@ -96,7 +95,7 @@ class RunXml
96
95
 
97
96
  # assume that the seed model has been placed in the directory
98
97
  baseline_model_path = File.expand_path(
99
- File.join(@options[:analysis_root_path], @analysis_json[:analysis][:seed][:path]))
98
+ File.join(@options[:analysis_root_path], @analysis_json[:analysis][:seed][:path]))
100
99
 
101
100
  if File.exist? baseline_model_path
102
101
  @logger.info "Reading in baseline model #{baseline_model_path}"
@@ -125,7 +124,7 @@ class RunXml
125
124
  # This last(4) needs to be cleaned up. Why don't we know the path of the file?
126
125
  # assume that the seed model has been placed in the directory
127
126
  weather_filename = File.expand_path(
128
- File.join(@options[:analysis_root_path], @analysis_json[:analysis][:weather_file][:path]))
127
+ File.join(@options[:analysis_root_path], @analysis_json[:analysis][:weather_file][:path]))
129
128
  unless File.exist?(weather_filename)
130
129
  @logger.warn "Could not find weather file for simulation #{weather_filename}. Will continue because may change"
131
130
  end
@@ -190,7 +189,7 @@ class RunXml
190
189
 
191
190
  @logger.info "Loading measure in relative path #{measure_path}"
192
191
  measure_file_path = File.expand_path(
193
- File.join(@options[:analysis_root_path], measure_path, 'measure.rb'))
192
+ File.join(@options[:analysis_root_path], measure_path, 'measure.rb'))
194
193
  fail "Measure file does not exist #{measure_name} in #{measure_file_path}" unless File.exist? measure_file_path
195
194
 
196
195
  require measure_file_path
@@ -211,14 +210,14 @@ class RunXml
211
210
  if wf[:arguments]
212
211
  wf[:arguments].each do |wf_arg|
213
212
  if wf_arg[:value]
214
- @logger.info "Setting argument value #{wf_arg[:name]} to #{wf_arg[:value]}"
213
+ @logger.info "Setting argument value '#{wf_arg[:name]}' to '#{wf_arg[:value]}'"
215
214
  # Note that these measures have symbolized hash keys and not strings. I really want indifferential access here!
216
215
  args[wf_arg[:name].to_sym] = wf_arg[:value]
217
216
  end
218
217
  end
219
218
  end
220
219
 
221
- @logger.info "iterate over variables for workflow item #{wf[:name]}"
220
+ @logger.info "iterate over variables for workflow item '#{wf[:name]}'"
222
221
  if wf[:variables]
223
222
  wf[:variables].each do |wf_var|
224
223
  # Argument hash in workflow looks like the following
@@ -157,7 +157,7 @@ module OpenStudio
157
157
  @adapter.communicate_results @directory, @job_results[:run_runmanager]
158
158
  elsif @job_results[:run_reporting_measures]
159
159
  @logger.info 'Sending the reporting measuers results back to the adapter'
160
- @time_logger.save(File.join(@directory,'profile.json'))
160
+ @time_logger.save(File.join(@directory, 'profile.json'))
161
161
  @adapter.communicate_results @directory, @job_results[:run_reporting_measures]
162
162
  end
163
163
  ensure
@@ -169,9 +169,7 @@ module OpenStudio
169
169
 
170
170
  @logger.info 'Workflow complete'
171
171
  # Write out the TimeLogger once again in case the run_reporting_measures didn't exist
172
- @time_logger.save(File.join(@directory,'profile.json'))
173
-
174
-
172
+ @time_logger.save(File.join(@directory, 'profile.json'))
175
173
 
176
174
  # TODO: define the outputs and figure out how to show it correctly
177
175
  obj_function_array ||= ['NA']
@@ -285,7 +283,7 @@ module OpenStudio
285
283
 
286
284
  def next_state
287
285
  @logger.info "Current state: '#{@current_state}'"
288
- ns = @transitions.select { |h| h[:from] == @current_state }.first[:to]
286
+ ns = @transitions.find { |h| h[:from] == @current_state }[:to]
289
287
  @logger.info "Next state will be: '#{ns}'"
290
288
 
291
289
  # Set the next state before calling the method
@@ -304,7 +302,7 @@ module OpenStudio
304
302
 
305
303
  # result
306
304
 
307
- # TODO fix this so that it gets the base config options plus its job options. Need to
305
+ # TODO: fix this so that it gets the base config options plus its job options. Need to
308
306
  # also merge in all the former job results.
309
307
  @options.merge(@job_results)
310
308
  end
@@ -13,17 +13,17 @@ class TimeLogger
13
13
  def start(channel)
14
14
  # warning -- "will reset timer for #{moniker}" if @monikers.key? moniker
15
15
  s = ::Time.now
16
- @channels[channel] = {start_time_str: "#{s}", start_time: s.to_f}
16
+ @channels[channel] = { start_time_str: "#{s}", start_time: s.to_f }
17
17
  end
18
18
 
19
19
  def stop(channel)
20
20
  end_time = ::Time.now.to_f
21
21
  @logger << {
22
- channel: channel,
23
- start_time: @channels[channel][:start_time],
24
- start_time_str: @channels[channel][:start_time_str],
25
- end_time: end_time,
26
- delta: end_time - @channels[channel][:start_time]
22
+ channel: channel,
23
+ start_time: @channels[channel][:start_time],
24
+ start_time_str: @channels[channel][:start_time_str],
25
+ end_time: end_time,
26
+ delta: end_time - @channels[channel][:start_time]
27
27
  }
28
28
 
29
29
  # remove the channel
@@ -43,11 +43,11 @@ class TimeLogger
43
43
 
44
44
  # this will report all the values for all the channels with this name.
45
45
  def delta(channel)
46
- @logger.map { |k| {channel.to_s => k[:delta]} if k[:channel] == channel }
46
+ @logger.map { |k| { channel.to_s => k[:delta] } if k[:channel] == channel }.compact
47
47
  end
48
48
 
49
49
  # save the data to a file. This will overwrite the file if it already exists
50
50
  def save(filename)
51
51
  File.open(filename, 'w') { |f| f << JSON.pretty_generate(@logger) }
52
52
  end
53
- end
53
+ end
@@ -19,6 +19,6 @@
19
19
 
20
20
  module OpenStudio
21
21
  module Workflow
22
- VERSION = '0.0.4'
22
+ VERSION = '0.1.1'
23
23
  end
24
24
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openstudio-workflow
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nicholas Long
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-22 00:00:00.000000000 Z
11
+ date: 2015-06-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -70,16 +70,16 @@ dependencies:
70
70
  name: facter
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ~>
73
+ - - '>='
74
74
  - !ruby/object:Gem::Version
75
- version: 2.0.2
75
+ version: '2.0'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ~>
80
+ - - '>='
81
81
  - !ruby/object:Gem::Version
82
- version: 2.0.2
82
+ version: '2.0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rubyXL
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -100,14 +100,14 @@ dependencies:
100
100
  requirements:
101
101
  - - ~>
102
102
  - !ruby/object:Gem::Version
103
- version: 1.1.6
103
+ version: 1.1.7
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - ~>
109
109
  - !ruby/object:Gem::Version
110
- version: 1.1.6
110
+ version: 1.1.7
111
111
  description: Run OpenStudio based simulations using EnergyPlus
112
112
  email:
113
113
  - nicholas.long@nrel.gov
@@ -115,6 +115,10 @@ executables: []
115
115
  extensions: []
116
116
  extra_rdoc_files: []
117
117
  files:
118
+ - CHANGELOG.md
119
+ - README.md
120
+ - Rakefile
121
+ - lib/openstudio-workflow.rb
118
122
  - lib/openstudio/workflow/adapter.rb
119
123
  - lib/openstudio/workflow/adapters/local.rb
120
124
  - lib/openstudio/workflow/adapters/mongo.rb
@@ -135,10 +139,6 @@ files:
135
139
  - lib/openstudio/workflow/run.rb
136
140
  - lib/openstudio/workflow/time_logger.rb
137
141
  - lib/openstudio/workflow/version.rb
138
- - lib/openstudio-workflow.rb
139
- - README.md
140
- - CHANGELOG.md
141
- - Rakefile
142
142
  homepage: https://github.com/NREL/OpenStudio-workflow-gem
143
143
  licenses:
144
144
  - LGPL
@@ -159,7 +159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
159
159
  version: '0'
160
160
  requirements: []
161
161
  rubyforge_project:
162
- rubygems_version: 2.0.14
162
+ rubygems_version: 2.4.5
163
163
  signing_key:
164
164
  specification_version: 4
165
165
  summary: Workflow Manager