如何在fortran mex文件中使用mxCalloc

时间:2016-10-19 14:41:46

标签: matlab fortran mex

我必须在mex文件中使用mxCalloc函数而不是常规分配,以避免matlab在使用dgesv时崩溃。 我尝试了很多方法,但没有一个方法奏效。 这是其中一个样本

 #include "fintrf.h"

C     Gateway subroutine
      subroutine mexfunction(nlhs, plhs, nrhs, prhs)

C     Declarations
      implicit none

C     mexFunction arguments:
      mwPointer plhs(*), prhs(*)
      integer nlhs, nrhs

C     Function declarations:
      mwPointer mxGetPr
      mwPointer mxCreateDoubleMatrix
      mwPointer mxGetM

C     Pointers to input/output mxArrays:
      mwPointer pr_A, pr_B

C     Array information:

      mwPointer sizea,mxCalloc
      real*8 :: A,B
      character*120 :: line

C     Get the size of the input array.
      sizea = mxGetM(prhs(1))

      A=mxCalloc(sizea*sizea,8)
      B=mxCalloc(sizea*sizea,8)

C     Create Fortran array from the input argument.
      pr_A = mxGetPr(prhs(1))

      call mxCopyPtrToReal8(pr_A,A,sizea**2)

C     Create matrix for the return argument.
      plhs(1) = mxCreateDoubleMatrix(sizea, sizea, 0)
      pr_B = mxGetPr(plhs(1))

      write(line,*), sizea
      call mexPrintf(line) 
      B=A

      call mxCopyReal8ToPtr(B,pr_B,sizea*sizea)

      return
      end

当我运行此代码时,我得到以下结果

  

A = [0.9575,0.1576; 0.9649,0.9706]

     

测试(A)= [0.9575,0; 0.9649,0]

但如果我改变了这条线 call mxCopyReal8ToPtr(B,pr_B,sizea*sizea)

call mxCopyReal8ToPtr(A,pr_B,sizea*sizea), 结果是正确的

变量sizea等于2这是正确的,但是我无法访问A的任何成员,比如说A(1,1),并且我遇到了错误:

  

错误#6410:此名称尚未声明为数组或a   功能。 [A]

2 个答案:

答案 0 :(得分:3)

代码中的A被声明为单个变量,但是大小(A,1)正在尝试访问它,就像它是一个数组一样。您必须明确告诉Fortran A具有数组的形状。在快速浏览一下其余的代码后,我假设A和B应该是2维

 real*8 :: A(:,:),B(:,:)

现在我不太了解mxCalloc的工作原理以及它如何处理内存分配以及与Fortran的接口,但可能还需要将A和B声明为指针。

real*8, pointer :: A(:,:),B(:,:)

答案 1 :(得分:3)

(免责声明:我没有使用Mex的经验,因此请采用以下代码......)

这是@ftiaronsem和Dave之前one的答案的延续。通过查看此tutorial,在mxCalloc()中使用Fortran可分配数组似乎没问题。但是,OP的目的是使用mxCalloc()而不是可分配的数组进行内存管理。

根据Matlab的在线手册,mwpointer似乎将分配的内存地址返回为integer*8(这只是64位计算机上mwpointer iA iA = mxCalloc( sizea * sizea, 8 ) 的别名,到头文件fintrf.h)。所以,我们首先得到地址为

B

(同样适用于iA)。接下来,我们想要从type(c_ptr)开始作为2-d Fortran阵列访问内存。这可以通过使用c_f_pointer()(在F2003中)来完成。但是,由于此函数的第一个参数接收use iso_c_binding type(c_ptr) cA real*8, pointer :: A(:,:) cA = transfer( iA, cA ) !! cast integer*8 to c_ptr call c_f_pointer( cA, A, [ sizea, sizea ] ) !! init an array pointer with c_ptr ,我们按如下方式进行:

A

在此语句之后,我们可以使用#include "fintrf.h" C Gateway subroutine subroutine mexfunction(nlhs, plhs, nrhs, prhs) use iso_c_binding !<--- C Declarations implicit none C mexFunction arguments: mwPointer plhs(*), prhs(*) integer nlhs, nrhs C Function declarations: mwPointer mxGetPr mwPointer mxCreateDoubleMatrix mwsize mxGetM, sizea !<--- changed to mwsize (may not be necessary, though) C Pointers to input/output mxArrays: mwPointer pr_A, pr_B C Array information: mwPointer mxCalloc mwPointer :: iA, iB !<--- type(c_ptr) :: cA, cB !<--- real*8, pointer :: A(:,:), B(:,:) !<--- character*120 :: line C Get the size of the input array. sizea = mxGetM(prhs(1)) iA = mxCalloc( sizea**2, 8 ) !<--- iB = mxCalloc( sizea**2, 8 ) !<--- cA = transfer( iA, cA ) !<--- cB = transfer( iB, cB ) !<--- call c_f_pointer( cA, A, [ nsizea, nsizea ] ) !<--- call c_f_pointer( cB, B, [ nsizea, nsizea ] ) !<--- C Create Fortran array from the input argument. pr_A = mxGetPr(prhs(1)) call mxCopyPtrToReal8( pr_A, A, sizea**2 ) C Create matrix for the return argument. plhs(1) = mxCreateDoubleMatrix(sizea, sizea, 0) pr_B = mxGetPr(plhs(1)) write(line,*), sizea call mexPrintf(line) B = A call mxCopyReal8ToPtr( B, pr_B, sizea**2 ) !! may need to call mxFree( iA ) and mxFree( iB ) manually? !! (or Matlab may automatically do it upon exit) return end 作为普通的2-d Fortran数组(例如,我们可以将它传递给LAPACK例程)。将这些修改包括在OP代码中给出了以下内容。那么你可以尝试一下,看它是否有效......?

更新的代码(ver1):

def main():

    endProgram = "no"

    #at the end the program will ask the user if the want to stop
    #if the say yes the program will end if they say no the will
    #cause the program to rerun
    while endProgram == "no":
        notGreenCost = [11]
        goneGreenCost = [11]
        savings = [11]
        months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]

        #function calls
        notGreenCosts[12] = getNotGreen(notGreenCost, months)
        getGoneGreen(goneGreenCost, months)
        energySaved(notGreenCost, goneGreenCost, savings)
        displayInfo(notGreenCost, goneGreenCost, savings, months)

        endProgram = str(input("Do you want to end the program? yes or no"))

        def getNotGreen(notGreenCost, months):
            counter = 0
            while counter < 11:
                print("Enter GONE GREEN energy costs for", months[counter])
                notGreenCost[index] = int(input(":"))
                counter =  counter + 1


    return notGreenCost


main()