Skip to content

Feature/resolve timelines#62

Open
maarten-ic wants to merge 11 commits into
developfrom
feature/resolve-timelines
Open

Feature/resolve timelines#62
maarten-ic wants to merge 11 commits into
developfrom
feature/resolve-timelines

Conversation

@maarten-ic

@maarten-ic maarten-ic commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Continuation of PR #27

  • Put determined timelines back on Component (absolute timelines) and Port (relative to Component?) objects
  • Update timeline annotations when importing/resolving (components are renamed to x.y.<component> and timeline annotations should as well to prevent clashes)
  • Move to v0_2.validation.timelines. Function: resolve_timelines() because it updates the timelines on the data objects
  • Cyclic dependency documentation (move to issue?)

Signature accepts a Sequence, but the logic previously only worked when providing a list. Other sequences silently didn't work.
Add `parent` property and `relative_to` (inspired by pathlib.Path)
@maarten-ic

maarten-ic commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator Author
  • Update timeline annotations when importing/resolving (components are renamed to x.y.<component> and timeline annotations should as well to prevent clashes)

N.B. Resolving imports doesn't rename components (only models) and therefore shouldn't rename timelines.
Timelines should be renamed when flattening, but that logic resides in muscle3 so it's not part of this PR.

Edit: thinking a bit more about this, I'm not sure if we must rename timelines when flattening the hierarchical models:

  1. Timelines that are exported on a model port must not change names
  2. Timelines that are internal to a model will never interact with components outside the model and so this is not a problem for the logic in this PR if they have the same name

Include information on the conduits instead of just the components.

Example error message:
> Detected a dependency cycle in model 'cycle'. The component 'first' has an F_INIT port that depends on data produced by one of its own O_F or O_I ports: Conduit(first.final -> second.init) -> Conduit(second.final -> third.init) -> Conduit(third.final -> first.init). You may have an error in the conduits or may need a different coupling schema.
@maarten-ic
maarten-ic marked this pull request as ready for review July 17, 2026 10:15
@maarten-ic

Copy link
Copy Markdown
Collaborator Author

N.B. I've improved the cyclic dependency error, hopefully this is clear enough without writing and pointing to a new documentation page.

@LourensVeen

Copy link
Copy Markdown
Contributor

Edit: thinking a bit more about this, I'm not sure if we must rename timelines when flattening the hierarchical models:

Imagine a top-level model with two components a and b, with a dispatching to b. Both a and b are implemented using a submodel, and each of those submodels has a macro-micro model inside it with components named macro and micro, and with macro's F_INIT and O_F connected to model ports.

After flattening, we have a flat model with components a.macro, a.micro, b.macro and b.micro. Component a.micro is on timeline :a.macro and component b.micro is on timeline :b.macro. Without renaming during flattening, they'd both be on :macro and would appear to be on the same timeline while they're really not.

Timelines that are exported on a model port must not change names
Timelines that are internal to a model will never interact with components outside the model and so this is not a problem for the logic in this PR if they have the same name

Timelines on ports are usually relative timelines, and those shouldn't be a problem as long as the absolute timeline they're appended to is correct. They can interact with components outside the model just fine though, we can have a component macro inside of a submodel that has its O_I and S ports connected to O_I and S ports on the submodel, and a micro component in another submodel.

@LourensVeen LourensVeen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Definitely headed in the right direction, nice work!

o_f: final
ports:
f_init: init
timeline macro:meso:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Oh, that final colon could be confusing. I never considered that. Not for this PR, but would it make sense to quote the timeline to clarify that?

timeline "macro:meso":

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Hmm, not sure. I'd expect that for the majority of cases you'll have no nested timelines, and then I like the unquoted version better.

I was actually not confused when writing this file: The syntax highlighting of my editor made it clear that the final colon is not part of the key, see screenshot:
image

ConduitTimelineError,
CyclicDependency,
InconsistentTimelines,
TooManyReducerFilters,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we have too many repeaters as well? If I connect an init component to a micro with two repeaters? Or would that come out as InconsistentTimelines? But there aren't two known timelines in this case, so that's not what I would expect...

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

That would indeed come out as InconsistentTimelines (which then suggests to add a reducer, or remove a repeater).

Note that TooManyReducerFilters only triggers when trying to reduce "above" the root timeline. You can also have too many reducers and end up with an InconsistentTimelines error (which will suggest to remove a reducer or add a repeater).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Would it make sense to rename this exception to ReducerFilterOnRootTimeline (or similar) to avoid this confusion?

second.final: third.init
third.final: first.init

reducer:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we have this also without the connection from first.o_f to second.f_init? That should work too, but does it?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yes, we can, and it works 😄

I've added a testcase for this.

Comment thread ymmsl/v0_2/timeline_resolver.py Outdated
"""Determine timelines for each component and their O_I and S ports in this model.

An exception will be raised when the model timelines are not consistent. This
function updates the timeline attributes of the components and ports in the model.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It would be useful for people building tools on top to know exactly which exceptions are raised under which circumstances.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good point, I've updated the documentation to point to the exception classes. The docstring of the exceptions explain the cases where they're raised.

Comment thread ymmsl/v0_2/timeline_resolver.py Outdated
@maarten-ic

Copy link
Copy Markdown
Collaborator Author

Edit: thinking a bit more about this, I'm not sure if we must rename timelines when flattening the hierarchical models:

Imagine a top-level model with two components a and b, with a dispatching to b. Both a and b are implemented using a submodel, and each of those submodels has a macro-micro model inside it with components named macro and micro, and with macro's F_INIT and O_F connected to model ports.

After flattening, we have a flat model with components a.macro, a.micro, b.macro and b.micro. Component a.micro is on timeline :a.macro and component b.micro is on timeline :b.macro. Without renaming during flattening, they'd both be on :macro and would appear to be on the same timeline while they're really not.

Yes, fully agreed! For complete correctness you'd have to rename these internal timelines.

My point (which I didn't describe clearly, sorry for that!) was that timeline renaming isn't required for the checks in this PR. The flattened model is more of an internal MUSCLE3 state and I expect it's not required to have the renaming functionality in to get a properly behaving simulation. We'll have to test though 🙂

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

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

2 participants