Skip to content

Giving unit to literals #3668

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
HansOlsson opened this issue Apr 4, 2025 · 28 comments
Open

Giving unit to literals #3668

HansOlsson opened this issue Apr 4, 2025 · 28 comments
Labels
MCP0027 Unit checking

Comments

@HansOlsson
Copy link
Collaborator

As part of unit-checking #3491 various ways of attaching units to Reals are proposed including withUnit(...) and 1 'm'. After additional internal discussion we have found a simpler proposal that voids most of the pitfalls.

The simple proposal is that Real (and any type derived from Real) can be called as follows:

function Real
  input Real _v;
  input String unit;
  input String displayUnit=unit;
  output Real y(unit=unit, displayUnit=displayUnit)=_v;
end Real;

Benefits:

  • No, new syntax or reserved words needed.
  • Close to the syntax of component declarations, and with the same semantics.
  • Would allow replacing parameter Real p(unit="m", displayUnit="mm")=0.001; by parameter Real p=Real(0.001, unit="m", displayUnit="mm"); - with the same semantics, in particular we make it easy to avoid non-base-units in equations.
  • Possible to vectorize (at least in the first argument)

Including types derived from Real would allow something like the following in the IdealDiode:

 v = (s * SI.Current(1) ) * (if off then 1 else Ron) + Vknee;
  i = (s * SI.Voltage(1) ) * (if off then Goff else 1) + Goff*Vknee;
@henrikt-ma
Copy link
Collaborator

I am strongly against the idea of using the types derived from Real, mainly because of the following two related reasons:

  • The name of a type is generally not expected to clearly express the value of its unit-attribute.
  • Pretty much all of the types in Modelica.Units are named based on the quantity, not the unit.

The use of SI.Current and friends is also limited in that the solution becomes dependent on having a nice selection of types with unit to choose from, in order to avoid being back on square one with one-off type definitions instead of one-off constant declarations. Further, even if the MSL comes with a fairly big collection of units mapped to types, finding the right type to use will require special tool support when editing the equations where a unitful literal is needed.

Regarding Real(0.001, unit = "m"), I can see that it would be an alternative to withUnit(0.001, "m"). However, since I believe that we will also want to have operators for unit conversion and extraction of numeric values in the end, it makes more sense to me to go for a new operator such as withUnit instead of overloading Real. For me, however, the introduction of withUnit is a topic for the future, and what matters more right now is that 0.001'm' is so much more readable compared to Real(0.001, "m").

Vectorization will not be a problem once we get to the operator forms in the future. In the meantime, there are still the two options of using a one-off constant array or to add the unit to each of the array elements in case the array is small. By the way, how many examples have we encountered so far where this is needed?

@HansOlsson
Copy link
Collaborator Author

HansOlsson commented Apr 6, 2025

I am strongly against the idea of using the types derived from Real, mainly because of the following two related reasons:

  • The name of a type is generally not expected to clearly express the value of its unit-attribute.
  • Pretty much all of the types in Modelica.Units are named based on the quantity, not the unit.

Those are some of the reasons why it is a good idea, as it expresses the underlying intent which isn't tied to the unit. I hadn't realized that when I wrote it, but now it becomes much clearer.

One reason is that quantities have understandable (and familiar) names, and that's why they are used in Modelica - and similarly the current work-arounds are normally called unitTime, unitCurrent, etc.

I simply don't see a problem with someone using Enthalpy in a formula to indicate that it is enthalpy and not something else that happen to have the same unit (even if only the unit is used for checking) - but I do see the benefits in terms of understandability.

More fundamentally the title of this issue says "Giving units to literals" - whereas it in the SI-standard is introduced as "Defining the unit of a quantity"; and the definition of base units are preceded by the corresponding quantities. That shift in perspective is important - one shouldn't think of starting with 1.6 in a formula and slap a unit on it, but start with a quantity - that has a numeric value and a unit.

The use of SI.Current and friends is also limited in that the solution becomes dependent on having a nice selection of types with unit to choose from, in order to avoid being back on square one with one-off type definitions instead of one-off constant declarations. Further, even if the MSL comes with a fairly big collection of units mapped to types, finding the right type to use will require special tool support when editing the equations where a unitful literal is needed.

Yes, tools can spend the effort of one simple way of finding them; that can be used both for declarations and for these cases; whereas we otherwise need one way of finding the type when declaring parameter with a certain quantity and another for finding units when defining the unit of a quantity inside equations.

@HansOlsson HansOlsson added the MCP0027 Unit checking label Apr 8, 2025
@henrikt-ma
Copy link
Collaborator

More fundamentally the title of this issue says "Giving units to literals" - whereas it in the SI-standard is introduced as "Defining the unit of a quantity"; and the definition of base units are preceded by the corresponding quantities. That shift in perspective is important - one shouldn't think of starting with 1.6 in a formula and slap a unit on it, but start with a quantity - that has a numeric value and a unit.

I agree in the sense that slapping units to 1.6 isn't how we should think about what we are doing. The problem I see that we need to solve is how to express a length of 160 centimeters in an equation. While the kind of quantity (here, length) is quite useful information about a variable, the role is minor if any inside equations (connect-equations being an exception). What really matters within equations is knowing the unit associated with the numeric value.

Who really cares if the 5e3'J' in this equation is work or energy?

Power power = 5e3'J' / 600's';

@HansOlsson
Copy link
Collaborator Author

More fundamentally the title of this issue says "Giving units to literals" - whereas it in the SI-standard is introduced as "Defining the unit of a quantity"; and the definition of base units are preceded by the corresponding quantities. That shift in perspective is important - one shouldn't think of starting with 1.6 in a formula and slap a unit on it, but start with a quantity - that has a numeric value and a unit.

I agree in the sense that slapping units to 1.6 isn't how we should think about what we are doing. The problem I see that we need to solve is how to express a length of 160 centimeters in an equation. While the kind of quantity (here, length) is quite useful information about a variable, the role is minor if any inside equations (connect-equations being an exception). What really matters within equations is knowing the unit associated with the numeric value.

Who really cares if the 5e3'J' in this equation is work or energy?

Power power = 5e3'J' / 600's';

I would say it is Work, but I view objecting to Energy there as a bit of nitpicking.
However, Enthalpy would seem quite odd (all of them have the same unit).

The difference is that Work is the Energy transferred, which goes together with a time-period (and Enthalpy is quite different).

However, I see two major drawbacks with 'J':

  • Having units as both strings and variable names interpreted as strings will be confusing.
  • There is a major ambiguity for 5'kJ' - normally equations in Modelica are written using base-units; so the natural interpretation is that 5'kJ' means Real(5000,unit="J",displayUnit="kJ") - but there are also less common cases of using prefixed units, other derived units, units acceptable for use with the SI-system and also other units. Thus thinking that it was meant to have unit "kJ" wouldn't seem outlandish - and that ambiguity would just break the good parts of units in Modelica. (Automatic conversions between prefixed units in equations is a big can of worms.)

I view both as blockers on their own, and and none of this is currently needed. There are some literals in libraries that need to be converted to quantities with unit to have better unit-checking.

@henrikt-ma
Copy link
Collaborator

henrikt-ma commented Apr 10, 2025

However, I see two major drawbacks with 'J':

  • Having units as both strings and variable names interpreted as strings will be confusing.

It is not nice, but still so good that it has support both in SimulationX and System Modeler.

Perhaps you would prefer 5e3["J"], which is also easy to implement?

  • There is a major ambiguity for 5'kJ' - normally equations in Modelica are written using base-units; so the natural interpretation is that 5'kJ' means Real(5000,unit="J",displayUnit="kJ") - but there are also less common cases of using prefixed units, other derived units, units acceptable for use with the SI-system and also other units. Thus thinking that it was meant to have unit "kJ" wouldn't seem outlandish - and that ambiguity would just break the good parts of units in Modelica. (Automatic conversions between prefixed units in equations is a big can of worms.)

There is no ambiguity here:

Real x(unit = "J") = 1;
Real y(unit = "kJ") = 5;
Real a = x + y;     // Unit error.
Real b = x + 5'kJ'; // Unit error, just like above.

To think about automatic conversions is making this a lot more complicated than it should be.

@HansOlsson
Copy link
Collaborator Author

HansOlsson commented Apr 10, 2025

However, I see two major drawbacks with 'J':

  • Having units as both strings and variable names interpreted as strings will be confusing.

It is not nice, but still so good that it has support both in SimulationX and System Modeler.

Whereas we have support in Dymola for:
5000 J and 5 kJ
in the parameter dialog, which conforms to BIPM recommendations (except for a minor issue with degree-symbol); and we also show them in that form (with correct handling of the degree-symbol). (And I'm not sure which interpretation SimulationX uses, I hope it is the same as Dymola.)

Real x(unit = "J") = 1;
Real y(unit = "kJ") = 5;
Real a = x + y;        // Unit error.
Real b = x + 5'kJ'; // Unit error, just like above.

That will just bring chaos and disappointed users.

In Modelica we have for decades used displayUnit to write SI.Energy y(displayUnit="kJ") = 5000; and show 5 kJ.
Introducing another way of writing 5 kJ - that will not work in the same scenario (even if you can write it) - is just a massive step backwards.

And more fundamentally I don't see that as needed to solve the actual issue of improving unit-checking of equations, as equations should normally be in base-SI-units whereas non-base-unit normally only appear in the external interface (as parameters and for plots).

@henrikt-ma
Copy link
Collaborator

I would say it is Work, but I view objecting to Energy there as a bit of nitpicking. However, Enthalpy would seem quite odd (all of them have the same unit).

The point is that reasoning about the kind of quantity is not possible in the way we can do it for units. The following looks stupid to me, but not possible to reject based on any general principle that I am aware of:

Power power = Torque(5e3) / 600's';

Hence, what you can see here is only the inapplicable information that the author had torque in mind, while you cannot see the important part, being the unit of 5e3.

@henrikt-ma
Copy link
Collaborator

henrikt-ma commented Apr 11, 2025

Whereas we have support in Dymola for:
5000 J and 5 kJ
in the parameter dialog, which conforms to BIPM recommendations (except for a minor issue with degree-symbol); and we also show them in that form (with correct handling of the degree-symbol). (And I'm not sure which interpretation SimulationX uses, I hope it is the same as Dymola.)

You are mixing things up. The introduction of a syntax for attaching a unit to a literal is not replacing the old way of editing parameter values in a chosen display unit. This mechanism works great for setting parameter values where the parameter is properly declared with a type that comes with quantity, unit, and possibly a displayUnit. This is working great also in System Modeler (not even a tiny space between the number and the degree symbol), and there is no intention of changing this.

Literals with unit should be used deeper down in expressions and equations, where the unit is not immediately available from the context.

In Modelica we have for decades used displayUnit to write SI.Energy y(displayUnit="kJ") = 5000; and show 5 kJ.
Introducing another way of writing 5 kJ - that will not work in the same scenario (even if you can write it) - is just a massive step backwards.

No, since tools will guide the users to using the decades old mechanism when editing these declaration equations.

@HansOlsson
Copy link
Collaborator Author

HansOlsson commented Apr 11, 2025

I would say it is Work, but I view objecting to Energy there as a bit of nitpicking. However, Enthalpy would seem quite odd (all of them have the same unit).

The point is that reasoning about the kind of quantity is not possible in the way we can do it for units. The following looks stupid to me, but not possible to reject based on any general principle that I am aware of:

Power power = Torque(5e3) / 600's';

Hence, what you can see here is only the inapplicable information that the author had torque in mind, while you cannot see the important part, being the unit of 5e3.

So, you are claiming that the syntax, that solves all of the actual problems without introducing any, would be bad because people might write bad code that we cannot currently detect?

Added: And similarly we wouldn't detect an error for Power power =5e3'N.m' / 600's'; even if the unit is visible.

@HansOlsson
Copy link
Collaborator Author

Whereas we have support in Dymola for:
5000 J and 5 kJ
in the parameter dialog, which conforms to BIPM recommendations (except for a minor issue with degree-symbol); and we also show them in that form (with correct handling of the degree-symbol). (And I'm not sure which interpretation SimulationX uses, I hope it is the same as Dymola.)

You are mixing things up.

No. I'm staying consistent - since I care about the entire user experience.

I don't want two different ways of writing 5 kJ with wildly different semantics (especially not to handle a corner case that we don't see a need for), and I don't want two different ways of introducing literals with unit - when one will do.

I'm trying to solve actual problems - where MSL have a few equations with real values that are some quantity with unit where the unit is currently omitted (and similarly in other libraries); and I want an actual solution.

This proposal shows that:

  • It doesn't require new syntax or keywords.
  • It can be done in a way that is consistent with existing Modelica
  • It doesn't introduce the risk of ambiguities (or "mixing things up")

@henrikt-ma
Copy link
Collaborator

And more fundamentally I don't see that as needed to solve the actual issue of improving unit-checking of equations, as equations should normally be in base-SI-units whereas non-base-unit normally only appear in the external interface (as parameters and for plots).

Sticking to SI base units doesn't remove the need for attaching units to literals:

  Modelica.Units.SI.Distance d = 50;
  Modelica.Units.SI.Velocity v = d / 20's';

@henrikt-ma
Copy link
Collaborator

So, you are claiming that the syntax, that solves all of the actual problems without introducing any, would be bad because people might write bad code that we cannot currently detect?

No. I'm saying that it solves the wrong problem. It solves the problem of being able to express the kind of quantity for a sub-expression, but doesn't solve the problem of clearly attaching a certain unit to the literal.

@HansOlsson
Copy link
Collaborator Author

HansOlsson commented Apr 11, 2025

And more fundamentally I don't see that as needed to solve the actual issue of improving unit-checking of equations, as equations should normally be in base-SI-units whereas non-base-unit normally only appear in the external interface (as parameters and for plots).

Sticking to SI base units doesn't remove the need for attaching units to literals:

  Modelica.Units.SI.Distance d = 50;
  Modelica.Units.SI.Velocity v = d / 20's';

And the proposal solves that either as:

Modelica.Units.SI.Distance d = 50;
Modelica.Units.SI.Velocity v = d / Real(20,unit="s");

or as:

import Modelica.Units.SI;
SI.Distance d = 50;
SI.Velocity v = d / SI.Time(20);

No new syntax, no new keywords even though in this case I would just write:

import Modelica.Units.SI;
SI.Distance d = 50;
SI.Time t = 20;
SI.Velocity v = d / t;

(Even if Real t(unit="s")=20; is legal as well. Added: As well as Real t=SI.Time(20);, Real t=Real(20, unit="s");, and SI.Time t = SI.Time(20);)

@gkurzbach
Copy link
Collaborator

For me, the proposals are not a big contradiction. One could allow both spellings. For simple units, such as 1 kJ, you could omit them single quotes, if you want to write 1 '°C' or 1 'm/s' you just have to use them. Syntactically, both are just IDENTs. The quotes only increase the number of representable units.
One could also allow the notation as a record constructor. However, I find it very cumbersome and writing or reading
d / Real(20, unit="s"); is not a good user experience. I don't think it's a good idea to require this just to avoid introducing new syntax (although 1 kJ is already new syntax).
Further, the provided type information with this notation is not needed, because currently there is no defined semantics about the quantity attribute and there is no way to infer the permitted units from the quantity attribute. Also the unit checking only deals with units.
The notation as a function also raises another question: one could come up with the idea of giving other attributes besides unit to the constructor call. What happens to them then? Or does that lead to an error message? I find it a bit excessive to do this only for the special case of the unit attribute.

@henrikt-ma
Copy link
Collaborator

henrikt-ma commented Apr 15, 2025

For me, the proposals are not a big contradiction. One could allow both spellings. For simple units, such as 1 kJ, you could omit them single quotes, if you want to write 1 '°C' or 1 'm/s' you just have to use them. Syntactically, both are just IDENTs. The quotes only increase the number of representable units.

I actually find it very helpful that quoted identifiers are a rare thing in Modelica models, so that 1'kJ' doesn't immediately make me think of a literal number followed by an identifier. I would also find it advantageous to only support the single-quoted form for the sake of distinguishing a tool's inclusion of a display unit for a numeric value from a unit carried by the expression itself.

@HansOlsson
Copy link
Collaborator Author

For me, the proposals are not a big contradiction. One could allow both spellings. For simple units, such as 1 kJ, you could omit them single quotes, if you want to write 1 '°C' or 1 'm/s' you just have to use them. Syntactically, both are just IDENTs. The quotes only increase the number of representable units.

I actually find it very helpful that quoted identifiers are a rare thing in Modelica models, so that 1'kJ' doesn't immediately make me think of a literal number followed by an identifier. I would also find it advantageous to only support the single-quoted form for the sake of distinguishing a tool's inclusion of a display unit for a numeric value from a unit carried by the expression itself.

Can we actually be serious?

The reasonable expectation of a user writing
1 kJ (or 1'kJ')
is that it works.

In Dymola that means that for parameter Modelica.Units.SI.Energy w; you can enter 1 kJ and you get the expected result, that is w(displayUnit="kJ")=1000; That just works.

The key for enabling that is that we know the underlying unit (in this case Joule) and the conversion, as that is consistent with the design that variables are (primarily) in base-units and display unit is for displaying (and entering) values, and unrecognized display units aren't an issue. (If we don't consider those constraints storing it as parameter Modelica.Units.SI.Energy w=1 kJ; would also be possible for parameter-bindings.)

This is especially important for cases where the display unit itself is not enough: 1°C; which depending on the underlying settings may be either be 1 K or 274.15 K.

If we now introduce 1°C or 1 kJ in expressions we no longer know the underlying unit, and for binding equations like Real w=1 kJ; or Real td=1°C; that would be a really bad problem, and as previously indicated equations in Modelica are normally in base-units so making it very convenient to add non-base units just breaks things.

Additionally, when we consider giving values to quantities in expressions the expectation is also that we should consider it more carefully.

One of the classic examples was Modelica.Mechanics.MultiBody.Examples.Loops.Utilities.GasForce2 with:
constant SI.SpecificHeatCapacity R_air = Modelica.Constants.R/0.0289651159;
That literal is a molar mass, and debating how to best add 'kg/mol' or use SI.MolarMass(0.0289651159) misses that it should be one of:

  • Modelica.Media.Air.SimpleAir.MM_const (indicating that it is the molar mass of simple air - not just any molar mass).
  • Removed (as in 4.1.0) since the computation isn't needed.

@HansOlsson
Copy link
Collaborator Author

HansOlsson commented Apr 15, 2025

For me, the proposals are not a big contradiction. One could allow both spellings. For simple units, such as 1 kJ, you could omit them single quotes, if you want to write 1 '°C' or 1 'm/s' you just have to use them. Syntactically, both are just IDENTs. The quotes only increase the number of representable units.

That depends. In some cases (like the parameter dialog) one can bypass the lexical analysis and thus don't care whether it is an IDENT or not; so 1 m/s (as well as 20 km/h) works perfectly (and even 1 °C and if you can find that symbol). I don't know if we could also have that inside expressions in a hand-written parser, but apart from other issues I see that it would make it impossible to have a reasonable grammar.

@HansOlsson
Copy link
Collaborator Author

The notation as a function also raises another question: one could come up with the idea of giving other attributes besides unit to the constructor call. What happens to them then? Or does that lead to an error message? I find it a bit excessive to do this only for the special case of the unit attribute.

Good question,
I don't see a problem with allowing them, so the question is what if anything should be the meaning: quantity currently doesn't matter except for connection variables, start/nominal/unbounded/fixed don't really make sense for a literal, so the only interesting attributes are min and max, right?

The question is whether min/max are useful - Real(2, min=4) seems silly (if you are supposed to change it make it a parameter), but detecting SI.AbsoluteTemperature(-2) makes some sense (and similarly for types with more advanced min/max).

@gkurzbach
Copy link
Collaborator

This is especially important for cases where the display unit itself is not enough: 1°C; which depending on the underlying settings may be either be 1 K or 274.15 K.

Btw., as I learned in the good old East German school, °C was always an absolute unit, temperature differences were always expressed in K.

That depends. In some cases (like the parameter dialog) one can bypass the lexical analysis and thus don't care whether it is an IDENT or not; so 1 m/s (as well as 20 km/h) works perfectly (and even 1°C if you can find that symbol). I don't know if we could also have that inside expressions in a hand-written parser, but apart from other issues I see that it would make it impossible to have a reasonable grammar.

Therefore the quotes. Inside them you are free to define a new grammar dealing with units. It is even possible to determine the base unit from derived units and to handle non SI units then.

@HansOlsson
Copy link
Collaborator Author

HansOlsson commented Apr 16, 2025

This is especially important for cases where the display unit itself is not enough: 1°C; which depending on the underlying settings may be either be 1 K or 274.15 K.

Btw., as I learned in the good old East German school, °C was always an absolute unit, temperature differences were always expressed in K.

BIPM (who defines the SI-standard https://www.bipm.org/en/publications/si-brochure ) disagrees and says:

"A difference or interval of temperature may be expressed in kelvins or in degrees Celsius, the numerical value of the temperature difference being the same in either case....
However, the numerical value of a Celsius temperature expressed in degrees Celsius is related to the numerical value of the thermodynamic temperature expressed in kelvins by the relation...
The unit degree Celsius is only coherent when expressing temperature differences."

I'm a bit unsure if there has been a relevant change (they dropped the °K for K in 1967/1968), or the school got it wrong, but anyway that's the current status.

Added:
Note the important word "coherent" above, https://en.wikipedia.org/wiki/Coherence_(units_of_measurement)

A coherent system of units is a system of units of measurement used to express physical quantities that are defined in such a way that the equations relating the numerical values expressed in the units of the system have exactly the same form, including numerical factors, as the corresponding equations directly relating the quantities.

Coherence was one of the design goals of the SI-system, and that allows writing equations without conversion factors as long as you stay with the base and coherent derived units (like Newton and Joule). Thus my goal here is to unleash the power of the SI-system by using coherent units to have equations without conversion factors (as much as possible); but still allow using non-coherent units for input/output.

Added: Historical note - based on my understanding:
In 1948-1967/1968 the Celsius scale was used for temperature in the SI-system (with the plan to switch to absolute temperature scale when they could measure it precisely enough), so from 1967/1968 it is Kelvin.
The 1967/1968 decision from CGPM (same **PM) actually seems as if it rules out degree Celsius for an absolute temperature (whereas a temperature interval may be given in degree Celsius); the opposite of what the school said. I couldn't see whether it was amended, the brochure slipped up by accepting the non-coherent use of degree Celsius, or something else.

@HansOlsson
Copy link
Collaborator Author

In addition to this new function(s) we (as previously discussed) also need a way to disable unit-checking in specific equations.
I went with annotation(UnitChecking(enable=false)) (well, with vendor-specific name for the time being), imagining that we can add other settings as well.

Introducing this in Modelica gives something like https://github.com/HansOlsson/Modelica/tree/UnitTest (based master and cherry-picking modelica/ModelicaStandardLibrary#4377 modelica/ModelicaStandardLibrary#4591 modelica/ModelicaStandardLibrary#4398 ).

That shows that this is a working proposal for libraries; in combination with extended unit-checking.

The conclusions are:

  • In many cases the models can be made clearer by replacing common numbers with the corresponding parameter which both improves the quality and removes unit-issue; the syntax makes the transition natural
  • There are only a few cases in MSL where we need to "define the unit of quantities", and similarly for disabling unit-checking
  • The literals only needed coherent units; once more confirming that introducing 5 'kJ' as a short-hand for Real(5, unit="kJ") is a bad idea that will just cause frustration among users. Using non-coherent units is not just hypothetical as there are some cases in MSL where the literal would naturally be given in non-coherent unit (like 1 'min' instead of 60 's'; and possibly 0.1 'mA'), and there are even more in other libraries (in particular 1 'h' ); and I see no reason to make it easy for users to shoot themselves in the foot.
  • In many cases the quantity was already in use in the models

Note that there are still some remaining issues in the library; such as modelica/ModelicaStandardLibrary#4241 but they require more domain knowledge to correct.

(oh, and it's fairly trivial to implement - we already have a similar syntax for record constructors etc)

@HansOlsson
Copy link
Collaborator Author

In case some others missed the coherent part:

The alternative proposal was that 5 'kJ' should be a short-hand for Real(5, unit="kJ") (using syntax from this proposal); that alternative introduces major problems without any real benefits as the rest of the formulas will then not work with that unit.

Modifying that so that 5 'kJ' is a short-hand for Real(5e3, unit="J", displayUnit="kJ") would also have some issues (in particular for temperatures and angular velocities/frequencies), but it might at least be considered.

BTW: I also re-read the original design for units when going through the tutorial document; I believe that is also relevant for others; see #3672 .

@d-hedberg
Copy link

d-hedberg commented Apr 29, 2025

For what it is worth I have to say that I think the short-hand form is fantastic as it is very explicit in what unit is used without affecting readability negatively. It actually enhances the readability as the unit is provided. An expression involving something like Real(5, unit="kJ") or even worse Real(5e3, unit="J", displayUnit="kJ") is disastrous for readability. The expression/equation is lost in syntactic insanity.

@HansOlsson
Copy link
Collaborator Author

HansOlsson commented Apr 29, 2025

For what it is worth I have to say that I think the short-hand form is fantastic as it is very explicit in what unit is used without affecting readability negatively. It actually enhances the readability as the unit is provided. An expression involving something like Real(5, unit="kJ") or even worse Real(5e3, unit="J", displayUnit="kJ") is disastrous for readability. The expression/equation is lost in syntactic insanity.

That may happen if it was needed (a lot), but in practice using this proposal looks like this: https://github.com/HansOlsson/Modelica/tree/UnitTest

  • Do you see any loss of readability?
  • What would you concretely do instead?

In particular people should avoid Real(5, unit="kJ"), or 5 'kJ' in equations; as that will lose one of the main benefits of the SI-system: coherence.

For Real(5e3, unit="J", displayUnit="kJ") it is a mouthful, but the only actual use for it I see at the moment would be storing some hierarchical modifiers (instead of source(k(unit="J",displayUnit="kJ")=5e3)), and similarly as the existing parameter SI.Energy x(displayUnit="kJ")=5e3; (and parameter Real x(unit="J", displayUnit="kJ")=5e3;) it can be shown as 5 kJ in the parameter dialog, (and diagram, and ...).

Or basically Modelica has so far worked by saying that in order to have a parameter with "value" 5 kJ you should use parameter SI.Energy x(displayUnit="kJ")=5e3; or possibly parameter Real x(unit="J", displayUnit="kJ")=5e3; ensuring that the stored value is in the coherent unit (and in many cases with both value and displayUnit as modifiers).

Tools have then made sure that it is presented in a good way; giving the combined benefit of safety (in terms of units), understandability (for users), and low entry point for tools.

And to me bad readability (when there's no tool support) is less of a problem than making it easy to have non-coherent units inside equations giving a real risk of errors; especially as you are not really required to use the parts that you view as having bad readability.

@d-hedberg
Copy link

I'm afraid I do not understand your coherence arguments. An equation involving a literal number with an explicit unit instead of just literal number (without an explicit unit) seems better in every possible way.

  • It helps the user to by being able to specify an intended unit for a literal value in an equation.
  • If the user would happen to specify the wrong unit the unit checking will inform the user.
  • It is clear for other users what the unit is, without having to dig down into type definitions.
  • If any other variable involved in the equation would change unit/type definition at some later point, the unit checking will catch the now possibly incorrect explicit unit for the literal.

@HansOlsson
Copy link
Collaborator Author

I'm afraid I do not understand your coherence arguments. An equation involving a literal number with an explicit unit instead of just literal number (without an explicit unit) seems better in every possible way.

The coherence is a major part of the design of the SI-system. The coherence means that the equations are the same for the values as for the quantities - if you go back to previous systems (like imperial or the various cgs-systems (*)) the problem was that extra factors sort of randomly appeared.

I remember one of my physics courses also had all equation in a non-coherent system - I hope to never see that again.

The unit system in Modelica was designed based on that coherence; that's why values are in the unit, but there's a displayUnit for input/output.

I agree that just having 5e3 for 5e3 J isn't good, but the issue is that 5 'kJ' viewed as a short-cut for Real(5, unit="kJ") is more problematic, as it is almost always is incorrect and it should have been Real(5e3, unit="J") or SI.Energy(5e3) similarly as if it had been en with constant SI.Energy en=5e3; And the reason I write Real(5e3, unit="J") (or equivalently SI.Energy(5e3)) in the explanation is to avoid any ambiguity.

The idea with sticking to the SI-system as a coherent system is that people don't have to wonder about the unit; so when you see SI.Energy(5e3) you don't have to wonder, as you know that unit is the coherent unit for energy (Joule).

Or basically this proposal solves the problem in a few needed cases without introducing any new syntax, and without making it easy to make errors. Considering that tools have not fully supported unit-checking I don't think it is a good idea to introduce something where it is so easy to make errors, and then rely on tools to catch those errors.

As previously stated: having 5 'kJ' as a short-cut for Real(5e3, unit="J") or only allowing coherent units might be discussed (there are some problems). Having it as a short-cut for Real(5, unit="kJ") as proposed would just be a mistake that would cause major problems.

And please look at the attached branch to see that this proposal actually works, in the rare cases it is helpful.

*: cgs stands for centimeter, gram, seconds. But the problem with the cgs-systems are the units for electricity.

@henrikt-ma
Copy link
Collaborator

As previously stated: having 5 'kJ' as a short-cut for Real(5e3, unit="J") or only allowing coherent units might be discussed (there are some problems). Having it as a short-cut for Real(5, unit="kJ") as proposed would just be a mistake that would cause major problems.

It would not cause major problems. Don't worry about coherence – we have unit checking which will detect mistakes. Only worry about the clarity and simplicity of expressions where a unit needs to be attached to a literal.

@HansOlsson
Copy link
Collaborator Author

As previously stated: having 5 'kJ' as a short-cut for Real(5e3, unit="J") or only allowing coherent units might be discussed (there are some problems). Having it as a short-cut for Real(5, unit="kJ") as proposed would just be a mistake that would cause major problems.

It would not cause major problems. Don't worry about coherence – we have unit checking which will detect mistakes. Only worry about the clarity and simplicity of expressions where a unit needs to be attached to a literal.

Please:

  • Show the alternative proposal and that it actually solves the problem.
  • Explain why making it easy to make mistakes (that tools can then detect) is a benefit for users

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
MCP0027 Unit checking
Projects
None yet
Development

No branches or pull requests

4 participants