API documentation for the base_model module

The base_model module defines the high level API for the different models within the Virtual Ecosystem. The module creates the BaseModel abstract base class (ABC) which defines a consistent API for subclasses defining an actual model. The API defines abstract methods for each of the key stages in the workflow of running a model: individual subclasses are required to provide model specific implementations for each stage, although the specific methods may simply do nothing if no action is needed at that stage. The stages are:

  • Creating a model instance (BaseModel).

  • Setup a model instance (setup()).

  • Perform any spinup required to get a model state to equilibrate (spinup()).

  • Update the model from one time step to the next update()).

  • Cleanup any unneeded resources at the end of a simulation (cleanup()).

The BaseModel class also provides default implementations for the __repr__() and __str__() special methods.

Declaring new subclasses

The BaseModel has four class attributes that must be specified as arguments to the subclass declaration: model_name, required_init_vars, model_update_bounds and vars_updated. This behaviour is defined in the BaseModel.__init_subclass__() method, which also gives example code for declaring a new subclass.

The usage of these four attributes is described in their docstrings and each is validated when a new subclass is created using the following private methods of the class: _check_model_name(), _check_required_init_vars(), _check_model_update_bounds() and _check_vars_updated().

Model checking

The BaseModel abstract base class defines the __init_subclass__() class method. This method is called automatically whenever a subclass of the ABC is imported and validates the class attributes for the new model class.

The BaseModel.__init__ method

Each model subclass will include an __init__ method that validates and populates model specific attributes. That __init__ method must call the BaseModel.__init__() method, as this populates core shared model attrributes - see the linked method description for details.

super().__init__(data, core_components)

The from_config factory method

The ABC also defines the abstract class method from_config(). This method must be defined by subclasses and must be a factory method that returns an instance of the model subclass. The method must follow the signature of that method, providing:

The method should provide any code to validate the configuration for that model and then use the configuration to initialise and return a new instance of the class.

Model registration

Models have three core components: the BaseModel subclass itself (model), a JSON schema for validating the model configuration (schema) and an optional set of user modifiable constants classes (constants, see ConstantsDataclass). All model modules must register these components when they are imported: see the registry module.

Classes:

BaseModel(data, core_components, **kwargs)

A superclass for all Virtual Ecosystem models.

class virtual_ecosystem.core.base_model.BaseModel(data: Data, core_components: CoreComponents, **kwargs: Any)

A superclass for all Virtual Ecosystem models.

This abstract base class defines the shared common methods and attributes used as an API across all Virtual Ecosystem models. This includes functions to setup, spin up and update the specific model, as well as a function to cleanup redundant model data.

The base class defines the core abstract methods that must be defined in subclasses as well as shared helper functions.

Parameters:
  • data – A Data instance containing variables to be used in the model.

  • core_components – A CoreComponents instance containing shared core elements used throughout models.

Methods:

__init__(data, core_components, **kwargs)

Performs core initialisation for BaseModel subclasses.

__init_subclass__(model_name, ...)

Initialise subclasses deriving from BaseModel.

__repr__()

Represent a Model as a string from the attributes listed in _repr.

__str__()

Inform user what the model type is.

_check_model_name(model_name)

Check the model_name attribute is valid.

_check_model_update_bounds(model_update_bounds)

Check that the model_update_bounds attribute is valid.

_check_required_init_vars(required_init_vars)

Check the required_init_vars property is valid.

_check_vars_updated(vars_updated)

Check that vars_updated is valid.

check_init_data()

Check the init data contains the required variables.

cleanup()

Function to delete objects within the class that are no longer needed.

from_config(data, core_components, config)

Factory function to unpack config and initialise a model instance.

setup()

Function to use input data to set up the model.

spinup()

Function to spin up the model.

update(time_index, **kwargs)

Function to update the model.

Attributes:

core_constants

The core constants used in the model.

data

A Data instance providing access to the shared simulation data.

layer_structure

The LayerStructure details used in the model.

model_name

The model name.

model_timing

The ModelTiming details used in the model.

model_update_bounds

Bounds on model update frequencies.

required_init_vars

Required variables for model initialisation.

vars_updated

Variables that are updated by the model.

__init__(data: Data, core_components: CoreComponents, **kwargs: Any)

Performs core initialisation for BaseModel subclasses.

This method must be called in the __init__ method of all subclasses.

It populates a set of shared instance attributes from the provided CoreComponents and Data value:

  • data: the provided Data instance,

  • model_timing: the ModelTiming instance from the core_components argument.

  • layer_structure: the LayerStructure instance from the core_components argument.

  • core_constants: the CoreConsts instance from the core_components argument.

It then uses the check_init_data() method to confirm that the required variables for the model are present in the provided data attribute.

classmethod __init_subclass__(model_name: str, model_update_bounds: tuple[str, str], required_init_vars: tuple[tuple[str, tuple[str, ...]], ...], vars_updated: tuple[str, ...]) None

Initialise subclasses deriving from BaseModel.

This method runs when a new BaseModel subclass is imported. It adds the new subclasses to the model registry and populates the values of the class attributes.

Subclasses of the BaseModel need to provide the values for class attributes in their signatures. Those values are defined by the arguments to this method, which validates and sets the class attributes for the subclass. See BaseModel for details on the class attributes. For example:

class ExampleModel(
    BaseModel,
    model_name='example',
    model_update_bounds= ("30 minutes", "3 months"),
    required_init_vars=(("required_variable", ("spatial",)),),
    vars_updated=("updated_variable"),
):
    ...
Parameters:
  • model_name – The model name to be used

  • model_update_bounds – Bounds on update intervals handled by the model

  • required_init_vars – A tuple of the variables required to create a model instance.

  • vars_updated – A tuple of the variable names updated by the model.

Raises:
  • ValueError – If the model_name or required_init_vars properties are not defined

  • TypeError – If model_name is not a string

__repr__() str

Represent a Model as a string from the attributes listed in _repr.

Each entry in self._repr is a tuple of strings providing a path through the model hierarchy. The method assembles the tips of each path into a repr string.

__str__() str

Inform user what the model type is.

classmethod _check_model_name(model_name: str) str

Check the model_name attribute is valid.

Parameters:

model_name – The model_name attribute to be used for a subclass.

Raises:

ValueError – the model_name is not a string.

Returns:

The provided model_name if valid

classmethod _check_model_update_bounds(model_update_bounds: tuple[str, str]) tuple[pint.util.Quantity, pint.util.Quantity]

Check that the model_update_bounds attribute is valid.

This is used to validate the class attribute model_update_bounds, which describes the lower and upper bounds on model update frequency. The lower bound must be less than the upper bound.

Parameters:

model_update_bounds – A tuple of two strings representing time periods that can be parsed using pint.Quantity.

Raises:

ValueError – If the provided model_update_bounds cannot be parsed as pint.Quantity with time units or if the lower bound is not less than the upper bound.

Returns:

The validated model_update_bounds, converted to a tuple of pint.Quantity values.

classmethod _check_required_init_vars(required_init_vars: tuple[tuple[str, tuple[str, ...]], ...]) tuple[tuple[str, tuple[str, ...]], ...]

Check the required_init_vars property is valid.

Parameters:

required_init_vars – The required_init_vars attribute to be used for a subclass.

Raises:
  • TypeError – the value of required_init_vars has the wrong type structure.

  • ValueError – required_init_vars uses unknown core axis names.

Returns:

The provided required_init_vars if valid

classmethod _check_vars_updated(vars_updated: tuple[str, ...]) tuple[str, ...]

Check that vars_updated is valid.

Returns:

The provided value if valid.

check_init_data() None

Check the init data contains the required variables.

This method is used to check that the set of variables defined in the required_init_vars class attribute are present in the Data instance used to create a new instance of the class.

Raises:

ValueError – If the Data instance does not contain all the required variables or if those variables do not map onto the required axes.

abstract cleanup() None

Function to delete objects within the class that are no longer needed.

core_constants: CoreConsts

The core constants used in the model.

data: Data

A Data instance providing access to the shared simulation data.

abstract classmethod from_config(data: Data, core_components: CoreComponents, config: Config) BaseModel

Factory function to unpack config and initialise a model instance.

layer_structure: LayerStructure

The LayerStructure details used in the model.

model_name: str

The model name.

This class attribute sets the name used to refer to identify the model class in the MODULE_REGISTRY, within the configuration settings and in logging messages.

model_timing: ModelTiming

The ModelTiming details used in the model.

model_update_bounds: tuple[Quantity, Quantity]

Bounds on model update frequencies.

This class attribute defines two time intervals that define a lower and upper bound on the update frequency that can reasonably be used with a model. Models updated more often than the lower bound may fail to capture transient dynamics and models updated more slowly than the upper bound may fail to capture important temporal patterns.

required_init_vars: tuple[tuple[str, tuple[str, ...]], ...]

Required variables for model initialisation.

This class property defines a set of variable names that must be present in the Data instance used to initialise an instance of this class. It is a tuple containing zero or more tuples, each providing a variable name and then a tuple of zero or more core axes that the variable must map onto.

For example: (('temperature', ('spatial', 'temporal')),)

abstract setup() None

Function to use input data to set up the model.

abstract spinup() None

Function to spin up the model.

abstract update(time_index: int, **kwargs: Any) None

Function to update the model.

Parameters:

time_index – The index representing the current time step in the data object.

vars_updated: tuple[str, ...]

Variables that are updated by the model.

At the moment, this tuple is used to decide which variables to output from the Data object, i.e. every variable updated by a model used in the specific simulation. In future, this could also be used to prevent multiple models from updating the same variable and similar problems.