Error Returning Modelica Record from External C Function - c

I have written a C dll function that I want to call from Modelica, and want it to return a Modelica record.
Based upon the data mapping described in the "Modelica by Example" book, I defined a structure in my C header and my function returns a pointer to the structure. You can see the header contents below:
#ifdef NZ1MAP_EXPORTS
#define NZ1MAP_API __declspec(dllexport)
#else
#define NZ1MAP_API __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C" {
#endif
// Define struct to match the SpeedlineVectors record in Modelica.
typedef struct
{
double Mach;
double PRVposition;
double DiffuserGap;
double Theta[24];
double Omega[24];
double MapEfficiency[24];
double OmegaStall[24];
} SpeedlineVectors;
NZ1MAP_API SpeedlineVectors* GetNZ1SpeedlineVectors_External(double Mach, double DiffuserGapFraction);
#ifdef __cplusplus
}
#endif
In Dymola, I created the record below:
record SpeedlineVectors
"Mach, PRV position, Diffuser Gap, and Vectors of Theta, Omega, Map Efficiency, Omega Stall"
Real Mach "impeller machine Mach";
Real PRVposition "PRV position, 0 = fully closed, 1 = fully open";
Real DiffuserGap
"Diffuser gap, 0 = fully closed, 1 = fully open, typical minimum = 0.05";
Real Theta[24] "vector of non-dimensional flow coefficients along speed line";
Real Omega[24] "vector of non-dimensional head coefficients along speed line";
Real MapEfficiency[24]
"vector of isentropic efficiency normalized to tip Reynolds number of 1E6 along speed line";
Real OmegaStall[24]
"vector of non-dimensional head where stall is expected to begin along speed line";
end SpeedlineVectors;
And I created the function that should call the external C dll and return a "SpeedlineVectors" record:
function GetNZ1SpeedlineVectors_External
"Get NZ1 speedline array from external C function"
input Real operatingMach "Machine Mach number";
input Real diffuserGapFraction "Diffuser gap open fraction, 0 to 1";
output SpeedlineVectors speedlineVectors "speedlineVectors record";
external "C" speedlineVectors = GetNZ1SpeedlineVectors_External(operatingMach, diffuserGapFraction);
annotation(Include="#include <NZ1Map.h>", Library="NZ1Map");
end GetNZ1SpeedlineVectors_External;
I built the simple test model below:
model GetNZ1SpeedlineVectors_Tester
Real mach = 1.32;
Real diffuserGapFraction = 0.50;
SpeedlineVectors myVectors;
equation
myVectors = GetNZ1SpeedlineVectors_External(mach, diffuserGapFraction);
annotation (Icon(coordinateSystem(preserveAspectRatio=false)), Diagram(
coordinateSystem(preserveAspectRatio=false)));
end GetNZ1SpeedlineVectors_Tester;
When I try to run the test model, I receive the following error messages from Dymola:
Compiling and linking the model (Visual C++).
dsmodel.c
dsmodel.c(74) : error C2440: '=' : cannot convert from 'SpeedlineVectors *' to 'DymStruc0'
Error generating Dymosim.
I also tried adjusting the C function return so that it returns the struct directly rather than a pointer to the struct, but I receive a similar error message:
dsmodel.c(74) : error C2440: '=' : cannot convert from 'SpeedlineVectors' to 'DymStruc0'
Any tips on what must be done to return a Modelica record from an external C function?
Thanks,
Justin

According to the Modelica specification section 12.9.1.3 arrays in a record cannot be mapped when returned from an external function. You could also try using the ExternalObject: https://build.openmodelica.org/Documentation/ModelicaReference.Classes.ExternalObject.html

As a workaround for my case, I was able to solve the problem by changing the external function. Instead of returning the arrays in a struct that is mapped to a record (thanks to Shaga for pointing out that this is not supported per the modelica specification), the function was changed to return void with four output arrays.
The new function definition in the C header is:
NZ1MAP_API void GetNZ1SpeedlineVectors_External(double Mach, double DiffuserGapFraction, double ThetaVector[], size_t SizeOfThetaVector, double OmegaVector[], size_t SizeOfOmegaVector, double MapEfficiencyVector[], size_t SizeOfMapEfficiencyVector, double OmegaStallVector[], size_t SizeOfOmegaStallVector);
The C function definition in the C file is:
NZ1MAP_API void GetNZ1SpeedlineVectors_External(double Mach, double DiffuserGapFraction,
double thetaVector[], size_t thetaVectorSize, // thetaVector[] is equivalent to double* thetaVector
double omegaVector[], size_t omegaVectorSize,
double efficiencyVector[], size_t efficiencyVectorSize,
double omegaStallVector[], size_t omegaStallVectorSize)
The modelica function is shown below:
function GetNZ1SpeedlineVectors_External
"Get NZ1 speedline array from external C function"
input Real operatingMach "Machine Mach number";
input Real diffuserGapFraction "Diffuser gap open fraction, 0 to 1";
output Real ThetaVector[24]
"vector of non-dimensional flow coefficients along speedline";
output Real OmegaVector[24]
"vector of non-dimensional head coefficients along speedline";
output Real MapEfficiencyVector[24]
"vector of non-dimensional map efficiency along speedline";
output Real OmegaStallVector[24] "vector of omega stall along speedline";
external "C" GetNZ1SpeedlineVectors_External(operatingMach, diffuserGapFraction, ThetaVector, size(ThetaVector,1), OmegaVector, size(OmegaVector,1), MapEfficiencyVector, size(MapEfficiencyVector,1), OmegaStallVector, size(OmegaStallVector, 1));
annotation(Include = "#include <NZ1Map.h>", Library="NZ1Map");
end GetNZ1SpeedlineVectors_External;
And a test model that calls the modelica function is:
model NZ1_External "NZ1 External Dll"
extends SpeedlineVectorsBase;
parameter Real inputMach = 1.4;
parameter Real inputDiffuserGapFraction = 1;
equation
Mach = inputMach;
PRVposition = 1;
DiffuserGapFraction = inputDiffuserGapFraction;
(ThetaVector, OmegaVector, MapEfficiencyVector, OmegaStallVector) =
GetNZ1SpeedlineVectors_External(Mach, DiffuserGapFraction);
end NZ1_External;
I hope this helps someone else see how they can return multiple arrays from an external function to modelica, since modelica will not map arrays returned as part of a struct.
Thanks,
Justin

You can hide the multiple arrays from the users of the Modelica function, by having hierarchical names in the external function call.
function GetNZ1SpeedlineVectors_External
input Real operatingMach "Machine Mach number";
input Real diffuserGapFraction "Diffuser gap open fraction, 0 to 1";
output SpeedlineVectors speedlineVectors "speedlineVectors record";
external "C" GetNZ1SpeedlineVectors_External(operatingMach,diffuserGapFraction, speedLineVectors.ThetaVector, size(speedLineVectors.ThetaVector,1), ...);
annotation(Include="#include <NZ1Map.h>", Library="NZ1Map");
end GetNZ1SpeedlineVectors_External;
This is a new feature added in Modelica 3.3 Revision 1, https://trac.modelica.org/Modelica/ticket/351
and should be available since Dymola 2015.

Related

C file not instrumented for coverage, bad expr node kind

I am using the legacy_code tool in MATLAB, to generate some S Functions, then I want the S Functions to be under analysis by the simulink coverage toolbox.
I am asking also here because maybe this is a C issue and not MATLAB related.
I am setting to true the flag to use the coverage toolbox when generating the S functions using the legacy_code tool.
def.Options.supportCoverage = true;
But I get the following error at compilation, I am using the MinGW 64 bits compiler for MATLAB in windows.
“lib_control.c", line 254: error: bad expr node kind (b:\matlab\polyspace\src\shared\cxx_front_end_kernel\edg\src\cp_gen_be.c, line 14084)
Warning: File "lib_control.c" not instrumented for coverage because of previous error
In codeinstrum.internal.LCInstrumenter/instrumentAllFiles
In codeinstrum.internal.SFcnInstrumenter/instrument
In slcovmexImpl
In slcovmex (line 48)
In legacycode.LCT/compile
In legacycode.LCT.legacyCodeImpl
In legacy_code (line 101)
In generate_sfun (line 70)
In the C code I have the following kind of functions:
void controller( int n_var,
double my_input,
double my_output )
{
double my_var[n_var];
for ( int i=0; i<n_var; i++ )
{
my_output = my_input + my_var[i];
}
}
The compiler is complaining about this line:
double my_var[n_var];
Do I have to do something to declare variables like this, so they can be included in the coverage analysis?
Is this error from MATLAB or is it a C error for instrumentation of files?
If I compile without the coverage flag there is no problems and the S Functions is generated without warnings.
Seems your code won't work because of issues.
First try to declare my_var like this
double *my_var = malloc(n_var * sizeof(double));
memset(my_var, 0, n_var * sizeof(double));
This is the correct way to allocate memory according to function parameter.
And there is also an issue.
my_output = my_input + my_var[i];
So it is correct solution.
*my_output = *my_input + my_var[i];
You are going to change value of parameter which is stack register variable
In C language, parameters are saved in to stack register so it will be freed after function ends.
so it won't reflect any changes
To do this, you need to send pointer of variable as parameter
void controller( int n_var,
double *my_input,
double *my_output ) {
*my_output = ....; // like this
}
and in caller side, you can do like this.
double a, b;
controller(10, &a, &b);
Hope this helps you

Create shared parameter file for C and Python

I need to create a parameter file that can be managed across a Python 3.7 and a C code base. This file needs to be modifiable either by the C or the Python program with the changes being taking effect on the other software (an update function will handle reading the updated file). It's best if the file is not human readable, as it contains information that is better left obfuscated.
**Is there a recommended method to do so? **
I could create separate python and C files, but the set of parameters will change over time (for code maintenance), and the values would be changed by these programs. The list would also be very long. It would be a hassle to maintain two different files and update them over time. Also, the file may need to be exchanged between users, such that a version modified by the software ran by user1 needs to be readable by the software run by user2. The idea is that other parts of both codes could access parts of the parameter list without knowing the full contents of the list.
To clarify the example, I could have a parameter.h file containing:
struct {
double par1 =1.1;
int par 2 =2;
} par_list
And I could have a parameter.py with:
class par_list:
def(__self__):
self.par1 = double(1.1)
self.par2 = int(2)
Then, by doing a import in Python or a include in C, I could initialize the parameter list. But in this case the parameters are being read on different files.
I'm considering using some kind of binary file to keep the values, and create a script that writes both the Python and C code that reads and updates the values. I'm concerned because the binary file would need to be interchangeable between ARM architecture running Linux, and x86 architecture running Windows.
Here is an example working with numpy:
C code:
#include <stdio.h>
#include <stdint.h>
struct Struct_format{
uint8_t the_unsigned_int8;
int32_t the_signed_int32[2];
double the_double;
};
typedef struct Struct_format upperStruct;
//Use separate file to define default value:
void printStruct(upperStruct test_struct){
printf("test_struct.the_unsigned_int8 = %d\n", test_struct.the_unsigned_int8);
printf("test_struct.the_signed_int32[0] = %d\n", test_struct.the_signed_int32[0]);
printf("test_struct.the_signed_int32[1] = %d\n", test_struct.the_signed_int32[1]);
printf("test_struct.the_double = %f\n", test_struct.the_double);
}
void main(){
//Define a "default" value:
upperStruct fromC2Python = {4U,{-3,-1},2.1};
printf("Printing fromC2Python\n");
printStruct(fromC2Python);
//Save this default in a file:
FILE * fid = fopen("fromC2Python.bin","w");
fwrite((void *)&fromC2Python, sizeof(fromC2Python) ,1, fid);
fclose(fid);
//Now load the file created by Python:
upperStruct fromPython2C;
FILE * fid_py = fopen("fromPython2C.bin","r");
fread(&fromPython2C, sizeof(fromPython2C) ,1, fid_py);
fclose(fid_py);
printf("Printing fromPython2C\n");
printStruct(fromPython2C);
}
Python code:
import numpy
datatype = numpy.dtype([('potato',
[('time', numpy.uint8),
('sec', numpy.int32, 2)]),
('temp', numpy.float64)],
align=True)
fromPython2C = numpy.array([((5, (-6, -7)), 61.55)], dtype=datatype)
print(fromPython2C)
fromPython2C.tofile("fromPython2C.bin", sep="")
fromC2Python = numpy.fromfile("fromC2Python.bin", dtype=datatype, count=-1, sep="")
print(fromC2Python)
print(fromC2Python['potato'])
print(fromC2Python['potato']['time'])
print(fromC2Python['temp'])
The ideia is that numpy allows reading and writing to structured binary files. Hence, it suffices to create the dtype specification with a text parser.

How to solve "bad pointer in write barrier" panic in cgo when C library uses opaque struct pointers

I'm currently writing a Go wrapper around a C library. That C library uses opaque struct pointers to hide information across the interface. However, the underlying implementation stores size_t values in there. This leads to runtime errors in the resulting program.
A minimum working example to reproduce the problem looks like this:
main.go:
package main
/*
#include "stddef.h"
// Create an opaque type to hide the details of the underlying data structure.
typedef struct HandlePrivate *Handle;
// In reality, the implementation uses a type derived from size_t for the Handle.
Handle getInvalidPointer() {
size_t actualHandle = 1;
return (Handle) actualHandle;
}
*/
import "C"
// Create a temporary slice containing invalid pointers.
// The idea is that the local variable slice can be garbage collected at the end of the function call.
// When the slice is scanned for linked objects, the GC comes across the invalid pointers.
func getTempSlice() {
slice := make([]C.Handle, 1000000)
for i, _ := range slice {
slice[i] = C.getInvalidPointer()
}
}
func main() {
getTempSlice()
}
Running this program will lead to the following error
runtime: writebarrierptr *0xc42006c000 = 0x1
fatal error: bad pointer in write barrier
[...stack trace omitted...]
Note that the errors disappear when the GC is disabled by setting the environment variable GOGC=off.
My question is which is the best way to solve or work around this problem. The library stores integer values in pointers for the sake of information hiding and this seems to confuse the GC. For obvious reasons I don't want to start messing with the library itself but rather absorb this behaviour in my wrapping layer.
My environment is Ubuntu 16.04, with gcc 5.4.0 and Go 1.9.2.
Documentation of cgo
I can reproduce the error for go1.8.5 and go1.9.2. I cannot reproduce the error for tip: devel +f01b928 Sat Nov 11 06:17:48 2017 +0000 (effectively go1.10alpha).
// Create a temporary slice containing invalid pointers.
// The idea is that the local variable slice can be garbage collected at the end of the function call.
// When the slice is scanned for linked objects, the GC comes across the invalid pointers.
A Go mantra is do not ignore errors. However, you seem to assume that that the GC will gracefully ignore errors. The GC should complain loudly (go1.8.5 and go1.9.2). At worst, with undefined behavior that may vary from release to release, the GC may appear to ignore errors (go devel).
The Go compiler sees a pointer and the Go runtime GC expects a valid pointer.
// go tool cgo
// type _Ctype_Handle *_Ctype_struct_HandlePrivate
// var handle _Ctype_Handle
var handle C.Handle
// main._Ctype_Handle <nil> 0x0
fmt.Fprintf(os.Stderr, "%[1]T %[1]v %[1]p\n", handle)
slice := make([]C.Handle, 1000000)
for i, _ := range slice {
slice[i] = C.getInvalidPointer()
}
Use type uintptr. For example,
package main
import "unsafe"
/*
#include "stddef.h"
// Create an opaque type to hide the details of the underlying data structure.
typedef struct HandlePrivate *Handle;
// In reality, the implementation uses a type derived from size_t for the Handle.
Handle getInvalidPointer() {
size_t actualHandle = 1;
return (Handle) actualHandle;
}
*/
import "C"
// Create a temporary slice of C pointers as Go integer type uintptr.
func getTempSlice() {
slice := make([]uintptr, 1000000)
for i, _ := range slice {
slice[i] = uintptr(unsafe.Pointer(C.getInvalidPointer()))
}
}
func main() {
getTempSlice()
}

.C() returns me an empty list

I'm a beginner in R and I'm trying to load a .dll file, named dll.dll, that's written in C, into R. It seems to work, now I want to use the functions that are stored in the .dll file and I encounter problems.
I've searched for a solution or other method in manuals, here and on google. Would be very thankful if I could get a suggestion of what to use or any idea!
My code:
setwd("C:/Users/MyUser/R")
dyn.load("dll.dll")
is.loaded("DLL_FUNK")
# For some reason True with capital letters, not in lower case
output <- .C("DLL_FUNK", in9 = as.integer(7))
#output # R Crashes before I can write this.
# R Crashes
# In outdata.txt: "in-value= 139375128"
The function should return a number, 1955. But I can't seem to get to that value. What am I doing wrong?
Update with code (Fortran runned as C), this is the code in dll.dll:
subroutine dll_funk(in9)
implicit none
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
!*** Declarations: variables, functions
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
integer(4) :: in9
!integer :: in9
! Definitions of variables in the external function calls
!!dec$ attributes c,alias :'dll_funk' :: dll_funk
!dec$ attributes dllexport :: dll_funk
!dec$ attributes value :: in9
open(194,file='outdata.txt')
write(194,*) 'in-value=', in9
! in9 = 1955
close(194)
end subroutine
!end function
So now when it runs, R crashes but before it writes to my file (outdata.txt) but it't not my number, maybe some kind of address...
Another question, do you recommend me to run the code with .C and from C run the Fortran code or is it better to run it with .Fortran with only Fortran code?
It seems like .Fortran have problem handling strings, or that's what I understood from: Interface func .C and .Fortran
Why did not you pass any arguments to your C function dll_function? When you use .C(), you have to pass function arguments as a list. .C() will return modified list. So, If you pass in nothing, you get nothing.
What does your C function dll_function looks like? Note that:
dll_function must be a void C function, with no return values. If this function should return something, it must return by modifying function arguments;
all function arguments of dll_function must be pointers.
Follow-up
The dll_function is only to test if I can get access to it.
You can use is.loaded() after dyn.load() to test whether you have access to the C function:
dyn.load("dll.dll")
is.loaded("dll_function") ## TRUE
Note that, is.loaded takes C function name, while dyn.load() takes .dll name. In general you can have multiple functions in a single .dll file. You can use is.loaded() to check either of them, to test whether shared library has been loaded successfully.
So if I want it to return something, I should give it an argument (of same type?)?
Yes. The other answer here does give a toy example. You can have a look at this answer I made half a month ago. At the bottom there is a summary of variable type.
When using .C, the extra arguments passed to .C are copied and passed on as pointers to the called c-function. This function can then modify the data pointer to by the pointers. The return value of the function is ignored by .C. So, you c-function should look something like:
void dll_function(int* result) {
/* Do some complicated computation that results in 1955 */
(*result) = 1955;
}
And your call from R:
.C("dll_function", integer(1))
An example with input (this calculates the sum of an integer vector; this example assumes that there are no missing values in vector):
void dll_function2(int* result, int* vector, int* length) {
int sum = 0;
for (int i = 0; i < (*length); ++i, ++vector) {
sum += (*vector)
}
(*result) = sum;
}
Called from R:
x <- c(1000, 900, 55)
.C("dll_function2", integer(1), as.integer(x), length(x))[[1]]

Using a custom memory allocation function in R

I would like to be able to use my own memory allocation function for certain data structures (real valued vectors and arrays) in R. The reason for this is that I need my data to be 64bit aligned and I would like to use the numa library for having control over which memory node is used (I'm working on compute nodes with four 12-core AMD Opteron 6174 CPUs).
Now I have two functions for allocating and freeing memory: numa_alloc_onnode and numa_free (courtesy of this thread). I'm using R version 3.1.1, so I have access to the function allocVector3 (src/main/memory.c), which seems to me as the intended way of adding a custom memory allocator. I also found the struct R_allocator in src/include/R_ext
However it is not clear to me how to put these pieces together. Let's say, in R, I want the result res of an evaluation such as
res <- Y - mean(Y)
to be saved in a memory area allocated with my own function, how would I do this? Can I integrate allocVector3 directly at the R level? I assume I have to go through the R-C interface. As far as I know, I cannot just return a pointer to the allocated area, but have to pass the result as an argument. So in R I call something like
n <- length(Y)
res <- numeric(length=1)
.Call("R_allocate_using_myalloc", n, res)
res <- Y - mean(Y)
and in C
#include <R.h>
#include <Rinternals.h>
#include <numa.h>
SEXP R_allocate_using_myalloc(SEXP R_n, SEXP R_res){
PROTECT(R_n = coerceVector(R_n, INTSXP));
PROTECT(R_res = coerceVector(R_res, REALSXP));
int *restrict n = INTEGER(R_n);
R_allocator_t myAllocator;
myAllocator.mem_alloc = numa_alloc_onnode;
myAllocator.mem_free = numa_free;
myAllocator.res = NULL;
myAllocator.data = ???;
R_res = allocVector3(REALSXP, n, myAllocator);
UNPROTECT(2);
}
Unfortunately I cannot get beyond a variable has incomplete type 'R_allocator_t' compilation error (I had to remove the .data line since I have no clue as to what I should put there). Does any of the above code make sense? Is there an easier way of achieving what I want to? It seems a bit odd to have to allocate a small vector in R and the change its location in C just to be able to both control the memory allocation and have the vector available in R...
I'm trying to avoid using Rcpp, as I'm modifying a fairly large package and do not want to convert all C calls and thought that mixing different C interfaces could perform sub-optimally.
Any help is greatly appreciated.
I made some progress in solving my problem and I would like to share in case anyone else encounters a similar situation. Thanks to Kevin for his comment. I was missing the include statement he mentions. Unfortunately this was only one among many problems.
dyn.load("myAlloc.so")
size <- 3e9
myBigmat <- .Call("myAllocC", size)
print(object.size(myBigmat), units = "auto")
rm(myBigmat)
#include <R.h>
#include <Rinternals.h>
#include <R_ext/Rallocators.h>
#include <numa.h>
typedef struct allocator_data {
size_t size;
} allocator_data;
void* my_alloc(R_allocator_t *allocator, size_t size) {
((allocator_data*)allocator->data)->size = size;
return (void*) numa_alloc_local(size);
}
void my_free(R_allocator_t *allocator, void * addr) {
size_t size = ((allocator_data*)allocator->data)->size;
numa_free(addr, size);
}
SEXP myAllocC(SEXP a) {
allocator_data* my_allocator_data = malloc(sizeof(allocator_data));
my_allocator_data->size = 0;
R_allocator_t* my_allocator = malloc(sizeof(R_allocator_t));
my_allocator->mem_alloc = &my_alloc;
my_allocator->mem_free = &my_free;
my_allocator->res = NULL;
my_allocator->data = my_allocator_data;
R_xlen_t n = asReal(a);
SEXP result = PROTECT(allocVector3(REALSXP, n, my_allocator));
UNPROTECT(1);
return result;
}
For compiling the c code, I use R CMD SHLIB -std=c99 -L/usr/lib64 -lnuma myAlloc.c. As far as I can tell, this works fine. If anyone has improvements/corrections to offer, I'd be happy to include them.
One requirement from the original question that remains unresolved is the alignment issue. The block of memory returned by numa_alloc_local is correctly aligned, but other fields of the new VECTOR_SEXPREC (eg. the sxpinfo_struct header) push back the start of the data array. Is it somehow possible to align this starting point (the address returned by REAL())?
R has, in memory.c:
main/memory.c
84:#include <R_ext/Rallocators.h> /* for R_allocator_t structure */
so I think you need to include that header as well to get the custom allocator (RInternals.h merely declares it, without defining the struct or including that header)

Resources