Skip to content

Avoid that Constants.pi gets the unit "rad"#4774

Open
henrikt-ma wants to merge 1 commit intomodelica:masterfrom
henrikt-ma:pi-unit
Open

Avoid that Constants.pi gets the unit "rad"#4774
henrikt-ma wants to merge 1 commit intomodelica:masterfrom
henrikt-ma:pi-unit

Conversation

@henrikt-ma
Copy link
Copy Markdown
Contributor

@henrikt-ma henrikt-ma commented Apr 21, 2026

The current definition of Modelica.Constants.pi gives it the unit "rad", but based on the ongoing discussions about standardizing a definition of unit consistency in the Modelica specification, I find it clear that pi should have "empty" unit, making the constant behave just like a numeric literal.

For example, the following is expected to be allowed if pi has empty unit, but not if it has unit "rad":

Modelica.Units.SI.Time piTime = Modelica.Constants.pi "π seconds";

With the unit "rad", the workaround would be to insert a conversion factor,

Real conversionFactor(unit = "s/rad") = 1;
Modelica.Units.SI.Time piTime = conversionFactor * Modelica.Constants.pi "π seconds";

but I have a clear impression that our community wouldn't like to have to do it this way (even though it would be much more convenient once the factor can be given in-line as 1's/rad').

In this PR, the change for pi avoids that it gets the unit "rad", and e is updated to keep the two definitions consistent.

The change for 'pi' avoids that it gets the unit "rad", and 'e' is updated to keep the two definitions consistent.
@henrikt-ma
Copy link
Copy Markdown
Contributor Author

By the way, I am intentionally avoiding the question of what units to have on the interface of Modelica.Math.asin. In SystemModeler, for comparison, we are providing the experimental function SystemModelerExtras.Experimental.Units.Radian.asin with unit "1" on the input and unit "rad" on the output, for those who prefer to do their trigonometry with units.

@AHaumer
Copy link
Copy Markdown
Contributor

AHaumer commented Apr 21, 2026

In my understand, "rad" is a pseudo unit as good as "1", just declaring "This is an angle, not a dimensionless ratio.".
With that point of view, "rad" is a helpful reminder.

Copy link
Copy Markdown
Contributor

@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.

I would argue that pi logically should have unit "rad", e.g., when you call sin(2*pi*f*time) it makes sense that f is in Hz and time in seconds, so that pi ensures that the argument has unit "rad".

Obviously there are cases where radians for pi are a bit confusing.

That's why it is important BIPM states that radians exist (for clarity), but it is expressed as having unit "1" in base units.

Additionally, for a user seeing these lines it doesn't seem clear that asin instead of Modelica.Math.asin has such an interpretation. I would even say that the built-in asin should behave the same as Modelica.Math.asin in this respect, so in that sense it seems like a non-change.

@henrikt-ma
Copy link
Copy Markdown
Contributor Author

In my understand, "rad" is a pseudo unit as good as "1", just declaring "This is an angle, not a dimensionless ratio.". With that point of view, "rad" is a helpful reminder.

Yes, I'd phrase it as "rad" being an alias for "1", which sounds more welcoming than calling it a "pseudo unit". However, this misses the point of this PR.

The point of this PR has to do with the sort of unit inconsistency you see here:

  Modelica.Units.SI.DimensionlessRatio x = 5; // x has unit "1"
  Modelica.Units.SI.Time t = x; // Inconsistent units!
  Modelica.Units.SI.Diameter d = x; // Inconsistent units!

If we want to use x in the declaration equations like that, it needs to come with eithI per empty unit (since it can't be consistent with both "s" and "m"). The current design idea for unit checking in Modelica is that we can make x a constant with empty unit:

  constant Real x = 5; // x has empty unit

Applied to pi, there are many places where π is just a number. I got the following examples from Claude:

  • The Basel problem (∑1/n² = π²/6)
  • The Gaussian integral
  • Stirling's approximation
  • The volume of n-balls

Add to that the desire to easily use pi in Modelica empty unit expressions like in the example with x above.

To make all this work nicely, we need pi to have empty unit and just let it decay to "1" in the places where one wants to think of it as having "rad", thanks to "1" and "rad" being aliases in SI.

When speaking about angles, I personally prefer saying:

π radians is the same as 180°

not this:

π is the same as 180°

Then over to @HansOlsson's argument:

I would argue that pi logically should have unit "rad", e.g., when you call sin(2pif*time) it makes sense that f is in Hz and time in seconds, so that pi ensures that the argument has unit "rad".

Well, as long as "rad" is an alias for "1" there is no difference to ensuring the argument has unit "1". Thus, with pi having empty unit you would get the same amount of unit safety in this expression as when it would have unit "rad" (or "1" for that matter); in both cases it will be detected when the unit if f is not compatible with "1/s". Anyway, the ambiguity of how to interpret Hz is a much too big question to be solved here. For now I think we should just be happy that SI avoids most of these tricky issues by making "rad" an alias for "1".

@HansOlsson
Copy link
Copy Markdown
Contributor

Then over to @HansOlsson's argument:

I would argue that pi logically should have unit "rad", e.g., when you call sin(2_pi_f*time) it makes sense that f is in Hz and time in seconds, so that pi ensures that the argument has unit "rad".

Well, as long as "rad" is an alias for "1" there is no difference to ensuring the argument has unit "1".

Exactly. However, the exact handling of "rad" is a bit complicated, and it seems more discussion is needed.

I see two ways of handling "rad" in unit-checks:

  • Just use "rad" as an alias for "1".
  • Have "rad" work slightly different than "1", but decaying to it in some cases. (Dymola has implemented this since a long time - it kind of works, and is one of the reasons the FMI-standard has "rad" as a base-unit.)

I don't see that this PR gives any benefit with either alternative. Additionally, it relies on the yet-to-be-specified semantics of the built-in function asin instead of the MSL function with the same name. In my opinion they should work the same.

The problem I see with having pi treated similarly as a numeric literal is that it would seem to suggest that similarly as SI.Length len1=12; one could use SI.Length len2=pi;, and I don't see that the latter is desirable.

Basically I see three possible units for pi:

  • "rad"
  • "1"
  • empty unit similarly as numeric literal.

and my preference is clearly for the first one, with the second one as the second best.

@henrikt-ma
Copy link
Copy Markdown
Contributor Author

I don't see that this PR gives any benefit with either alternative. Additionally, it relies on the yet-to-be-specified semantics of the built-in function asin instead of the MSL function with the same name. In my opinion they should work the same.

In the future, they might be made the same simply by removing all units from the interface of Math.asin, but as we all know we have some serious work to do for unit propagation through function calls before this can become reality. Until then, we need to make sure that at least the language function's unit design is clever enough.

One thing I find necessary that the language function supports is to take part in empty unit expressions, meaning that asin(1.0) should be usable anywhere an empty unit expression is allowed, for example when defining a constant that shall behave as an empty unit expression where referenced.

@henrikt-ma
Copy link
Copy Markdown
Contributor Author

The problem I see with having pi treated similarly as a numeric literal is that it would seem to suggest that similarly as SI.Length len1=12; one could use SI.Length len2=pi;, and I don't see that the latter is desirable.

If we think about the other uses of pi that has nothing to do with angles, I don't find it strange that it can also be used instead of 3.14 to initialize a peculiar length. Yes, it is peculiar, but not particularly problematic. You can also initialize the length to other peculiar values such as $e$ given by exp(1.0).

@henrikt-ma
Copy link
Copy Markdown
Contributor Author

henrikt-ma commented Apr 22, 2026

Maybe some of the disagreement could be resolved by also having a constant for one revolution:

final constant SI.Angle rev = 2 * pi "Angle corresponding to 1 revolution";

Then,

Real angle = f * rev * time; // Unit is "rad"
Real area = r^2 * pi / 2; // Unit is "m2", not "m2.rad"

@mestinso
Copy link
Copy Markdown
Collaborator

mestinso commented Apr 22, 2026

I'm firmly in the camp that pi should have unit="1", which was the original change made. I had thought that the plan was to revert to that once the implied unit issues throughout the library were resolved.

@henrikt-ma I'm also aligned with your last comment or at least the intent of your comment regarding how we could connect pi and angles.

And regarding this PR specifically: I don't have a problem wth it and would gladly approve if others see value, but I see it as a half measure. Instead, I think the unit for pi should be set back to 1.

@HansOlsson
Copy link
Copy Markdown
Contributor

If we think about the other uses of pi that has nothing to do with angles, I don't find it strange that it can also be used instead of 3.14 to initialize a peculiar length. Yes, it is peculiar, but not particularly problematic. You can also initialize the length to other peculiar values such as e given by exp(1.0).

You can - but it could also indicate that something is missing, and to me unit checking is intended to catch such issues (you might still do it - but then with some extra work arounds to indicate that you know what you are doing).

Consider an actual use case , Modelica.Electrical.Analog.Examples.SeriesResonance which has:

  Basic.Inductor inductor2(i(fixed=true), L=0.1/(2*pi))
...
  Basic.Capacitor capacitor2(v(fixed=true), C=0.001/(2*pi))

Using pi in that way can cause unit-issues (the goal is that SI.Frequency f0=1/(2*pi*sqrt(L*C)); corresponds to the 100Hz resonance frequency), but to me the solution is to update the calculations in some way instead of just viewing pi as having the empty unit in general.

Similarly for Modelica.Electrical.Analog.Examples.CauerLowPassAnalog that didn't/doesn't have pi, but had similar odd computations:

  parameter SI.Inductance l1=1.304 "Filter coefficient I1";
  ...
  parameter SI.Capacitance c2=1/(1.704992^2*l1)

@HansOlsson
Copy link
Copy Markdown
Contributor

HansOlsson commented Apr 22, 2026

I'm firmly in the camp that pi should have unit="1", which was the original change made. I had thought that the plan was to revert to that once the implied unit issues throughout the library were resolved.

Yes, and it is more than 2 years since #4191 was merged with that hope, and it's a pity that we haven't progressed further.

Updated: missed negation.

@henrikt-ma
Copy link
Copy Markdown
Contributor Author

Basic.Inductor inductor2(i(fixed=true), L=0.1/(2pi))
...
Basic.Capacitor capacitor2(v(fixed=true), C=0.001/(2
pi))

Let's try the obvious:

  SI.Inductance L = 0.1'H' / (2 * pi);
  SI.Capacitance C = 0.001'F' / (2 * pi);
  SI.Frequency f0 = 1 / (2 * pi * sqrt(L * C));

You can have any power of "rad" in the unit of pi here; it will just cancel out in the unit of the f0 binding. That is, "1" is just as good as "rad" when it comes to these equations.

However, the effect of setting unit "1" for pi, as opposed to having empty unit, is primarily that any expression including a factor of pi can no longer be an empty unit expression. It will force the entire expression to suddenly have a consistent concrete unit. There can be many reasons for enforcing unit checking of an expression, but including a factor of π should not be one of them. For expressions where there already are units, the unit "1" or empty unit will make no difference.

@henrikt-ma
Copy link
Copy Markdown
Contributor Author

henrikt-ma commented Apr 22, 2026

I'm firmly in the camp that pi should have unit="1", which was the original change made. I had thought that the plan was to revert to that once the implied unit issues throughout the library were resolved.

Since then, I think we have developed a better idea for how units of constants should behave. The idea is that a constant with empty unit shall behave just like a numeric literal; there should be just as little "wild-card effect" when using the factor pi as when using the factor 3.14. An important part of the design is that the unit of a constant should only be determined as the unit of its binding expression (note that all constants must have a binding expression, so the constants can be sorted and unit-checked one after another); when the binding expression has empty unit, the constant gets the empty unit too, and will not get a unit inferred from how the constant is being used.

@AHaumer
Copy link
Copy Markdown
Contributor

AHaumer commented Apr 22, 2026

Just my 5 cent:

  SI.Inductance L = 0.1'H' / (2 * pi);
  SI.Capacitance C = 0.001'F' / (2 * pi);

This is a misleading formulation - I would avoid that.

  Basic.Inductor inductor2(i(fixed=true), L=0.1/(2*pi));
  Basic.Capacitor capacitor2(v(fixed=true), C=0.001/(2*pi));

This is really a bad example, frequency is missing. it should read as:

  parameter SI.Frequency f=1;
  Basic.Inductor inductor2(i(fixed=true), L=0.1/(2*pi*f));
  Basic.Capacitor capacitor2(v(fixed=true), C=0.001/(2*pi*f));

@henrikt-ma
Copy link
Copy Markdown
Contributor Author

Just my 5 cent:

Your input is appreciated.

This is really a bad example, frequency is missing. it should read as:

  parameter SI.Frequency f=1;
  Basic.Inductor inductor2(i(fixed=true), L=0.1/(2*pi*f));
  Basic.Capacitor capacitor2(v(fixed=true), C=0.001/(2*pi*f));

That won't work out of the box since regardless of what of the unit alternatives we pick for pi, the f turns the expressions into unit business, and then the entire bindings need to have unit consistent with the modified components.

Anyway, I can see that 2 * pi * f looks like it is meant to be angular frequency, so it would be neat if it would have the unit "rad/s" and not just "1/s". However, in my mind the 2 * pi stands for "2π radians", and the introduction of the radian factor is not clearly seen in the expression. Since a syntax for attaching the unit "rad" to pi on the fly is not on the table at the moment (in System Modeler we would do it with the cumbersome operator form withUnit(pi, "rad")), this brings me back to using a more clear constant (trying a different name than rev this time):

final constant SI.Angle two_pi_rad = 2 * pi "Angle corresponding to 1 revolution";

So, two_pi_rad * f would clearly be an angular frequency, and unless we want to introduce more factors in the expressions, we end up with this to make units consistent:

L = 0.1'H.rad/s' / (two_pi_rad * f)

That looks strange to me, but maybe it somehow makes sense to you?

@mestinso
Copy link
Copy Markdown
Collaborator

ok, I'll bite.

So, looking at these recent examples, I want to rewind slightly to an upstream equation here that is connected to the equation that has been discussed.

So for inductors we have
$V = L \frac{dI}{dt}$
By all measures, this is dimensionally consistent, no explanation needed.

But now, for sinusoidal current, we can derive the relationship for inductive reactive:
$X_l = \omega L$
I won't show the derivation, but take note that in the process, we differentiated a sine function (we'll come back to this).

Looking at the units, and if we take units for angle seriously, we have
$[X_l] = \ohm$
$[L] = \ohm s$
$[\omega] = rad/s$

But wait, this apparently isn't dimensionally consistent anymore (Assuming we care about the angle units). What happened? Where did this $rad$ come from, and why isn't it cancelling out?

Following the logic in this article: https://iopscience.iop.org/article/10.1088/1681-7575/ac7bc2
... the answer is that the full equation for inductive reactance is actually
$X_l = C \omega L$
where $C$ has units and shows up when we differentiate a sine function. $C$ is unity but with units equal to $1/[rad]$. Additionally, this is actually fully generic for any angle measurements, and radians aren't special except for the fact that radians give a unity correction.
for frequency
$X_l = C f L$ and $C = 2 \pi / [Hz s]$
for degrees
$X_l = C \omega_{deg} L$ and $C = 2 \pi / 360 [deg]$

So we can see that we are dimensionally correct again (regardless of angle choice).

To conclude, you can see that it's not $\pi$ that we need to stick units on. Rather, it's that the equation itself has this $C$ term that shows up when we differentiate a sine or cosine function. This is not rigorously included 99.9% of the time. But if you follow the derivation and logic, you can see it resolves any angle unit inconsistencies.

Now, of course, every equation with angle units has a different story and way angle units are balanced out, but this is the story for this one.

@HansOlsson
Copy link
Copy Markdown
Contributor

This is really a bad example, frequency is missing. it should read as:

  parameter SI.Frequency f=1;
  Basic.Inductor inductor2(i(fixed=true), L=0.1/(2*pi*f));
  Basic.Capacitor capacitor2(v(fixed=true), C=0.001/(2*pi*f));

As noted above it is more that $f=1/(2\cdot\pi\cdot\sqrt{L \cdot C})$, so $(L 2 \pi)\cdot(C 2 \pi)=1/f^2$ or $C=1/f^2/(L 2 \pi)/(2 \pi)$.

There's clearly one degree of freedom here, i.e,, as long as the product of L and C stays the same it doesn't matter for the frequency. Whether that freedom is just used for setting L, C, or the ratio between them just depends.

If we use the square root of the ratio as the degree of freedom the formula is (unless I made some mistake):

  parameter SI.Frequency f=100 "As in problem description";
  parameter SI.Resistance R=10 "Not a real resistance or?";
  Basic.Inductor inductor2(i(fixed=true), L=R/(2*pi*f));
  Basic.Capacitor capacitor2(v(fixed=true), C=1/(R*2*pi*f));

Nice symmetry - I would say.
The problems are that it takes some effort to find it; and I'm not sure if it is better for users.

And as far as I understand we have understood that radians are useful in formulas (and pi sort of has that unit), but technically is the same as unit "1"; so we want to allow Area=pi*radius^2, but detect errors for Area=pi*radius and Area=pi .

@HansOlsson
Copy link
Copy Markdown
Contributor

For example, the following is expected to be allowed if pi has empty unit, but not if it has unit "rad":

Modelica.Units.SI.Time piTime = Modelica.Constants.pi "π seconds";

Thus, the relevant question is: is allowing that a good thing?

Consider the following model:

model Unnamed
  Real x(unit="1", start=1);
  Real v;
  parameter Modelica.Units.SI.Time timeScale=0.1;
  final parameter Modelica.Units.SI.Time onePeriod=(2*Modelica.Constants.pi*timeScale);
equation 
  der(x)=v/timeScale;
  der(v)=-x/timeScale;
  when time>=onePeriod then
    terminate("1 oscillation");
  end when;
end Unnamed;

(Should likely rewrite in some more advanced way, and have a better unit for x and v.)
And possibly change timeScale to 1.0 - you might have to change the stopTime.

After changing it to 1.0, one could skip the time-scale in both the equations and in the computation of onePeriod, making it look similar to piTime - but to me the unit handling is intended to find both that it was missing in the equations and in the computations of onePeriod. I'm fully aware that there are simplified models that fail that (cp. the original Modelica.Media.Examples.IdealGasH2O). That is not related to pi, but to people caring more about simplicity than about unit-consistency.

Note that I deliberately introduced it as timeScale - not TimeUnit; as it isn't intended to add a unit-factor "s" - but to correspond to an actual time-scale (or with a clearer name that captures the 2*pi part).

@casella
Copy link
Copy Markdown
Contributor

casella commented Apr 23, 2026

I'll repeat here what I already posted somewhere else in similar form, but can't find right now. Apologies for any duplicate content and for the long post.

1. Definition of pi

According to Wikipedia and to any mathematics textbook I know of, $\pi$ is defined as the ratio of a circle's circumference to its diameter. Both the circumference and its diameter are undoubtedly lengths. Whatever unit they are measured with, the ratio of two lengths is a nondimensional quantity in per unit. Hence, IMHO the unit of $\pi$ should be "1".

Unfortunately, this is far from settling the matter, see below.

2 The unit Entscheidungsproblem

I may be mistaken, but I am afraid that with units in Modelica 3.8 we are repeating David Hilbert's mistake. Hilbert (one of the greatest mathematicians of all time, mind you) had a grand plan to completely formalize mathematics. In particular, he argued that the Entscheidungsproblem could be solved mechanically, by an algorithm. Until Alonso Church and Alan Turing proved this was not possible. I'm of course not even remotely as smart as Church or Turing, but I'd like to try doing the same in this context 😅

My fundamental argument is that, when considering physical equations, context matters. Unfortunately, context is not completely formalized: a Modelica compiler does not understand what equations actually mean and where they come from. This is a big deal.

2.1 An example problem, which formalizes requirements on dimensional consistency checking

Consider the following Modelica code. It contains some basic equations from mechanics, which are correct and thus also dimensionally consistent, as well as some equations which are not dimensionally consistent, so they are for sure wrong and ought to be rejected by a unit-conscious compiler.

Some equations are redundant, but that's not an issue here, nor is the variability of the variables (constants vs. parameters vs. time-varying variables). The only thing we care about in this model is the dimensional consistency of the equations, not their solvability.

model Examples
  constant Real pi =  3.141592653589793;
  Real D(unit = "m") "Diameter of the wheel";
  Real p(unit = "m") "Perimeter of the wheel";
  Real r(unit = "m") "Radius of the wheel";
  Real phi(unit = "rad") "Rotation angle of the wheel";
  Real phi_t(unit = "rad") "Target rotation angle of the wheel";
  Real w(unit = "rad/s") "Angular velocity of the wheel";
  Real T(unit = "s") "Period of rotation of the wheel";
  Real f(unit = "Hz") "Frequency of rotation of the wheel";
  Real L(unit = "m") "Distance travelled by the wheel";
  Real v(unit = "m/s") "Translational velocity of the wheel";
  Real J(unit = "kg.m2") "Moment of inertia of the wheel";
  Real M(unit = "kg") "Mass of the wheel";
  Real tau(unit = "N.m") "Torque applied to the wheel";
  Real E(unit = "J") "Mechanical energy of the wheel";
  Real P(unit = "W") "Power applied to the wheel";
  Real pi;
equation
  // Dimensionally consistent equations, should be accepted
  der(phi) = omega;  // (1)
  der(phi) = 2*pi*f ;  // (2)
  der(L) = pi*D*f;  // (3)
  J*der(w) = tau; // (4)
  der(E) = P;  // (5)
  p = pi*D;  // (6)
  p = 2*pi*R;  // (7)
  D = 2*r;  // (8)
  f = 1/T;  // (9)
  L = phi*r;  // (10)
  E = J*omega^2/2 + M*v^2/2; // (11)
  P = omega*tau; // (12)
  phi_t = pi; // (13)

  // Dimensionally inconsistent equations, should be rejected
  der(phi) = 2*pi*f^2; // (14)
  p = pi*D^2;  // (15)
  p = 2*pi*R^2;  // (16)
  D = 2*r^2;  // (17)
  f = 1/T^2;  // (18)
  L = phi*r^2;  // (19)
  der(E) = omega;  // (20)
end Examples;

Whatever decision we take on the unit of $\pi$ and on how we handle units in Modelica in the future, my requirement as a modeller is that equations (1)-(13) should be accepted, since that is what any first-year engineering student would write, straight out of a physics textbook, whereas equations (14)-(20) should be rejected, because they are dimensionally inconsistent and thus they are for certain wrong.

I assume we can all agree about this requirement. If not, then I would suggest to discuss this matter separatly and settle it down first, because that's a pre-requisite for any further discussion.

2.2 What is the unit of $\pi$?

In this ticket, I read arguments in favour of:

  1. constant Real pi = 3.141592653589793 "unitless";
  2. constant Real pi(unit = "1") = 3.141592653589793 "dimensionless, per-unit";
  3. constant Real pi(unit = "rad") = 3.141592653589793 "pi is a flat angle, so radians";

As I understand, unfortunately none of these choices is acceptable, because each one leads to bad consequences.

  • If we choose 1., then pi becomes a wildcard, so (15) will not be rejected. As to (16), it will not be rejected as well, though this issue compounds with the status of literal constants MCP-0027 Units of Literal Constants ModelicaSpecification#2127, which is still not settled.
  • If we choose 2., (13) will be rejected, because the LHS has unit "rad" and the RHS has unit "1"
  • If we choose 3., (10) will be rejected, because the LHS has unit "m" and the RHS has unit "rad.m"

The crucial point here is that there is no single choice of units for $\pi$ that can make both (10) and (13) unit-consistent. Please let that sink in. There's nothing wrong with equations (10) and (13): one is basic kinematics and another one is just setting a threshold angle to $\pi$. Unfortunately, deciding about their correctness is only possible if you consider what these equations mean. That information is not included in the unit strings. Maybe it's a good job for AI, if you are willing to accept the occasional hallucination (I don't, for the record).

The only way out of this quagmire that I can see is to consider both "rad" and "1" as dimensionless units, so they are effectively equivalent when doing dimensional consistency checks, not unit checking. If we do so, then both 2. and 3. ar acceptable, though I'm slightly in favour of 2. because of how $\pi$ is defined. 1. remains unacceptable because it allows clearly invalid equations to be accepted.

2.3 Is it possible to automatically decide whether a Modelica equation is dimensionally consistent or not?

As far as I understand, by looking at my Examples above, this is indeed possible, but only if:

  • we consider "rad" and "1", as well as "Hz" and "s-1", as interchangeable
  • we define $\pi$ to either have unit "1" or "rad"
  • we find a means to make sure that the factor 2 is considered as a non-dimensional factor, not as a wildcard

2.4 Is it possible to automatically decide whether a Modelica equation is unit-consistent?

This task is trickier than just determining dimensional consistency. Consider this example

model Examples2
  Real Ltot(unit = "m") "Total length";
  Real L1(unit = "m") "Length of first part";
  Real alpha(unit ="1") "Fraction of part to total, in p.u.";
  Real beta(unit = "%") "Fraction of part to total in p.u.";
equation
  L = alpha*Ltot; // (1)
  L = beta*Ltot // (2)
end Examples2;

Equation (1) is correct, and in fact has units "m" and "m.1" = "m" on both sides, whereas equation (2) is wrong, and in fact it has unit "m" on the LHS and unit "m.%" on the RHS, so there is a factor 100 missing to make it unit consistent. Note, however, that also (2) is dimensionally consistent.

Now, what I determined before is that in order to fulfill my requirements on Example, you need to forgo the difference between "rad" and "1", which are both non-dimensional but differ by a factor $\pi$. So, in general, automatically finding if the proper factors are in place (or performing unit conversions automatically if they don't) doesn't seem to me something that can always be done. At least when quantities involving rotation and angles are involved.

As far as I understand, this fundamentally undermines the possibility of general, rigorous and automatic unit-checking and automatic unit conversions in Modelica.

3. Summary

I'm afraid I don't have the time and the compentences to get into the details of unit checking algorithms. My contribution to the whole unit discussion, as a modeller, is to provide the Examples model as a litmus test. My requirement is that the first batch of equation should be accepted, and the second rejected. I hope there's agreement on that, I will open a separate ticket to formalize this in the Modelica Specification issue tracker, where it belongs.

To my understanding, if that requirement is fulfilled:

  • it is only possible do perform dimensional consistency checking, not unit checking, in general.
  • whether the unit of Modelica.Constants.pi is "rad" or "1" doesn't really matter, as both are dimensionless units.

My 2 cts 😃

@HansOlsson
Copy link
Copy Markdown
Contributor

3. Summary

I'm afraid I don't have the time and the compentences to get into the details of unit checking algorithms. My contribution to the whole unit discussion, as a modeller, is to provide the Examples model as a litmus test. My requirement is that the first batch of equation should be accepted, and the second rejected. I hope there's agreement on that, I will open a separate ticket to formalize this in the Modelica Specification issue tracker, where it belongs.

Good. One could add p = 2*pi; // (16B)

To my understanding, if that requirement is fulfilled:

  • it is only possible do perform dimensional consistency checking, not unit checking, in general.
  • whether the unit of Modelica.Constants.pi is "rad" or "1" doesn't really matter, as both are dimensionless units.

My 2 cts 😃

Agreed, so the unit-checking has to sort of accept that "rad" and "1" can be mixed, but still try to differentiate between them when possible.

@AHaumer
Copy link
Copy Markdown
Contributor

AHaumer commented Apr 23, 2026

I totally agree with @casella looking at his chapter 2.3, tht's what I meant.

@AHaumer
Copy link
Copy Markdown
Contributor

AHaumer commented Apr 23, 2026

The problem of removing "rad" that I see for the usage in drives:
The rotational speed n is given in "1/s" (or even rev/s).
The angular velocity w is given in "rad/s".
w and n both stand for the same effect: rotation, but you have to know "which unit".
Easy to convert: w = 2pin; Therefore pi has the unit "rad" (and I keep in mind that "rad" is equivalent to "1").
I told my students: In Modelica internally we use w in rad/s, but for humans it's easier to deal with n in 1/s.
With w is easier to calculate speed of a rolling wheel: v = rw; (not using 2pi*n).

@henrikt-ma
Copy link
Copy Markdown
Contributor Author

henrikt-ma commented Apr 23, 2026

No! This is what I made very clear above: Our design work for unit consistency has converged to a good design long time ago:

  • Literals, having "empty unit", are not acting as multiplicative wildcards in equations; they "decay to unit 1".
  • Constants may also have "empty unit", enabling us to use a constant named pi instead of writing 3.1415926535897931 everywhere.
  • Do not mistake the "empty unit" for being the state of a unit which has yet to be inferred!

Yes, there are remaining topics in Modelica unit consistency which are still being debated, but I have a very clear picture of the handling of constants not being one of them.

Regarding

  phi_t = pi; // (13)

we have too much legacy to be able to reject

  phi_t = 3.14;

so therefore (13) will also be accepted when pi has empty unit.

I don't see what this has to do with the unit of pi:

  L = phi*r;  // (10)

However I just want to point out that, as @mestinso explained in #4774 (comment), this sort of relation may actually be missing a hidden factor with unit, and because of the widespread use of sloppy relations like this we end up being forced to make the radian an alias for the unit 1.

Also remember that when comparing to other literature on units, there may be no distinction between a numeric value and a "value of quantity" with unit 1. In Modelica this distinction is important, since we have a long tradition relying on the so-called empty unit expressions being accepted where the unit 1 would be wrong. For example,

Real p(unit = "m") = 6.28; // OK
Real p(unit = "m") = 6.28'1'; // Inconsistent

Hence, adequate support for also working without units is important in Modelica, and forcing the user to just throw units away is not adequate support. Failure to stay in the unitless world should be rejected in the same way as unit inconsistency is rejected. If the MSL provides a pi that cannot be used in empty unit expressions, then I am afraid that other libraries will define their own pi which they can use just like a numeric literal.

I just can't see the big point of rejecting

Real p(unit = "m") = 2 * pi;  // (16B)

and forcing the user to use a literal instead:

Real p(unit = "m") = 2 * 3.14;

@mestinso
Copy link
Copy Markdown
Collaborator

It seems there are two separate discussion points here:

  1. Units of pi --> still think "1" is the right choice..
  2. Assigning with literals. This issue seems to be beyond just pi. What if I want to define a length that has the numeric number equal to the speed of light? Isn't this the same situation?
    Let's take that case (to not conflate with the first issue):

In dymola i see the following:

Real p(unit = "m") = c; // option 1: this gives unit warnings (seems reasonable)
Real p(unit = "m") = 1*c; // option 2: this is ok (seems reasonable, 1 has an implied conversion)
Real p(unit = "m") = 1.0*c; // option 3: this is ok (seems reasonable, 1.0 has an implied conversion)

Why don't we have the same logic for pi? Give it unit="1" and the same way out if we want to set the length equal to pi?

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.

5 participants