Class: OpenStudio::Workflow::Run

Inherits:
Object
  • Object
show all
Defined in:
lib/openstudio/workflow/run.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(adapter, directory, options = {}) ⇒ Run

initialize a new run class

Parameters:

  • adapter

    an instance of the adapter class

  • directory

    location of the datapoint directory to run. This is needed independent of the adapter that is being used. Note that the simulation will actually run in ‘run’

  • options (defaults to: {})

    that are sent to the adapters



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/openstudio/workflow/run.rb', line 91

def initialize(adapter, directory, options = {})
  @adapter = adapter
  @final_message = ''
  @current_state = nil
  @transitions = {}
  @directory = directory
  @time_logger = TimeLogger.new
  # TODO: run directory is a convention right now. Move to a configuration item
  @run_directory = "#{@directory}/run"

  defaults = nil
  if options[:is_pat]
    defaults = {
      transitions: OpenStudio::Workflow::Run.pat_transition,
      states: OpenStudio::Workflow::Run.pat_states,
      jobs: {}
    }
  else
    defaults = {
      transitions: OpenStudio::Workflow::Run.default_transition,
      states: OpenStudio::Workflow::Run.default_states,
      jobs: {}
    }
  end
  @options = defaults.merge(options)

  @job_results = {}

  # By default blow away the entire run directory every time and recreate it
  FileUtils.rm_rf(@run_directory) if File.exist?(@run_directory)
  FileUtils.mkdir_p(@run_directory)

  # There is a namespace conflict when OpenStudio is loaded: be careful!
  log_file = File.open("#{@run_directory}/run.log", 'a')

  l = @adapter.get_logger @directory, @options
  if l
    @logger = ::Logger.new MultiDelegator.delegate(:write, :close).to(STDOUT, log_file, l)
  else
    @logger = ::Logger.new MultiDelegator.delegate(:write, :close).to(STDOUT, log_file)
  end

  @logger.info "Initializing directory #{@directory} for simulation with options #{@options}"
  @logger.info "OpenStudio loaded: '#{$openstudio_gem}'"

  # load the state machine
  machine
end

Instance Attribute Details

#adapterObject (readonly)

Returns the value of attribute adapter.



27
28
29
# File 'lib/openstudio/workflow/run.rb', line 27

def adapter
  @adapter
end

#directoryObject (readonly)

Returns the value of attribute directory.



28
29
30
# File 'lib/openstudio/workflow/run.rb', line 28

def directory
  @directory
end

#final_messageObject (readonly)

Returns the value of attribute final_message.



31
32
33
# File 'lib/openstudio/workflow/run.rb', line 31

def final_message
  @final_message
end

#job_resultsObject (readonly)

Returns the value of attribute job_results.



32
33
34
# File 'lib/openstudio/workflow/run.rb', line 32

def job_results
  @job_results
end

#loggerObject

Returns the value of attribute logger.



24
25
26
# File 'lib/openstudio/workflow/run.rb', line 24

def logger
  @logger
end

#optionsObject (readonly)

Returns the value of attribute options.



26
27
28
# File 'lib/openstudio/workflow/run.rb', line 26

def options
  @options
end

#run_directoryObject (readonly)

Returns the value of attribute run_directory.



29
30
31
# File 'lib/openstudio/workflow/run.rb', line 29

def run_directory
  @run_directory
end

Class Method Details

.default_statesObject

The default states for the workflow. Note that the states of :queued of :finished need to exist for all cases.



48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/openstudio/workflow/run.rb', line 48

def self.default_states
  warn "[Deprecation Warning] explicitly specifying states will no longer be required in 0.3.0. Method #{__method__}"
  [
    { state: :queued, options: { initial: true } },
    { state: :preflight, options: { after_enter: :run_preflight } },
    { state: :openstudio, options: { after_enter: :run_openstudio } }, # TODO: this should be run_openstudio_measures and run_energyplus_measures
    { state: :energyplus, options: { after_enter: :run_energyplus } },
    { state: :reporting_measures, options: { after_enter: :run_reporting_measures } },
    { state: :postprocess, options: { after_enter: :run_postprocess } },
    { state: :finished },
    { state: :errored }
  ]
end

.default_transitionObject

load the transitions



35
36
37
38
39
40
41
42
43
44
# File 'lib/openstudio/workflow/run.rb', line 35

def self.default_transition
  [
    { from: :queued, to: :preflight },
    { from: :preflight, to: :openstudio },
    { from: :openstudio, to: :energyplus },
    { from: :energyplus, to: :reporting_measures },
    { from: :reporting_measures, to: :postprocess },
    { from: :postprocess, to: :finished }
  ]
end

.pat_statesObject

states for pat job



73
74
75
76
77
78
79
80
81
82
83
# File 'lib/openstudio/workflow/run.rb', line 73

def self.pat_states
  warn "[Deprecation Warning] explicitly specifying states will no longer be required in 0.3.0. Method #{__method__}"
  [
    { state: :queued, options: { initial: true } },
    { state: :preflight, options: { after_enter: :run_preflight } },
    { state: :runmanager, options: { after_enter: :run_runmanager } },
    { state: :postprocess, options: { after_enter: :run_postprocess } },
    { state: :finished },
    { state: :errored }
  ]
end

.pat_transitionObject

transitions for pat job



63
64
65
66
67
68
69
70
# File 'lib/openstudio/workflow/run.rb', line 63

def self.pat_transition
  [
    { from: :queued, to: :preflight },
    { from: :preflight, to: :runmanager },
    { from: :runmanager, to: :postprocess },
    { from: :postprocess, to: :finished }
  ]
end

Instance Method Details

#runObject

run the simulations. TODO: add a catch if any job fails; TODO: make a block method to provide feedback



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/openstudio/workflow/run.rb', line 142

def run
  @logger.info "Starting workflow in #{@directory}"
  begin
    while @current_state != :finished && @current_state != :errored
      sleep 2
      step
    end

    @logger.info 'Finished workflow - communicating results and zipping files'

    # TODO: this should be a job that handles the use case with a :guard on if @job_results[:run_postprocess]
    # or @job_results[:run_reporting_measures]
    # these are the results that need to be sent back to adapter
    if @job_results[:run_runmanager]
      @logger.info 'Sending the run_runmananger results back to the adapter'
      @adapter.communicate_results @directory, @job_results[:run_runmanager]
    elsif @job_results[:run_reporting_measures]
      @logger.info 'Sending the reporting measuers results back to the adapter'
      @time_logger.save(File.join(@directory, 'profile.json'))
      @adapter.communicate_results @directory, @job_results[:run_reporting_measures]
    end
  ensure
    if @current_state == :errored
      @adapter.communicate_failure @directory
    else
      @adapter.communicate_complete @directory
    end

    @logger.info 'Workflow complete'
    # Write out the TimeLogger once again in case the run_reporting_measures didn't exist
    @time_logger.save(File.join(@directory, 'profile.json'))

    # TODO: define the outputs and figure out how to show it correctly
    obj_function_array ||= ['NA']

    # Print the objective functions to the screen even though the file is being used right now
    # Note as well that we can't guarantee that the csv format will be in the right order
    puts obj_function_array.join(',')
  end

  @current_state
end

#run_energyplusObject

TODO: these methods needs to be dynamic or inherited run energplus



207
208
209
210
211
212
# File 'lib/openstudio/workflow/run.rb', line 207

def run_energyplus
  @logger.info "Running #{__method__}"
  klass = get_run_class(__method__)

  @job_results[__method__.to_sym] = klass.perform
end

#run_finishedObject Also known as: final_state

last method that is called.



266
267
268
269
270
# File 'lib/openstudio/workflow/run.rb', line 266

def run_finished
  @logger.info "Running #{__method__}"

  @current_state
end

#run_openstudioObject

run openstudio to create the model and apply the measures



215
216
217
218
219
220
221
# File 'lib/openstudio/workflow/run.rb', line 215

def run_openstudio
  @logger.info "Running #{__method__}"
  klass = get_run_class(__method__)

  # TODO: save the resulting filenames to an array
  @job_results[__method__.to_sym] = klass.perform
end

#run_postprocessObject



241
242
243
244
245
246
# File 'lib/openstudio/workflow/run.rb', line 241

def run_postprocess
  @logger.info "Running #{__method__}"
  klass = get_run_class(__method__)

  @job_results[__method__.to_sym] = klass.perform
end

#run_preflightObject

preconfigured run method for preflight. This configures the input directories and sets everything up for running the simulations.



250
251
252
253
254
255
# File 'lib/openstudio/workflow/run.rb', line 250

def run_preflight
  @logger.info "Running #{__method__}"
  klass = get_run_class(__method__)

  @job_results[__method__.to_sym] = klass.perform
end

#run_reporting_measuresObject

run reporting measures



233
234
235
236
237
238
239
# File 'lib/openstudio/workflow/run.rb', line 233

def run_reporting_measures
  @logger.info "Running #{__method__}"
  klass = get_run_class(__method__)

  # TODO: save the resulting filenames to an array
  @job_results[__method__.to_sym] = klass.perform
end

#run_runmanagerObject

run a pat file using runmanager



224
225
226
227
228
229
230
# File 'lib/openstudio/workflow/run.rb', line 224

def run_runmanager
  @logger.info "Running #{__method__}"
  klass = get_run_class(__method__)

  # TODO: save the resulting filenames to an array
  @job_results[__method__.to_sym] = klass.perform
end

#run_xmlObject



257
258
259
260
261
262
263
# File 'lib/openstudio/workflow/run.rb', line 257

def run_xml
  @logger.info "Running #{__method__}"
  klass = get_run_class(__method__)

  @job_results[__method__.to_sym] = klass.perform
  @logger.info @job_results
end

#step(*args) ⇒ Object

Step through the states, if there is an error (e.g. exception) then go to error



186
187
188
189
190
191
192
# File 'lib/openstudio/workflow/run.rb', line 186

def step(*args)
  next_state

  send("run_#{@current_state}")
rescue => e
  step_error("#{e.message}:#{e.backtrace.join("\n")}")
end

#step_error(*args) ⇒ Object

call back for when there is an exception running any of the state transitions



195
196
197
198
199
200
201
202
203
# File 'lib/openstudio/workflow/run.rb', line 195

def step_error(*args)
  # Make sure to set the instance variable @error to true in order to stop the :step
  # event from being fired.
  @final_message = "Found error in state '#{@current_state}' with message #{args}}"
  @logger.error @final_message

  # transition to an error state
  @current_state = :errored
end