Skip to content

Add built-in unidirectional time bridge - #418

Open
LourensVeen wants to merge 3 commits into
developfrom
new_time_bridges
Open

LourensVeen wants to merge 3 commits into
developfrom
new_time_bridges

Conversation

@LourensVeen

Copy link
Copy Markdown
Contributor

This adds a new built-in time bridge actor to MUSCLE3.

It's only the documentation at the moment, describing how it will work, so that can be reviewed to make sure it makes sense before I add the implementation.

@LourensVeen LourensVeen self-assigned this Sep 18, 2026
Comment thread docs/source/time_bridges.rst Outdated

If the two programs do not run on exactly the same timeline, but one has somewhat
smaller or larger time steps than the other or the size of the steps varies, then this
will no longer work, because the number of messages sent by one side will not match the

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is not just the number of messages, you could have equal number but still the clock skew you mention

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm trying to say too many things at the same time here maybe. But then you can get both clock skew and deadlocks with and without the same number of messages. Although you can't get clock skew if the time steps are the same. Okay, I'll try to phrase this better.

Comment thread docs/source/time_bridges.rst Outdated
Connecting components using a time bridge
-----------------------------------------

The standard MUSCLE3 time bridge provides for unidirectional communication between two

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe this is the 'simplest' one but not the standard one?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's only one now anyway, and I'm not sure which other ones could exist and be useful. I can't imagine a simpler one though, so that's a good point.

Comment thread docs/source/time_bridges.rst Outdated
The time bridge will ignore the contents of that message, but it will use the timestamps
to decide which input messages to send to the receiver in its next message. It will then
receive those messages from the sender if needed and available, collate them into a
list, and send that list to the receiver, after which it will receive the next clock

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this sounds like the entire list is always sent, but actually you specify below what kind of aggegration functions exist. Maybe worth a pointer

calculated based on the current state and any other inputs at ``t_r_cur``, and the
receiver will likely want to use the latest value before ``t_r_cur``.

- The receiver uses an implicit Euler solver. Its next state will be calculated based on

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can generalize the euler implicit/explicit to a theta scheme perhaps (gets you crank nicholson). But the implicit Euler coupling scheme through muscle3 confuses me anyway for now

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, never heard of but I looked it up and I'll put it on the list for the future. Ideally, we'd have a description of all the different coupling schemes and how to implement them, but that's a bit too much for right now.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you relate this to the theta-scheme:

  • θ = 0: explicit Euler: evaluates at t_r_cur
  • θ = 1: implicit Euler: evaluates at t_r_next
  • θ = 0.5: Crank–Nicolson (2nd-order accurate): evaluates at the midpoint, (t_r_cur + \Delta t / 2)
    The goal is to always obtain the timestamp that is closest to the desired timestamp.

messages may be received twice, once as the last message before ``t_r_next`` and then
again on the next timestep as the last message before ``t_r_cur``.

At each time step, the receiver will receive a list from the time bridge, containing

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But that would mean that the component gets a different interface just from being connected to the interface, because it may want to unpack the list? I think it is nicer to keep the interface (single messages) the same, because two of your typical settings are resulting in single messages being sent at all

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea! I can also imagine a helper component in between the time bridge and the receiver that takes the list and processes it down to a single value somehow. But if you just want the latest value then it's nice to be able to connect directly. Should be a configuration option I think.


If the two programs do not run on exactly the same timeline, but one has somewhat
smaller or larger time steps than the other, then we will get clock skew, where the
simulation time in the two components doesn't match anymore and information from the

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would use “simulated time” instead of “simulation time,” as the latter could be confusing. It might be interpreted as either the time it took to run the simulation or the amount of physics time being simulated.


The simplest MUSCLE3 time bridge provides for unidirectional communication between two
instances' O_I and S ports. The sending side needs to have an O_I port sending the data
needed by the receiver, and the receiver needs the corresponding S port to receive it.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could add a figure of this coupling which is generated by the yMMSL2svg:

Image

Or does the sender not have an S port connected to the bridge actor with an O_I port?

calculated based on the current state and any other inputs at ``t_r_cur``, and the
receiver will likely want to use the latest value before ``t_r_cur``.

- The receiver uses an implicit Euler solver. Its next state will be calculated based on

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you relate this to the theta-scheme:

  • θ = 0: explicit Euler: evaluates at t_r_cur
  • θ = 1: implicit Euler: evaluates at t_r_next
  • θ = 0.5: Crank–Nicolson (2nd-order accurate): evaluates at the midpoint, (t_r_cur + \Delta t / 2)
    The goal is to always obtain the timestamp that is closest to the desired timestamp.

Note that if the time step of the receiver is smaller than that of the sender, or if the
receiver starts its simulation before the sender starts, then there may not be any
messages with timestamps between ``t_r_cur`` and ``t_r_next``, and the receiver may
receive an empty list.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if it receives an empty list?


If ``recv_last_before_cur`` and ``recv_last_before_next`` are both ``1``, then
messages may be received twice, once as the last message before ``t_r_next`` and then
again on the next timestep as the last message before ``t_r_cur``.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does it matter how many times the messages of a certain time stamp are included?


If only ``recv_last_before_cur`` or ``recv_last_before_next`` is selected, then at most
one message will be sent to the receiver. In that case, you may want to set the setting
``recv_list`` to ``false`` (it is ``true`` by default), to tell the time bridge to just

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • If recv_last_before_cur or recv_last_before_next is set, can’t we automatically set recv_list to false instead of requiring the user to specify it?
  • Are there more settings next to recv_last_before_cur, recv_last_before_next, recv_cur_to_next, and recv_list?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants