`BlockSystems.AbstractIOSystem`

— Type`BlockSystems.BlockSpec`

— Type```
struct BlockSpec
BlockSpec(in::Vector, out::Vector; in_strict=true, out_strict=false)
```

Block specification, defines which inputs/outputs an `AbstractIOSystem`

should have. Contains two vectors of `Symbols`

. Can be initialized with Vectors of `Symbols`

, `Num`

or `<:Symbolic`

.

If `strict=true`

the in/outputs *must equal* the specification. If `strict=false`

the block *must contain* the in/outputs from the specification.

Object is functor: call `(::BlockSpec)(ios)`

to check whether `ios`

fulfills specification. See also `fulfills`

.

```
iob = IOBlock(...)
spec = BlockSpec([:uᵣ, :uᵢ], [:iᵣ, :iᵢ])
fulfills(iob, spec)
spec(iob)
```

`BlockSystems.IOBlock`

— Type`struct IOBlock <: AbstractIOSystem`

A basic IOSystem which consists of a single ODESystem.

`name::Symbol`

`inputs::Vector{SymbolicUtils.Symbolic}`

`iparams::Vector{SymbolicUtils.Symbolic}`

`istates::Vector{SymbolicUtils.Symbolic}`

`outputs::Vector{SymbolicUtils.Symbolic}`

`system::ODESystem`

`removed_states::Vector{SymbolicUtils.Symbolic}`

`removed_eqs::Vector{Equation}`

`BlockSystems.IOBlock`

— Method```
IOBlock(iob; name, warn)
```

Construct a new IOBlock based on an existing. Deep-copy all fields and assigns new name.

`BlockSystems.IOBlock`

— Method```
IOBlock(eqs, inputs, outputs; name, iv, warn, rem_eqs)
```

Construct a new IOBlock for the given arguments.

```
using BlockSystems, ModelingToolkit
@parameters t i(t)
@variables x(t) o(t)
D = Differential(t)
iob = IOBlock([D(x) ~ i, o ~ x], [i], [o], name=:iob)
```

`BlockSystems.IOSystem`

— Type`struct IOSystem <: AbstractIOSystem`

A composite `IOSystem`

which consists of multiple `AbstractIOSystem`

which are connected via a vector of namespaced pairs (`subsys1.out => subsys2.in`

).

An `IOSystem`

contains maps how to promote the namespaced variables of the subsystem to the new scope subsys1₊x(t) => x(t) subsys1₊y(t) => subsys1₊y(t) subsys2₊y(t) => subsys2₊y(t)

`name::Symbol`

`inputs::Vector{SymbolicUtils.Symbolic}`

`iparams::Vector{SymbolicUtils.Symbolic}`

`istates::Vector{SymbolicUtils.Symbolic}`

`outputs::Vector{SymbolicUtils.Symbolic}`

`removed_states::Vector{SymbolicUtils.Symbolic}`

`connections::Vector{Pair{SymbolicUtils.Symbolic, SymbolicUtils.Symbolic}}`

`namespace_map::Dict{SymbolicUtils.Symbolic, SymbolicUtils.Symbolic}`

`systems::Vector{AbstractIOSystem}`

`BlockSystems.IOSystem`

— Method```
IOSystem(
cons,
io_systems;
namespace_map,
globalp,
outputs,
name,
autopromote
)
```

Construct a new IOSystem from various subsystems. Arguments:

`cons`

:The connections in the form

`sub1.output => sub2.input`

. It is also possible to use simple algebraic equations such as`sub1.o1 + sub2.o2 => sub3.input`

.If

`:autocon`

, BlockSystems will automaticially create connections based on matchin output and input names. This requires the output name to be unique. The same output may be connected to several inputs with the same name.`io_systems`

: Vector of subsystems`namespace_map`

: Provide collection of custom namespace promotions / renamings e.g.`sub1.input => voltage`

. Variables without entry in the map will be promoted automatically. Automatic promotion means that the sub-namespace is removed whenever it is possible without naming conflicts. The map may contain inputs, outputs, istates, iparams and removed_states. The rhs of the map can be provided as as Symbol:`sub1.input => :newname`

.Specify outputs of composite system:

`outputs=:all`

(default): All of the subsystem outputs will become system outputs.`outputs=:remaining`

: Outputs, which have been used in`connections`

won't become outputs of the composite system.`outputs=[sub1.o, sub2.o]`

: only specified outputs will become outputs of composite sytem. All other sub-outputs will become internal states of the connected system (and might be optimized away in`connect_system`

).`name`

: namespace`autopromote=true`

: enable/disable automatic promotion of variable names to system namespace`globalp=Symbol[]`

: List of symbols, which represent system-wide parameters (iparams or inputs). All occurences in subsystems will be promoted to the system namespace (i.e. if`globalp=[:K]`

, each component block which has some parameter`:K`

will be represented by the same parameter rather than)`blk1.K`

and`blk2.K`

.

`SciMLBase.ODEFunction`

— Method`ODEFunction(iob::IOBlock; f_states=Symbol[], f_params=Symbol[], verbose=false)`

Return an `ODEFunction`

object with the corresponding mass matrix and variable names.

`BlockSystems._algebraic_substitution_rules`

— Method`_algebraic_substitution_rules(eqs; skip=nothing)`

Extract substitution rules for explicit algebraic equations in given equations. Makes sure that those substitutions are pairwise cycle free.

Returns Tuple of substitution dict and corresponding indices of algebraic equations in the given equations.

`BlockSystems._chkmsg`

— Method`_chkmsg(cond, msg)`

Create an expression which evaluates as a error string which contains the original msg and some debug information based on the condition.

`BlockSystems._cut_substitutions_from`

— Method`_cut_substitutions_from(g, vertices)`

Cut all connections from and to given vertices in Graph. Returns a new graph.

`BlockSystems._expl_algebraic_dependency_graph`

— Method`_expl_algebraic_dependency_graph(eqs)`

Get the dependency graph for a given set of explicit algebraic equations. Edge 1->2 means, that state 1 appears in state 2.

`BlockSystems._substitute_along_depgraph!`

— Method`_substitute_along_depgraph!(eqs, g, keep)`

Remove all connections from from equations in `keep`

. The remaining graph should be cycle free. Start with the outermost equations and substitute along the dependency graph. After this, the `eqs`

object should only depend on `eqs[keep]`

without any further interdependency between them!

`BlockSystems._transform_implicit_algebraic`

— Method`_transform_implicit_algebraic(eq; trysolve=true, verbose=false)`

Transforms implicit algebraic equations with non-nohting lhs. If `trysolve`

tries to solve them for lhs. Otherwise just transforms to `0 ~ rhs - lhs`

.

`BlockSystems._uncouple_algebraic_equations`

— Method`_uncouple_algebraic_equations(eqs; verbose=false)`

Uncouple a given set of explicit algebraic equations. Returns a tuple

`(rules, keep)`

of independent substitution rules (non recursive) and a list of indices of equations, which could not be reduced.

`BlockSystems.autoconnections`

— Function`autoconnections(io_systems)`

Create a list of namespaced connections based on variable names. Names are compared without namespace. A single output may connect to several inputs of the same name.

`BlockSystems.connect_system`

— Method```
connect_system(
ios;
verbose,
simplify_eqs,
remove_superflous_states,
substitute_algebraic_states,
substitute_derivatives,
name,
warn
)
```

Recursively transform `IOSystems`

to `IOBlocks`

.

- substitute inputs with connected outputs
- try to eliminate equations for internal states which are not used to calculate the specified outputs of the system.
- try to eliminate explicit algebraic equations (i.e. outputs of internal blocks) by substituting each occurrence with their rhs. Explicit algebraic states which are marked as system outputs won't be removed.

Arguments:

`ios`

: system to connect`verbose=false`

: toggle verbosity (show equations at different steps)`remove_superflous_states=false`

: toggle whether the system should try to get rid of unused states`substitute_algebraic_states=true`

: toggle whether the algorithm tries to get rid of explicit algebraic equations`substitute_derivatives=true`

: toggle whether to expand all derivatives and try to substitute them`simplify_eqs=true`

: toggle simplification of all equations at the end

`BlockSystems.create_namespace_promotions`

— Method`create_namepsace_promotions(syms, forbidden, autopromote)`

Takes two lists of Symbolics.Syms, `syms`

and `forbidden`

. Returns a Dict of namespace promotions for each symbol in `syms`

. Avoids name collisions inside the list as well as with the `forbidden`

symbols.

`BlockSystems.cycle_intersec_recursive!`

— Method`cycle_intersec_recursive!(g, v1, v2, blocked, B, stack, cycle_intersecs)`

Find circuits in `g`

recursively starting from v1.

`BlockSystems.cyclebreaking_vertices`

— Method`cyclebreaking_vertices(g)`

Find a minimal set of vertices, which has an intersection with all circles in the Graph, i. e. by removing those vertices, the Graph becomes cycle free.

Returns a `Vector{Vector{T}}`

for a given `SimpleDiGraph{T}`

. Each combination, which picks at least 1 element from each of those subvectors will be sufficient to break all cycles.

**References**

- Hawick & James, "Enumerating Circuits and Loops in Graphs with Self-Arcs and Multiple-Arcs", 2008
- Julia Implementation taken from https://github.com/JuliaGraphs/Graphs.jl/blob/master/src/cycles/hawick-james.jl

`BlockSystems.eq_type`

— Method`eq_type(eq::Equation)`

Checks the type of the equation. Returns:

`(:explicit_diffeq, lhs_variable)`

for explicit differential equations`(:implicit_diffeq, lhs_variable)`

for implicit differential equations`(:explicit_algebraic, lhs_variable)`

for explicit algebraic equations`(:implicit_algebraic, lhs_variable)`

for implicit algebraic equations

`BlockSystems.fix_map_types`

— Method`fix_map_types(map)`

Creates Dict from `map`

. Changes `Num`

-types to `Symbolic`

-types in the user provided maps. Map can be Dict or Array of Pairs. If the rhs is of type `Symbol`

it will be converted to a `Symbolic`

type.

`BlockSystems.fulfills`

— Method`fulfills(io, bs::BlockSpec)::Bool`

Check whether `io`

fulfills the given `BlockSpec`

.

`BlockSystems.generate_io_function`

— Method```
generate_io_function(
ios;
f_states,
f_inputs,
f_params,
f_rem_states,
expression,
verbose,
type,
observed,
warn
)
```

Generate callable functions for an `AbstractIOSystem`

. An `IOSystem`

will be transformed to an `IOBlock`

first. At this level there is no more distinction between internal states and outputs: `states=(istates ∪ outputs)`

.

Arguments:

`ios`

: the system to build the function

optional:

`type=:auto`

:`:ode`

or`:static`

, determines the output of the function`f_states`

: define states=(istates ∪ outputs) which should appear first`f_inputs`

: define inputs which should appear first`f_params`

: define parameters which should appear first`f_rem_states`

: define removed states algebraic state order`expression=Val{false}`

: toggle expression and callable function output`warn=WARN[]`

: toggle warnings for missing`f_*`

parameters`observed=false`

: toggle creation ob "observed" function

Returns an named tuple with the fields

- for
`type=:ode`

:`f_ip`

in-place function`f(dstates, states, inputs, params, iv)`

`f_oop`

out-of-place function`f(states, inputs, params, iv) => dstates`

- for
`type=:static`

:`f_ip`

in-place function`f(states, inputs, params, iv)`

`f_oop`

out-of-place function`f(inputs, params, iv) => states`

- always:
`massm`

mass matrix of the system (`nothing`

if :static)`states`

symbols of states (in order)`inputs`

symbols of inputs (in order)`params`

symbols of parameters (in order)`rem_states`

symbols of removed states (in order)`g_ip`

,`g_oop`

functions`g((opt. out), states, inputs, params, iv)`

to calculate the removed states (substituted expl. algebraic equations).`nothing`

if empty.`obsf`

: Only if`observed=true`

. Function in the SciML "observed" style`(sym, u, p, t)`

`BlockSystems.lhs_var`

— Method`lhs_var(eq::Equation)`

Returns the variable on the lhs of the equation for equations.

`BlockSystems.make_input`

— Method`make_input(blk::IOBlock, sym; warn=WARN[])`

Change given sym from iparam to input.

`BlockSystems.make_iparam`

— Method`make_iparam(blk::IOBlock, sym; warn=WARN[])`

Change given sym from input to iparam.

`BlockSystems.make_istate`

— Method`make_istate(blk::IOBlock, sym; warn=WARN[])`

Move one or multiple outputs `sym`

to internal states.

`BlockSystems.make_output`

— Method`make_output(blk::IOBlock, sym; warn=WARN[])`

Move one or internal stats `sym`

to outputs.

`BlockSystems.prepare_f_vector`

— Method`prepare_f_vector(iob, vector)`

Prepare the user given variable lists which should appear first. If `Symbol`

type is given, it will look up the symbol as in `iob.:sym`

. The leading namespace of `iob`

is removed from all variables if it exists. Returns new vector of `Symbolic`

.

`BlockSystems.print_variables`

— MethodHelper function for `Base.show`

for IOBlock and IOSystem

`BlockSystems.recursive_substitute`

— Method`recursive_substitute(term, rules::Dict)`

Apply substitutions until there is no more change in `term`

.

`BlockSystems.remove_namespace`

— Method`remove_namespace(x)`

Strips `x`

of its first namespace. `A₊B₊x -> B₊x`

`BlockSystems.remove_namespace`

— Method`remove_namespace(namespace, x)`

If first namespace of `x`

is `namespace`

then remove it. `remove_namespace(A, A₊B₊x) -> B₊x remove_namespace(B, A₊B₊x) -> A₊B₊x`

`

`BlockSystems.remove_superfluous_states`

— Method`remove_superfluous_states(iob::IOBlock; verbose=false, warn=WARN[])`

This function removes equations from block, which are not used in order to generate the outputs. It looks for equations which have no path to the outputs equations in the dependency graph. Returns a new IOBlock.

The removed equations will be not available as removed equations of the new IOBlock

TODO: Maybe we should try to reduce the inputs to.

`BlockSystems.rename_vars`

— Method```
rename_vars(blk::IOBLock; warn=WARN[], kwargs...)
rename_vars(blk::IOBlock, subs::Dict{Symbolic,Symbolic}; warn=WARN[])
```

Returns new IOBlock which is similar to blk but with new variable names. Variable renaming should be provided as keyword arguments, i.e.

`rename_vars(blk; x=:newx, k=:knew)`

to rename `x(t)=>newx(t)`

and `k=>knew`

. Substitutions can be also provided as dict of `Symbolic`

types (`Sym`

s and `Term`

s).

`BlockSystems.replace_vars`

— Method```
replace_vars(blk::IOBlock, p::Dict; warn=WARN[])
replace_vars(blk::IOBlock, p::Pair; warn=WARN[])
replace_vars(blk::IOBlock; warn=WARN[], v1=val1, v2=val2)
```

Replace variables, either rename them by giving a new `Symbol`

or replace them by actual numerical values (only possible for inputs and iparams). Returns new `IOBlock`

.

Keys of dict can be either `Symbols`

or the `Symbolic`

subtypes. I.e. `blk.u => 1.0`

is as valid as `:u => 1.0`

.

```
replace_vars(blk; π = 3.14, foo = :bar) # set blk.π to number and rename foo
replace_vars(blk, Dict(:π => 3.14, :foo = :bar))
replace_vars(blk, blk.π => 3.14)
```

`BlockSystems.rhs_differentials`

— Method`rhs_differentials(iob::IOBlock)`

Return Set of all differentials which are present in the rhs of the system.

`BlockSystems.set_input`

— Method`set_input(blk::IOBlock, p::Pair; verbose=false)`

Close an input of blk. Given as an pair of (input=>substitution). The input may be given as an symbol (i.e. :a) or symbolic (i.e. blk.a). The substitution term can be either a numer or a term of parameters (which will become internal parameters).

`BlockSystems.set_p`

— Method```
set_p(blk::IOBlock, p::Dict; warn=WARN[])
set_p(blk::IOBlock, p::Pair; warn=WARN[])
set_p(blk::IOBlock; warn=WARN[], p1=val1, p2=val2)
```

Substitutes certain parameters by actual Float values. Returns an IOBlock without those parameters. Can be used for both iparams as well as inputs!

Keys of dict can be either `Symbols`

or the `Symbolic`

subtypes. I.e. `blk.u => 1.0`

is as valid as `:u => 1.0`

.

`BlockSystems.simplify_eqs`

— Method`simplify_eqs(iob::IOBlock; verbose=false, warn=WARN[])`

Simplify eqs and removed eqs and return new IOBlock.

`BlockSystems.strip_iv`

— Method`strip_iv(x, iv)`

Strip functional dependency of the independent variable `x(iv) -> x`

.

`BlockSystems.substitute_algebraic_states`

— Method`substitute_algebraic_states(iob::IOBlock; verbose=false, warn=WARN[])`

Reduces the number of equations by substituting explicit algebraic equations. Returns a new IOBlock with the reduced equations. The removed eqs are stored together with the previous `removed_eqs`

in the new IOBlock. Won't reduce algebraic states which are labeled as `output`

.

`BlockSystems.substitute_derivatives`

— Method`substitute_derivatives(iob::IOBlock; verbose=false, warn=WARN[])`

Expand all derivatives in the RHS of the system. Try to substitute in the lhs with their definition.

I.e.

```
D(o) ~ 1 + D(i) => D(o) ~ 2 + a
D(i) ~ 1 + a D(i) ~ 1 + a
```

Process happens in multiple steps:

- try to find explicit equation for differential
- if none found try to recursively substitute inside differential with known algebraic states
- expand derivatives and try again to substitute with known differentials

`BlockSystems.unblock!`

— Method`unblock!(v, blocked, B)`

Unblock the value `v`

from the `blocked`

list and remove from `B`

.

`BlockSystems.@check`

— Macro`@check cond msg`

If `cond`

evaluates false throw `ArgumentError`

and print evaluation of `cond`

.

`BlockSystems.@checkwarn`

— Macro`@checkwarn [showwarn] cond msg`

If `cond`

evaluates false warn and print evaluation of `cond`

. If optional argument `showwarn=false`

hide warning.

`BlockSystems.@connect`

— Macro```
@connect blkA.o => blkB.i
@connect blkA.o=>blkB.i blkB.o=>blkC.i kwargs...
@connect blkA.(o1,o2) => blkB.(i1, i2) kwargs...
```

Quickly connect several blocks. Optional space-separated list of kw args gets passed down to `IOSystem`

constructor.