Mex/Fortran passing data

Hello,
Is it possible to pass from matlab data labeled as follows and if so what would be the efficient way to do it?
AeroConfig_Hub_position %a (3*1) vector
AeroConfig_Hub_orientation %a (3*3) matrix
AeroConfig_Hub_translationvel %a (3*1)vector
AeroConfig_Hub_rotationvel %a (3*1) vector
through a mex interface that will format them to be read by the fortan code as:
Aeroconfig%Hub%position
Aeroconfig%Hub%orientation
AeroConfig%Hub%rotationvel
AeroConfig%Hub%translationvel
any help is greatly appreciated.

 Accepted Answer

Download this package from the FEX:
Follow the instructions to compile the modules. Then you can do stuff like this:
m-code:
myFortranMexRoutine(AeroConfig_Hub_position,...
AeroConfig_Hub_orientation,...
AeroConfig_Hub_translationvel,...
AeroConfig_Hub_rotationvel);
Fortran code:
#include "fintrf.h"
subroutine mexFunction(nlhs,plhs,nrhs,prhs)
use MatlabAPImx
implicit none
integer nlhs, nrhs
mwPointer plhs(*), prhs(*)
__yourtype__ Aeroconfig
AeroConfig%Hub%position = fpGetPr1(prhs(1))
AeroConfig%Hub%orientation = fpGetPr(prhs(2))
AeroConfig%Hub%translationvel = fpGetPr1(prhs(3))
AeroConfig%Hub%rotationvel = fpGetPr1(prhs(4))
Caution: The above is just an outline with no error checking. In production code you would need to check nrhs and nlhs to see if there are the correct number of inputs & outputs. And you would have to retrieve the data pointers via fpGetPr1 and fpGetPr into separate variables and examine if they are associated prior to using them. Etc.

13 Comments

Chris
Chris on 26 Jun 2012
Hi James,
Thanks for the response. The package will help a lot. I get the following errors using it and wondered if you could tell me what is wrong.:
aerodyngateway.f90(32): error #6404: This name does not have a type, and must have an explicit type. [TURBINECOMPONENTS_HUB_POSITION]
TurbineComponents_Hub_position = fpGetPr1(plhs(1))
^
aerodyngateway.f90(32): error #6366: The shapes of the array expressions do not conform. [TURBINECOMPONENTS_HUB_POSITION]
TurbineComponents_Hub_position = fpGetPr1(plhs(1))
^
Declarations as follows:
TYPE :: Marker
REAL(8) :: Position(3)
REAL(8) :: Orientation(3,3)
REAL(8) :: TranslationVel(3)
REAL(8) :: RotationVel(3)
END TYPE Marker
TYPE :: AeroConfig
TYPE(Marker) :: Hub
END TYPE AeroConfig
Type(AeroConfig) :: TurbineComponents
You are using the MATLAB variable names with underscores on the Fortran side. Use the percent signs (%) as shown above and as shown in your original code to get at the structure components in Fortran. E.g.,
TurbineComponents%Hub%position = fpGetPr1(prhs(1))
TurbineComponents%Hub%orientation = fpGetPr(prhs(2))
TurbineComponents%Hub%translationvel = fpGetPr1(prhs(3))
TurbineComponents%Hub%rotationvel = fpGetPr1(prhs(4))
Chris
Chris on 26 Jun 2012
Thanks James. My mex file is now done correctly but I get the following link problems:
aerodyngateway.obj : error LNK2019: unresolved external symbol MATLABAPIMX_mp_FPGETPR1DOUBLE referenced in function MEXFUNCTION
aerodyngateway.obj : error LNK2019: unresolved external symbol MATLABAPIMX_mp_FPGETPR2DOUBLE referenced in function MEXFUNCTION
aerodyngateway.mexw64 : fatal error LNK1120: 3 unresolved externals
are these due to the modules not being compiled correctly?
Also am I correct in thinking that all I need to change the matlab compile programs to match it with my compiler/VS studio edition is the following :
options = [matlabroot '\bin\win32\mexopts\intelf91msvs2005engmatopts.bat']
You need to include the pre-compiled module object modules in the mex command line. E.g.,
% Do this once to get the module compiled
mex -c MatlabAPImx.f
% Then do this to compile your mex function
mex myFortranMexFunction.f MatlabAPImx.obj
Regarding the mex options, did you use mex -setup to select the compiler?
Chris
Chris on 26 Jun 2012
yes i selected the compiler using mex - setup. It works when I include the .obj. Thanks alot for the help.
A theoretical question: Is there a way to use the derived data types in fortran in a matlab code? So if say matlab calculated each component thats in type aeronconfig ( like hub, blade, tower) with each of those components having position, orientation, translationvel, rotationvel vectors then passed it via mex file to a function in fortran:
%Type(aeroconfig) :: turbinecomponents
%function(turbinecomponents).
So instead of passing each component individually, have it included in one large array that is passed once.
On the MATLAB side you can have a struct with the same component naming convention as on the Fortran side. E.g.,
TurbineComponents.Hub.Position = whatever;
TurbineComponents.Hub.Orientation = whatever;
:
etc.
Then you only have to pass in the one MATLAB struct variable. Inside the mex routine you can use mxGetField to pick off the desired components and then use the fpGetPr1 etc functions on the mxGetField results to get at the data and one-by-one copy them into their Fortran counterparts. There is no magic bullet to do the copying all in one fell swoop ... you have to write the component copying for each individual component since the actual storage of the data in memory is different on both sides.
Another alternative is to have your Fortran user defined data type contain pointers instead of arrays, and then just point them to the incoming MATLAB variable data. Works as long as you treat the input as read-only.
Hi James,
I'm trying to follow your instructions with the struct command. I have TurbineComponents=struct('Hub',hub,'Tower',tower) with hub = struct('position',turbinecomponents.hub.position, 'orientation'...etc)
Is this the correct way for passing the array?
I also get the following errors when trying to compile my mex file and wanted to see if you knew what was wrong:
>> mex aerotest.f90 aerodyntest.obj
aerotest.f90(75): error #5082: Syntax error, found END-OF-STATEMENT when expecting one of: ( % [ . = =>
Two(TurbineComponents,A,B,C,D)
------------------------------------^
aerotest.f90(58): error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. [MXGETARRAY]
TurbineComponents = mxGetArray(turbine_ptr)
--------------------------^
compilation aborted for aerotest.f90 (code 1)
Chris, go ahead and post your m-code snippet for constructing the input and calling the mex routine, and also the mex routine itself and I can look at it.
Ignore the previous code, I think I figured it out and saw how poor the code was.
I'm only having a little trouble understanding how to use the mxGetField. Do you know of any examples of this used with Fortran? The only examples I've seen are with C
mxGetField returns a pointer to an mxArray, which you can then use just like any other pointer to an mxArray. E.g., if on the MATLAB side you did this:
myvar.myfield = 1:3
mymexroutine(myvar)
And if mymexroutine was the Fortran mex routine, then inside this mex routine you could have code like this to get at the data:
use MatlabAPImx
mwPointer mx
mwIndex i
real*8, pointer :: x(:)
i = 1
mx = mxGetField(prhs(1),i,"myfield")
x => fpGetPr1(mx)
The Fortran variable x will point to the 1:3 double data.
Chris
Chris on 4 Jul 2012
Edited: Chris on 4 Jul 2012
Thanks James, so for a nested struct like turbinecomponents.hub.position, I would need to use the mxGetField twice, something like:
use MatlabAPImx
mwPointer mx, dx
mwIndex i
real*8, pointer :: x(:), (y:)
i= 1
mx = mxGetField(prhs(1),i,"Hub")
x = fpGetPr1(mx)
dx = mxGetField(prhs(1),i,"Position")
y = fpGetPr1(dx)

Sign in to comment.

More Answers (0)

Categories

Community Treasure Hunt

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

Start Hunting!