openstudio-workflow 2.2.1 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/openstudio/workflow/adapters/input/local.rb +95 -0
- data/lib/openstudio/workflow/run.rb +4 -0
- data/lib/openstudio/workflow/util/energyplus.rb +47 -11
- data/lib/openstudio/workflow/util/model.rb +59 -2
- data/lib/openstudio/workflow/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fcb791c63593c4b0a7c7050c243c4e7214e8e62f04d3f4e3c29652c6690b5372
|
4
|
+
data.tar.gz: c831e36b5024f861eee6a46e5fc751ec0dc965a4e358fd0532ad293069acfc4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5191c3ec1be4a4b801afb357f46ef35b127a73b92c0c0d5c2831f1bb3374ec365675c6baa70e2513884ab87d5f6ffb80f69e540f90310db6ea99cf1d1962fe56
|
7
|
+
data.tar.gz: 7aceb6c2b096e47522ed68b978f3e36d46c8dd2dd79ace0a7b5415a685078dfd9852f75e626c98ea2d875e4365ae5787ea6a5007178fbda5b84490868b92ff30
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
OpenStudio::Workflow Change Log
|
2
2
|
==================================
|
3
3
|
|
4
|
+
Version 2.3.0
|
5
|
+
-------------
|
6
|
+
* Feature [#135](https://github.com/NREL/OpenStudio-workflow-gem/issues/135) Add option to export/run epJSON
|
7
|
+
|
4
8
|
Version 2.2.1
|
5
9
|
-------------
|
6
10
|
* Fixes [#4150](https://github.com/NREL/OpenStudio/issues/4150) LoadError changes current working directory in CLI
|
@@ -291,6 +291,101 @@ module OpenStudio
|
|
291
291
|
return default
|
292
292
|
end
|
293
293
|
|
294
|
+
def epjson(user_options, default, logger)
|
295
|
+
# check version for this feature
|
296
|
+
os_version = OpenStudio::VersionString.new(OpenStudio.openStudioVersion)
|
297
|
+
min_version_feature = OpenStudio::VersionString.new('3.3.0')
|
298
|
+
unless os_version >= min_version_feature
|
299
|
+
log_message = 'epJSON is only supported for versions >= 3.3.0. Falling back to using IDF'
|
300
|
+
logger.info log_message
|
301
|
+
return default
|
302
|
+
end
|
303
|
+
|
304
|
+
# user option trumps all others
|
305
|
+
return user_options[:epjson] if user_options[:epjson]
|
306
|
+
|
307
|
+
# try to read from OSW
|
308
|
+
|
309
|
+
if @run_options.is_initialized && @run_options.get.respond_to?(:epjson)
|
310
|
+
return @run_options.get.epjson
|
311
|
+
end
|
312
|
+
|
313
|
+
return default
|
314
|
+
end
|
315
|
+
|
316
|
+
# Process the `run` method `ft_options` subhash
|
317
|
+
#
|
318
|
+
# This will validate that each suboption is supported in the current
|
319
|
+
# version as well as enhance the hash with the corresponding
|
320
|
+
# ForwardTranslator method name to set the value on the FT later
|
321
|
+
# in `translate_to_energyplus`
|
322
|
+
# user option trumps all others
|
323
|
+
def ft_options(user_options, default, logger)
|
324
|
+
# check version for this feature
|
325
|
+
os_version = OpenStudio::VersionString.new(OpenStudio.openStudioVersion)
|
326
|
+
|
327
|
+
os300 = OpenStudio::VersionString.new('3.0.0')
|
328
|
+
os330 = OpenStudio::VersionString.new('3.3.0')
|
329
|
+
known_ft_opts = {
|
330
|
+
# All Versions
|
331
|
+
runcontrolspecialdays: { method_name: :setKeepRunControlSpecialDays, min_version: nil },
|
332
|
+
ip_tabular_output: { method_name: :setIPTabularOutput, min_version: nil },
|
333
|
+
no_lifecyclecosts: { method_name: :setExcludeLCCObjects, min_version: nil },
|
334
|
+
# 3.0.0
|
335
|
+
no_sqlite_output: { method_name: :setExcludeSQliteOutputReport, min_version: os300 },
|
336
|
+
no_html_output: { method_name: :setExcludeHTMLOutputReport, min_version: os300 },
|
337
|
+
no_variable_dictionary: { method_name: :setExcludeVariableDictionary, min_version: os300 },
|
338
|
+
# 3.3.0
|
339
|
+
no_space_translation: { method_name: :setExcludeSpaceTranslation, min_version: os330 }
|
340
|
+
}
|
341
|
+
|
342
|
+
# user option trumps all others
|
343
|
+
if user_options[:ft_options]
|
344
|
+
ft_opts = {}
|
345
|
+
user_options[:ft_options].each do |opt_flag_name, opt_flag|
|
346
|
+
puts "#{opt_flag_name} = #{opt_flag}"
|
347
|
+
unless known_ft_opts.key?(opt_flag_name)
|
348
|
+
log_message = "'ft_options' suboption '#{opt_flag_name}' is not recognized, ignoring it."
|
349
|
+
logger.warn log_message
|
350
|
+
next
|
351
|
+
end
|
352
|
+
min_version = known_ft_opts[opt_flag_name][:min_version]
|
353
|
+
if !min_version.nil? && os_version < min_version
|
354
|
+
log_message = "'ft_options' suboption '#{opt_flag_name}' is only supported for OpenStudio Version >= #{min_version.str}, ignoring it."
|
355
|
+
logger.warn log_message
|
356
|
+
next
|
357
|
+
end
|
358
|
+
ft_opts[opt_flag_name] = { method_name: known_ft_opts[opt_flag_name][:method_name], value: opt_flag }
|
359
|
+
end
|
360
|
+
|
361
|
+
return ft_opts
|
362
|
+
end
|
363
|
+
|
364
|
+
# try to read from OSW
|
365
|
+
|
366
|
+
if @run_options.is_initialized && @run_options.get.respond_to?(:forwardTranslateOptions)
|
367
|
+
ft_opts = {}
|
368
|
+
JSON.parse(@run_options.get.forwardTranslateOptions, symbolize_names: true).each do |opt_flag_name, opt_flag|
|
369
|
+
unless known_ft_opts.key?(opt_flag_name)
|
370
|
+
log_message = "'ft_options' suboption '#{opt_flag_name}' is not recognized, ignoring it."
|
371
|
+
logger.warn log_message
|
372
|
+
next
|
373
|
+
end
|
374
|
+
min_version = known_ft_opts[opt_flag_name.to_sym][:min_version]
|
375
|
+
if !min_version.nil? && os_version < min_version
|
376
|
+
log_message = "'ft_options' suboption '#{opt_flag_name}' is only supported for OpenStudio Version >= #{min_version.str}, ignoring it."
|
377
|
+
logger.warn log_message
|
378
|
+
next
|
379
|
+
end
|
380
|
+
ft_opts[opt_flag_name] = { method_name: known_ft_opts[opt_flag_name][:method_name], value: opt_flag }
|
381
|
+
end
|
382
|
+
|
383
|
+
return ft_opts
|
384
|
+
end
|
385
|
+
|
386
|
+
return default
|
387
|
+
end
|
388
|
+
|
294
389
|
def weather_file(user_options, default)
|
295
390
|
# user option trumps all others
|
296
391
|
return user_options[:weather_file] if user_options[:weather_file]
|
@@ -95,6 +95,8 @@ module OpenStudio
|
|
95
95
|
# @option user_options [Hash] :targets Log targets to write to, defaults to standard out and run.log
|
96
96
|
# @option user_options [Hash] :verify_osw Check OSW for correctness, defaults to true
|
97
97
|
# @option user_options [Hash] :weather_file Initial weather file to load, overrides OSW option if set, defaults to empty
|
98
|
+
# @option user_options [Hash] :epjson - Create, export and run using epjson format. Default is IDF
|
99
|
+
# @option user_options [Hash] :ft_options - A subhash of options to set on the ForwardTranslator
|
98
100
|
def initialize(osw_path, user_options = {})
|
99
101
|
# DLM - what is final_message?
|
100
102
|
@final_message = ''
|
@@ -199,6 +201,8 @@ module OpenStudio
|
|
199
201
|
@options[:weather_file] = @input_adapter.weather_file(user_options, nil)
|
200
202
|
@options[:fast] = @input_adapter.fast(user_options, false)
|
201
203
|
@options[:skip_zip_results] = @input_adapter.skip_zip_results(user_options, false)
|
204
|
+
@options[:epjson] = @input_adapter.epjson(user_options, false, @logger)
|
205
|
+
@options[:ft_options] = @input_adapter.ft_options(user_options, {}, @logger)
|
202
206
|
|
203
207
|
openstudio_dir = 'unknown'
|
204
208
|
begin
|
@@ -43,6 +43,8 @@ module OpenStudio
|
|
43
43
|
module EnergyPlus
|
44
44
|
require 'openstudio/workflow/util/io'
|
45
45
|
include OpenStudio::Workflow::Util::IO
|
46
|
+
require 'openstudio/workflow/util/model'
|
47
|
+
include OpenStudio::Workflow::Util::Model
|
46
48
|
ENERGYPLUS_REGEX = /^energyplus\D{0,4}$/i.freeze
|
47
49
|
EXPAND_OBJECTS_REGEX = /^expandobjects\D{0,4}$/i.freeze
|
48
50
|
|
@@ -94,8 +96,8 @@ module OpenStudio
|
|
94
96
|
Dir["#{energyplus_path}/*"].each do |file|
|
95
97
|
next if File.directory? file
|
96
98
|
|
97
|
-
# copy idd and
|
98
|
-
if File.extname(file).downcase =~ /.idd|.ini/
|
99
|
+
# copy idd, ini and epJSON schema files
|
100
|
+
if File.extname(file).downcase =~ /.idd|.ini|.epjson/
|
99
101
|
dest_file = "#{run_directory}/#{File.basename(file)}"
|
100
102
|
energyplus_files << dest_file
|
101
103
|
FileUtils.copy file, dest_file
|
@@ -130,7 +132,9 @@ module OpenStudio
|
|
130
132
|
current_dir = Dir.pwd
|
131
133
|
energyplus_path ||= find_energyplus
|
132
134
|
logger.info "EnergyPlus path is #{energyplus_path}"
|
135
|
+
|
133
136
|
energyplus_files, energyplus_exe, expand_objects_exe = prepare_energyplus_dir(run_directory, logger, energyplus_path)
|
137
|
+
|
134
138
|
Dir.chdir(run_directory)
|
135
139
|
logger.info "Starting simulation in run directory: #{Dir.pwd}"
|
136
140
|
|
@@ -152,18 +156,50 @@ module OpenStudio
|
|
152
156
|
end
|
153
157
|
end
|
154
158
|
|
155
|
-
#
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
159
|
+
# Translate the IDF to an epJSON if @options[:epjson] is true
|
160
|
+
# Ideally, this would be done sooner in the workflow process but many processes
|
161
|
+
# manipulate the model_idf, some which are ep_measures that may not work with json
|
162
|
+
# and ExpandObjects does not currently support epjson anyway to that still needs to run
|
163
|
+
# before this can be changed.
|
164
|
+
if @options[:epjson]
|
165
|
+
@logger.info 'Beginning the translation to epJSON'
|
166
|
+
@registry[:time_logger]&.start('Translating to EnergyPlus epJSON')
|
167
|
+
idf_final = load_idf("#{run_directory}/in.idf", @logger)
|
168
|
+
model_epjson = translate_idf_to_epjson idf_final, @logger
|
169
|
+
@registry[:time_logger]&.stop('Translating to EnergyPlus')
|
170
|
+
@logger.info 'Successfully translated to epJSON'
|
171
|
+
@registry[:time_logger]&.start('Saving epJSON')
|
172
|
+
epjson_name = save_epjson(model_epjson, run_directory)
|
173
|
+
@registry[:time_logger]&.stop('Saving epJSON')
|
174
|
+
@logger.debug "Saved epJSON as #{epjson_name}"
|
175
|
+
end
|
176
|
+
|
177
|
+
# Run using epJSON if @options[:epjson] true, otherwise use IDF
|
178
|
+
if @options[:epjson]
|
179
|
+
command = popen_command("\"#{energyplus_exe}\" in.epJSON 2>&1")
|
180
|
+
logger.info "Running command '#{command}'"
|
181
|
+
File.open('stdout-energyplus', 'w') do |file|
|
182
|
+
::IO.popen(command) do |io|
|
183
|
+
while (line = io.gets)
|
184
|
+
file << line
|
185
|
+
output_adapter&.communicate_energyplus_stdout(line)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
r = $?
|
190
|
+
else
|
191
|
+
command = popen_command("\"#{energyplus_exe}\" 2>&1")
|
192
|
+
logger.info "Running command '#{command}'"
|
193
|
+
File.open('stdout-energyplus', 'w') do |file|
|
194
|
+
::IO.popen(command) do |io|
|
195
|
+
while (line = io.gets)
|
196
|
+
file << line
|
197
|
+
output_adapter&.communicate_energyplus_stdout(line)
|
198
|
+
end
|
163
199
|
end
|
164
200
|
end
|
201
|
+
r = $?
|
165
202
|
end
|
166
|
-
r = $?
|
167
203
|
|
168
204
|
logger.info "EnergyPlus returned '#{r}'"
|
169
205
|
unless r.to_i.zero?
|
@@ -101,13 +101,49 @@ module OpenStudio
|
|
101
101
|
# ensure objects exist for reporting purposes
|
102
102
|
model.getFacility
|
103
103
|
model.getBuilding
|
104
|
-
|
105
|
-
|
104
|
+
ft = OpenStudio::EnergyPlus::ForwardTranslator.new
|
105
|
+
|
106
|
+
ft_options = @options[:ft_options]
|
107
|
+
if !ft_options.empty?
|
108
|
+
|
109
|
+
msg = "Custom ForwardTranslator options passed:\n"
|
110
|
+
|
111
|
+
ft_options.each do |opt_flag_name, h|
|
112
|
+
ft_method = h[:method_name]
|
113
|
+
opt_flag = h[:value]
|
114
|
+
|
115
|
+
# Call the FT setter with the value passed in
|
116
|
+
ft.method(ft_method).call(opt_flag)
|
117
|
+
|
118
|
+
msg += "* :#{opt_flag_name}=#{opt_flag} => ft.#{ft_method}(#{opt_flag})\n"
|
119
|
+
end
|
120
|
+
|
121
|
+
logger.info msg
|
122
|
+
end
|
123
|
+
|
124
|
+
model_idf = ft.translateModel(model)
|
106
125
|
b = ::Time.now
|
107
126
|
logger.info "Translate object to EnergyPlus IDF took #{b.to_f - a.to_f}"
|
108
127
|
model_idf
|
109
128
|
end
|
110
129
|
|
130
|
+
# Translates an IDF model into an EnergyPlus epJSON object
|
131
|
+
#
|
132
|
+
# @param [Object] OpenStudio::IdfFile instance to translate into an OpenStudio epJSON object -- see
|
133
|
+
# the OpenStudio SDK for details on the process
|
134
|
+
# @return [Object] Returns and OpenStudio::epJSONobject
|
135
|
+
#
|
136
|
+
def translate_idf_to_epjson(model_idf, logger = nil)
|
137
|
+
logger ||= ::Logger.new($stdout)
|
138
|
+
logger.info 'Translate IDF to epJSON in preparation for EnergyPlus'
|
139
|
+
a = ::Time.now
|
140
|
+
model_epjson = OpenStudio::EPJSON.toJSONString(model_idf)
|
141
|
+
b = ::Time.now
|
142
|
+
logger.info "Translate IDF to EnergyPlus epJSON took #{b.to_f - a.to_f}"
|
143
|
+
|
144
|
+
model_epjson
|
145
|
+
end
|
146
|
+
|
111
147
|
# Saves an OpenStudio model object to file
|
112
148
|
#
|
113
149
|
# @param [Object] model The OpenStudio::Model instance to save to file
|
@@ -149,6 +185,27 @@ module OpenStudio
|
|
149
185
|
end
|
150
186
|
idf_filename
|
151
187
|
end
|
188
|
+
|
189
|
+
# Saves an OpenStudio EpJSON model object to file
|
190
|
+
#
|
191
|
+
# @param [Object] model The OpenStudio::Workspace instance to save to file
|
192
|
+
# @param [String] save_directory Folder to save the model in
|
193
|
+
# @param [String] name ('in.epJSON') Option to define a non-standard name
|
194
|
+
# @return [String] epJSON file name
|
195
|
+
#
|
196
|
+
def save_epjson(model_epjson, save_directory, name = 'in.epJSON')
|
197
|
+
epjson_filename = File.join(save_directory.to_s, name.to_s)
|
198
|
+
File.open(epjson_filename, 'w') do |f|
|
199
|
+
f << model_epjson.to_s
|
200
|
+
# make sure data is written to the disk one way or the other
|
201
|
+
begin
|
202
|
+
f.fsync
|
203
|
+
rescue StandardError
|
204
|
+
f.flush
|
205
|
+
end
|
206
|
+
end
|
207
|
+
epjson_filename
|
208
|
+
end
|
152
209
|
end
|
153
210
|
end
|
154
211
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: openstudio-workflow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nicholas Long
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2021-
|
12
|
+
date: 2021-10-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: builder
|