Nathaniel
2011-10-13 18:49:27 UTC
I recently came across this example on how to allocate arrays in Fortran. Up until I've been hard-coding the dimensions, which is works fine except when you want to change them. The example below works on a 64-bit windows machine with 2010a repeatedly, it works once on a 64-bit windows machine with 2011a (MATLAB freezes without an error message on the second execution) and it does not work at all on a 32-bit windows machine with 2011a (MATLAB crashes with generic Windows "program has stopped working" message, not freezes). It is my understanding that allocate should work with mex. I wonder, is this a bug in 2011a?
This is the script I run:
********************************************************************\
mex xf_allocatable_5D.F
x = rand(5,5,5,5,10);
y = xf_allocatable_5D(x);
********************************************************************
This is the Fortran code:
********************************************************************
#include "fintrf.h"
C ALLOCATABLE arrays are Fortran's version of malloc/free or new/delete.
C Copyright 1984-2010 MathWorks, Inc.
C $Revision: 1.1.6.1 $
module work_array
mwSize, dimension(:), allocatable :: m
real*8, dimension(:,:,:,:,:), allocatable :: x
real*8, dimension(:,:,:,:,:), allocatable :: y
end module
subroutine timestwo()
use work_array
implicit none
mwSize i,j,k,l,p
C
do i = 1,m(1)
do j = 1,m(2)
do k = 1,m(3)
do l = 1,m(4)
do p = 1,m(5)
y(i,j,k,l,p) = 2.0 * x(i,j,k,l,p)
end do
end do
end do
end do
end do
return
end
subroutine mexFunction(nlhs, plhs, nrhs, prhs)
use work_array
implicit none
mwPointer plhs(*), prhs(*)
integer nlhs, nrhs
integer*4 mxClassIDFromClassName
mwPointer mxGetPr, mxCreateNumericArray, mxGetDimensions
mwPointer x_pr, y_pr, m_pr
integer mxIsNumeric
mwSize mxGetM, mxGetN, mxGetNumberofDimensions
mwSize size, mdim
integer*4 myclassid
integer status
C Check for proper number of arguments.
if(nrhs .ne. 1) then
call mexErrMsgTxt('One input required.')
elseif(nlhs .ne. 1) then
call mexErrMsgTxt('One output required.')
endif
C Get the size of the input array.
m_pr = mxGetDimensions(prhs(1))
mdim = mxGetNumberofDimensions(prhs(1))
allocate(m(mdim))
call mxCopyPtrToReal8(m_pr,m,5)
size = m(1)*m(2)*m(3)*m(4)*m(5)
C Check to insure the input is a number.
if(mxIsNumeric(prhs(1)) .eq. 0) then
call mexErrMsgTxt('Input must be a number.')
endif
C Create matrix for the return argument.
myclassid = mxClassIDFromClassName('double')
plhs(1) = mxCreateNumericArray(5,m,myclassid,0)
x_pr = mxGetPr(prhs(1))
y_pr = mxGetPr(plhs(1))
C Allocate work arrays
allocate(x(m(1),m(2),m(3),m(4),m(5)), STAT=status)
allocate(y(m(1),m(2),m(3),m(4),m(5)), STAT=status)
C Call the computational subroutine.
call mxCopyPtrToReal8(x_pr,x,size)
call timestwo()
call mxCopyReal8ToPtr(y,y_pr,size)
C Free work arrays
deallocate(x)
deallocate(y)
deallocate(m)
return
end
*******************************************************************
As an experiment to try to get it to work on the 32-bit windows system with 2011a I hard-coded the vector m. This runs once and on the second time MATLAB freezes. I also tested it on the 64-bit 2010a and 64-bit 2011a and get the same result. None of the three systems can run this function a second time.
Here is the Fortran code (used the same script above to mex and call the function):
********************************************************************
#include "fintrf.h"
C ALLOCATABLE arrays are Fortran's version of malloc/free or new/delete.
C Copyright 1984-2010 MathWorks, Inc.
C $Revision: 1.1.6.1 $
module work_array
mwSize :: m(5)
real*8, dimension(:,:,:,:,:), allocatable :: x
real*8, dimension(:,:,:,:,:), allocatable :: y
end module
subroutine timestwo()
use work_array
implicit none
mwSize i,j,k,l,p
C
do i = 1,m(1)
do j = 1,m(2)
do k = 1,m(3)
do l = 1,m(4)
do p = 1,m(5)
y(i,j,k,l,p) = 2.0 * x(i,j,k,l,p)
end do
end do
end do
end do
end do
return
end
subroutine mexFunction(nlhs, plhs, nrhs, prhs)
use work_array
implicit none
mwPointer plhs(*), prhs(*)
integer nlhs, nrhs
integer*4 mxClassIDFromClassName
mwPointer mxGetPr, mxCreateNumericArray, mxGetDimensions
mwPointer x_pr, y_pr, m_pr
integer mxIsNumeric
mwSize mxGetM, mxGetN, mxGetNumberofDimensions
mwSize size, mdim
integer*4 myclassid
integer status
C Check for proper number of arguments.
if(nrhs .ne. 1) then
call mexErrMsgTxt('One input required.')
elseif(nlhs .ne. 1) then
call mexErrMsgTxt('One output required.')
endif
C Get the size of the input array.
m_pr = mxGetDimensions(prhs(1))
call mxCopyPtrToReal8(m_pr,m,5)
size = m(1)*m(2)*m(3)*m(4)*m(5)
C Check to insure the input is a number.
if(mxIsNumeric(prhs(1)) .eq. 0) then
call mexErrMsgTxt('Input must be a number.')
endif
C Create matrix for the return argument.
myclassid = mxClassIDFromClassName('double')
plhs(1) = mxCreateNumericArray(5,m,myclassid,0)
x_pr = mxGetPr(prhs(1))
y_pr = mxGetPr(plhs(1))
C Allocate work arrays
allocate(x(m(1),m(2),m(3),m(4),m(5)), STAT=status)
allocate(y(m(1),m(2),m(3),m(4),m(5)), STAT=status)
C Call the computational subroutine.
call mxCopyPtrToReal8(x_pr,x,size)
call timestwo()
call mxCopyReal8ToPtr(y,y_pr,size)
C Free work arrays
deallocate(x)
deallocate(y)
return
end
********************************************************************
Please let me know if you have any ideas on what could be happening that prevents a successful second call of this function.
Much appreciation,
Nate
This is the script I run:
********************************************************************\
mex xf_allocatable_5D.F
x = rand(5,5,5,5,10);
y = xf_allocatable_5D(x);
********************************************************************
This is the Fortran code:
********************************************************************
#include "fintrf.h"
C ALLOCATABLE arrays are Fortran's version of malloc/free or new/delete.
C Copyright 1984-2010 MathWorks, Inc.
C $Revision: 1.1.6.1 $
module work_array
mwSize, dimension(:), allocatable :: m
real*8, dimension(:,:,:,:,:), allocatable :: x
real*8, dimension(:,:,:,:,:), allocatable :: y
end module
subroutine timestwo()
use work_array
implicit none
mwSize i,j,k,l,p
C
do i = 1,m(1)
do j = 1,m(2)
do k = 1,m(3)
do l = 1,m(4)
do p = 1,m(5)
y(i,j,k,l,p) = 2.0 * x(i,j,k,l,p)
end do
end do
end do
end do
end do
return
end
subroutine mexFunction(nlhs, plhs, nrhs, prhs)
use work_array
implicit none
mwPointer plhs(*), prhs(*)
integer nlhs, nrhs
integer*4 mxClassIDFromClassName
mwPointer mxGetPr, mxCreateNumericArray, mxGetDimensions
mwPointer x_pr, y_pr, m_pr
integer mxIsNumeric
mwSize mxGetM, mxGetN, mxGetNumberofDimensions
mwSize size, mdim
integer*4 myclassid
integer status
C Check for proper number of arguments.
if(nrhs .ne. 1) then
call mexErrMsgTxt('One input required.')
elseif(nlhs .ne. 1) then
call mexErrMsgTxt('One output required.')
endif
C Get the size of the input array.
m_pr = mxGetDimensions(prhs(1))
mdim = mxGetNumberofDimensions(prhs(1))
allocate(m(mdim))
call mxCopyPtrToReal8(m_pr,m,5)
size = m(1)*m(2)*m(3)*m(4)*m(5)
C Check to insure the input is a number.
if(mxIsNumeric(prhs(1)) .eq. 0) then
call mexErrMsgTxt('Input must be a number.')
endif
C Create matrix for the return argument.
myclassid = mxClassIDFromClassName('double')
plhs(1) = mxCreateNumericArray(5,m,myclassid,0)
x_pr = mxGetPr(prhs(1))
y_pr = mxGetPr(plhs(1))
C Allocate work arrays
allocate(x(m(1),m(2),m(3),m(4),m(5)), STAT=status)
allocate(y(m(1),m(2),m(3),m(4),m(5)), STAT=status)
C Call the computational subroutine.
call mxCopyPtrToReal8(x_pr,x,size)
call timestwo()
call mxCopyReal8ToPtr(y,y_pr,size)
C Free work arrays
deallocate(x)
deallocate(y)
deallocate(m)
return
end
*******************************************************************
As an experiment to try to get it to work on the 32-bit windows system with 2011a I hard-coded the vector m. This runs once and on the second time MATLAB freezes. I also tested it on the 64-bit 2010a and 64-bit 2011a and get the same result. None of the three systems can run this function a second time.
Here is the Fortran code (used the same script above to mex and call the function):
********************************************************************
#include "fintrf.h"
C ALLOCATABLE arrays are Fortran's version of malloc/free or new/delete.
C Copyright 1984-2010 MathWorks, Inc.
C $Revision: 1.1.6.1 $
module work_array
mwSize :: m(5)
real*8, dimension(:,:,:,:,:), allocatable :: x
real*8, dimension(:,:,:,:,:), allocatable :: y
end module
subroutine timestwo()
use work_array
implicit none
mwSize i,j,k,l,p
C
do i = 1,m(1)
do j = 1,m(2)
do k = 1,m(3)
do l = 1,m(4)
do p = 1,m(5)
y(i,j,k,l,p) = 2.0 * x(i,j,k,l,p)
end do
end do
end do
end do
end do
return
end
subroutine mexFunction(nlhs, plhs, nrhs, prhs)
use work_array
implicit none
mwPointer plhs(*), prhs(*)
integer nlhs, nrhs
integer*4 mxClassIDFromClassName
mwPointer mxGetPr, mxCreateNumericArray, mxGetDimensions
mwPointer x_pr, y_pr, m_pr
integer mxIsNumeric
mwSize mxGetM, mxGetN, mxGetNumberofDimensions
mwSize size, mdim
integer*4 myclassid
integer status
C Check for proper number of arguments.
if(nrhs .ne. 1) then
call mexErrMsgTxt('One input required.')
elseif(nlhs .ne. 1) then
call mexErrMsgTxt('One output required.')
endif
C Get the size of the input array.
m_pr = mxGetDimensions(prhs(1))
call mxCopyPtrToReal8(m_pr,m,5)
size = m(1)*m(2)*m(3)*m(4)*m(5)
C Check to insure the input is a number.
if(mxIsNumeric(prhs(1)) .eq. 0) then
call mexErrMsgTxt('Input must be a number.')
endif
C Create matrix for the return argument.
myclassid = mxClassIDFromClassName('double')
plhs(1) = mxCreateNumericArray(5,m,myclassid,0)
x_pr = mxGetPr(prhs(1))
y_pr = mxGetPr(plhs(1))
C Allocate work arrays
allocate(x(m(1),m(2),m(3),m(4),m(5)), STAT=status)
allocate(y(m(1),m(2),m(3),m(4),m(5)), STAT=status)
C Call the computational subroutine.
call mxCopyPtrToReal8(x_pr,x,size)
call timestwo()
call mxCopyReal8ToPtr(y,y_pr,size)
C Free work arrays
deallocate(x)
deallocate(y)
return
end
********************************************************************
Please let me know if you have any ideas on what could be happening that prevents a successful second call of this function.
Much appreciation,
Nate