Message Boards Message Boards

GROUPS:

Why can't a parameter be used to set the unit-attribute?

Posted 2 months ago
647 Views
|
11 Replies
|
5 Total Likes
|

Hi everybody,

The following minimal example does compile without any problems in WSM 4.3 and 5.1. But it will cause an error in WSM 12.0 all of a sudden:

model UnitErrorModel
  MyComponent c( hasUnit = "myUnit" );

  block MyComponent
    parameter String hasUnit = "1";
    output Real y( unit = hasUnit );
  equation
    y = 10;
  end MyComponent;

end UnitErrorModel;

So the global model will have a component c that modifies a parameter hasUnit which is used by the component to set the unit-attribute of its output y.

In Mathematica [12.0.0 for Microsoft Windows (64-bit) (April 6, 2019)] I observe this:

model = Import[ "UnitErrorModel.mo" ];
SystemModelSimulate[ model, { 0, 10 } ]

SystemModelSimulate::bldl

Internal error: Codegen.getValueString: Non-constant expression:c.hasUnit

What has changed in WSM that this is causing an error? Why can't a parameter (note, that making the modification final will not resolve the issue) be used to set the unit-attribute - after all it is known at runtime when compiling the model?

Best regards, Guido

Note: I cross-posted an extended question on StackOverflow.

Background: I am developing a library for (acausal) System Dynamics modeling. Since SD is very low level (e.g. stocks and flows) working with “hard-wired” SI-units is not helpful for modeling managerial or economical problems. Yet, unit checking is very useful and widely embraced in the SD community. Thus, having a flexible way to use parameters to assign units to output (and input) connectors wouldmbe very helpful; this is also how most dedicated SD tools go about it.

11 Replies

While I still cannot find a parameter to be in violation with Modelica specifications (it would be the natural thing to handle this and it has worked so far in WSM and still works in Dymola), changing the declaration for hasUnit from parameter to constant solves the issue!

That at least means, that my library can be rescued with minimal effort ... ;)

Guido

You are correct in that it's not in violation with the specification, although making it a constant makes more sense since you would invalidate all your static unit checking if you are allowed to change the unit after building the simulation. We filed an issue on the specification regarding this (https://github.com/modelica/ModelicaSpecification/issues/2362).

Otto

In case you are not aware of it constants wont be visible in the GUI by default, but you can make them visible with the dialog annotation:

model Foo
  constant Real hiddenConstant;
  constant Real visibleConstant annotation(Dialog(group = "GroupName"));
end Foo;

It's also available in the "Add ..." dialog: Add constant dialog

Hello Otto,

Thank you very much for your helpful advice. I was aware of the dialog annotation, but not that it can be nicely accessed via menu.

I still am not totally convinced about constants being better than parameters for units: Modelica allows to have parametric structure, e.g. a component (and its connections) can be turned on or off by a parameter. If you allow the structure of a component to be open to parametric variability wouldn’t by necessity also the units for that components output be having parametric variability?

Having unit checking in place for “apples & oranges” as in SD is imo not always easy - to make this work out quite generally for components is still something I have pushed back with a lower priority. To me components can be build robustly so that indeed the compliance to unit checking is so static that it can be included in the documentation for components. In the end we would simply have to check inputs matching the necessary prerequisites on the level of predefined components?

Guido

Edit: The last paragraph is misleading without explanation: Defining a component we may recourse to using abstract units (e.g. “widgets” or “widgets per model time period”). So unit checking could be done one some abstract level (e.g. replace widgets with oranges and continue from there). So the unit checking needed may be done in Mathematica eventually using pattern matching features.

A constant is a parameter that cannot be changed after translation. That is exactly the behaviour in your unit scenario and "parametric structure" scenario. In my opinion it would be better to actually use the constant construct in those scenarios to better communicate what is expected to happen instead of having the compiler force evaluation of the parameter (and there by effectively transform it to a constant).

Otto

Otto,

There is something to your arguments and I am a bit unused (still) to thinking about before and after compilation - not being a software engineer myself... ;-)

To reframe what your are saying, let us simply assume, that I have an exectuable instance of a model and the user can enter a value that is used when the simulation is actually started. On the screen I would have to tell the user an "instance before his entry", that he is supposed to give say a rate in days, weeks, or months - because this is how the model is set up to calculate in the formulas. So, in Modelica lingo the time base of the model (i.e. the unit of time) would have to be of constant variability (e.g. set before the model is made an executable) and the entry of the user would be of parametric variability. Right?

Note: The other option (@Jan Brugard - as with time zones ;-) ) would be to have everything converted to some standard e.g. SI-units like seconds in the case of time. This being very unusual for SD ... I have not done it (yet).

Now, I am still confused about the following code (which is used at the top level of every model I set up with my library):

inner parameter TimeBases modelTimeBase = TimeBases.years "The model's time base";
inner constant String modelTimeBaseUnit = BusinessSimulation.Constants.timeBaseUnits[modelTimeBase];
inner parameter Time dt(unit = modelTimeBaseUnit) = 1 / 16 "Smallest possible interval of time for compatibility with conventional fixed-step System Dynamics models";

I am having an enumeration TimeBases (seconds, minutes, hours, ... ) which is used to choose the unit of time for the model (which then nicely works as a drop down menu). Even though the String modelTimeBaseUnit above is stated to be a constant, it seems to "inherit" the parametric variability of modelTimeBase.

In short: The above use of modelTimeBaseUnit to set the unit attribute inside the lower level components of models does cause an error also.

So, change the above variables to be constants? (or better stick to SI-units with scaling?)

Guido

PS:

Constants and parameters are very similar, but also have some differences (Section 3.11.2, page 99). Parameters are typically much more common in application models. When in doubt whether to use constant or parameter, use parameter, except when declaring a constant in a package/ library where constant is allowed but not parameter.

Fritzson, Peter. Principles of Object-Oriented Modeling and Simulation with Modelica 3.3: A Cyber-Physical Approach (Kindle-Positionen1795-1799). Wiley. Kindle-Version.

When in doubt ... After thinking about what you have written, I still believe that the user may well choose time and the unit of time as a parameter given a compiled model.

Most Modelica tools support resimulating a model without recompilation after changing a parameter, which usually makes the time waiting for results much shorter.

Fritzson, Peter. Principles of Object-Oriented Modeling and Simulation with Modelica 3.3: A Cyber-Physical Approach (Kindle-Positionen1785-1786). Wiley. Kindle-Version.

Everything in that model could be made to act upon that parametric choice (as with all other parameters also). Chosing the unit of time for giving rates could (and maybe should) well be a parameter of a model (the choice of time scale could be passed onto other components as an inner parameter). While I cannot simply "rescale" apples to be oranges, I can well do so for any unit of time. Where is the fault in my thinking?

To reframe what your are saying, let us simply assume, that I have an exectuable instance of a model and the user can enter a value that is used when the simulation is actually started. On the screen I would have to tell the user an "instance before his entry", that he is supposed to give say a rate in days, weeks, or months - because this is how the model is set up to calculate in the formulas. So, in Modelica lingo the time base of the model (i.e. the unit of time) would have to be of constant variability (e.g. set before the model is made an executable) and the entry of the user would be of parametric variability. Right?

Yes.

Note: The other option (@Jan Brugard - as with time zones ;-) ) would be to have everything converted to some standard e.g. SI-units like seconds in the case of time. This being very unusual for SD ... I have not done it (yet).

That would be my suggestion and preference, some of the advantages are:

  • You avoid one source for misstakes.
  • Your library has a higher chance of being interoperable with other libraries (since everything is modeled in the same units).

Now, I am still confused about the following code (which is used at the top level of every model I set up with my library): ...

I don't really know how you use that, but doesn't it gets confusing since the simulation time unit in Modelica is always in seconds so when plotting results they will be presented in seconds?

To me it would make more sense to do all modelling in a standard unit and then making things like the model time base simply a display issue, does that fit your use case or am I missing something?

So what functionality are you missing to achieve that, a user selectable displayUnit for time (probably per model) is one thing I guess. What else do you need?

Otto

Hello Otto,

Thank you for those clarifying statements, they are quite helpful. I will start working with WSM next week again after a short break, but I agree with what you pointed out in general about having units of time allways converted (internally) into seconds and then make us of displayUnit.

At first glance these questions pop up for me:

  1. Could you point out how one can add custom conversions (e.g. if needed to convert from and to Non-SI-Units like days, months, weeks, quarters, years) and how theses are used in drop down menues for input?
  2. Will there be numerical issues arising with a model running with very large units of time (e.g. years in seconds)? If yes, how can this be handled (e.g. how to make use of the nominal attribute maybe)?
  3. Will working with the attribute displayUnit for model base time have similar issues as unit (e.g. parametric variability vs. constant variability)?

Guido

PS: Regarding the use of a constant, which is then given the Dialog annotation to make it editable, instead of a parameter: Would having the Evaluate = True annotation be another option to the same effect?

Hi Otto,

to make this post complete, I will try to answer what I have found out til now and wrap this discussion up:

  1. Custom conversions can be found under Tools>Options>Global>Unit Conversions (the documentation could be optimized in this regard since you will not easily find a hint there looking for "conversion").

    A slight glitch with adding conversions for Non-SI-units: If you want to enter a conversion from "weeks" to "seconds", System Modeler will automatically discover the conversion from "seconds" to "weeks" and only allow updating the existing conversion. Unfortunately, the software will not make use of that conversion though, so that if you have entered a conversion from "seconds" to "weeks" this will preclude a way to have "weeks" as the standard unit of default and then go to "seconds" using displayUnit. (For unit conversions we should only have to define a diagonal in the conversion matrix and then have the matrix filled automatically using reciprocal factors).

    Another thing, not so easily solved, is the fact that for rates we would need (?) a different conversion factor for each possible rate if we allow Non-SI-units for stocks in economic models: e.g. have adifferent conversion factor for apples/s and oranges/s to apples/yr and oranges/yr?

  2. Numerical issues - still waiting for some advice how far a modeler has to think about such things...

  3. displayUnit is usually changed in drop down menus (e.g. in the Simulation Center while choosing vars for display, in the Parameter-Windows within the Modeling Center). This is quite often fine and all one needs. I would still be interested in a way to programmatically override drow-down choices: Will using final achieve this?

In the end, everything would maybe be fine using seconds if System Modeler would allow what OpenModelica allows: Changing the displayUnit for Simulation Time. Unfortunately, I am not aware of any convenience in this regard. There is to my knowledge no way to nicely adjust display of time in the diagrams from "seconds" to say "years", is there?

So, without that convenience we may still try to use Non-SI-Units using type and replaceable somehow. But that is another question I posted here. UPDATE: Note, that I just now expaned that post demonstrating, that it appears that we cannot use a constant expression with the inner prefix (e.g. inner constant String GlobalUnitOfTime = "yr" ) as this also will give errors during compilation.

Guido

Posted 1 month ago

Hi Guido,

  1. I agree that the interaction between search and how the documentation is organised isn't optimal. However, if you search for unit conversions, the first hit in SystemModeler Documentation is Model Center -- VariableViews which is the page that documents custom unit conversions.

I cannot reproduce (or understand your issue), it's only necessary to add the conversion s - week, the display unit system will reverse that relation if you have something in weeks and wants it displayed in s. What it won't do is give you the option to convert to for example days (it doesn't do any multi step conversions so even though it can convert a-b and b-c it cannot convert a-c).

  1. It all depends on the dynamics of your model, but if you are simulating for years I assume you arn't dealing with very fast dynamics. We have customers that simulates for decades (in seconds) without problems. Time (as well as all other Real variables) are calculated using doubles (and stored as such by default) that have about 16 decimal digits, so you can represent quite small time steps even thousand years in the future.

  2. Do you mean that you want to prevent the user from changing the displayUnit, in say SimulationCenter? I guess that semantically final should have that effect, but we for sure do not implement that. I don't see the use case for preventing changing it in SimulationCenter. However, in ModelCenter it will prevent users of the class to change the displayUnit in the next version of SystemModeler (12.0 still allows you to change it).

In the end, everything would maybe be fine using seconds if System Modeler would allow what OpenModelica allows: Changing the displayUnit for Simulation Time. Unfortunately, I am not aware of any convenience in this regard. There is to my knowledge no way to nicely adjust display of time in the diagrams from "seconds" to say "years", is there?

That is for sure something we want to support, probably in different ways:

  1. Global setting
  2. Per model by using an annotation
  3. Selectable per experiment in SimulationCenter.

Otto

Hi Otto,

I completely agree with what you are saying.

What I meant is the use of conversions for a different choice of basic unit. So you cannot have:

Real myTime( quantity = "Time", unit = "yr", displayUnit = "mo")

... if you have defined a cumstom conversion for mo → yr somewhere. But once you allow to go into a non-SI-Unit as base unit, you imo need to be able to define the full matrix? (Coming from Mathematica with arbitrary precision arithmetic I, of course, would rather define a conversion from the larger unit to the smaller so that I may use integers or rational numbers and then make use of these exact fractions automatically for the reverse conversion. But it will probably not matter here.)

I am fine with seconds as base unit if you come up with the support for displayUnit as you have indicated.

Guido

PS: What about rates?

PPS: Regarding the final attribute. I have come to avoid it a bit. For example, if I redeclare the type for the output of a component (e.g. maybe to control unit, displayUnit or simply to switch from a Real to Boolean to build a different model using a generic class), then that output will be hidden in the default settings of the Simulation Center which filters these vars).

Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract