- Index
- » Usage and Applications
- » OpenModelica Usage and Applications
- » External function returning C struct
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.
- sjoelund.se
- 1700 Posts
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.
- sjoelund.se
- 1700 Posts
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
- Index
- » Usage and Applications
- » OpenModelica Usage and Applications
- » External function returning C struct