Workflows¶
Starting with EnergyPlus-Launch 3.0, the code has been 100% rewritten from VB6 to Python, with an eye toward creating a cross-platform tool that can be developed, built, and packaged easily by many developers. Also at the heart of this new version of EnergyPlus-Launch is something called “Workflows.”
Definition¶
A workflow can be defined as:
a Python class,
that inherits from an EnergyPlus-Launch Workflow base class, and
properly overrides all abstract methods on the base class.
Some additional interesting features:
A workflow has a context function that allows the EPLaunch interface to group related workflows.
If multiple workflow files are packaged up with one tool, like they are with EnergyPlus, all those workflows should have the same context.
If the workflow is tied to a specific version of a piece of software, and you might have more than one version on your computer, the context should have the version number in it.
Example¶
Let’s move now to an example of a workflow.
To begin, we must know enough about the base class to know what methods we need to override.
For base class BaseEPLaunchWorkflow1
, the methods that must be overridden are:
name()
(returns a string)context()
(returns a string)description()
(returns a string)get_file_types()
(returns a list of file extensions)get_output_suffixes()
(returns a list of output file suffixes)main()
(main operation, returns an instance of anEPLaunchWorkflowResponse1
Another function of interest that can be overridden is the get_interface_columns()
, which is used to pass data back to the GUI.
Now that we know what methods need to be written, let’s just write out a workflow. For this example, a workflow named “dummy” will be written that operates on “.txt” files, and returns data in the “foo” column. Here’s the entire code for the workflow, followed by commentary:
from eplaunch.workflows.base import BaseEPLaunchWorkflow1, EPLaunchWorkflowResponse1
class SiteLocationWorkflow(BaseEPLaunchWorkflow1):
def name(self):
return 'foo'
def context(self):
return 'my_workflow_collection'
def description(self):
return 'Foo workflow'
def get_file_types(self):
return ['*.txt']
def get_output_suffixes(self):
return []
def get_interface_columns(self):
return ['foo']
def main(self, run_directory, file_name, args):
return EPLaunchWorkflowResponse1(success=True, message='Hello', column_data={'foo': 'bar'})
We’ll run through this code line by line:
We first import the required base classes so we can inherit the base workflow, and return an instance of the expected return type.
We create a Python class that inherits from the base class.
We override the
name
function,and return a suitable name for our workflow.
We override the
context
function,and return a suitable context for this workflow.
We override the
description
function,and return a suitable description for our workflow.
We override the
get_file_types
function,and return a list of file extensions; for this workflow, it’s just one:
.txt
We override the
get_output_suffixes
function,and return an empty array, since no output files will be associated with this workflow
We override the
get_interface_columns
function,and return an array of column names; for this workflow, it’s just one:
foo
We override the
main
function,and return a trivial
EPLaunchWorkflowResponse1
instance, with a hello response message, and column data containing one key (foo) and the value (bar)
Actual Workflow Operation¶
When a workflow run is started, the following process is put into motion:
Verify that this workflow is not already being run (uniqueness is calculated through workflow name, run directory, and run file)
Generate a new unique identifier for this particular workflow run
Create a new instance of the workflow
Store the unique id, and an instantiated callback function with the workflow base class, so that the workflow can easily call back to the GUI
Create a new workflow thread instance with all the data required to setup the workflow run (constructor will also run the workflow)
Create and show a dialog with parameters and output from the workflow run
Update the GUI to reflect a workflow is running
When a workflow calls back with progress updates, the update comes with the unique identifier created for that run. The update triggers the workflow output dialog to update the textbox to include the updated information.
When a workflow is completed, the following series of events occur:
The workflow status flag is checked, and if it was NOT successful, the output dialog is left with additional info and held open for the user to inspect
If the workflow was successful, additional information is mined from the run, including the run directory and file name
Mined information is used to determine if the current file list should be refreshed to reflect updated outputs from the workflow run
The workflow output dialog is closed, the status bar is updated, and the workflow thread is deleted
Workflow Testing¶
A standalone tool has been developed to allow users to test their workflows. The script accepts one command line argument, the path to the workflow to test. Consider the workflow that was created for the example above. If we run that through the test script, this is the output:
$ energyplus_launch_workflow_tester /tmp/workflow.py
OK: File path exists at: /tmp/workflow.py
OK: File ends with .py
OK: Python import process completed successfully!
INFO: Encountered class: "BaseEPLaunchWorkflow1", testing now...
INFO: Inheritance does not check out, will continue with other classes in this file
INFO: Encountered class: "EPLaunchWorkflowResponse1", testing now...
INFO: Inheritance does not check out, will continue with other classes in this file
INFO: Encountered class: "SiteLocationWorkflow", testing now...
OK: Basic inheritance checks out OK for class: SiteLocationWorkflow
OK: Instantiation of derived class works
OK: Overridden name() function execution works
OK: Overridden description() function execution works
OK: Overridden get_file_types() function execution works
OK: Overridden get_output_suffixes() function execution works
OK: Overridden get_interface_columns() function execution works
OK: Overridden context() function execution works
OK: Found 1 successful workflow imports:
SiteLocationWorkflow
If running from the Python script, you would need to execute using Python, and ensure that the PYTHONPATH includes the folder where EPLaunch can be accessed. The command line, if run from the root of the repository would bee:
PYTHONPATH="." python3 eplaunch/workflows/workflow_tester.py /tmp/example_workflow.py
The tester checks some basic file details, then loops over all classes encountered in the file and validates them. Note that classes found in the module include classes that are imported, so even though we only defined one workflow class, it checks four. The final note summarizes the results of the test. The process return code also captures the success/failure:
0: success
1: failure due to bad workflow file
2: failure for some other reason
Checking these error codes can allow groups of workflow files to be tested in an automated fashion.