desmod.component

Component is the building block for desmod models.

Hierarchy

A desmod model consists of a directed acyclical graph (DAG) of Component subclasses. Each Component is composed of zero or more child Components. A single top-level Component class is passed to the simulate() function to initiate simulation.

The Component hierarchy does not define the behavior of a model, but instead exists as a tool to build large models out of composable and encapsulated pieces.

Connections

Components connect to other components via connection objects. Each component is responsible for declaring the names of external connections as well as make connections for its child components. The final network of inter-component connections is neither directed (a connection object may enable two-way communication), acyclic (groups of components may form cyclical connections), nor constrained to match the component hierarchy.

Ultimately, a connection between two components means that each component instance has a [pythonic] reference to the connection object.

In the spirit of Python, the types connection objects are flexible and dynamic. A connection object may be of any type–it is up to the connected components to cooperatively decide how to use the connection object for communication. That said, some object types are more useful than others for connections. Some useful connection object types include:

Processes

A component may have zero or more simulation processes (simpy.events.Process). It is these processes that give a model its simulation-time behavior. The process methods declared by components are started at simulation time. These “standing” processes may dynamically launch addtional processes using self.env.process().

Use Cases

Given the flexibility components to have zero or more children, zero or more processes, and zero or more connections, it can be helpful to give names to the various roles components may play in a model.

  • Structural Component – a component with child components, but no processes
  • Behavioral Component – a component with processes, but no child components
  • Hybrid Component – a component with child components and processes
  • State Component – a component with neither children or processes

It is typical for the top-level component in a model to be purely structural, while behavioral components are leaves in the model DAG.

A component with neither children or processes may still be useful. Such a component could, for example, be used as a connection object.

class desmod.component.Component(parent: Optional[Component], env: Optional[desmod.simulation.SimEnvironment] = None, name: Optional[str] = None, index: Optional[int] = None)[source]

Building block for composing models.

This class is meant to be subclassed. Component subclasses must declare their children, connections, and processes.

Parameters:
  • parent (Component) – Parent component or None for top-level Component.
  • env (SimEnvironment) – SimPy simulation environment.
  • name (str) – Optional name of Component instance.
  • index (int) – Optional index of Component. This is used when multiple sibling components of the same type are instantiated as an array/list.
env

The simulation environment; a SimEnvironment instance.

name

The component name (str).

index

Index of Component instance within group of sibling instances. Will be None for un-grouped Components.

scope

String indicating the full scope of Component instance in the Component DAG.

children
error(*values)

Log an error message.

warn(*values)

Log a warning message.

info(*values)

Log an informative message.

debug(*values)

Log a debug message.

add_process(g: Callable[[...], Generator[simpy.events.Event, Any, None]], *args, **kwargs) → None[source]

Add a process method to be run at simulation-time.

Subclasses should call this in __init__() to declare the process methods to be started at simulation-time.

Parameters:
  • process_func (function) – Typically a bound method of the Component subclass.
  • args – arguments to pass to process_func.
  • kwargs – keyword arguments to pass to process_func.
add_processes(*generators) → None[source]

Declare multiple processes at once.

This is a convenience wrapper for add_process() that may be used to quickly declare a list of process methods that do not require any arguments.

Parameters:process_funcs – argument-less process functions (methods).
add_connections(*connection_names) → None[source]

Declare names of externally-provided connection objects.

The named connections must be connected (assigned) by an ancestor at elaboration time.

connect(dst: desmod.component.Component, dst_connection: Any, src: Optional[Component] = None, src_connection: Optional[Any] = None, conn_obj: Optional[Any] = None) → None[source]

Assign connection object from source to destination component.

At elaboration-time, Components must call connect() to make the connections declared by descendant (child, grandchild, etc.) components.

Note

connect() is nominally called from connect_children().

Parameters:
  • dst (Component) – Destination component being assigned the connection object.
  • dst_connection (str) – Destination’s name for the connection object.
  • src (Component) – Source component providing the connection object. If omitted, the source component is assumed to be self.
  • src_connection (str) – Source’s name for the connection object. If omitted, dst_connection is used.
  • conn_obj – The connection object to be assigned to the destination component. This parameter may typically be omitted in which case the connection object is resolved using src and src_connection.
connect_children() → None[source]

Make connections for descendant components.

This method must be overridden in Component subclasses that need to make any connections on behalf of its descendant components. Connections are made using connect().

classmethod pre_init(env: desmod.simulation.SimEnvironment) → None[source]

Override-able class method called prior to model initialization.

Component subclasses may override this classmethod to gain access to the simulation environment (env) prior to __init__() being called.

elaborate() → None[source]

Recursively elaborate the model.

The elaboration phase prepares the model for simulation. Descendant connections are made and components’ processes are started at elaboration-time.

elab_hook() → None[source]

Hook called after elaboration and before simulation phase.

Component subclasses may override elab_hook() to inject behavior after elaboration, but prior to simulation.

post_simulate() → None[source]

Recursively run post-simulation hooks.

post_sim_hook() → None[source]

Hook called after simulation completes.

Component subclasses may override post_sim_hook() to inject behavior after the simulation completes successfully. Note that post_sim_hook() will not be called if the simulation terminates with an unhandled exception.

get_result(result: Dict[str, Any]) → None[source]

Recursively compose simulation result dict.

Upon successful completion of the simulation phase, each component in the model has the opportunity to add-to or modify the result dict via its get_result_hook() method.

The fully composed result dict is returned by simulate().

Parameters:result (dict) – Result dictionary to be modified.
get_result_hook(result: Dict[str, Any]) → None[source]

Hook called after result is composed by descendant components.