How to add, register and initialize a new plugin#
pyCIF is organized around so-called plugins interacting with each other.
Further details about plugins are given here.
Here, you will learn how to add a new plugins of any type.
Adding a plugin to pyCIF#
A plugin is simply a python module.
To add a new plugin of a given class to pyCIF, you need to create a new folder in the correct class folder in
pycif/plugins/.
You then need to create an empty file called __init__.py, so python interprets the new folder as a python module.
cd pycif/plugins
cd the-class-you-need-to-create
mkdir your-new-plugin
cd your-new-plugin
touch __init__.py
Note
Although the __init__.py is not strictly needed by the newest version of python, pycif fetches information
directly from this file, for initializing the plugin and automatically documenting it.
Therefore, please include it anyway
Registering your new plugin to pyCIF#
pyCIF attaches plugin functions as defined in the corresponding python module in pycif/plugins/ automatically
from the yaml configuration file.
When the new plugin is created, it must be registered, so it can be called by other routines of pyCIF.
plugins in pyCIF are identified with:
a name
optional: a version (default: std)
To register a new plugin, one must define the name and (if relevant) version in the file __init__.py :
_name = "the_name"
_version = "the_version_if_not_std"
You can check that your plugin is correctly registered by using the following commands in python:
from pycif.utils.classes.baseclass import Plugin
Plugin.print_registered()
Adding requirements to your plugin#
All plugins are not stand-alone modules, but instead need attributes, data or functions from other plugins.
pyCIF allows you to easily interface plugins with each other through so-called requirements.
Further details on requirements can be found here.
Information about requirements are specified in the __init__.py file of your plugin.
Below is an example of requirements for the model CHIMERE:
requirements = {
"domain": {
"name": "CHIMERE",
"version": "std",
"empty": False,
"any": False,
},
"chemistry": {
"name": "CHIMERE",
"version": "gasJtab",
"empty": False,
"any": False,
},
"flux": {
"name": "CHIMERE",
"version": "AEMISSIONS",
"empty": True,
"any": False,
"subplug": True,
"preftree": "datavect/components",
},
[...]
}
With the example above, the model plugin, CHIMERE, requires a domain plugin to work.
In the sub-routines of the model plugin, data from the domain can simply be summoned with:
def some_model_function(self, *args, **kwargs):
# Needs the number of grid cells
nlon = self.domain.nlon
nlat = self.domain.nlat
The content of the requirements python dictionary is interpreted when a pyCIF run is initializing.
Requirements are fulfilled with regards to the Yaml configuration file.
Depending the values of the arguments, name, version, empty any, pyCIF will need the
requirement to be explicitly specified or not, default plugins could be used, etc.
All details on how this works are given here.
Input arguments for your plugin#
Not all plugins have input arguments. Input arguments are variables provided by the user through the yaml defining the simulation.
Input arguments are grouped in a dictionary input_arguments, which contains, for each argument, the documentation, its default value (‘None’ if no default is permitted i.e. the argument must be explicitly defined) and the accepted type(s) or value(s).
input_arguments = {
"direxec": {
"doc": "Path to CHIMERE sources and/or executables. "
"For executables, ``fwdchimere.e``, ``tlchimere.e`` and ``achimere.e`` should be in "
"``${path}/src``, ``${path}/src_tl`` and ``${path}/src_ad`` respective sub-folders.",
"default": None,
"accepted": str
},
"ideepconv": {
"doc": "Computation of the deep convection.",
"default": None,
"accepted": {
0: "No deep convection",
1: "Select deep convection automatically according to resolution, "
"deep conv fluxes from Tiedtke",
2: "Select deep convection automatically according to resolution, "
"deep conv fluxes from meteorological data"
}
},
[...]
}
Initializing your plugin#
Your plugin may need some special operations at initialization.
For instance, it may need to copy files, to compile scripts, to read data, to specified default values, etc.
All these operations can be specified in the __init__.py by creating a function called ini_data.
Below is the ini_data method for the model plugin, CHIMERE:
def ini_data(plugin, **kwargs):
"""Initializes CHIMERE
Args:
plugin (dict): dictionary defining the plugin
**kwargs (dictionary): possible extra parameters
Returns:
loaded plugin and directory with executable
"""
info("Initializing the model")
workdir = getattr(plugin, 'workdir', './')
# Initializes the directory
path.init_dir('{}/model'.format(workdir))
# Copying the executables
target = '{}/model/'.format(workdir)
source = '{}/src/fwdchimere.e'.format(plugin.direxec)
shutil.copy(source, target)
source = '{}/src_tl/tlchimere.e'.format(plugin.direxec)
shutil.copy(source, target)
source = '{}/src_ad/achimere.e'.format(plugin.direxec)
shutil.copy(source, target)
# Required inputs for running a CHIMERE simulation
plugin.required_inputs = ['exe', 'nml', 'fluxes',
'meteo', 'inicond', 'boundcond']
# Default values:
# period: '1D'
plugin.periods = getattr(plugin, 'periods', '1D')
# Number of hours per period
plugin.nhours = int(pd.to_timedelta(plugin.periods).total_seconds() / 3600)
plugin.nho = '{:.0f}'.format(plugin.nhours)
# Replace name for AEMISSION files
plugin.fluxes.file = plugin.fluxes.file.format(nho=plugin.nho)
return plugin
During initialization of the model plugin, CHIMERE, the following operations are carried out:
creating a new directory
model/in the working directory with CHIMERE executables to be called later for simulationsspecifying a default value for the attribute
periodif not given in the configuration filemodifying the template name of CHIMERE fluxes
Attaching functions to the plugin#
Any plugin is a combination of functions that will be called by itself or by other plugins. It is necessary to attach functions to your plugin so that they can be called this way in other scripts:
my-plugin.my-function(*args, **kwargs)
To do so, you simply need to import the function of interest at the module level, i.e., in the file __init__.py.
For any function of interest the import line should be added to the __init__.py file.
import my-function