Search code examples
matlabfortranintegermex

MEX MATLAB/FORTRAN: Integer passing as a very high number


I'm writing a simple MEX file for a Matlab/Fortran interface. The code is compiling, however, the integer number n (e.g., 5) is passing as a huge number (O(14)). When n is integer*4 it passes as 0.

The user runs the compiled mex file as [z,w] = smmat(c,e,eps,n), where c is a complex matrix of size 20xnl, e is a real matrix of size 8xnl, eps is a real matrix of size 5xnl, n in a integer scalar. z is an output complex matrix and w should be an output real matrix.

Can someone provide their expertise? Thanks :) Here is the code:

#include "fintrf.h"      
C     Gateway routine
      subroutine mexFunction(nlhs, plhs, nrhs, prhs)

C     Declarations
      implicit none

C mexFunction arguments: plhs - left (output) pointers of unknown (*) size
C                        prhs - right (input) pointers of unknown (*) size
C                        nlhs - number (integer) of left (output) arguments
C                        nrhs - number (integer) of right (input) arguments
      mwPointer plhs(*), prhs(*)
      integer nlhs, nrhs

C     Function declarations:
      mwPointer mxGetPr, mxGetPi  
      mwPointer mxCreateDoubleMatrix
      mwPointer mxGetM, mxGetN
      integer mxIsComplex, mexEvalString

C     Array information:
      mwPointer mc, nc, me, ne, mep, nep, mn, nn, nz, nw, elc, ele, elep

      integer*8 n
      real*8 e(80), eps(50), w(5000000)
      complex*16 c(200), z(5000000)

C-----------------------------------------------------------------------
C     Check for proper number of arguments. 
      if (nrhs .ne. 4) then
         call mexErrMsgIdAndTxt ('MATLAB:smmat:nInput',
     +                           'Four inputs required.')
      elseif (nlhs .gt. 2) then
         call mexErrMsgIdAndTxt ('MATLAB:convec:nOutput',
     +                           'Too many output arguments.')
      endif

C     Validate inputs
      mc = mxGetM(prhs(1))
      nc = mxGetN(prhs(1))
      me = mxGetM(prhs(2))
      ne = mxGetN(prhs(2))
      mep = mxGetM(prhs(3))
      nep = mxGetN(prhs(3))
      mn = mxGetM(prhs(4))
      nn = mxGetN(prhs(4))

C     Size of inputs
      elc = mc*nc
      ele = me*ne
      elep = mep*nep

C     Check number of lines of cij, eij, epsij
      if(mc .ne. 20 .or. me .ne. 8 .or. mep .ne. 5) then
         call mexErrMsgIdAndTxt ('Matlab:smmat:NotEnoConst',
     +            'Inputs must have correct number of constants.')
C     Check that inputs are scalar.
      elseif(mn .ne. 1 .or. nn .ne. 1) then
         call mexErrMsgIdAndTxt ('MATLAB:smmat:NonScalar',
     +                           'Inputs must be a scalar.')
C     Check size of the inputs.
      elseif(elc .gt. 200 .or. ele .gt. 80 .or. elep .gt. 50) then
         call mexErrMsgIdAndTxt ('MATLAB:smmat:nLayer',
     +                 'Maximum number of layers is 10.')
C     Check if cij is complex.
      elseif(mxIsComplex(prhs(1)) .ne. 1) then
         call mexErrMsgIdAndTxt ('MATLAB:smmat:NonComplex',
     +                           'Cij must be complex.')
C     Check if number of layers is correct for every constant.
      elseif(nc .ne. ne .or. nc .ne. nep .or. ne .ne. nep) then
         call mexErrMsgIdAndTxt ('MATLAB:smmat:nLayer',
     +           'Number of layers of constants must be equal.')      
      endif

C     Create the output array.
      nz = mc*me
      nw = mc*mep
      plhs(1) = mxCreateDoubleMatrix(mc, me, 1)
      plhs(2) = mxCreateDoubleMatrix(mc, mep, 0)

C     Load the data into Fortran arrays(native COMPLEX data).
      call mxCopyPtrToComplex16(mxGetPr(prhs(1)),
     +                          mxGetPi(prhs(1)),c,elc)
      call mxCopyPtrToReal8(mxGetPr(prhs(2)),e,ele)
      call mxCopyPtrToReal8(mxGetPr(prhs(3)),eps,elep)
      call mxCopyPtrToInteger4(mxGetPr(prhs(4)),n,1)

C     Call the computational subroutine.
      call smmat(c,e,eps,n,z,w,mc,me,mep,nc)

C     Load the output into a MATLAB array.
      call mxCopyComplex16ToPtr(z,mxGetPr(plhs(1)),
     +                          mxGetPi(plhs(1)),nz)
      call mxCopyReal8ToPtr(w,mxGetPr(plhs(2)),nw)

      return
      end

C-----------------------------------------------------------------------
C     Computational subroutine
      subroutine smmat(c,e,eps,n,z,w,mc,me,mep)

      implicit none

      integer*8 n
      real*8 e(8,*), eps(5,*), w(mc,mep)
      complex*16 c(20,*), z(mc,me)
      mwSize mc, nc, me, mep, i, j

C     Determine size of stiff and mass matrices
C     Initialize the output arrays
      w = 0.0_8

      do 20 i=1,mc
         do 10 j=1,me
             z(i,j) = (0.0,0.0)
 10      continue
 20   continue

      do 40 i=1,mc
         do 30 j=1,me
            z(i,j) = z(i,j) + e(j,1) * c(i,1)
 30      continue
 40   continue

      do 60 i=1,mc
          do 50 j=1,mep
              w(i,j) = w(i,j) + real(n)
 50       continue
 60   continue
      return
      end
C-----------------------------------------------------------------------

Solution

  • When you type

    n=5;
    smmat(c,e,eps,n)
    

    in MATLAB, n is a double, even though it has an integer value. In your MEX-file, you need to read it as a double. You cannot interpret the mxArray data as whatever type is convenient. Always use functions such as mxIsDouble to verify the type of the array before you read the data from it.

    If you expect an integer value, you should probably still read it as double, and then cast to integer.