Subsystem¶
- class pathsim.subsystem.Interface[source]¶
Bases:
BlockBare-bone block that serves as a data interface for the ‘Subsystem’ class.
It works like this:
Internal blocks of the subsystem are connected to the inputs and outputs of this Interface block via the internal connections.
It behaves like a normal block (inherits the main ‘Block’ class methods).
It implements some special methods to get and set the inputs and outputs of the blocks, that are used to translate between the internal blocks of the subsystem and the inputs and outputs of the subsystem.
Handles data transfer to and from the internal subsystem blocks to and from the inputs and outputs of the subsystem.
- class pathsim.subsystem.Subsystem(blocks=None, connections=None, events=None, tolerance_fpi=1e-10, iterations_max=200)[source]¶
Bases:
BlockSubsystem class that holds its own blocks and connecions and can natively interface with the main simulation loop.
IO interface is realized by a special ‘Interface’ block, that has extra methods for setting and getting inputs and outputs and serves as the interface of the internal blocks to the outside.
The subsystem doesnt use its ‘inputs’ and ‘outputs’ dicts directly. It exclusively handles data transfer via the ‘Interface’ block.
This class can be used just like any other block during the simulation, since it implements the required methods ‘update’ for the fixed-point iteration (resolving algebraic loops with instant time blocks), the ‘step’ method that performs timestepping (especially for dynamic blocks with internal states) and the ‘solve’ method for solving the implicit update equation for implicit solvers.
Example
This is how we can wrap up multiple blocks within a subsystem. In this case vanderpol system built from discrete components instead of using an ODE block (in practice you should use a monolithic ODE whenever possible due to performance).
from pathsim import Subsystem, Interface, Connection from pathsim.blocks import Integrator, Function #van der Pol parameter mu = 1000 #blocks in the subsystem If = Interface() # this is the interface to the outside I1 = Integrator(2) I2 = Integrator(0) Fn = Function(lambda x1, x2: mu*(1 - x1**2)*x2 - x1) sub_blocks = [If, I1, I2, Fn] #connections in the subsystem sub_connections = [ Connection(I2, I1, Fn[1], If[1]), Connection(I1, Fn, If), Connection(Fn, I2) ] #the subsystem acts just like a normal block vdp = Subsystem(sub_blocks, sub_connections)
- Parameters:
blocks (list[Block] | None) – internal blocks of the subsystem
connections (list[Connection] | None) – internal connections of the subsystem
tolerance_fpi (float) – absolute tolerance for convergence of algebraic loops default see ´SIM_TOLERANCE_FPI´ in ´_constants.py´
iterations_max (int) – maximum allowed number of iterations for algebraic loop solver, default see ´SIM_ITERATIONS_MAX´ in ´_constants.py´
- graph¶
internal graph representation for fast system funcion evluations using DAG with algebraic depths
- Type:
Graph
- boosters¶
list of boosters (fixed point accelerators) that wrap algebraic loop closing connections assembled from the system graph
- Type:
None | list[ConnectionBooster]
- add_block(block)[source]¶
Adds a new block to the subsystem.
This works dynamically for running simulations.
- Parameters:
block (Block) – block to add to the subsystem
- remove_block(block)[source]¶
Removes a block from the subsystem.
This works dynamically for running simulations.
- Parameters:
block (Block) – block to remove from the subsystem
- add_connection(connection)[source]¶
Adds a new connection to the subsystem.
This works dynamically for running simulations.
- Parameters:
connection (Connection) – connection to add to the subsystem
- remove_connection(connection)[source]¶
Removes a connection from the subsystem.
This works dynamically for running simulations.
- Parameters:
connection (Connection) – connection to remove from the subsystem
- add_event(event)[source]¶
Adds an event to the subsystem.
This works dynamically for running simulations.
- Parameters:
event (Event) – event to add to the subsystem
- remove_event(event)[source]¶
Removes an event from the subsystem.
This works dynamically for running simulations.
- Parameters:
event (Event) – event to remove from the subsystem
- property size¶
Get size information from subsystem, recursively assembled from internal blocks, including nested subsystems.
- plot(*args, **kwargs)[source]¶
Plot the simulation results by calling all the blocks that have visualization capabilities such as the ‘Scope’ and ‘Spectrum’.
- collect()[source]¶
Aggregate results from internal blocks.
Deprecated since version 1.0.0: its against pathsims philosophy
- to_checkpoint(prefix, recordings=False)[source]¶
Serialize subsystem state by recursively checkpointing internal blocks.
- load_checkpoint(prefix, json_data, npz)[source]¶
Restore subsystem state by recursively loading internal blocks.
- on()[source]¶
Activate the subsystem and all internal blocks, sets the boolean evaluation flag to ‘True’.
- off()[source]¶
Deactivate the subsystem and all internal blocks, sets the boolean evaluation flag to ‘False’. Also resets the subsystem.
- linearize(t)[source]¶
Linearize the algebraic and dynamic components of the internal blocks.
This is done by linearizing the internal ‘Operator’ and ‘DynamicOperator’ instances of all the internal blocks of the subsystem in the current system operating point. The operators create 1st order taylor approximations internally and use them on subsequent calls after linearization.
Recursively traverses down the hierarchy for nested subsystems and linearizes all of them.
- Parameters:
t (float) – evaluation time
- Returns:
A, B, C, D – local state space model of the subsystem, see ‘to_statespace’
- Return type:
np.ndarray
- to_statespace(t)[source]¶
Return the linear state space model of the subsystem, seen from its interface, in the current operating point.
The interface already designates what is an input and what is an output, so unlike ‘Simulation.to_statespace’ no break and tap points have to be given. This makes the subsystem boundary the natural place to linearize a part of a model.
Since a ‘Subsystem’ is a ‘Block’, the result composes: a subsystem nested inside another system contributes its assembled model there, and hierarchies linearize hierarchically.
Note
This is a pure query, the internal blocks keep evaluating their original functions afterwards.
- Parameters:
t (float) – evaluation time
- Returns:
A, B, C, D – state space model of the subsystem, shaped (nx,nx), (nx,nu), (ny,nx), (ny,nu)
- Return type:
np.ndarray
- Raises:
LinearizationError – if an internal block has no linear model, or if the subsystem is not well posed
- property events¶
Recursively collect and return events spawned by the internal blocks of the subsystem, for discrete time blocks such as triggers / comparators, clocks, etc.
- property inputs¶
- property outputs¶
- property state¶
Expose the states of the internal dynamic blocks as a single vector, in the order of ‘_blocks_dyn’.
Note
A ‘Subsystem’ only carries a dummy engine, it does not integrate anything itself. Its state lives in the internal blocks, so the inherited ‘Block.state’ would report the untouched dummy state instead. Nested subsystems recurse through this same property.
- Returns:
state – concatenated states of the internal dynamic blocks, or ‘None’ if the subsystem has no dynamic blocks
- Return type:
None | np.ndarray
- get_all()[source]¶
Retrieve the subsystem inputs and outputs and the recursively collected states of the internal blocks.
- Returns:
inputs (array) – subsystem input register
outputs (array) – subsystem output register
states (array) – internal states of all blocks of the subsystem
- derivative(t)[source]¶
Return the time derivatives of the internal dynamic blocks, concatenated in the same order as ‘state’.
Blocks that do not define a derivative contribute zeros, so the result always matches the length of the state vector.
- Parameters:
t (float) – evaluation time
- Returns:
dxdt – time derivative of the subsystem state, or ‘None’ if the subsystem has no dynamic blocks
- Return type:
None | np.ndarray
- sample(t, dt)[source]¶
Update the internal connections again and sample data from the internal blocks that implement the ‘sample’ method.
- update(t)[source]¶
Update the instant time components of the internal blocks to evaluate the (distributed) system equation.
- Parameters:
t (float) – evaluation time
- step(t, dt)[source]¶
Explicit component of timestep for internal blocks including error propagation.
Notes
This is pretty much an exact copy of the ‘_step’ method from the ‘Simulation’ class.