Skip to content

Improve the specification of fmi3GetInterval and interval qualifiers#2050

Open
PTaeuberDS wants to merge 10 commits intomodelica:mainfrom
PTaeuberDS:fixGetIntervalDescription
Open

Improve the specification of fmi3GetInterval and interval qualifiers#2050
PTaeuberDS wants to merge 10 commits intomodelica:mainfrom
PTaeuberDS:fixGetIntervalDescription

Conversation

@PTaeuberDS
Copy link
Contributor

@PTaeuberDS PTaeuberDS commented Jun 6, 2025

This pull request clarifies the definition and usage of Clock intervals, primarily by making fmi3GetInterval more flexible and explicitly defining its behavior in all situations.

Key Changes:

  • Broaden fmi3GetInterval calling conditions: The function may now be called for any time-based Clock at any time in InitializationMode, EventMode, ClockActivationMode, and ClockUpdateMode.
  • Define fmi3IntervalQualifier return values: A new table is introduced to rigorously define the allowed fmi3IntervalQualifier return values for every time-based Clock in different states.
  • Clarify interval definitions: The definition of what an "interval" represents has been made more precise across different Clock types and situations:
    • The special case for a tunable Clock's interval at the moment of a change is now explicitly covered.
    • The distinction in behavior for fixed/tunable Clocks based on whether the intervalDecimal attribute is specified is sharpened.

Resolves #2018

@PTaeuberDS PTaeuberDS self-assigned this Jun 6, 2025
@PTaeuberDS PTaeuberDS force-pushed the fixGetIntervalDescription branch from 227daca to 18448dd Compare August 22, 2025 08:59
@PTaeuberDS PTaeuberDS force-pushed the fixGetIntervalDescription branch from bfec03e to d7ce096 Compare August 28, 2025 16:13
@PTaeuberDS PTaeuberDS marked this pull request as ready for review August 29, 2025 09:28
@chrbertsch chrbertsch requested a review from clagms October 8, 2025 17:37
|Generally, the time interval from the previous Clock tick to the current Clock tick.
An exception applies to a tunable Clock whose interval has just changed in <<EventMode>> or <<ClockActivationMode>>.
In this specific case, the new interval is relative to the time of the current <<EventMode>> or <<ClockActivationMode>>, not to the time of the previous Clock tick.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Would't it be more concise if we say: "The time interval from the current Clock tick to the next Clock tick, specified differently for the different Clock types." That would hold for Tunable clock too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, it wouldn't. The interval of a tunable clock can change at any (event) time without the clock having ticked. So there is not necessarily a current clock tick.

@masoud-najafi
Copy link
Collaborator

I wonder if there is a way to visualize the tables? Any artifact has been created for these changes?

@chrbertsch
Copy link
Collaborator

I wonder if there is a way to visualize the tables? Any artifact has been created for these changes?

@masoud-najafi :
The Specification is created at every commit via GitHub Actions. You can download and inspect the created specificiation without any local installation of AsciiDoc:
grafik
grafik
grafik

The importer must use <<fmi3GetShift>> to retrieve the Clock shift in <<InitializationMode>>.

+
In both cases, when an interval changes, the new interval is relative to the time of the current <<EventMode>> or <<ClockActivationMode>>, not to the time of the previous Clock tick.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure if I understand this correctly. Suppose the previous clock tick has been at time=T_k and the next tick will be at time=T_{k+1}=T_K+DT, where DT is the current interval of the clock. If an event happens at T_e where T_K< T_e <T_{k+1}, and at this time event the interval of the clock is changed by the importer to DT2, what would be the time of the next clock tick?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In this case T_e + DT2, as the interval is defined from the current event time to the next clock tick.

_Subsequent Clock ticks follow the general interval definition for periodic Clocks until the tunable interval changes again._

^|_(7)_
|_In super state <<Initialized>>, for a changing Clock, <<fmi3IntervalChanged>> is returned if and only if the Clock has just ticked._
Copy link
Collaborator

Choose a reason for hiding this comment

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

I do not understand why you have extended this part to the superState . The GetInterval cannot return fmi3IntervalChanged in other state than EventMode.

Copy link
Contributor Author

@PTaeuberDS PTaeuberDS Feb 10, 2026

Choose a reason for hiding this comment

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

Super state "Initialized" also covers the scheduled execution state Clock Activation Mode.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Since we are talking about changing clocks, this phrase might be a bit confusing:
"is returned if and only if the Clock has just ticked."
We should give a message like this:
fmi3GetInterval must return fmi3IntervalChanged only when the FMU is in the superdense time instant that handles the current activation of the changing clock. If the FMU is in the same event mode but at a different superdense time instant, one in which the changing clock is not activated, then fmi3GetInterval should return fmi3IntervalUnchanged.

Comment on lines 668 to 669

is a time-based Clock with a constant interval, except when <<intervalVariability>> = <<tunable>>, which indicates that the interval can change.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Minor remark:
I wouldn't use "when" in this context it might be confusing because when might indicate a certain time point.
"except for Clocks with <> = <>"

[[fmi3IntervalUnchanged,`fmi3IntervalUnchanged`]]
* `fmi3IntervalUnchanged` is returned if a previous call to <<fmi3GetInterval>> already returned a value qualified with <<fmi3IntervalChanged>> which has not changed since.
* `fmi3IntervalUnchanged` is returned if a previous call to <<fmi3GetInterval>> already returned a value qualified with <<fmi3IntervalChanged>> which has not changed since, or if the FMU is not allowed to change the interval because it is meant to be set by the importer or already fixed for the simulation (e.g., the interval of a constant Clock).
In this case, <<intervals-get>> returns the old unchanged interval.
Copy link
Collaborator

Choose a reason for hiding this comment

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

"old unchanged interval" relative to what time? The current time instant or the time instant when the qualifier for this clock was "fmi3IntervalChanged" the last time.
Shouldn't we change this to "has no meaning"?

Copy link
Contributor Author

@PTaeuberDS PTaeuberDS Feb 10, 2026

Choose a reason for hiding this comment

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

It means that the interval value that is returned is the same as the last time when getInterval was called.
To what time it is relative to depends on the Clock type. E.g. for constant Clocks the returned unchanged interval is relative to the last clock tick. Or for countdown clocks it is relative to the last time fmi3IntervalChanged was returned.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That is, btw. also what is stated in the first sentence:
"[...] a value [...] which has not changed since."

* `fmi3IntervalNotYetKnown` is returned for a <<countdown-aperiodic-clock,`countdown`>> Clock for which the next interval is not yet known.
This qualifier value can only be returned directly after the Clock was active and previous calls to <<fmi3GetInterval>> never returned <<fmi3IntervalChanged>> (nor <<fmi3IntervalUnchanged>>).
In Scheduled Execution this return value means that the corresponding model partition cannot be scheduled yet.
* `fmi3IntervalNotYetKnown` is returned for a <<countdown-aperiodic-clock,`countdown`>> Clock for which the next interval is not yet known.
Copy link
Collaborator

@klausschuch klausschuch Nov 18, 2025

Choose a reason for hiding this comment

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

we use "known" for 2 different perspectives here:

  1. the FMU doesn't know it yet
  2. the importer doesn't know it yet and hence has to ask the FMU

Here it is option (1) but above it was option (2).
I suggest to distinguish between these two explicitly.

This qualifier value can only be returned directly after the Clock was active and previous calls to <<fmi3GetInterval>> never returned <<fmi3IntervalChanged>> (nor <<fmi3IntervalUnchanged>>).
In Scheduled Execution this return value means that the corresponding model partition cannot be scheduled yet.
* `fmi3IntervalNotYetKnown` is returned for a <<countdown-aperiodic-clock,`countdown`>> Clock for which the next interval is not yet known.
This qualifier value can only be returned directly after the Clock was active and previous calls to <<fmi3GetInterval>> never returned <<fmi3IntervalChanged>> (nor <<fmi3IntervalUnchanged>>).
Copy link
Collaborator

Choose a reason for hiding this comment

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

To me this reads like the clock cannot have an undefined interval at all anymore after it had an interval once, even after the clock was active already.
This is not what I would expect

Copy link
Collaborator

Choose a reason for hiding this comment

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

The second sentence is not clear or easy to understand.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the wording of the current spec, but I see your point. I will propose the following in the next commit:
"This qualifier can only be returned if, since the most recent Clock activation, no call to fmi3GetInterval has returned fmi3IntervalChanged or fmi3IntervalUnchanged.

Copy link
Collaborator

@masoud-najafi masoud-najafi Feb 10, 2026

Choose a reason for hiding this comment

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

Let's be clear about the count-down-clock and its purpose. I have understood the CountDown clock as follows: Unlike the changing Clock where the next activation time can be scheduled only at the current clock activation time (clock tick) of the changing clock, the CountDown clock can schedule a clock activation at the current event time. If the importer calls GetInterval on a CountDown clock, if the FMU has no clock activation ready to be schedulled, returns fmi3IntervalNotYetKnown, if the FMU know the next activation time, returns fmi3IntervalChanged. fmi3IntervalUnchanged is meaningless for CoundDown Clock.
Now consider this scenario: Suppose that a CountDown clock CK schedules an activation time at Te+TD where Te is the current event time and TD is the return value of fmi3GetInterval. Inside any event state at time>Te, if the fmi3GetInterval is called for that countDown clock, If the FMU is pushed to the event mode for whatever reason, at any Te<time<Te+TD, fmi3GetInterval for clock CK, must return fmi3IntervalNotYetKnown. An FMU cannot cancel an event already fired or schedulled. (For the last paragraph, there is nothing in the standard, it is just my deduction)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

An FMU cannot cancel an event already fired or schedulled.

Yes, it cannot cancel it, but it can provide a new interval, which means the clock needs to be re-scheduled. The description of fmi3IntervalChanged states:
"Any previously returned intervals (if any) are overwritten with the current value."

And in the following, even more explicit for SE:
"In Scheduled Execution this means that the corresponding model partition must be scheduled or re-scheduled (if a previous call to fmi3GetInterval returned fmi3IntervalChanged)."

So, in Te<time<Te+TD, the FMU can either return fmi3IntervalChanged, which means the clock must be re-scheduled, or fmi3IntervalUnchanged, which means the old value is still valid. It cannot return fmi3IntervalNotYetKnown until the clock has been active again.

That is what

This qualifier can only be returned if, since the most recent Clock activation, no call to fmi3GetInterval has returned fmi3IntervalChanged or fmi3IntervalUnchanged.

states.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we have a table to consider [mi3IntervalChanged ,fmi3IntervalUnchanged, fmi3IntervalNotYetKnown ] for all clock types? and also the behavior of fmi3GetInterval after the clock being fired for all clock types? This would help to not miss something... and have a clear common understanding. I remeber you did something in this regard.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, this table is the main part of this PR. Please check it. If there is anything missing we can add it.

@chrbertsch
Copy link
Collaborator

@klausschuch , @masoud-najafi , @pmai : we will look into this
Pierre: We have to communicate clearly, what has changed.
Christian: Probably in the document with a NOTE: on the change.
Pierre, Klaus: could also be elevated to a "warning"

_Subsequent Clock ticks follow the general interval definition for periodic Clocks until the tunable interval changes again._

^|_(7)_
|_In super state <<Initialized>>, for a changing Clock, <<fmi3IntervalChanged>> is returned if and only if the Clock has just ticked._
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since we are talking about changing clocks, this phrase might be a bit confusing:
"is returned if and only if the Clock has just ticked."
We should give a message like this:
fmi3GetInterval must return fmi3IntervalChanged only when the FMU is in the superdense time instant that handles the current activation of the changing clock. If the FMU is in the same event mode but at a different superdense time instant, one in which the changing clock is not activated, then fmi3GetInterval should return fmi3IntervalUnchanged.

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.

Clarify rules on fmi3GetInterval*/fmi3GetShift* functions with regards to periodic input clocks

5 participants