modelica / ModelicaSpecification

Specification of the Modelica Language
https://specification.modelica.org
Creative Commons Attribution Share Alike 4.0 International
102 stars 41 forks source link

Proper handling of discontinuos functions by event generation #1026

Open modelica-trac-importer opened 6 years ago

modelica-trac-importer commented 6 years ago

Reported by fcasella on 13 Mar 2013 22:23 UTC There are cases (e.g. in Modelica.Media) where some functions are known to be discontinuous, potentially causing trouble to the ODE integration algorithms. It would be nice to handle the corresponding zero crossing functions, so that events can be generated, allowing to handle the discontinuity in a clean way.

In Modelica 3.2r2 and 3.3, functions cannot generate events, except when the GenerateEvents = true annotation is set. This is a kind of a hack, because an annotation actually changes the semantics of the model using this function.

A more proper way should be found to handle this case. SimulationX already has some built-in mechanism for this purpose, it could be used as a basis for discussion.


Migrated-From: https://trac.modelica.org/Modelica/ticket/1026

modelica-trac-importer commented 6 years ago

Comment by kurzbach on 26 Mar 2013 14:13 UTC From my point of view, event generating functions are another kind of impure functions (as specified in MLS 3.3) with different properties:

A possible solution for that would need a gobal accessible context, where a stack (a tree which behaves like a stack to have a permanent storage of call contexts) of call contexts (with ids) is explicitely maintained: every call to an event generating function creates a new frame on the stack (if it already exists in the tree, it is reused). At the end of the call, the current frame is removed from the stack (but kept in the tree). With this implementation the restriction would not be necessary, but having global objects is also a serious restriction /source of problems, especially in parallel computing environments. Further discussion is needed.

modelica-trac-importer commented 6 years ago

Comment by fcasella on 26 Mar 2013 19:20 UTC It is not clear to me how pre() etc. could be handled in this context. For example:

function f
  input Real x;
  output Real y;
algoritm
  y := x;
  y := y+3;
  if pre(y) < 4 then y :=6 else y:=2 end if;
end f;

what would be the meaning of pre(y)?

More in general, unless we want to define the semantics in terms of inlining, I think we should specify the crossing functions explicitly, because in general it is not easy (or maybe even theoretically impossible) to tell it from the algorithm. For example:

function g
  input Real x;
  output Real y;
algorithm
  y:=if x>0 then x else -1-x;
  y:=2*x;
  y:=if y<2 then y else 2*y;
end g;

what should be the crossing function in this case?

modelica-trac-importer commented 6 years ago

Comment by otter on 27 Mar 2013 07:43 UTC Replying to [comment:2 fcasella]:

More in general, unless we want to define the semantics in terms of inlining, I think we should specify the crossing functions explicitly, because in general it is not easy (or maybe even theoretically impossible) to tell it from the algorithm. For example:

function g
input Real x;
output Real y;
algorithm
y:=if x>0 then x else -1-x;
y:=2\*x;
y:=if y<2 then y else 2\*y;
end g;

what should be the crossing function in this case?

Defining the crossing function by a modeler is very error prone and will lead to a mess (the compiler can do a much more reliable job). Defining the crossing function in the example above by a tool is similar as in a model (positiveCrossing(..) is a tool-specific function that returns false or true depending on the simulation state; e.g. during continuous integration is always returns the value from the last event instant; at an event instant, it returns crossing![..] > 0 with the actual crossing value).

function g input Real x; input Integer id_crossing[2] // hidden argument introduced by translator output Real y; output Real crossing[2]; // hidden argument introduced by translator algorithm crossing[1] := x; y:=if positiveCrossing(id_crossing[1], crossing[1]) then x else -1-x; y:=2*x; crossing[2] := 2 - y; y:=if positiveCrossing(id_crossing[2], crossing[2]) then y else 2*y; end g;

}}}
modelica-trac-importer commented 6 years ago

Comment by fcasella on 27 Mar 2013 13:00 UTC Replying to [comment:3 otter]:

Defining the crossing function by a modeler is very error prone and will lead to a mess (the compiler can do a much more reliable job).

I agree with the principle, if this is indeed possible

Defining the crossing function in the example above by a tool is similar as in a model (positiveCrossing(..) is a tool-specific function that returns false or true depending on the simulation state; e.g. during continuous integration is always returns the value from the last event instant; at an event instant, it returns crossing![..] > 0 with the actual crossing value).

function g
   input Real x;
   input  Integer id_crossing[2]  // hidden argument introduced by translator 
   output Real y;
   output Real crossing[2];       // hidden argument introduced by translator
algorithm
   crossing[1] := x;
   y:=if positiveCrossing(id_crossing[1], crossing[1]) then x else -1-x;
   y:=2\*x;
   crossing[2] := 2 - y;
   y:=if positiveCrossing(id_crossing[2], crossing[2]) then y else 2\*y;
end g;

As far as I understand, this approach cannot be applied in general. Consider the two following functions:

function h
  input Real x;
  output Real y;
algorithm
  y:=x;
  while abs(y)>1 loop
    y:=if y>10 then y/4 else y/2;
  end while;
end h;

function p
  input Real x;
  input Integer N;
  output Real y;
algorithm
  for i in 1:N loop
    y:=if y>10 then y/4 else y/2;
  end for;
end p;

In both cases, the size of the crossing[] vector can change every time the function is called, and it is even unknown a priori in the case of function h. I understand ODE/DAE solvers with event handling need a fixed number of crossing functions to monitor, which should always be well defined and consistent at each time step - this won't be possible in these cases.

If we want to automatically generate the crossing functions, I guess we need to restrict the algorithm section quite a bit (e.g., no for/while loops).

modelica-trac-importer commented 6 years ago

Comment by kurzbach on 27 Mar 2013 15:15 UTC Replying to [comment:4 fcasella]:

In both cases, the size of the crossing[] vector can change every time the function is called, and it is even unknown a priori in the case of function h. I understand ODE/DAE solvers with event handling need a fixed number of crossing functions to monitor, which should always be well defined and consistent at each time step - this won't be possible in these cases.

I agree.

If we want to automatically generate the crossing functions, I guess we need to restrict the algorithm section quite a bit (e.g., no for/while loops).

And therefore I would not generate any crossing functions inside loops with unknown (during compile time) iteration number, and it should be forbidden to call event generating functions in it. This may change the behavior of such loops in blocks and models, but then it works only ba accident and are not portable. The problem here is, that the change of the iteration number of a loop from a parameter expression to a variable changes the semantics of the whole loop.

modelica-trac-importer commented 6 years ago

Comment by hansolsson on 23 Sep 2013 16:14 UTC Language group: Too much work for 3.3r1.