Fortran MEX returns only some elements of output array.
Show older comments
Hi all, I'm trying to learn how to write MEX functions using Fortran. I have encountered a couple issues, and the documentation is quite dated (mostly fixed-form Fortran, and predating the current -R2018a API). Many suggestions lead to functions like mxGetPr and mxGetPi which are 'not recommended' in the current API. This goes for all the .F examples in $matlabroot/extern/examples/.
I am on Ubuntu 20.04, Matlab R2019b, gfortran 9.3.0
I have two issues:
- If I declare my arrays as allocatable, and then allocate them, I will hit a segfault or some other instability causing Matlab to lock or crash. The "solution" is to pre-allocate the arrays with some maximum size, and then work with inputs smaller than that hidden limit. It no longer segfaults, but this harms the ability to write a general-purpose array input without adding an arbitrarily large allocation for all arrays. I'm not sure of a way to use `%VAL(A)` with matrix operations -- perhaps `RESHAPE()` into a local variable that is matrix-shaped within the computational subroutine?
- In my minimum-working training example, I just pass array A to a subroutine, and then copy it to B, and return B. Some, but not all of the elements of A are returned in B. The usage in Matlab is B = copyab(A).
The F90 file, 'copyab.F90' (both gateway and computational subroutines)
#include "fintrf.h"
subroutine mexFunction(nlhs, plhs, nrhs, prhs)
implicit none
mwPointer :: plhs(*), prhs(*)
integer :: nlhs, nrhs
mwPointer :: mxGetDoubles
mwPointer :: mxCreateDoubleMatrix
mwPointer :: mxGetM, mxGetN
mwPointer :: A_ptr, B_ptr
mwPointer :: m, n
mwSize :: mn
! Issue here: using allocatable, allocate() causes segfault.
integer, parameter :: maxm = 10
integer, parameter :: maxn = 10
real :: A(maxm,maxn), B(maxm,maxn)
! real, allocatable :: A(:,:), B(:,:)
m = mxGetM(prhs(1))
n = mxGetN(prhs(1))
mn = m * n
! allocate(A(m,n), B(m,n))
! RHS: input args
A_ptr = mxGetDoubles(prhs(1))
call mxCopyPtrToReal8(A_ptr, A, mn)
! LHS: return vals
plhs(1) = mxCreateDoubleMatrix(m, n, 0)
B_ptr = mxGetDoubles(plhs(1))
call copyab(A, B, m, n)
call mxCopyReal8ToPtr(B, B_ptr, mn)
end subroutine mexFunction
subroutine copyab(A, B, m, n)
implicit none
mwSize :: m, n
real :: A(m,n), B(m,n)
B = A
end subroutine copyab
Makefile with compile options:
FC = gfortran
FCFLAGS = -O3 -cpp -fPIC -ffree-form -fdefault-real-8 -fdefault-integer-8 -Wall
MATLABDIR = /usr/local/MATLAB/R2019b
MEX = $(MATLABDIR)/bin/mex
MEXLIBDIR = $(MATLABDIR)/sys/os/glnxa64
MEXLIBS = -lgfortran
MEXINCLUDE = $(MATLABDIR)/extern/include
MEXFLAGS = -R2018a COMPFLAGS='$(FCFLAGS)'
EXT = mexa64
copyab.$(EXT): copyab.F90
$(MEX) $^ $(MEXFLAGS) -output $@ -I$(MEXINCLUDE) -L$(MEXLIBDIR) $(MEXLIBS)
clean:
rm -rf *.$(EXT) *.o *.mod
And the test Matlab code, 'test.m'
A = rand(3,3)
B = copyab(A)
which results in,
>> test
A =
0.8147 0.9134 0.2785
0.9058 0.6324 0.5469
0.1270 0.0975 0.9575
B =
0.8147 0.9134 0.0000
0.9058 0.0000 0.0000
0.1270 0.0000 0.0000
B appears to containg floor(numel(A)/2) correct elements, regardess of the shape of A.
Accepted Answer
More Answers (0)
Categories
Find more on Fortran with MATLAB in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!