MATLAB: Problem passing large array between matlab and mex function

fortranlarge arraymex

[EDIT: 20110523 19:35 CDT – reformat – WDR]
On 64-bit Windows 7 and 64-bit matlab, I have the following problem. When I pass a 2D array of type single (float32) and size (43500, 29200) from matlab to a mex function, only the first 196458176 values are passed to the mex function correctly. The same problem occurred when I passed a 2D array of type single and size (43500, 29200) from the mex function to matlab. The mex function is written in Fortran and the code was compiled by the Intel 64 Fortran compiler XE version 12.0.4.196 Build 20110427.
I can send you the Fortran code (io_64bit.f) for the mex function. I test the mex function by the following script:
nC = 43500;
nR = 29200;
din = ones(nC, nR, 'single');
[dout1, dout2] = io_64bit(din);
sdin = sum(sum( int32(din) ));
sdout1 = sum(sum( int32(dout1) ));
sdout2 = sum(sum( int32(dout2) ));
If all goes well, sdout1 = sdin = – sdout2 = 1270200000 (= nC * nR)
Following is the Fortran code:
c***********************************************************************
c
c Check fidelity of large array passed from Matlab to mex function
c and vice versa.
c
c [dout1, dout2] = io_64bit(din)
c
c***********************************************************************
c
c Original: 18 May 2011 Final: 18 May 2011
c
c***********************************************************************
subroutine mexFunction(nlhs, plhs, nrhs, prhs)
implicit none
integer*4 nlhs, nrhs
c <-----------------------------------------------------------------
c For 32-bit OS, change following to integer*4
c --------------------------------------------
integer*8 plhs(*), prhs(*)
integer*8 mxGetCell, mxGetM, mxGetN, mxGetPr
integer*8 mxGetNumberOfElements, mxClassIDFromClassName
integer*8 mxCreateNumericArray, mxCreateNumericMatrix
integer*8 mxIsInt8, mxIsInt32, mxIsSingle
integer*8 mexPrintf
integer*8 nCol, nRow, din_p, dout1_p, dout2_p
integer*8 n, ClassID, ComplexFlag
c ----------------------------------------------------------------->
character (len = 48) eMsg
integer i, iStatus
real xmin, xmax
real, allocatable :: din(:,:)
logical, parameter :: lDebug = .true.
c ------------------------------------------------------------------
if(nrhs /= 1) call mexerrmsgtxt('1 input argument is required')
if(nlhs /= 2) call mexerrmsgtxt('2 outputs are produced')
nCol = mxGetM(prhs(1))
nRow = mxGetN(prhs(1))
n = mxGetNumberOfElements(prhs(1))
if(lDebug) then
open(1,file='mex_io.log',status='unknown')
write(1,*) nCol, nRow, n
endif
if(n /= nCol*nRow) then
call mexErrMsgTxt('Cannot determine size of 2D array dem')
endif
c -------------------------------- Check inputs are of correct types
eMsg = 'Argument x must be of type single / float32'
do i=1, 1
if(mxIsSingle(prhs(i)) == 0) then
write(eMsg(10:10),'(i1)') i
call mexErrMsgTxt(eMsg)
endif
enddo
c -------------------------------- Allocate memory and setup pointer
allocate(din(nCol,nRow),stat=iStatus)
call check_allocation(iStatus, 'din')
din = 0.0
if(lDebug) write(1,*) 'Done memory allocation'
din_p = mxGetPr(prhs(1))
if(lDebug) write(1,*) 'Done pointer ', din_p
c -------------------------------------------- Copy data from Matlab
call mxCopyPtrToReal4(din_p, din, n)
if(lDebug) then
write(1,*) 'Done copy ptr to real'
call minmax(n, din, xmin, xmax)
write(1,*) xmin, xmax
endif
c ------------------------------ Create output matrix of type single
ClassID = mxClassIDFromClassName('single')
ComplexFlag = 0
plhs(1) = mxCreateNumericMatrix(nCol, nRow, ClassID, ComplexFlag)
plhs(2) = mxCreateNumericMatrix(nCol, nRow, ClassID, ComplexFlag)
dout1_p = mxGetPr(plhs(1))
dout2_p = mxGetPr(plhs(2))
if(lDebug) then
write(1,*) ClassID
close(1)
endif
c -------------------------------------------- Copy data 1 to Matlab
call mxCopyReal4ToPtr(din, dout1_p, n)
c -------------------------------------------- Copy data 2 to Matlab
din = -1.0
call mxCopyReal4ToPtr(din, dout2_p, n)
deallocate(din)
return
end subroutine mexFunction
c
c=======================================================================
c
subroutine minmax(n, x, xmin, xmax)
integer*8 n
real xmin, xmax, x(n)
integer i, ix, m
xmin = huge(xmin)
xmax = -xmin
m = 0
do i=1, n
xmin = min(xmin, x(i))
xmax = max(xmax, x(i))
if(x(i) /= 0.0) ix = i
if(x(i) == 0.0) m = m + 1
enddo
c ------------------------------------------------------------------
c ix = no of values passed from Matlab correctly
c
c m = no of no-values from Matlab
c
c (n - m) should = ix
c
c ------------------------------------------------------------------
write(1,*) ix, m, n - m
return
end subroutine minmax
c
c=======================================================================
c
subroutine check_allocation(iStatus, name)
integer iStatus
character*(*) name
if(iStatus /= 0) then
call mexErrMsgTxt('Cannot allocate memory for array '//name)
stop
endif
return
end subroutine check_allocation

Best Answer

Your FORTRAN code is missing:
#include "fintrf.h"
At the beginning of the file. This header is needed when using -largeArrayDims because it it responsible for switching which mx* functions are called. See the standard mex documentation and this solution be sure to read the faq that is linked to at the end of solution. The last section of the text faq has useful FORTRAN information.