openstudio-workflow 2.2.1 → 2.3.0

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
  SHA256:
3
- metadata.gz: 03716fad02e514aa60fbb2e3a14dd2c50286fe2621219f63137f4e1bb77afcb9
4
- data.tar.gz: 525a28b94195445ccf890f784898f9868226aea11d0137d112223c2ea0abd099
3
+ metadata.gz: fcb791c63593c4b0a7c7050c243c4e7214e8e62f04d3f4e3c29652c6690b5372
4
+ data.tar.gz: c831e36b5024f861eee6a46e5fc751ec0dc965a4e358fd0532ad293069acfc4f
5
5
  SHA512:
6
- metadata.gz: bc22ddb2820ea5155ce5308a49cfc405f5bdfa43a6b54fbac46ad8486deadb0f8bd866305566dc6fc70d65dbe71feb2c249fd6c0fa94623427f27b630b4c6fc7
7
- data.tar.gz: de613152849f97dd568c2f91a3411cb0c3a0f37d48f3e86a3fd37e7922d074e058eab6515e82f4359edb3e175baa718a91c8cbf6cbe1cc414afacee0d9c3253a
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 ini files
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
- # create stdout
156
- command = popen_command("\"#{energyplus_exe}\" 2>&1")
157
- logger.info "Running command '#{command}'"
158
- File.open('stdout-energyplus', 'w') do |file|
159
- ::IO.popen(command) do |io|
160
- while (line = io.gets)
161
- file << line
162
- output_adapter&.communicate_energyplus_stdout(line)
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
- forward_translator = OpenStudio::EnergyPlus::ForwardTranslator.new
105
- model_idf = forward_translator.translateModel(model)
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
@@ -37,6 +37,6 @@
37
37
 
38
38
  module OpenStudio
39
39
  module Workflow
40
- VERSION = '2.2.1' # Suffixes must have periods (not dashes)
40
+ VERSION = '2.3.0' # Suffixes must have periods (not dashes)
41
41
  end
42
42
  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.2.1
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-06-02 00:00:00.000000000 Z
12
+ date: 2021-10-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: builder