Syntax reference ​
Dyad source files (.dyad) describe reusable models and analysis configurations. This reference covers syntax accepted by the compiler and supported by its ModelingToolkit backend. Start with the language guide for a reading path; use this page to look up a form while writing a model.
Code fragments below illustrate the indicated context. Names such as BaseComponent, Resistor, and MyLibrary stand for definitions supplied by your library.
Files and definitions ​
A file can contain imports, types, structs, enums, connectors, components, and analyses. Definitions end with end when they have a body. A # starts a line comment; comments immediately before a definition or declaration also supply documentation.
# A first-order decay model.
component Decay
parameter rate::Real = 1.0
variable x::Real(guess = 1.0)
relations
initial x = 1.0
der(x) = -rate * x
endDeclarations precede relations. Equations and connections follow it. An optional metadata object follows the relations and precedes end.
| Definition | Purpose |
|---|---|
component Name ... end | A reusable model with equations and subcomponents |
partial component Name ... end | A base model to complete through extension |
external component Name ... end | A component whose implementation is written in Julia; see Writing an external component |
example component Name ... end | A component marked as an example |
test component Name ... end | A component marked for testing |
analysis Name ... end | A configuration extending an analysis implementation |
connector Name ... end | A physical port with named fields |
connector Name = input Real | A scalar input signal type; output defines its counterpart |
type Name = Real(...) | A named type carrying attributes |
struct Name ... end | A record with typed fields |
| `enum Name = A | B` |
Declarations and modifications ​
A typed declaration has the form qualifier name::Type(attributes) = value. Attributes and the value are optional where the definition supplies the necessary information.
parameter gain::Real = 2.0
structural parameter N::Integer = 3
final parameter identity::Integer = 123
constant scale::Real = 1000.0
variable position::Real(units = "m", guess = 0.0)
variable velocity::Real(units = "m/s")| Qualifier | Meaning |
|---|---|
variable | A model unknown, typically varying during simulation |
parameter | A value fixed during a simulation |
structural parameter | A construction-time value that can determine dimensions, declarations, or equations |
constant | A fixed value defined when constructing the model |
final before a declaration | Prevents an enclosing model from overriding the declaration |
path | A value shared through a connector network |
A structural parameter can determine an array size or select a component configuration. Changing it requires constructing and processing the model again. final structural parameter combines the structural and override restrictions.
Attributes use named modifications: Real(min = 0, max = 10, guess = 1, units = "m"). A guess supplies a numerical starting point for initialization; an initial equation imposes a constraint. Supply units consistently across connected quantities and equations.
Subcomponents and inheritance ​
component Assembly
extends BaseComponent(gain = 2.0)
resistor = Resistor(R = 100.0)
stage = Controller(filter(T = 0.1))
endResistor(R = 100.0) modifies the resistor's R parameter. Controller(filter(T = 0.1)) modifies T inside its filter. A component can contain multiple extends clauses; each base must resolve to a compatible component definition.
A declaration condition selects whether an element exists when the model is constructed:
structural parameter use_filter::Boolean = true
filter = Filter() if use_filterUse the same structural condition around relations that reference an optional element.
Parameter files ​
A subcomponent constructor can apply a TOML or JSON parameter file:
controller = Controller(apply "dyad://MyLibrary/parameters/controller.toml")The URI identifies a file in the library. File entries must match the target model's parameter and initialization schema. This form belongs directly in a subcomponent's modification list; use ordinary nested modifications for individual nested settings.
Types and imports ​
Primitive and named types ​
The primitive types include Real, Integer, Boolean, String, and Native. Native carries a Julia value, useful for data objects and interfaces implemented in Julia.
type Length = Real(units = "m")
type PositiveLength = Length(min = 0)
struct Point
x::Real
y::Real
endAccess record fields with a dot, such as point.x. Define record fields using scalar or supported record types; enum-valued struct fields are outside the supported ModelingToolkit subset.
Function types and imports ​
A named function type describes a Julia function's interface:
type BinaryOp = func(::Real, ::Real)::Real
using MyLibrary: myfunc::BinaryOpArgument types follow ::; a function type can also declare keyword argument types after ;, as in func(::Real; tolerance::Real)::Real. The return type follows the closing parenthesis.
using Mechanical: Flange, Spring
using .: density::DensityFunction| Form | Scope |
|---|---|
using Mechanical: Flange, Spring | Imports names from a dependency declared in Project.toml. |
using .: density::DensityFunction | Imports a typed function from the current library's Julia module. |
BlockComponents.Sources.Constant | Refers to a definition by its qualified name. |
A library can also expose Julia definitions through dyad/definitions.jl; see Julia-based component libraries.
Expressions ​
Expressions combine literals, references, operators, and function calls. A dotted reference selects a field or nested component; brackets select array elements. Array indices start at one.
| Form | Example |
|---|---|
| Integer, real, scientific notation | 10, 3.14, 1.5e-3 |
| Metric suffix | 10k means 10000; 2m means 0.002 |
| String and Boolean | "water", true, false |
| Arithmetic | a + b, a - b, a * b, a / b, a % b, a ^ b |
| Elementwise arithmetic | a .+ b, a .- b, a .* b, a ./ b, a .^ b |
| Comparison | a < b, a <= b, a > b, a >= b, a == b, a != b |
| Logic | a and b, a or b, !a |
| Grouping | (a + b) * c |
| Conditional value | condition ? yes_value : no_value |
| Function call | sin(angle), myfunc(x, y) |
| Named argument | custom_func(x, tolerance = 0.01) |
| Range | 1:N, 1:2:N |
| Field and index | motor.flange.phi, cells[i].x, A[i, j] |
Use parentheses to make compound conditions and powers unambiguous. Functions must be available to the library and compatible with the symbolic values they receive. A function signature describes its types; it does not make every Julia operation symbolic.
time is the simulation time, and der(x) is the time derivative of x:
relations
y = time < 10 ? 0.0 : 1.0
der(x) = sin(time) - xFor a symbolic condition, the conditional expression becomes an ifelse expression. Both branches must be valid to evaluate, including domains of functions such as sqrt and log.
Arrays ​
Array dimensions follow the type. Use dimensions known when constructing the model.
structural parameter N::Integer = 3
parameter weights::Real[3] = [1.0, 2.0, 3.0]
parameter A::Real[2, 2] = [[1.0, 2.0], [3.0, 4.0]]
variable x::Real[N]
resistors = [Resistor(R = i * 10.0) for i in 1:N]Array literals use commas. A matrix literal contains rows, each written as an array. Rows must have equal length. fill(0.0, 2, 2) creates a uniform matrix. Component comprehensions create one instance per index value.
Equations, initialization, and connections ​
Equations ​
Within relations, lhs = rhs declares an equation. The equation constrains its two sides throughout the model's operation. Equality testing inside an expression uses ==.
relations
initial x = 0.0
der(x) = v
force = mass * der(v)
guess v = 1.0
connect(source.p, resistor.p)Initialization ​
initial equations constrain the initialization problem. guess relations supply initialization guesses, including for variables reached through subcomponents. Choose enough consistent initial conditions for the model's independent states.
Connectors and connections ​
connect joins compatible connectors. A connection can list more than two connectors. The connector's field qualifiers determine the generated connection equations.
connector Pin
potential v::Real(units = "V")
flow i::Real(units = "A")
end
connector SignalInput = input Real
connector SignalOutput = output Real| Field qualifier | Connection meaning |
|---|---|
potential | Equal values across the connection set |
flow | Signed flows sum to zero; positive flow enters a component |
stream | A transported outflow property, read from other ports with instream |
path | A shared value propagated through the network |
input, output | Directed signals |
A connector with stream fields has one flow field. See media and fluids for stream equations and medium configuration.
Path continuity ​
A top-level continuity(a, b) relation joins compatible path values into a shared continuity set. A component-level path declaration supplies the shared value. Use a single provider for a connected set.
For example, PathLiquidNetwork defines heat capacity once as final path cp::Real = 4184.0. Its continuity(cp, inlet.port.cp) binds that value to the inlet. Connections and the resistance's continuity(a.cp, b.cp) carry it to the outlet, where the boundary reads port.cp for its enthalpy calculation.
Analysis points ​
An analysis point names a signal connection for later analysis:
relations
loop_signal: analysis_point(controller.y, plant.u)See analysis points for its use in linearization and control design.
Structural control ​
Relation loops generate repeated equations or connections while constructing the model:
relations
for i in 1:N
der(x[i]) = -x[i]
endA relation if selects equations at construction time. Use a constant or structural condition:
relations
if use_filter
connect(source.y, filter.u)
connect(filter.y, sink.u)
else
connect(source.y, sink.u)
endAdditional branches use elseif. For a value that changes during simulation, put a conditional expression on an equation's right-hand side.
Enums and switch ​
Enums express a finite set of configurations. An alternative can carry typed data:
enum Initialization = Fixed(x0::Real) | Steady
component ConfigurableDecay
structural parameter mode::Initialization = Initialization.Fixed(x0 = 1.0)
variable x::Real
relations
der(x) = -x
switch mode
case Fixed
initial x = mode.x0
case Steady
initial der(x) = 0.0
end
endswitch selects the model configuration at construction time using an enum value. Here Fixed(x0 = 1.0) starts x at 1. Selecting Steady() imposes der(x) = 0 initially; together with der(x) = -x, this starts x at zero.
| Form | Meaning |
|---|---|
Initialization.Fixed(x0 = 1.0) | Constructs an alternative with a payload. |
Initialization.Steady() | Constructs an alternative without fields; parentheses are required. |
case Fixed | Selects relations for the named alternative. |
mode.x0 | Accesses the payload through the switched value. |
default | Handles the remaining alternatives. |
Assertions ​
A top-level assertion in relations records a model condition and an optional diagnostic message:
relations
assert(temperature > 0, "Temperature must be positive")The compiler passes these conditions to ModelingToolkit as model assertions. ModelingToolkit checks them when evaluating the generated equation function. By default, a failed assertion produces NaN in that function's output.
Clocked syntax ​
Clock parameters appear after a component name; clock bindings appear after a referenced type:
component Delay@[input clk extends Discrete]
u = RealInput@[clk]()
y = RealOutput@[clk]()
relations
initial u@(clk-1) = 0.0
y@clk = u@(clk-1)
end| Form | Meaning |
|---|---|
x@clk | Selects the current sample. |
x@(clk-1) | Selects the preceding sample. |
Block@[clk = other_clock]() | Binds the component's clk to other_clock. |
variable x::Real@[clk = clk] | Declares a clocked variable. |
See Clocks and discrete-time models for clock constraints, initialization, sampling, and holding.
Analyses ​
An analysis extends an existing analysis implementation and supplies model instances and options:
analysis DecaySimulation
extends TransientAnalysis(stop = 10.0)
model = Decay()
endThe base analysis defines its accepted options and result. See analyses for the available workflows and custom analyses to implement one in Julia.
Metadata ​
A definition's metadata block contains a JSON object. Inline element metadata follows a declaration or relation; {^tag} refers to an entry in the definition's _links object.
component AnnotatedDecay
variable x::Real
relations
der(x) = -x
metadata {
"ACME": {"partNumber": "D-1"}
}
endThe Dyad namespace holds tool-defined metadata. Custom namespaces can hold application-specific information. See graphical metadata for diagram authoring.