Skip to content

Clock inference shares the SampleTime() term across partitions, so only one clock in a model may use it #159

Description

@baggepinnen

I am building a model with two periodic clocks in which more than one component reads its own
sample period with SampleTime(). Each such component is written clock-agnostically and is
instantiated on whichever clock the model connects it to: one on a 1 ms sensing clock, another on
a 5 ms control clock. Clock inference rejects the model, reporting one partition with two clocks.

The two partitions share no variable. The only thing they have in common is the SampleTime()
term, and it appears in the list of involved variables:

using ModelingToolkit
using ModelingToolkit: t_nounits as t

kf = ShiftIndex(Clock(0.001))
ks = ShiftIndex(Clock(0.005))

# Two discrete partitions that share no variable, each accumulating its own sample time.
function build(slow_period)
    @variables xf(t) = 0.0 xs(t) = 0.0
    @named sys = System([xf(kf) ~ xf(kf - 1) + SampleTime(),
                         xs(ks) ~ xs(ks - 1) + slow_period], t)
    return sys
end

for (what, slow_period) in (("SampleTime() in both partitions", SampleTime()),
                            ("SampleTime() in one partition", 0.005))
    try
        mtkcompile(build(slow_period))
        println(what, " -> compiles")
    catch e
        println(what, " -> ", sprint(showerror, e))
    end
end
SampleTime() in both partitions -> ArgumentError: Found clock partition with multiple associated
clocks. Involved variables: [xf(t), xs(t), Shift(t, -1)(xf(t)), Shift(t, -1)(xs(t)),
ModelingToolkitBase.SampleTime(nothing)()]. Involved clocks:
[PeriodicClock(0.001, 0.0), PeriodicClock(0.005, 0.0)].

SampleTime() in one partition -> HybridSystemNotSupportedException: Discrete systems with
multiple clocks are not supported with the standard MTK compiler.

The second line is the control: with the slow partition's period given as a number, inference
completes and the model gets as far as code generation, where it meets the standard compiler's
unrelated multi-clock limitation. (My real model goes through SynchToolkit's compile_lustre pass
instead, and compiles once the second SampleTime() is removed.) So the difference between the
two runs is only whether inference separates the two partitions.

What makes this look like the term rather than the model:

  • SampleTime()'s own docstring defines it per equation -- "time sampled at the inferred clock for
    that equation".
  • The substitution honours that: substitute_sample_time
    (ModelingToolkitTearing/src/clock_inference/interface.jl) walks the equations with their
    eq_domain and substitutes each equation's own period, so by the time a period is needed the
    per-partition answer is already available.
  • Inference itself does not: it builds its graph over fullvars
    (ModelingToolkitTearing/src/clock_inference/clock_inference.jl), and SampleTime() is a single
    nullary term sitting in there like any other variable, so it is one node shared by every equation
    that mentions it. Two such equations on two clocks therefore form one connected component with
    two clock vertices, which is what the error reports.

The practical effect is that a model may contain at most one SampleTime() if it has more than one
clock, which is a restriction I could not find documented. It is also hard to trace from the error:
the message lists the whole merged partition, so in a real model it names a few dozen variables
belonging to components that have nothing to do with each other, and mentions neither the term nor
the two components that use it. Localising it in my own model took a bisect over the structural
parameters that switch the second use on.

Versions: ModelingToolkit 11.42.0, ModelingToolkitBase 1.69.0, ModelingToolkitTearing 1.20.6,
Julia 1.13.0.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions