Interfaces
This book has moved to the FINAM documentation. You are viewing an outdated version!
FINAM is primarily a collection of interfaces that allows different models and other components to communicate.
For all interfaces, FINAM also provides abstract or concrete implementations to speed up component development.
Class diagram
The following figure shows a diagram of FINAM's core interfaces and classes. Arrows indicate inheritance. The properties and methods are those typically used or implemented by developers.
Components
Components represent linkable entities like models.
There are two interfaces for components: IComponent
and ITimeComponent
.
IComponent
IComponent
serves for pull-based components without an explicit time step.
It provides all the basic methods required for component communication and execution.
initialize(self)
sets up the componentconnect(self)
pushes initial values to output slotsvalidate(self)
checks the component for validityupdate(self)
makes a calculation stepfinalize(self)
shuts down the component
These methods are called by the scheduler in the given order (and repeatedly for update()
), each for all components, before proceeding to the next method.
For each of these methods, there is a private method with the same name and an underscore prefix, like _initialize(self)
.
Component developers implement these private methods, which are called internally by their public counterpart.
For details, see chapter Writing components.
To access a component's input and output slots, there are the properties:
inputs
returns adict-like
ofIInput
slots by nameoutputs
returns adict-like
ofIOutput
slots by name
Finally:
status
returns the component's currentComponentStatus
(CREATED
,INITIALIZED
, ...)
The abstract class Component
provides a basic implementation for IComponent
.
Classes extending Component
must override methods named of the first block, with underscore, like _initialize()
.
inputs
, outputs
and status
are provided as basic implementations.
ITimeComponent
ITimeComponent
extends IComponent
and serves for components with explicit time step, like simulation models.
In addition to IComponent
, it adds one property:
time
should report the component's current time, as adatetime
object
As ITimeComponent
extends IComponent
, only ITimeComponent
needs to be implemented.
The abstract class TimeComponent
provides a basic implementation for ITimeComponent
.
It is basically identical to Component
, and in addition provides a basic implementation for time
.
Inputs and Outputs
Interfaces IInput
and IOutput
define coupling slots.
In module sdk
, Input
and Output
are provided as implementations for IInput
and IOutput
, respectively.
They should suffice most use cases.
IInput
IInput
represents a data exchange input slot, with the following methods:
set_source(self, source)
sets anIOutput
as source for this inputget_source(self)
returns theIOutput
that is the source for this inputsource_updated(self, time)
informs the input that the connectedIOutput
has new data availablepull_data(self, time)
retrieves and returns the connectedIOutput
's data
Components usually only use pull_data(self, time)
in their _update(self)
method.
All other methods are only used under the hood.
All these methods are implemented in Input
, so there is normally no need to write an own implementation for IInput
.
Another implementation is provided by CallbackInput
, for use in push-based components without a time step.
They can connect to source_updated(self, time)
by providing a callback function.
Other classes derived from Input
can overwrite the private _source_updated(self, time)
method,
which is called by source_updated(self, time)
.
IOutput
IOutput
represents a data exchange output slot, with the following methods:
add_target(self, target)
adds anIInput
as target for this outputget_target(self)
returns the list ofIInput
targets of this outputpush_data(self, data, time)
is used to populate the output with data after an updatenotify_targets(self, time)
informs coupledIInput
s that new data is availableget_data(self, time)
returns the data in this outputchain(self, input)
connects this output to anIInput
(or an adapter)
Components usually only use _push_data(self, data, time)
in their update(self)
method.
During coupling setups, chain(self, input)
or it's synonym operator >>
are used.
All other methods are only used under the hood.
All these methods are implemented in Output
, so there is normally no need to write an own implementation for IOutput
.
Other classes derived from Output
can overwrite the private _get_data(self, time)
method,
which is called by get_data(self, time)
.
Adapters
Adapters serve for data transformations between outputs and inputs of different components.
IAdapter
The interface IAdapter
serves for implementing adapters.
It simply combines IInput
and IOutput
, so it is both at the same time.
IAdapter
provides all the methods of IInput
and IOutput
, but most of them are only used under the hood.
Classes implementing IAdapter
can extend Adapter
, which provides default implementations for Input
and Output
methods.
Time-independent/one-shot adapters need to override _get_data(self, time)
.
Inside this method, they get their input via self.pull_data(time)
, transform it, and return the result.
Time-aware adapters, e.g. for temporal interpolation, usually override _source_updated(self, time)
and _get_data(self, time)
.
In _source_updated(self, time)
, incoming data is collected (and potentially aggregated), while in _get_data(self, time)
the result is returned.
For details, see chapter Writing adapters.
NoBranchAdapter
Some time-aware adapters may not allow for branching in the subsequent adapter chain.
I.e. they do not support multiple target components.
For these cases, NoBranchAdapter
is provided as a marker interface without any methods.