Fortran Call Matlab

Fortran调用Matlab
本文介绍如何通过Fortran程序调用Matlab编译后的动态链接库,实现数据交互过程。涉及Fortran与Matlab之间的接口设置、dll加载及使用等关键技术。

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

Fortran代码中调用MATLAB的功能或函数,通常有以下几种方法,具体取决于应用场景、目标平台以及性能需求。以下是几种常见的实现方式: ### 1. 使用MATLAB Engine API调用MATLAB函数 MATLAB提供了Engine API,允许外部程序(如Fortran)启动MATLAB会话,并调用其中的函数。这种方式适合于需要在Fortran程序中动态调用MATLAB脚本或函数的情况。 在Fortran中使用Engine API,需要: - 安装MATLAB及其C/C++ API支持; - 通过`mex`和`eng`相关的C接口进行封装; - 使用`call mexFunction`或通过C-Fortran混合编程实现调用。 例如,Fortran程序可以调用C语言封装的MATLAB引擎函数来执行MATLAB命令: ```fortran ! Fortran代码片段(需与C接口结合) call engOpen(matlabPointer) call engEvalString(matlabPointer, 'A = inv([1 2; 3 4]);') ``` 该方式需要Fortran与C语言接口支持,并配置MATLAB的编译环境[^2]。 --- ### 2. 使用MEX接口编写MATLAB可调用的Fortran函数 MATLAB支持通过MEX接口调用Fortran编写的函数。虽然MEX主要是为C/C++设计的,但也支持Fortran。开发者可以编写Fortran子程序,并通过MATLAB的`mex`命令编译成MEX文件,在MATLAB环境中直接调用。 示例Fortran MEX函数结构如下: ```fortran subroutine mexFunction(nlhs, plhs, nrhs, prhs) ! 声明参数和变量 ! 处理输入输出 ! 调用实际的计算函数 end subroutine mexFunction ``` 编译方式: ```matlab mex your_fortran_file.f90 ``` 这样可以在MATLAB中像普通函数一样调用Fortran实现的功能,适用于高性能计算需求[^1]。 --- ### 3. 调用MATLAB生成的DLL或共享库 如果使用MATLAB Compiler将MATLAB函数编译为独立的DLL或共享库,则Fortran程序可以通过调用这些库的方式使用MATLAB功能。该方法适用于将MATLAB算法部署到生产环境,尤其是不需要MATLAB运行时交互的场景。 具体步骤包括: - 使用MATLAB Compiler生成C/C++共享库; - 在Fortran中通过C接口调用这些库函数; - 配置链接库路径和编译器选项。 这种方式适合构建独立的应用程序,但需要MATLAB Compiler许可证支持[^3]。 --- ### 4. 使用文件或管道进行数据交换 对于不需要实时交互的场景,可以采用文件或管道的方式在FortranMATLAB之间传递数据。例如: - Fortran程序将数据写入文本或二进制文件; - MATLAB脚本读取该文件并执行相应计算; - 计算结果写回文件供Fortran读取。 这种方法实现简单,但效率较低,适用于批处理任务或调试用途[^4]。 --- ### 总结 | 方法 | 适用场景 | 实现难度 | 实时性 | |------|----------|----------|--------| | MATLAB Engine API | 动态调用MATLAB函数 | 中等 | 高 | | MEX接口 | 在MATLAB中调用Fortran函数 | 中等 | 高 | | DLL/共享库 | 部署MATLAB算法到外部程序 | 高 | 中 | | 文件/管道 | 简单的数据交换 | 低 | 低 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yueliang2100

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值