How to write a Veros plug-in

Writing a plug-in for Veros is relatively simple. A plug-in can be any Python package that accepts a VerosState object. The plug-in is then free to modify the model state in any way it pleases.

The only requirement for the plug-in to be usable in Veros setups is that it declares a special object in its top __init__.py file:

__VEROS_INTERFACE__ = dict(
    name='my-plugin',
    setup_entrypoint=my_setup_function,
    run_entrypoint=my_main_function
)

The functions passed in setup_entrypoint and run_entrypoint are then called by Veros during model set-up and after each time step, respectively, with the model state as the sole argument.

An example for these functions could be:

from veros import veros_method


@veros_method
def my_setup_function(vs):
    pass


@veros_method
def my_main_function(vs):
    # apply simple ice mask
    mask = np.logical_and(vs.temp[:, :, -1, vs.tau] * vs.maskT[:, :, -1] < -1.8,
                          vs.forc_temp_surface < 0.)
    vs.forc_temp_surface[mask] = 0.0
    vs.forc_salt_surface[mask] = 0.0

In this case, the setup function does nothing, while the main function sets temperature and salinity forcing to 0 where the surface temperature is smaller than -1.8 degrees (a very crude sea ice model).

Custom settings, variables, and diagnostics

In real-world applications, you probably want to use custom settings, variables, and/or diagnostics in your plug-in. You can specify those as additional arguments to __VEROS_INTERFACE__:

__VEROS_INTERFACE__ = dict(
    name='my-plugin',
    setup_entrypoint=my_setup_function,
    run_entrypoint=my_main_function,
    settings=my_settings,
    variables=my_variables,
    conditional_variables=my_conditional_variables,
    diagnostics=[MyDiagnostic]
)

In this case, my_settings is a dict mapping the name of the setting to a Setting object:

from collections import OrderedDict  # to preserve order
from veros.settings import Setting

my_settings = OrderedDict([
    ('enable_my_plugin', Setting(False, bool, 'Enable my plugin')),
    ('temperature_cutoff', Setting(-1.8, float, 'Cut-off surface temperature')),
])

Similarly, for variables and conditional variables:

from collections import OrderedDict  # to preserve order
from veros.variables import Variable, T_GRID

my_variables = OrderedDict([
    ('my_variable', Variable('Description', T_GRID, 'unit', 'Long description')),
])

my_conditional_variables = OrderedDict([
    ('enable_my_plugin',  # condition
     OrderedDict([
         ('my_conditional_variable', Variable(
             'description', T_GRID, 'unit', 'Long description'
         )),
     ])),
])

The so-defined settings and variables are then available as attributes of the Veros state object, as usual:

@veros_method
def my_function(vs):
    if vs.enable_my_plugin:
        vs.my_variable[...] = 0.

See also

For more inspiration on how to specify settings and variables, have a look at the built-in settings.py and variables.py files.

Diagnostics are defined similarly, but they have to be a subclass of VerosDiagnostic.

Shipping custom model setups

You can use a special entrypoint in the setup.py file of your plug-in to inform the Veros command-line interface of your custom setups:

from setuptools import setup

setup(
   name='my-plugin',
   packages='my_plugin',
   entry_points={
     'veros.setup_dirs': [
         'my_plugin = my_plugin.setup'
     ]
   }
)

This assumes, that your custom setups are located in the folder my_plugin/setup. Then, veros copy-setup will automatically find your custom setups if the plug-in is installed:

$ veros copy-setup --help
Usage: veros copy-setup [OPTIONS] SETUP

Copy a standard setup to another directory.

Available setups:

   acc, acc_basic, acc_sector, eady, global_1deg, global_4deg,
   global_flexible, my_setup, north_atlantic, wave_propagation

Example:

   $ veros copy-setup global_4deg --to ~/veros-setups/4deg-lowfric

Further directories containing setup templates can be added to this
command via the VEROS_SETUP_DIR environment variable.

Options:
--to PATH  Target directory, must not exist (default: copy to current
           working directory)
--help     Show this message and exit.

In this case, the custom setup is located in the folder my_plugin/setup/my_setup, and thus shows up as my_setup.