Skip to content

Conversation

henrikt-ma
Copy link
Collaborator

@henrikt-ma henrikt-ma commented May 7, 2025

This is the design for attaching units to literals that was discussed at the most language design meeting in Linköping held in March this year. The proposal is an alternative to #3668, with emphasis on simple design, ease of use, and human readability.

This design was originally implemented in SimulationX, and later given two parallel implementations in System Modeler - one for testing it in regular Modelica expressions, and one for (undocumented) use in vendor-specific annotations.

@henrikt-ma
Copy link
Collaborator Author

The ease of use and readability provided by this proposal is important for the acceptance of this as a correct way to address the unit error in a situation like this:

Real distance(unit = "m") = 100;
Real v(unit = "m/s") = distance / 9.58; // Unit error
Real v(unit = "m/s") = distance / 9.58's'; // Correct

This PR makes no changes to unit checking; the following should be rejected as inconsistent:

Real distance(unit = "m") = 1000'cm';

@HansOlsson
Copy link
Collaborator

This PR makes no changes to unit checking; the following should be rejected as inconsistent:

Real distance(unit = "m") = 1000'cm';

The latter isn't even close to beginning to meaningfully adress the actual problems this would introduce in practice.
Please look at actual models as in MSL.

@HansOlsson HansOlsson self-requested a review May 7, 2025 15:49
Copy link
Collaborator

@HansOlsson HansOlsson left a comment

Choose a reason for hiding this comment

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

To avoid merging by mistake:
As repeatedly indicated this makes it easy to introduce non-coherent units, which requires a detailed analysis.

@henrikt-ma
Copy link
Collaborator Author

It is hard to think of a programming language where units and unit checking matter more than in Modelica. It is just silly that the language is lacking this basic construct of constructing unitful literals.

Applications are everywhere:

  • Making expressions and equations with literals unit consistent without the need to introduce protected helper variables just to attach the missing units.
  • Avoiding dangers of the wildcard effect, see example below.
  • Last but not least, clarity; even if an expression or equation with literals is unit consistent according to the unstated unit checking rules of Modelica, making the implicit units of the literals explicit is a great enhancement of clarity.

Example of the day:

model AcuteAngle
  parameter Modelica.Units.SI.Angle a = 0;
equation
  assert(abs(a) < 90, "The angle must be acute.");
end AcuteAngle;

Due to the lack of clarity and the wildcard effect, the error above is easy to make, and the model developer who knows that the model only works for acute angles might fail to check that the assertion actually works.

If the developer would have used a unitful literal instead, a unit inconsistency would have revealed the problem:

  assert(abs(a) < 90'deg', "The angle must be acute.");

When corrected, the attached unit adds clarity and removes any uncertainty related to the wildcard effect:

  assert(abs(a) < 1.57'rad', "The angle must be acute.");

If the modeler decides to use Angle_deg instead (maybe it is the angle of a FixedRotation), the need to also update the assert would be detected.

@henrikt-ma
Copy link
Collaborator Author

As repeatedly indicated this makes it easy to introduce non-coherent units, which requires a detailed analysis.

Let's not pretend that we can't perform a decent amount of unit checking, and let's not assume that the feature would be massively misused to exploit any gaps we still have in the unit checking semantics.

The alternative, using numeric literals without unit and relying on the wildcard effect is so much worse than the tiny risk of introducing a unitful literal with non-coherent unit in a place where it wouldn't be caught by unit checking.

@HansOlsson
Copy link
Collaborator

The alternative, using numeric literals without unit and relying on the wildcard effect is so much worse than the tiny risk of introducing a unitful literal with non-coherent unit in a place where it wouldn't be caught by unit checking.

The original design was to have equations in coherent units; and have non-coherent units in the user interface at the boundary.
That design doesn't have any of those issues, and was made exactly because units matter.

Apart from that the previously raised issues with temperatures, and rotations are still unresolved.

@henrikt-ma
Copy link
Collaborator Author

I think we need external input to make progress here. @casella, @AHaumer, @GallLeo, @hubertus65, would you be interested in joining us for a session about the pros and cons of being able to express unitful literals in expressions and equations?

@HansOlsson
Copy link
Collaborator

I think we need external input to make progress here.

I don't see it as meaningful to involve more people when there are still no answers regarding how possibly non-coherent units in equations would actually work, especially for temperatures and rotations.

@HansOlsson
Copy link
Collaborator

HansOlsson commented May 8, 2025

I think we need external input to make progress here.

I don't see it as meaningful to involve more people when there are still no answers regarding how possibly non-coherent units in equations would actually work, especially for temperatures and rotations.

It's also misleading to tell others that the issue is 'unitful literals' when the problem is that it's suddenly easy to add possibly non-coherent units like 2 'kW', 50 'Hz', 12 'rad/s', or 200 'degC' inside equations, and then rely on some yet-to-be-specified unit-check to figure out that it wasn't the right unit.

I have still not seen anything meaningful addressing those issues, or how it would work in practice.

Just to be clear: the proposal isn't to allow 2 'kW' as a short-cut for 2e3 'W' inside equations, as most users would expect based on the rest of the user experience (that variant would also have some problems temperatures and rotations), but as something having unit "kW".

@casella
Copy link
Collaborator

casella commented Sep 12, 2025

After a long discussion at the MAP-Lib meeting in Lucern (see the minutes, it is agreed that this is not controversial and orthogonal to all other proposals/issues regarding units and unit checking, so we should go ahead with that.

The only thing that needs to be checked is if this somehow conflicts with existing syntax in SimulationX that has different meaning. @gkurzbach, @TorstenBlochwitz can you please comment on that?

@casella
Copy link
Collaborator

casella commented Sep 12, 2025

I have to contradict my previous statement, sorry. I found another potential issue after writing #3744. In Chapter 19 of the latest MLS draft on master, it is stated that:

It is recommended that non-SI units are only used for the displayUnit-attribute in order to reduce impact of unrecognized unit symbols when using another Modelica tool.

I think that, for consistency, we should then restrict unitful literals to only use SI-units (including the listed 7 non-SI units that are allowed in the SI system), as we do with unit attributes. @henrikt-ma do you agree?

Also, should we add the three example cases listed in the minutes of our meeting as non-normative text for further clarification?

@henrikt-ma
Copy link
Collaborator Author

henrikt-ma commented Sep 13, 2025

I think that, for consistency, we should then restrict unitful literals to only use SI-units (including the listed 7 non-SI units that are allowed in the SI system), as we do with unit attributes. @henrikt-ma do you agree?

-Yes, the same sort of recommendation makes sense for unitful literals. I'll add it.-

Edit: The current recommendation already applies to unitful literals, since these don't go under displayUnit usage.

@henrikt-ma
Copy link
Collaborator Author

Also, should we add the three example cases listed in the minutes of our meeting as non-normative text for further clarification?

Personally I would have preferred to not include a bigger example like that for a "simple" construct like this, but considering the wild discussions i Rotkreutz I realize that it might be unrealistic to think that the average specification reader would be annoyed by such a "trivial" example. I'll add the example, and then we can take the discussion from there.

@henrikt-ma
Copy link
Collaborator Author

When making the extended example I realized that it is difficult to tell the story without making any assumptions about how unit consistency is defined in Modelica. For me, this is a stronger reason than the triviality to not include the example.

@casella, what do you think about the extended example?

@cbu-hw
Copy link

cbu-hw commented Sep 19, 2025

I like the proposal (saw it first at the conference in your talk) and the extended example (in my book, more illustrative examples are typically better than fewer)!
It's great that a specific, uncontroversial, part of the unit improvements could be isolated and moved forward!

@cbu-hw
Copy link

cbu-hw commented Sep 23, 2025

After a long discussion at the MAP-Lib meeting in Lucern (see the minutes, it is agreed that this is not controversial and orthogonal to all other proposals/issues regarding units and unit checking, so we should go ahead with that.

@casella are the minutes going to be published or summarized so that non-MA members can learn what has been decided? At least the unit-related parts would be interesting, to learn where MCP0027-related efforts stand now.

@HansOlsson
Copy link
Collaborator

HansOlsson commented Sep 25, 2025

Based on the discussion in Lucern it seems this is the preferred syntax, and that the preferred semantics is that it is automatically converted to suitable units (normally base units).

The current proposal intends to have a more restrictive semantics, that may possibly work.
However, it doesn't clearly the define semantics - and that must be improved; and I have added most of the needed changes at the end.

Background
As far as I understand SimulationX already has the semantics that Real(unit="m")=1 'cm'; roughly means: Real(unit="m", displayUnit="cm")=0.01; - and Dymola has similar semantics in the GUI for a slightly different syntax.

We might delay conversions (and/or restrict them - e.g., to parameter bindings with unit) provided that:

  • We do not later change the new semantics for valid models
  • We have some indication that this is the direction

I have some doubts whether completely delaying it will actually work as tools will naturally attempt to support conversions, in some way. (Those ways should then converge.)

In order to simplify the discussion I find it useful to only consider unitful literals in parameter bindings as other cases can be reduced to that, e.g. the example code y = x + 2'cm'; could be handled as:

  parameter Real temp=2'cm';
equation
 y=x+temp;

I'm not saying that we should restrict the unitful literals to these cases, merely that this is useful for understanding the general issues as any issue for unitful literals in expressions can be reproduced using only unitful literals in parameter bindings. It also shows that automatically converting unitful literals in general isn't more complicated than only converting them in parameter bindings.

Specifically considering parameter bindings show a number of issues related to the following areas:

  • If we don't have a unit for the parameter we don't know whether it is valid (without conversion) or which value to use (with conversion)
  • If it is a temperature we also need absoluteValue
  • Some issues related to angular frequencies (etc)
  • Some units should not be mixed even if they are compatible

( Regarding conversion: if models only had used SI-base-units one could have automatically added a conversion to SI-base-units. However, since that is not the case one needs to check whether that is the case first, and that check seems as complicated as inferring the actual unit. )

Proposed semantics
However, as long as we admit that there are issues I believe that it would be possible to handle most cases in some pragmatic way:

  • Only allow unitful literals when the unit can be inferred (based on other information) and the unitful literal is consistent with the inferred unit; I assume that is the intention of the PR but it is not explicitly written
  • Only allow unitful literals that may involve offsets (i.e., temperatures) if absoluteValue can be inferred (especially when we add conversions, but even otherwise); see Infer absoluteValue #3748
  • And some specific restrictions for angular frequencies (and related quantities); will detail later (especially when we add conversions, but even otherwise)
  • Allow diagnostics if the unit of the unitful literal and the inferred unit shouldn't be mixed (like "N.m" for an energy variable)

The key part is that goal isn't to handle everything, but instead that many problematic constructs should generate errors (or warnings for the last case).

This is important, as users (and tools) can currently ignore/disable unit checking and inference (or at least ignore the diagnostics), but once we start considering unit conversion one cannot unit checking - as unit conversion and ignored unit checking will give different results for the same model (and unit conversion for models with unit errors will be a mess.)

The implication is that:

model MValid
  Real x(unit="m"), y;
equation
 y=x+0.02'm';  //Or using temp as above.
end MValid;

would be legal, whereas

model MMixing1
  Real x(unit="m"), y;
equation
 y=x+2'cm'; 
end MMixing1;

model MMixing2
  Real x(unit="cm"), y;
equation
 y=x+0.02'm'; 
end MMixing;

would currently both be in-valid (they require conversion), and

model MNonValid
  Real x, y;
equation
 y=x+0.02'm'; 
end MNonValid;

would not be valid as we couldn't infer the unit for x (so it could be MMixing2 or MValid).

Additionally, this implies:

  • Unit inference can start small, and add more rules - without breaking unitful literals in valid models
  • Automatic unit conversion of unitful literals can be added safely with this restriction
  • Connecting such components with other components will not invalidate the unitful literals

Or in summary: we can safely extend both models and the language.

( An interesting consequence is that some ambiguous unitful literals could be disambiguated by the inferred unit (so "T" could mean Tesla or Tonne depending on the unit; and similarly for the different pounds), but I don't think that's a good idea. )

@henrikt-ma
Copy link
Collaborator Author

Based on the discussion in Lucern it seems this is the preferred syntax, and that the preferred semantics is that it is automatically converted to suitable units (normally base units).

Let's not allow anything involving conversion to creep into the scope of this PR. It is crucial that this PR is only about the syntax, so that we don't need to make any assumptions about the rules for unit checking which are still under development.

Then, once we have rules for unit checking, it will be a much better time to talk about implicitly converting these literals to units that don't lead to unit inconsistency.

If we want some sort of conversion before we have a definition of unit consistency, I think the conversion needs to be explicit, like so:

parameter Real p(unit = "m") = inUnit(1'cm', "m");

Here, tools can figure out what inUnit(1'cm', "m") means without knowing the rules of unit checking. Once we have unit checking rules, it will be easy to say that a unit conflict in a declaration equation may be resolved using implicit unit conversion if the variable has a literal (not inferred) unit.

(While inUnit is mainly of interest for users as long as the language doesn't offer implicit unit conversion, it will still remain a useful operator for describing semantics of implicit conversion.)

As suggested by Hans.

Co-authored-by: Hans Olsson <HansOlsson@users.noreply.github.com>
@HansOlsson
Copy link
Collaborator

HansOlsson commented Sep 29, 2025

Based on the discussion in Lucern it seems this is the preferred syntax, and that the preferred semantics is that it is automatically converted to suitable units (normally base units).

Let's not allow anything involving conversion to creep into the scope of this PR. It is crucial that this PR is only about the syntax, so that we don't need to make any assumptions about the rules for unit checking which are still under development.

Then, once we have rules for unit checking, it will be a much better time to talk about implicitly converting these literals to units that don't lead to unit inconsistency.

I didn't add the semantics of unit conversion, I only made the semantic restriction that you are only able to use the construct if you can infer the unit (and the unit of the unitful literal is compatible with that) fully clear.

As far as I understand SimulationX users can write parameter Modelica.Units.SI.Length len=1'cm'; and it is interpreted in the natural way as 0.01 m. That's also what users seem to expect.

Making it an error for the time being also works, my main concern is that it must be clear; and I'm very worried that trying to clarify the text (including error cases) is met with push-back.

If we don't specify any semantics some could follow the normal idea that units can be ignored (or disable unit checking) and think that it means the same as parameter Modelica.Units.SI.Length len=1;

The current proposal sort of suggests that the model should be invalid due to unit inconsistency, which requires that the unit is inferred. The specification shouldn't merely suggest semantics for the value of parameters (that so significantly impact the result), and thus I proposed to explicitly add it to the proposal - and in particular clarify that if the unit cannot be inferred it is an error; so that tools cannot say "we don't infer units so it's obviously valid". (Even if the conversion-check is the hard part, and the actual conversion is the easy part.)

That unclarity for what a model means (is the value of len 1, 0.01, or is the model just invalid?) would be disastrous for users, or in other words syntax without semantics is literal non-sense.

(If we didn't allow Real len(unit="cm") one could always interpret it as converted to SI-base units, but that's not the case. It would also theoretically be possible to limit the syntax to SI-base-units, but that seems unlikely to work in practice. Adding inUnit(..., "m") makes it more verbose, without removing the problem, as there's the possibility of Real len(unit="cm")=inUnit(1'cm', "m"); - or users just skipping that part.)

Importantly, it is easy to determine the unit in this case (it's part of the type for the variable) and it would be silly to ignore it, but as I understand the intended goal is to allow them in places where the unit inference is less straightforward - with the same problems for the unit and which value to use or whether it is invalid.

Therefore, if we want to just add the syntax without problems we could say that it is currently only allowed in simple bindings for variables with unit and it is then automatically converted. Alternatively, we could state that they are only allowed in those cases and it is in an error if the units would require a conversion - but as previously stated the actual conversion is the easy part.

As far as I understand that possibility:

  • Introduces the syntax
  • Corresponds to the SimulationX case (AFAIK)
  • It avoids rules for unit checking/inference etc; as the unit is already explicitly given
  • Is compatible with my proposed changes above, as e.g., temperatures require absoluteValue - and it is a bad idea to write parameter Modelica.Units.SI.Torque t = 1'W'

Using a unitful literal makes the intention clear:
\begin{lstlisting}[language=modelica]
y = x + 2'cm';
\end{lstlisting}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
\end{lstlisting}
\end{lstlisting}
Tools must infer the unit information of the unitful literal, including absolueValue when applicable, from the rest of the model, and verify that the given unit is compatible.
It is an error if the needed unit information cannot be inferred.
Diagnostics may be given for consistent units that shouldn't be mixed (like \lstinline!"N.m"! and \lstinline!"J"!).
Special care is needed to handle rotational frequencies.

Copy link
Collaborator

Choose a reason for hiding this comment

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

To make it clearer that it is just adding lines to clarify, and that the following lines are unchanged.

@HansOlsson
Copy link
Collaborator

HansOlsson commented Sep 30, 2025

After a long discussion at the MAP-Lib meeting in Lucern (see the minutes, it is agreed that this is not controversial and orthogonal to all other proposals/issues regarding units and unit checking, so we should go ahead with that.

The only thing that needs to be checked is if this somehow conflicts with existing syntax in SimulationX that has different meaning. @gkurzbach, @TorstenBlochwitz can you please comment on that?

As far as I recall from previous discussion it does cause a conflict, and I would be surprised if SimulationX spent time to introduce the syntax so that users could write SI.Length len=1'cm'; to get an error - instead of automatic conversion to meters.

@gkurzbach
Copy link
Collaborator

As far as I recall from previous discussion it does cause a conflict, and I would be surprised if SimulationX spent time to introduce the syntax so that users could write SI.Length len=1'cm'; to get an error - instead of automatic conversion to meters.

Yes, this notation does not lead to any conflict and we use it mainly for conversation.

@HansOlsson
Copy link
Collaborator

To be concrete consider:

model Ok
  Modelica.Units.SI.Length len=1'm';
  Modelica.Units.SI.TemperatureDifference Td=1'degC';
end Ok;

model Bad
   Modelica.Units.SI.Length len=1'degC';
end Bad;

model NeedConversion
   Modelica.Units.SI.Length len=1'cm';
   Modelica.Units.SI.Temperature T=20'degC';
end NeedConversion;

model Ambiguous
   Real x=1'cm';
   Real y(unit="K")=1'degC';
end Ambiguous;

Either we agree that Ok is ok while Bad, and Ambiguous should be errors, and NeedConversion is also an error (unless we add conversions) - and then I see no harm in clarifying that. Or we are adding something without knowing what it means.

@DagBruck
Copy link
Collaborator

DagBruck commented Oct 1, 2025

I'm happy to see that SI.Length len=1'cm' is handled in SimulationX, that makes a lot of sense. In any case, it seems we have to answer the question what it means, syntax without semantics is meaningless.

@gkurzbach
Copy link
Collaborator

gkurzbach commented Oct 1, 2025

Because we have no unit checking in SimulationX, the numbers with units in quotes are always converted to the SI base unit, so 1'cm' is equal to 0.01'm' but the unit is dropped then, so 0.01 remains. If there would be unit checking, the unit could be kept and checked for consistency with the inferred unit. Further, if the units are not the same, but both have the same SI base unit, the result could be converted to the inferred unit. So, if the inferred unit would be 'mm', 0.01'm' would be converted to 10 'mm' and the unit then could be dropped, and 10 remains.

@HansOlsson
Copy link
Collaborator

HansOlsson commented Oct 1, 2025

Because we have no unit checking in SimulationX, the numbers with units in quotes are always converted to the SI base unit, so 1'cm' is equal to 0.01'm' but the unit is dropped then, so 0.01 remains.

Ok, one solution that is very easy to implement - and allows the use of 1'cm' meaning 0.01 (meter) that works in about 99% of the cases. (Another solution that is easy to implement is to restrict the use to simple parameter bindings with known unit.)
Certainly better than dropping the unit without converting.

Do you also assume that temperatures are absolute temperatures so that 20'degC' means 293.15 K? (I think I got that from some comments, but I might misremember.)

If there would be unit checking, the unit could be kept and checked for consistency with the inferred unit. Further, if the units are not the same, but both have the same SI base unit, the result could be converted to the inferred unit. So, if the inferred unit would be 'mm', 0.01'm' would be converted to 10 'mm' and the unit then could be dropped, and 10 remains.

Yes, that would be the expected result with unit checking and non-base units (in addition to detecting 1'cm' used for e.g., an area or temperature). And as indicated by you, if you are able to infer the unit you can also convert to the unit (i.e., the hard part is unit checking/inference - the actual conversion is trivial).

@HansOlsson HansOlsson added this to the 2025-October milestone Oct 1, 2025
@gkurzbach
Copy link
Collaborator

Do you also assume that temperatures are absolute temperatures so that 20'degC' means 293.15 K? (I think I got that from some comments, but I might misremember.)

Yes, we do. Instead, we introduced new unit symbols for temperature differences in addition to K, e.g. 'd°C'.

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.

6 participants