MEX file always crashes when I run it
21 vues (au cours des 30 derniers jours)
Afficher commentaires plus anciens
Clément Carré
le 11 Mai 2022
Commenté : Clément Carré
le 12 Mai 2022
Hello,
I am currently learning to use MEX files, and I browsed the different questions asked here in Mathworks community, that was very helpful I succeeded to make run simple mex files.
However, the main objective for me is to use the following subroutine, which is calling inside itself an other big subroutine. It is about airfoil coordinates.
I took care to have as input single precision arrays and scalar, yet, even if I have the "MEX completed successfully" statement, matlab always crashes when I try to call the function in a matlab script.
PS : the fortran program is working, I have used it several times before.
Any help is highly appreciated,
Clément
The MEX file :
#include "fintrf.h"
C The gateway routine
subroutine mexFunction(nlhs, plhs, nrhs, prhs)
C Declarations
implicit none
C mexFunction arguments:
mwPointer plhs(*), prhs(*)
integer nlhs, nrhs
integer*4, external :: mxIsNumeric
mwPointer, external :: mxGetData
mwPointer, external :: mxCreateNumericMatrix
mwPointer, external :: mxGetNumberOfElements
mwPointer, external :: mxDuplicateArray
mwPointer xr, yr, n
mwPointer xor, yor
mwSize :: one = 1
C Check for proper number of arguments.
if (nrhs .ne. 3) then
call mexErrMsgTxt('Three inputs required.')
elseif (nlhs .ne. 2) then
call mexErrMsgTxt('Two outputs required.')
endif
C Check to see both inputs are numeric.
if (mxIsNumeric(prhs(1)) .ne. 1) then
call mexErrMsgTxt('Input #1 is not a numeric.')
elseif (mxIsNumeric(prhs(2)) .ne. 1) then
call mexErrMsgTxt('Input #2 is not a numeric.')
elseif (mxIsNumeric(prhs(3)) .ne. 1) then
call mexErrMsgTxt('Input #3 is not a numeric.')
endif
C Check that input #3 is a scalar.
if(mxGetNumberOfElements(prhs(3)) /= 1 ) then
call mexErrMsgTxt("Input #3 must be scalar")
endif
C Create matrixes for the return argument.
plhs(1) = mxDuplicateArray(prhs(1))
plhs(2) = mxDuplicateArray(prhs(2))
xr = mxGetData(prhs(1))
yr = mxGetData(prhs(2))
n = mxGetData(prhs(3))
xor = mxGetData(plhs(1))
yor = mxGetData(plhs(2))
C Call the computational subroutine.
call smoothing (%val(xr), %val(yr), %val(n),%val(xor),%val(yor))
return
end
C Computational subroutine
subroutine smoothing(x,y,np,xo,yo)
dimension x(201),y(201)
dimension xu(100),yu(100),xl(100),yl(100)
dimension xo(201),yo(201)
c minimum searching
xmin=x(1)
do 30 i=2,np
if(x(i).lt.x(i-1)) go to 30
xmin=x(i-1)
imin=i-1
go to 31
30 end do
31 continue
c organise coordinates
nu=np-imin+1
nl=imin
ii=1
do i=imin,1,-1
xl(ii)=x(i)
yl(ii)=y(i)
ii=ii+1
end do
ii=1
do i=imin,np
xu(ii)=x(i)
yu(ii)=y(i)
ii=ii+1
end do
call afsmo(nu,nl,xu,yu,xl,yl,x,y)
do i=1,np
xo(i)=x(i)
yo(i)=y(i)
end do
return
end
The matlab script :
X = dataBuffer{1}(:,1); %Boundary points filtered from a .txt file
Y = dataBuffer{1}(:,2); %
np=length(X);
X=single(X);
Y=single(Y);
np=single(np);
mex -R2018a subtest4.f90
[xout,yout] = subtest4(X,Y,np) ;
0 commentaires
Réponse acceptée
James Tursa
le 11 Mai 2022
Modifié(e) : James Tursa
le 11 Mai 2022
In the MATLAB code you have this:
np=single(np);
Then inside the Fortran gateway routine you have this:
mwPointer xr, yr, n
:
n = mxGetData(prhs(3))
So n "points" to a single precision value.
Then you call the smoothing routine with arguments passed by value:
call smoothing (%val(xr), %val(yr), %val(n),%val(xor),%val(yor))
Inside the smoothing routine you have this signature:
subroutine smoothing(x,y,np,xo,yo)
BUT YOU DO NOT DECLARE np!!! So it is just a default integer type, either 4-byte or 8-byte depending on your system and compiler settings. The main point, however, is IT IS NOT A SINGLE PRECISION VARIABLE. So you are interpreting an IEEE single precision floating point bit pattern as an integer and using that downstream. Of course this is going to fail miserably.
I'm being a bit harsh with my UPPERCASE above, but you really need to get in the habit of using IMPLICIT NONE in every single routine in Fortran. You don't get a lot of compiler help in Fortran, particularly for implicit interface routines such as this and with the %val( ) stuff there is going to be no help at all. So use every bit of compiler help you can get. In fact, none of the variables in the smoothing routine are typed and you are relying on the A-H,O-Z real and I-N integer defaults. That practice is old school and should be discouraged. I'm guessing that this is an old routine you picked up from somewhere and are trying to incorporate it into MATLAB. But this can get you into trouble as seen above.
There are a couple of ways to fix this. Either change the MATLAB variable np to be an integer of the same length as n in the smoothing routine (you will have to figure out if it is integer*4 or integer*8, and use either int32 or int64 on the MATLAB side), or create a variable in your mexFunction gateway routine that has the same exact type as n in the smoothing routine and pass that instead. I would suggest the latter method because then your code will not depend on system and compiler settings.
Finally, it is good that you check the prhs and plhs inputs, but your checks are inadequate. They should also check for exact type (single or integer), complexity, sparsity, and number of elements as well. You should be using mxIsSingle, mxIsInt32 or mxIsInt64, mxIsComplex, mxIsSparse, and mxGetNumberOfElements for this.
Not related to your problem is a pet peeve of mine: Comments that are aligned with code are bad! This makes more work for your brain to separate the comments from the code. You should make it easy for your brain to immediately separate the two without any additional effort. E.g., compare this commenting style with yours above:
C\
C Check for proper number of arguments.
C/
if (nrhs .ne. 3) then
call mexErrMsgTxt('Three inputs required.')
elseif (nlhs .ne. 2) then
call mexErrMsgTxt('Two outputs required.')
endif
C\
C Check to see both inputs are numeric.
C/
if (mxIsNumeric(prhs(1)) .ne. 1) then
call mexErrMsgTxt('Input #1 is not a numeric.')
elseif (mxIsNumeric(prhs(2)) .ne. 1) then
call mexErrMsgTxt('Input #2 is not a numeric.')
elseif (mxIsNumeric(prhs(3)) .ne. 1) then
call mexErrMsgTxt('Input #3 is not a numeric.')
endif
C\
C Check that input #3 is a scalar.
C/
if(mxGetNumberOfElements(prhs(3)) /= 1 ) then
call mexErrMsgTxt("Input #3 must be scalar")
endif
IMO this is much easier to read. Your brain doesn't have to work hard at all to see which is code and which is comments.
Plus de réponses (0)
Voir également
Catégories
En savoir plus sur Write C Functions Callable from MATLAB (MEX Files) dans Help Center et File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!