It is possible to add metadata to symbolic variables. The following information can be added (note, it's possible to extend this to user-defined metadata as well)

## Input or output

Designate a variable as either an input or an output using the following

using ModelingToolkit
@variables u [input=true]
isinput(u)
true
@variables y [output=true]
isoutput(y)
true

## Bounds

Bounds are useful when parameters are to be optimized, or to express intervals of uncertainty.

@variables u [bounds=(-1,1)]
hasbounds(u)
true
getbounds(u)
(-1, 1)

## Mark input as a disturbance

Indicate that an input is not available for control, i.e., it's a disturbance input.

@variables u [input=true, disturbance=true]
isdisturbance(u)
true

## Mark parameter as tunable

Indicate that a parameter can be automatically tuned by automatic control tuning apps.

@parameters Kp [tunable=true]
istunable(Kp)
true

## Probability distributions

A probability distribution may be associated with a parameter to indicate either uncertainty about it's value, or as a prior distribution for Bayesian optimization.

using Distributions
d = Normal(10, 1)
@parameters m [dist=d]
hasdist(m)
getdist(m)

For systems that contain parameters with metadata like described above have some additional functions defined for convenience. In the example below, we define a system with tunable parameters and extract bounds vectors

@parameters t
Dₜ = Differential(t)
@variables x(t)=0 u(t)=0 [input=true] y(t)=0 [output=true]
@parameters T [tunable = true, bounds = (0, Inf)]
@parameters k [tunable = true, bounds = (0, Inf)]
eqs = [
Dₜ(x) ~ (-x + k*u) / T # A first-order system with time constant T and gain k
y ~ x
]
sys = ODESystem(eqs, t, name=:tunable_first_order)
\begin{align} \frac{dx(t)}{dt} =& \frac{k u\left( t \right) - x\left( t \right)}{T} \\ y\left( t \right) =& x\left( t \right) \end{align}
p = tunable_parameters(sys) # extract all parameters marked as tunable
2-element Vector{Sym{Real, Base.ImmutableDict{DataType, Any}}}:
k
T
lb, ub = getbounds(p) # operating on a vector, we get lower and upper bound vectors
(lb = [0, 0], ub = [Inf, Inf])
b = getbounds(sys) # Operating on the system, we get a dict
Dict{Sym{Real, Base.ImmutableDict{DataType, Any}}, Tuple{Int64, Float64}} with 2 entries:
k => (0, Inf)
T => (0, Inf)

## Docstrings

ModelingToolkit.getboundsMethod
lb, ub = getbounds(p::AbstractVector)

Return vectors of lower and upper bounds of parameter vector p. Create parameters with bounds like this

@parameters p [bounds=(-1, 1)]
ModelingToolkit.getboundsMethod
getbounds(x)

Get the bounds associated with symbolc variable x. Create parameters with bounds like this

@parameters p [bounds=(-1, 1)]
ModelingToolkit.getboundsMethod
getbounds(sys::ModelingToolkit.AbstractSystem)

Returns a dict with pairs p => (lb, ub) mapping parameters of sys to lower and upper bounds. Create parameters with bounds like this

@parameters p [bounds=(-1, 1)]
ModelingToolkit.getdistMethod
getdist(x)

Get the probability distribution associated with symbolc variable x. If no distribution is associated with x, nothing is returned. Create parameters with associated distributions like this

using Distributions
d = Normal(0, 1)
@parameters u [dist=d]
hasdist(u) # true
getdist(u) # retrieve distribution
ModelingToolkit.hasdistMethod
hasdist(x)

Determine whether or not symbolic variable x has a probability distribution associated with it.

ModelingToolkit.istunableFunction
istunable(x, default = false)

Determine whether or not symbolic variable x is marked as a tunable for an automatic tuning algorithm.

default indicates whether variables without tunable metadata are to be considered tunable or not.

Create a tunable parameter by

@parameters u [tunable=true]
ModelingToolkit.tunable_parametersFunction
tunable_parameters(sys, p = parameters(sys); default=false)

Get all parameters of sys that are marked as tunable.

Keyword argument default indicates whether variables without tunable metadata are to be considered tunable or not.

Create a tunable parameter by

@parameters u [tunable=true]