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()). This method should include any initialization logic including validating and populating class attributes.

  • 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 the following class attributes that must be specified as arguments to the subclass declaration:

This behaviour is defined in the BaseModel.__init_subclass__() method, which also gives example code for declaring a new subclass.

The usage of these attributes is described in their docstrings and each is validated when a new subclass is created using the following private methods of the class:

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 should include an __init__ method that defines all model specific attributes. The __init__ should not contain any further initialization logic, which should happen in the subclass _setup method instead. The __init__ method must call the BaseModel.__init__() method, as this populates core shared model attributes - 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 two core components: the BaseModel subclass itself (model) and a model configuration module that both defines the configuration options and constants associated with the model and provides validation of configuration data from TOML files. All model modules must register these components when they are imported: see the registry module.

Classes:

BaseDisturbance(data, models, ...)

A superclass for all Virtual Ecosystem disturbance models.

BaseModel(data, core_components[, static])

A superclass for all Virtual Ecosystem models.

Functions:

discover_disturbances()

Discover all the disturbances in Virtual Ecosystem.

discover_models()

Discover all the models in Virtual Ecosystem.

to_camel_case(snake_str)

Convert a snake_case string to CamelCase.

class virtual_ecosystem.core.base_model.BaseDisturbance(data: Data, models: dict[str, BaseModel], disturbance_timing: DisturbanceTiming, **kwargs)[source]#

A superclass for all Virtual Ecosystem disturbance models.

This abstract base class defines the shared common methods and attributes used as an API across all Virtual Ecosystem disturbance models. This includes functions to setup and run the specific model.

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, models, disturbance_timing, ...)

Performs core initialization for BaseModel subclasses.

__init_subclass__(model_name, ...)

Checks the disturbed models and variables are all known.

__repr__()

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

_check_model_name(model_name)

Check the model_name attribute is valid.

disturb(time_index)

Run the disturbance, updating the self.data and/or self.models as needed.

from_config(data, configuration, ...)

Factory function to unpack config and initialise a model instance.

Attributes:

data

A Data instance providing access to the shared simulation data.

data_variables_disturbed

A list of data variables that will be updated.

disturbed_models

A list of model names that this disturbance will affect.

model_name

The model name.

models

The models this disturbance will disturb.

timing

The DisturbanceTiming details used in the model.

__init__(data: Data, models: dict[str, BaseModel], disturbance_timing: DisturbanceTiming, **kwargs)[source]#

Performs core initialization for BaseModel subclasses.

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

  • data: the provided Data instance.

  • models: dictionary of BaseModel instances of the models available in the simulation.

  • disturbance_timing: the DisturbanceTiming instance.

classmethod __init_subclass__(model_name: str, disturbed_models: tuple[str, ...], data_variables_disturbed: tuple[str, ...])[source]#

Checks the disturbed models and variables are all known.

If so, it adds the disturbance to the registry.

__repr__() str[source]#

Represent a Disturbance 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.

classmethod _check_model_name(model_name: str) str[source]#

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

data#

A Data instance providing access to the shared simulation data.

data_variables_disturbed: tuple[str, ...]#

A list of data variables that will be updated.

This list will be used to validate the configuration and ensure that all the variables to be disturbed will be available in the simulation. Disturbance models do not create new variables.

disturb(time_index: int) None[source]#

Run the disturbance, updating the self.data and/or self.models as needed.

First, the timing is checked, returning if the disturbance shall not be run at this timestep. Otherwise, it calls the inner _disturb method where the actual disturbance is executed.

Parameters:

time_index – The index of the current timestep.

disturbed_models: tuple[str, ...]#

A list of model names that this disturbance will affect.

This list will be used to validate the configuration - check that all the models to disturb are available in the simulation - as well at runtime to select those models when creating an instance of the disturbance.

abstractmethod classmethod from_config(data: Data, configuration: CompiledConfiguration, core_components: CoreComponents, models: dict[str, BaseModel]) BaseDisturbance[source]#

Factory function to unpack config and initialise a model instance.

model_name: str#

The model name.

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

models#

The models this disturbance will disturb.

timing#

The DisturbanceTiming details used in the model.

class virtual_ecosystem.core.base_model.BaseModel(data: Data, core_components: CoreComponents, static: bool = False, *args: Any)[source]#

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[, static])

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_variables_attribute(...)

Check a model variables attribute property is valid.

_setup(*args)

Function to setup the model during initialisation.

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, configuration, core_components)

Factory function to unpack config and initialise a model instance.

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.

grid

The Grid details used in the model.

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.

vars_populated_by_first_update

Variables that are initialised by the model during the first update.

vars_populated_by_init

Variables that are initialised by the model during the setup.

vars_required_for_init

Required variables for model initialisation.

vars_required_for_update

Variables that are required by the update method of the model.

vars_updated

Variables that are updated by the model.

__init__(data: Data, core_components: CoreComponents, static: bool = False, *args: Any)[source]#

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.

  • grid: the Grid instance from the core_components argument.

  • layer_structure: the LayerStructure instance from the core_components argument.

  • core_constants: the CoreConstants 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], vars_required_for_init: tuple[str, ...], vars_updated: tuple[str, ...], vars_required_for_update: tuple[str, ...], vars_populated_by_init: tuple[str, ...], vars_populated_by_first_update: tuple[str, ...]) None[source]#

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"),
    vars_required_for_init=(("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

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

  • vars_populated_by_init – A tuple of the variables initialised when a model instance is created.

  • vars_populated_by_first_update – A tuple of the variables initialised when a model update method first run.

  • vars_required_for_update – A tuple of the variables required to update a model instance.

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

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

  • TypeError – If model_name is not a string

__repr__() str[source]#

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[source]#

Inform user what the model type is.

classmethod _check_model_name(model_name: str) str[source]#

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[Quantity, Quantity][source]#

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_variables_attribute(variables_attribute_name: str, variables_attribute_value: tuple[str, ...]) tuple[str, ...][source]#

Check a model variables attribute property is valid.

Creating an instance of the BaseModel class requires that several variables attributes are set. Each of these provides a list of variable names that are required or updated by the model at various points. This method is used to validate the structure of the new instance and ensure the resulting model structure is consistent.

Parameters:
  • variables_attribute_name – The name of the variables attribute

  • variables_attribute_value – The provided value for the variables attribute

Raises:

TypeError – the value of the model variables attribute has the wrong type structure.

Returns:

The validated variables attribute value

abstractmethod _setup(*args: Any) None[source]#

Function to setup the model during initialisation.

check_init_data() None[source]#

Check the init data contains the required variables.

This method is used to check that the set of variables defined in the vars_required_for_init 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.

abstractmethod cleanup() None[source]#

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

core_constants: CoreConstants#

The core constants used in the model.

data: Data#

A Data instance providing access to the shared simulation data.

abstractmethod classmethod from_config(data: Data, configuration: CompiledConfiguration, core_components: CoreComponents) BaseModel[source]#

Factory function to unpack config and initialise a model instance.

grid: Grid#

The Grid details used in the model.

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.

abstractmethod spinup() None[source]#

Function to spin up the model.

update(time_index: int, **kwargs: Any) None[source]#

Function to update the model.

If the model is static, the inner update method, self._update will only run once, at most.

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

  • **kwargs – Further arguments to the update method.

vars_populated_by_first_update: tuple[str, ...]#

Variables that are initialised by the model during the first update.

These are the variables that are initialised by the model and stored in the data object when running the update method for the first time. They will be available for other models to use in their update methods but not in the setup methods.

vars_populated_by_init: tuple[str, ...]#

Variables that are initialised by the model during the setup.

These are the variables that are initialised by the model and stored in the data object when running the setup method and that will be available for other models to use in their own setup or update methods.

vars_required_for_init: 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')),)

vars_required_for_update: tuple[str, ...]#

Variables that are required by the update method of the model.

These variables should have been initialised by another model or loaded from external sources, but in either case they will be available 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. It is also be used warn if multiple models will be updating the same variable and to verify that these variables are indeed initialised by another model, and therefore will be available.

virtual_ecosystem.core.base_model.discover_disturbances() list[type[BaseDisturbance]][source]#

Discover all the disturbances in Virtual Ecosystem.

virtual_ecosystem.core.base_model.discover_models() list[type[BaseModel]][source]#

Discover all the models in Virtual Ecosystem.

virtual_ecosystem.core.base_model.to_camel_case(snake_str: str) str[source]#

Convert a snake_case string to CamelCase.

Parameters:

snake_str – The snake case string to convert.

Returns:

The camel case string.