您的位置:首页 > 编程语言 > MATLAB

如何由Fortran中呼叫MATLAB的M檔案

2004-08-03 01:08 267 查看
如何由Fortran中呼叫MATLAB的M檔案
基本的作法是先將M檔案轉換為.dll檔
再由Fortran去呼叫之

程式是使用 Matlab 6.5.1
Matlab compiler v3.0.1
Compaq Visual Fortran Pro v6.6.0 (CVF) (Compaq bought DEC and HP bought Compaq)

原始m檔案為

function b= matlabinc(a)
% Increment given argument a and return result b to caller, displaying both on screen as well
disp(a)
explore(a)
b = a + 1;
disp(b)
explore(b)

使用以下的方式compile 為DLL
eval(['mcc -t -L C -W lib:QuGeneLib -T link:lib -h ' progName '.m libmmfile.mlib'])

%如果m 檔案中有繪圖請使用以下方式
%eval(['mcc -B sgl -t -L C -W libhg:QuGeneLib -T link:lib -h ' progName '.m libmmfile.mlib'])

以下為原始檔與描述
This heavily commented Fortran program serves as a simple example on how a MATLAB .m file can be called from Fortran. Suitable if this is your first time trying this.

The basic mechanism is to pack the C-compiled .m into a .dll and link to it from Fortran. Argument and result xfer mechanism is explained so that program can be easily expanded.

程式開始
以下藍色部分為MATLAB中使用方式
藍色以下部分為Fortran中使用方式

program test

!===============================================================================================================
!
! This program serves as a simple example on how to interface a Fortran program to Matlab,
! not the other way round which is well documented elsewhere.
!
!
! ENVIRONMENT
! This will work using the following environment on a Windows XPpro PC, other environments have not been tested
! but may work as well.
!
! * Matlab v6.5.1 R13 SP1
! * Matlab compiler v3.0.1
! * Compaq Visual Fortran Pro v6.6.0 (CVF) (Compaq bought DEC and HP bought Compaq)
!
!
! OVERVIEW
! We start with a simple .m script and create C-code from it, which is then compiled and placed into a .dll.
! This process is performed fairly automatic in the Matlab environment.
!
! Now we write a Fortran program that calls this Matlab routine. For this to work properly we have to setup
! Matlab structures containing the data values (the mx array and pointers to it), take care of the underscores
! added to routine names in dll's, the way the arguments are referenced because the routine was generated
! from C-code and the fact that the routine resides in a dll. All this need only be done for the Matlab script
! we create, we may call any mx* routines in a normal Fortran fashion. All this is described in detail now.
!
!
! DETAIL
! Our task is to call the following Matlab script from a Fortran program.
!
! function b = matlabinc(a)
! % Increment given argument a and return result b to caller, displaying both on screen as well
! disp(a)
! explore(a)
! b = a + 1;
! disp(b)
! explore(b)
!
! We compile our Matlab script using a function like this
!
! function compileDLL(progName)
! % Compile the .m file given and place result into a dll
! eval(['mcc -t -L C -W lib:QuGeneLib -T link:lib -h ' progName '.m libmmfile.mlib'])
! % Use this line instead if you call graphics routines in your .m file
! %eval(['mcc -B sgl -t -L C -W libhg:QuGeneLib -T link:lib -h ' progName '.m libmmfile.mlib'])
!
! This will create two files, QuGeneLib.lib and QuGeneLib.dll. The.lib file contains information for the Fortran
! compiler on what is in the .dll file. The .dll is the dynamic link library that contains our compiled Matlab
! routine. Copy both to the Fortran development directory were the .f90 files live. Also copy all Matlab .dll's
! you are using to the same location, libmx.dll is one you will definitely need. If you call graphics routines
! you will also need sgl.dll and you have to place FigureMenuBar.fig and FigureToolBar.fig into the path of
! the executing Fortran program as well.
!
! In CVF use "project->add to project->files" and pick the QuGeneLib.lib file. Read through the comments in this
! Fortran program to understand how everything works. You can use the DOS command
!
! dumpbin/exports libmx.lib
!
! or the Windows Dependency Walker
!! http://www.dependencywalker.com/
!
! to see the names of the routines included in the corresponding .dll, this is what has to go into the
! ALIAS directive when defining the interface for the C routine in the dll with the !DEC$ compiler statement.
! You will note an added underscore and sometimes also a @number after the name. The number indicates the number
! of bytes used for arguments. Also, C is case sensitive so cases in routine names must match.
!
! Note: You do not need to do this for any mx* routines, Matlab has defined an API for all of these. Although you will
! encounter a name such as MXCOPYPTRTOREAL8@12 in libmx.lib, you have to call mxCopyPtrToReal8 instead.
!
! The main way of achieving data transfer between Fortran and the Matlab C program created from our .m file script
! is via the mx routines supplied by Matlab in the libmx.dll. Read through Matlab HELP titled
! "External Interfaces/API Reference: Fortran MX-Functions" before expanding this example.
!
! Note: You do not need to define any interfaces, pointers etc for the mx* routines. You do also not need
! to call loadlibrary or getprocaddress for the mx* routines. It will not work if you do any of this.
!
!
! Alex Pudmenzky, 24 September 2003, The University of Queensland, Brisbane, Australia (http://alex.pudmenzky.com).!
!===============================================================================================================
! Declaration section

! Definitions for the "loadlibrary", "freelibrary" and "getprocaddress" routines are included in the following files
!use dfwin ! More stuff than is in kernel32
use kernel32 ! Use this to safe compilation time if other stuff is not needed

IMPLICIT NONE ! Produce error during compilation if variables aren't declared

!---------------------------------------------------------------------------------------------------------------
INTERFACE

! Define the interfaces to our own Matlab scripts
! The <dllname>LibInitialize() and <dllname>LibTerminate() routines are automatically added by the compilation
! and dll creation progress in Matlab.
SUBROUTINE matlabinc(nlhs,plhs, nrhs,prhs)
integer*4 :: nlhs,nrhs
integer*4 :: plhs(*),prhs(*)
!DEC$ ATTRIBUTES C, DLLIMPORT, ALIAS:"_mlxMatlabinc" :: matlabinc
!DEC$ ATTRIBUTES VALUE :: nlhs,nrhs
!DEC$ ATTRIBUTES REFERENCE :: plhs,prhs
END SUBROUTINE

SUBROUTINE QuGeneLibInitialize()
!DEC$ ATTRIBUTES C, DLLIMPORT, ALIAS:"_QuGeneLibInitialize" :: QuGeneLibInitialize
END SUBROUTINE

SUBROUTINE QuGeneLibTerminate()
!DEC$ ATTRIBUTES C, DLLIMPORT, ALIAS:"_QuGeneLibTerminate" :: QuGeneLibTerminate
END SUBROUTINE

END INTERFACE

!---------------------------------------------------------------------------------------------------------------
! This part only required for our own Matlab routine, not the mx* routines
integer :: p_QuGeneLib_dummy, p_libmx_dummy
logical :: status

! QuGeneLib.dll
pointer (p_QuGeneLib,p_QuGeneLib_dummy)
pointer (pr1_QuGeneLib,QuGeneLibInitialize)
pointer (pr2_QuGeneLib,matlabinc)
pointer (pr3_QuGeneLib,QuGeneLibTerminate)

!---------------------------------------------------------------------------------------------------------------
! Declare all mx* routines we call
INTEGER*4 :: mxGetData !
INTEGER*4 :: mxGetNumberOfElements !
INTEGER*4 :: mxCreateScalarDouble !
INTEGER*4 :: mxCreateNumericMatrix !
INTEGER*4 :: mxClassIDFromClassName !

!---------------------------------------------------------------------------------------------------------------
real*8 :: a(3) ! What I store in Matlab mx array
real*8 :: b(3) ! What I read out of Matlab mx array
integer*4 :: a_mx_p ! Pointer to mx array for a
integer*4 :: a_dx_p ! Pointer to data in mx array for a
integer*4 :: b_mx_p ! Pointer to mx array for b
integer*4 :: b_dx_p ! Pointer to data in mx array for b
integer*4 :: na ! Number of entries in a
integer*4 :: nb ! Number of entries in b

!===============================================================================================================
! Executable section

! Locate the QuGeneLib.dll and load it into memory
! This library contains all of our own Matlab functions
p_QuGeneLib = loadlibrary("QuGeneLib.dll"C)
if (p_QuGeneLib == 0) then
type *, "Error occurred opening QuGeneLib.dll"
type *, "Program aborting"
goto 1000
endif

! Set up a pointers to the routines of interest
pr1_QuGeneLib = getprocaddress(p_QuGeneLib, "_QuGeneLibInitialize"C)
if (pr1_QuGeneLib == 0) then
type *, "Error occurred finding _QuGeneLibInitialize in QuGeneLib.dll"
type *, "Program aborting"
goto 1000
endif

pr2_QuGeneLib = getprocaddress(p_QuGeneLib, "_mlxMatlabinc"C)
if (pr2_QuGeneLib == 0) then
type *, "Error occurred finding _mlxMatlabinc in QuGeneLib.dll"
type *, "Program aborting"
goto 1000
endif

pr3_QuGeneLib = getprocaddress(p_QuGeneLib, "_QuGeneLibTerminate"C)
if (pr3_QuGeneLib == 0) then
type *, "Error occurred finding _QuGeneLibTerminate in QuGeneLib.dll"
type *, "Program aborting"
goto 1000
endif

!===============================================================================================================
! Initialise interface to our Matlab routine
! (this initialisation routine is automatically created by Matlab during compilation)
call QuGeneLibInitialize()

! The real*4 value we want to pass from this Fortran code to our Matlab routine
a(1) = 1.0
a(2) = 2.0
a(3) = 3.0

! Create mx array for this value and remember pointer to that mx array (not the value!)
! The mx Array is a special structure that can contain any Matlab datatype
! We omit checking pointers from here on to preserve simplicity, if they are returned zero the operation failed
!a_mx_p = mxCreateScalarDouble(a)
a_mx_p = mxCreateNumericMatrix(3, 1, mxClassIDFromClassName('double'), 0)

! Remember pointer to the data in the mx array, given the pointer to the mx array itself
a_dx_p = mxGetData(a_mx_p)

type *, a
! Store data in Matlab mx array
call mxCopyReal8ToPtr(a, a_dx_p, 3)

! Now we want to prove the data above has been stored by retrieving it again

! Retrieve the number of values (elements) in the mx array, given the pointer to the mx array (not the value!)
na = mxGetNumberOfElements(a_mx_p)

! Check
type *, na

! Now call our Matlab routine which returns b given the argument a (actually pointers to a & b)
call matlabinc(1,b_mx_p, 1,a_mx_p)

! Retrieve data pointer given the mx array pointer
b_dx_p = mxGetData(b_mx_p)

! Convert the value(s) stored in the mx array to Fortran representation, given the pointer to the data in the mx array
call mxCopyPtrToReal8(b_dx_p, b, 3)

! Just to see if it worked
type *, b

! Release memory
call mxDestroyArray(a_mx_p)
call mxDestroyArray(b_mx_p)

! Terminate interface to our Matlab routine
! (this termination routine is automatically created by Matlab during compilation)
call QuGeneLibTerminate()

1000 continue

! Release library
status = freelibrary(p_QuGeneLib)

end

大家可以參考一下
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: