C/Fortran callback to MATLAB

18 visualizaciones (últimos 30 días)
A.B.
A.B. el 14 de Sept. de 2019
Comentada: A.B. el 16 de Abr. de 2020
I have a large library (~100K lines of code) written in modern Fortran, out of which I need to call only one function with the following C-signature,
#include <stdint.h>
void runFoo (
// nd
int32_t *
// getFuncFromMatlab(nd, Point(nd)): procedure pointer to the MATLAB function
, double (*)(int *, double [])
// input character vector
, char []
// the length of the input chracter vector
, size_t *
);
Note that this function contains a callback to MATLAB. In other words, MATLAB calls this function, and this DLL function has to call another function in MATLAB provided by the original calling MATLAB function. I can generate a DLL from this library, and it loads in MATLAB via lodlibrary() with the above C header. However, that is no help, and I believe I am seriously missing some fundamental step to make this callback work. What is the best approach to solve this problem? MATLAB mex file compilation is no help either, as it apprently cannot even understand the syntax of modern Fortran, for example, module keyword. appreciate you help very much.
As a side note, as much as I find MATLAB a great standalone computing tool, I also find it terrible for any interoperation with any other languages. Hope this issue gets fixed. Are there any interoperation capabilities in MATLAB that would be equivalent to the simple, yet extremely powerful ctypes package of Python?
  19 comentarios
Walter Roberson
Walter Roberson el 16 de Abr. de 2020
With regards to /usr/bin :
I find it hard to believe that Apple cannot trust MATLAB. This seems to be more of a corporation rivalry than anything else
Apple cares little what Mathworks thinks. Mathworks is not buying many systems from Apple, and not so many people buy Apple systems specifically to run MATLAB. Mathworks is just another customer of the Developer's Program as far as Apple is concerned.
Apple blew off NVIDIA, which is a $US100B+ company; Mathworks is small potatos by comparison. It isn't a matter of corporate rivalry: Mathworks is too small for Apple to notice. Apple makes decision, and Mathworks just has to live with the decisions.
A.B.
A.B. el 16 de Abr. de 2020
That's fair. Incidentally, do you (or James, now that we ended up on this question,) happen to know how to redirect the stdout from the dylib to the MATLAB command prompt (on macOS)?

Iniciar sesión para comentar.

Respuesta aceptada

James Tursa
James Tursa el 31 de Mzo. de 2020
Maybe this can give you the framework you need. I have made some assumptions about how things are connected. You pass in a char string of the MATLAB function you want called, and the callback function inside the C code calls it using some C native memory as input, simple as that.
The code:
// C = callback_test(fun)
// fun = char string containing the MATLAB function name
// C = the result of the callback
#include "mex.h"
#include <stdlib.h>
#include <stdint.h>
void runFoo (
// nd
int32_t *
// getFuncFromMatlab(nd, Point(nd)): procedure pointer to the MATLAB function
, double (*)(int *, double [])
// input character vector
, char []
// the length of the input chracter vector
, size_t *
);
double callback(int *, double []); // The callback function
char *mname; // MATLAB function name
//-------------------------------------------------------------------------
void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
int32_t n = 7;
char *thestring = "testing123";
size_t len = 10;
if( nrhs && mxIsChar(prhs[0]) ) {
mname = mxArrayToString(prhs[0]);
mexPrintf("MATLAB function = %s\n",mname);
runFoo( &n, callback, thestring, &len );
}
}
//-------------------------------------------------------------------------
void runFoo (
// nd
int32_t *nd
// getFuncFromMatlab(nd, Point(nd)): procedure pointer to the MATLAB function
, double (*getFuncFromMatlab)(int *, double [])
// input character vector
, char str[]
// the length of the input chracter vector
, size_t *len
)
{
int i, ind;
double *d;
double result;
// Generate some fake data using C native memory
d = (double *) malloc( *nd * sizeof(*d) );
for( i=0; i<*nd; i++ ) {
d[i] = (double) (i+1);
}
// Call the callback function
ind = *nd; // Just in case an int32_t is not the same as an int
result = getFuncFromMatlab( &ind, d );
// Print the results
mexPrintf("Result = %g\n",result);
mexPrintf("String passed = ");
for( i=0; i<*len; i++ ) {
mexPrintf("%c",str[i]);
}
mexPrintf("\n");
// Deallocate the C native memory
free(d);
}
//-------------------------------------------------------------------------
double callback(int *nd, double d[])
{
mxArray *rhs[1], *lhs[1];
double *pr;
double result;
int i;
mexPrintf("Inside callback for function %s\n",mname);
// Create the input argument
rhs[0] = mxCreateUninitNumericMatrix( *nd, 1, mxDOUBLE_CLASS, mxREAL );
// Copy the data (need to get C native memory into MATLAB memory)
pr = (double *) mxGetData( rhs[0] );
for( i=0; i<*nd; i++ ) {
*pr++ = *d++;
}
// Make the call
if( mexCallMATLAB( 1, lhs, 1, rhs, mname ) ) {
mexErrMsgTxt("Callback didn't work");
}
result = mxGetScalar( lhs[0] );
// Free the temporary variables
mxDestroyArray( lhs[0] );
mxDestroyArray( rhs[0] );
//Done
return result;
}
And some sample runs:
>> mex callback_test.c
Building with 'Microsoft Visual C++ 2013 (C)'.
MEX completed successfully.
>> callback_test('sum')
MATLAB function = sum
Inside callback for function sum
Result = 28
String passed = testing123
>> callback_test('prod')
MATLAB function = prod
Inside callback for function prod
Result = 5040
String passed = testing123
>> callback_test('sin')
MATLAB function = sin
Inside callback for function sin
Result = 0.841471
String passed = testing123
>> sin(1)
ans =
0.8415
>> callback_test('garbage')
MATLAB function = garbage
Inside callback for function garbage
Error using callback_test
Undefined function 'garbage' for input arguments of type 'double'.
  2 comentarios
James Tursa
James Tursa el 2 de Abr. de 2020
Editada: James Tursa el 2 de Abr. de 2020
Alas, I have never used MPI. One of the things I always intended to learn someday but as yet haven't found the time. How did you include the compiler flag? Are you sure it is getting to the compiler? E.g., are you building the mex routine via the mex command and modifying the $COMPFLAGS stuff, or are you building the mex routine outside of MATLAB?
You also mention the MATLB engine. Are you running the mex routine within a MATLAB Engine? Are you trying to run multiple MATLAB Engines in parallel using MPI?
A.B.
A.B. el 2 de Abr. de 2020
I followed an example on a NASA page that explained how to compile Fortran mex with extra compile flags, so I extrapolated the approach to Intel icc compiler. For example,
mex CC=icc CFLAGS="/IC:\Program Files (x86)\IntelSWTools\parallel_studio_xe_2019.4.066\compilers_and_libraries_2019\windows\mpi\intel64\include" main.c mydll.lib
That did not work though. Based on the examples I have seen on the web, the MPI-parallelism basically requires starting one MATLAB engine per MPI task. On a side note, I do not think MATLAB officially supports MPI parallelism. But there are several external old packages written for this purpose.

Iniciar sesión para comentar.

Más respuestas (1)

Bruno Luong
Bruno Luong el 14 de Sept. de 2019
Editada: Bruno Luong el 14 de Sept. de 2019
Not sure what you mean by "Callback". Callback to me is kind of event trigger function like an SW interruption.
Anyway if you have the compiler, you can compile any MATLAB function in C shared library, and call it from external C program.
I have no idea about FORTRAN, but in the pass I have linked fortran (gcc,g77) with MSVSC/Intel-C, a bit tricky but doable.
  1 comentario
A.B.
A.B. el 14 de Sept. de 2019
Hi Bruno, Thanks, the code being in Fortran is almost irrelevant here, since modern Fortran enabled virtually full interoperation with C, as if you are dealing with C code instead of Fortran. So here is the situation: The user (me) wants to call subroutine Foo() in this Fortran library, which has the above C interface. I have this library's DLL file compiled by the Intel compiler, but apparently that is not enough. So what other methods exist to call this DLL library function from inside MATLAB?
How can I call this function via MATLAB's loadlibrary()? thanks again.

Iniciar sesión para comentar.

Categorías

Más información sobre Write C Functions Callable from MATLAB (MEX Files) en Help Center y File Exchange.

Productos


Versión

R2019a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by