CEA Plugins - Part 4: How to add your own tools to the CEA
Author - Daren Thomas
Now that you have an overview of the CEA plugin template, let's dive into some of the files responsible for adding a new tool to the CEA.
This is part 4 in a series of articles on CEA plugins:
Part 4: How to add your own tools to the CEA (this article)
Adding tools to the CEA
Remember the files in the CEA plugin template? Here's a quick reminder:
my-awesome-plugin │ .gitignore │ LICENSE │ README.md │ setup.py │ \---cea_plugin_template demand_summary.pyplots.yml plugin.config schemas.yml scripts.yml __init__.py
We've already covered some of these files in Part 3: Introduction to the CEA plugin template.
In this article we'll cover the following files:
demand_summary.py
,scripts.yml
,schemas.yml
,and
plugin.config
demand_summary.py
This file contains an important definition:
class DemandSummaryPlugin(cea.plugin.CeaPlugin): pass
Now... this definition class DemandSummaryPlugin(cea.plugin.CeaPlugin)
does some "magic", in that by inheriting from cea.plugin.CeaPlugin
, most of the work of creating a CEA plugin is already done - you only need to edit some yaml files.
Theoretically, a CEA plugin could be any class that supports the same interface as cea.plugin.CeaPlugin
and it's possible to override how certain parts work. For example, you could replace how plots are defined in your plugin and avoid (or augment) the plots.yml
feature to gain more flexibility. Let's stick to the beaten path here and just keep in mind that if you _do_ need more flexibility, it's there.
This file also contains the demand-summary
script exposed by the plugin. It follows some conventions used in the CEA project:
The main
function that accepts a single argument of type cea.config.Configuration
. This function needs to be called main
to be picked up by the CEA. Normally, it's job is to read the arguments from the config
object and then call a function to compute the results - in this case summarize
. Asside from the main
function, how you actually organize your code is up to you.
Let's look at the main
function for demand-summary
quickly:
def main(config): locator = cea.inputlocator.InputLocator(config.scenario, config.plugins) summary_df = summarize(locator.get_total_demand.read(), config.demand_summary.fudge_factor) locator.demand_summary.write(summary_df)
The locator
variable is created using the scenario and list of plugins installed. Refer to the section on schemas.yml
for more information on InputLocator
objects. Here we use it to read in the data from Total_deman.csv
file generated by the demand
script, create a summary and write it out to the demand-summary.csv
file. How to find, read and write these data files is handled by the InputLocator
class (with some help from cea.schemas.SchemaIo
).
The config
file contains some important information for the script:
config.scenario
is used in most scripts to create anInputLocator
config.plugins
is also used for this purpose - it contains a list of all plugin classes registered with the CEA - it should also includecea_plugin_template.DemandSummaryPlugin
.config.demand_summary.fudge_factor
is a plugin-specific parameter added inplugin.config
- see below.
Note that having the following code at the bottom of your file will help you debug it more easily from the code editor - you just need to run the current file to run your script with the current configuration:
# (it's not necessary to have this in your script - # it has just proven practical) if __name__ == "__main__": main(cea.config.Configuration())
plugin.config
The plugin.config
file describes sections and parameters within those sections for use in your plugin. See the Configuration File Details section in the CEA Documentation for more information on how Configuration files work. The plugin.config
file uses the exact same format as the default.config
file in the CEA.
Here's an example from the CEA plugin template:
[demand-summary] fudge-factor = 1.0 fudge-factor.type = RealParameter fudge-factor.help = A factor to fudge (multiply) the results by
This defines a section (demand-summary
) as well as a parameter (fudge-factor
) to be used in scripts and plots. The fudge-factor.type
defines the type of the parameter - see the subclasses of cea.config.Parameter
for the list of valid parameter types. Note that plugins can't define their own parameter types.
fudge-factor.help
describes the parameter - this is shown in the command line interface (CLI) when you use the --help
parameter as well as in the GUI for running tools using this parameter.
The plugin.config
file is optional. If you don't specify one, then the scripts in your plugin can only use parameters defined elsewhere - e.g. the CEA or other plugins.
scripts.yml
The scripts.yml
file declares the list of tools defined in your plugin. This is how the CEA knows where to find the demand-summary
script. In fact, the CEA core uses the exact same mechanism to define it's own list of scripts - be sure to check out the original in the CEA repository.
Let's look at the contents of this file:
Demand Summary: - name: demand-summary label: Demand Summary description: Creates a simple summary of the demand totals from the cea demand script. interfaces: [cli, dashboard] module: cea_plugin_template.demand_summary parameters: ["general:scenario", "demand-summary:fudge-factor"] input-files: - [get_total_demand]
The scripts.yml
file is a mapping of category names to a sequence of tool dictionaries. You might want to look up a tutorial of YAML if the syntax seems confusing.
In this example, the category name "Demand Summary" contains a single tool. Each tool contains the following fields:
name
: the tool's name - as used on the command line interface (CLI). The convention is to use hyphens (-
) to connect words. Thename
should only use lowercase letters and hyphens.label
: This is the name to display the tool as in the GUI in the Tools menu.description
: Use this field to give a short description of what your tool does and how to use it.interfaces
: A list of interfaces to show this tool in. For the purposes of CEA plugins,[cli, dashboard]
should be used - you can omitdashboard
to hide your script from the GUI.module
: this is the fully qualified name of your script - the module containing themain
function to call. This module should be importable by thepython
provided by the CEA Console. Open up the CEA Console and typepython -m cea_plugin_template.demand_summary
. If you get an Error message likeNo module named cea_plugin_template.demand_summary
then you haven't installed the plugin yet.parameters
: This is a list of the parameters to be made available to your plugin - each parameter is written in the formsection:parameter
as it appears in the config file. Note you can add your own parameters - seeplugin.config
above.input-files
: This is an (optional) list of files that need to be present before the script can run. Each entry in the list is itself a list of the form[locator_method, arg1, arg2, ..., argn]
. The arguments to the locator method are optional. For more information on locator methods, see the description ofschemas.yml
.
The scripts.yml
file is optional. If you don't provide one, then your plugin can only work on files described elsewhere - e.g. in the CEA or other plugins.
schemas.yml
The file schemas.yml
defines the shape of input files and output files used by scripts (and plots) in the CEA as well as their location inside a scenario. The CEA core uses exact same mechanism for definining it's own data files - each entry in the schemas.yml
defines a locator method, a method of the cea.inputlocator.InputLocator
class that is used throughout the CEA to locate data files.
These locator methods are used in places like the input-files
key in scripts.yml
as well as the location
part of plots.yml
. They're also used for reading Dataframes from (and writing them to) disk.
When the CEA creates an InputLocator
object, the information from your plugin is appended to the list of known locator methods.
Each entry in the schemas.yml
file is the name of a locator method. Here's the example from the CEA plugin template:
demand_summary: created_by: - demand-summary file_path: outputs/data/demand-summary/demand-summary.csv file_type: csv schema: columns: Name: description: Unique building ID. It must start with a letter. type: stringunit: NA values: alphanumeric GFA_m2: description: Gross floor area type: float unit: '[m2]'min: 0.0 values: '{0.0...n}' QC_sys_MWhyr: description: Total system cooling demand type: floatmin: 0.0 unit: '[MWh/yr]' values: '{0.0...n}'plot-color: blue QH_sys_MWhyr: description: Total system heating demand type: float min: 0.0 unit: '[MWh/yr]' values: '{0.0...n}' plot-color: red used_by: []
There's quite a lot going on here, so let's take it apart piece by piece:
demand_summary
the first line defines the name of a locator method - the CEA adds this to thecea.inputlocator.InputLocator
instances at runtime. This means you can do things likelocator.demand_sumary()
to get the path to the fileoutputs/data/demand-summary/demand-summary.csv
located in the current scenario.created_by
: A list of script names (entries inscripts.yml
- either the one defined in your plugin or the one defined by CEA) that produce this file.file_path
: The path to the file, relative to the scenario path. This path may include variable references in the form{variable_name}
. When calling a locator method, you can pass in additional keywords, like this:locator.demand_summary(variable_name="abc")
and the result will have the replacement. Note that withread()
andwrite()
you'll also need to pass in these variables.file_type
: The type of file this locator method points to. Currently, for plugins, we suggest usingcsv
files. The classcea.schemas.CsvSchemaIo
has some nice features - like reading and writing DataFrames as well as validation of the schema on reading / writing. This functionality will be extended for the other file types known to the CEA at a later stage.schema
: For "flat" file types likecsv
,dbf
andshp
files, the contents of theschema
dictionary is justcolumns
, which itself is a dictionary of columns contained inside the data file.
A column definition contains the following keys:
description
: A description of the contents of the column. This is also used for the legend in columns that are plotted.type
: The type of the data in the column. The CEA knows aboutstring
,int
,float
,date
andboolean
column types. Files withfile_type: shp
(shapefiles) also can havePoint
,Polygon
andLineString
.unit
: Describes the unit of a column - especially for columns of typefloat
, this is usually the physical unit of measurment. By convention, we place the unit inside square brackets - see the example forQH_sys_MWhyr
:unit: "[[MWh/yr]]"
. If a unit is not available / does not apply, useNA
instead.values
: This is a short description for the user of the type of values to be found in here and ignored by the CEA.min
/max
: Columns with typesint
orfloat
can optionally specify minimum and maximum values for the range of data in the column. E.g. setmin
to0.0
to specify that only positive values are to be found in the column.plot-color
: Optional. If a column is used in a plot, this color will be used to plot that series. This is either a color in the format"rgb(255, 255, 255)"
or a color taken from the list incea/plots/colors.py
like "red", "blue" etc.
Summary
We've covered all the files necessary to add a new tool to the CEA using the CEA plugin template - in Part 5: How to add your own plots to the CEA we'll add the final touch.