Archived OpenModelica forums. Posting is disabled.

Alternative forums include GitHub discussions or StackOverflow (make sure to read the Stack Overflow rules; you need to have well-formed questions)


Forgot password? | Forgot username? | Register

External function returning C struct

External function returning C struct

I have a problem with using a struct as a return type for an external fucntion. E.g. none of the following external function calls work:

record Parameters
  Real p1=0,p2=0;
end Parameters;

function twovals
  output Parameters p;
    // external "C" C_initpar(p) annotation(Library="initpar.o");    // doesn't work
    external "C" p = C_initpar() annotation(Library="initpar.o");   // doesn't work either
end twovals;

class DAE05
   Real x(start=0.9);
   Real y;
     parameter Parameters p = twovals();      // call parameter initialization
equation
   der(y)+(1+p.p1*sin(y))*der(x) = sin(time);
    x - y = exp(-p.p2*x)*cos(y);
end DAE05;

...where initpar.c is:


struct Parameters {
    double p1,p2;
};

void C_initpar(struct Parameters *p)
{
    p->p1 = 1.0;  /* actually, will be read from external. */
    p->p2 = 2.0; /* idem */
};

Actually, the omc compiler completely bypasses initpar.c and makes in the flattened modelica the straightaway assignment:

"""
parameter Real p1 = 0.0;
parameter Real p2 = 0.0;
"""

where both values are taken straight away from the default record initialization (?!)

I had it working this way with a modelica array, i.e. Real[2],...; how about using a struct (i.e. the above situation)? Thanks.

-- Henk

Re: External function returning C struct

Are you sure? I get:

Code:

class DAE05

  Real x(start = 0.9);
  Real y;
  parameter Real p.p1 = 1.0;
  parameter Real p.p2 = 2.0;
equation
  der(y) + (1.0 + p.p1 * sin(y)) * der(x) = sin(time);
  x - y = exp((-p.p2) * x) * cos(y);
end DAE05;

Using the first one (since your C-code did not match up to the second one). Make sure you have recompiled your o-file to match the C interface and not using some old file you forgot to recompile.
Or use Library="xxx.c" instead of .o to always recompile the library.

Re: External function returning C struct

sjoelund.se wrote:

Are you sure? I get:

Code:

class DAE05

  Real x(start = 0.9);
  Real y;
  parameter Real p.p1 = 1.0;
  parameter Real p.p2 = 2.0;
equation
  der(y) + (1.0 + p.p1 * sin(y)) * der(x) = sin(time);
  x - y = exp((-p.p2) * x) * cos(y);
end DAE05;

...   

You're right, but it also shows the problem: in this trivial example the external function call (setting values for the Modelica record) is eliminated (parsed out) during the flattening stage (which doesn't happen when the argument is an Real array). My intention is to use a bit less trivial record initialization routine (that shouldn't be flattened out), but the external function call combined with a record argument is systematically parsed out.

I believe the problem may have to do with the fact that in OMC a record is 'systematically' (or not...?!) transformed into a record initialization function; at least that's what I believe when I see the flattened file:

Code:


function Parameters "Automatically generated record constructor for Parameters"  <<<=== a "function"!
  input Real p1 = 0.0;
  input Real p2 = 0.0;
  output Parameters res;
end Parameters;

function twovals                                               <<<=== not used at all!
  output Parameters p;

  external "C" C_initpar(p);
end twovals;

class DAE05
  Real x(start = 0.9);
  Real y;
  parameter Real p.p1 = 0.0;                                      <<<=== result of flattening
  parameter Real p.p2 = 0.0;                                      <<<=== result of flattening
equation
  der(y) + (1.0 + p.p1 * sin(y)) * der(x) = sin(time);
  x - y = exp((-p.p2) * x) * cos(y);
end DAE05;

To state my basic desire briefly: how can I return multiple values from a single external function call (and not, as is the case with arrays, to have multiple indexed calls...)? Thanks.

-- Henk

Re: External function returning C struct

How you keep getting p1=p2=0.0 I do not know (since I get the correct values).

But if you do not want the call evaluated during flattening, you need to tell the compiler that it is impure, because all functions are assumed to be pure.

annotation(__OpenModelica_Impure=true) in the function should do the trick.

Re: External function returning C struct

sjoelund.se wrote:

How you keep getting p1=p2=0.0 I do not know (since I get the correct values).

The correct values you get, are they 'flattened in' (i.e. statically assigned), or the result of a (intended) function call? (my zeros initialization are 'flattened in', i.e. the function call is bypassed/eliminated all together -- it only happens when using as argument to the C-function a modelica record/C-struct, it doesn't happen with a Real[2]).

sjoelund.se wrote:


But if you do not want the call evaluated during flattening, you need to tell the compiler that it is impure, because all functions are assumed to be pure.

annotation(__OpenModelica_Impure=true) in the function should do the trick.

OK, now my code is:

Code:


record Parameters
  Real p1=0,p2=0;
end Parameters;

function twovals "Function with output arguments passed through python;"
  annotation(__OpenModelica_Impure=true);           // <<=== Impure ANNOTATION inserted
  //output Real p[2];
  output Parameters p;
  //external "C" C_twovals_reals(p) annotation(Library="initpar.o");  // arg p is Real[2]
  external "C" C_twovals_struct(p) annotation(Library="initpar.o");   // arg p is record (C-struct)
end twovals;

class DAE05
  Real x(start=0.9);
  Real y;
  //parameter Real[2] p = twovals();
  parameter Parameters p = twovals();                                    // line 17 (where variability error happens)
equation
  //der(y)+(1+p[1]*sin(y))*der(x) = sin(time);
  //x - y = exp(-p[2]*x)*cos(y);
  der(y)+(1+p.p1*sin(y))*der(x) = sin(time);
  x - y = exp(-p.p2*x)*cos(y);
end DAE05;

where initpar.c is:

Code:



/* initpar.c */

void import_twovals()
{

    /* module is loaded only once. */
    printf("Importing twovals module!\n");
    import_twovals_py2c();
};

struct Parameters {
    double p1,p2;
};

void C_twovals_struct(struct Parameters *p)   /* flattened out, doesn't return proper initialization values, i.e p.{p1,p2} stay {0.0,0.0} */
{
    p->p1 = 1.0;
    p->p2 = 2.0;
};

void C_twovals_reals(double p[2])    /* flattened out, yet returns proper initialization values */
{
        p[0] = 1.0;
        p[1] = 2.0;
};

Now I obtain a variability error message:

Code:


omc +s DAE05.mo
Error processing file: DAE05.mo
[DAE05.mo:17:3-17:38:writable] Error: Component p of variability PARAM has binding initpars() of higher variability VAR.

Any idea?

-- Henk

There are 0 guests and 0 other users also viewing this topic
You are here: