胡亚鹏朱东华郭小宾李玉芝李 影冯光辉
(1.河南油田测井公司 河南南阳) (2.河南油田通信公司 河南南阳)
VC++和FORTRAN混合编程在阵列感应数值模拟软件中的应用
胡亚鹏1朱东华1郭小宾1李玉芝2李 影1冯光辉1
(1.河南油田测井公司 河南南阳) (2.河南油田通信公司 河南南阳)
为了利用已有成熟的FORTRAN程序,避免重复编程和资源浪费,节省编程时间,在工程与科学研究中C/C++和Fortran混合编程有很大的应用价值。主要论述了VisualC++和Fortran混合编程中动态链接库方法。阐明了如何通过CompaqVisualFortran6.x生成动态链接库,VisualC++中如何调用生成动态链接库的方法。并通过两者的混合编程实现阵列感应测井数值模拟软件的开发。
混合编程;动态链接库;阵列感应响应
随着石油测井行业的发展,由于阵列感应测井[1]在划分薄层、描述地层电阻率径向变化、识别油水层等方面体现出的优越性,在石油测井行业中的地位越来越重要。而阵列感应响应计算技术在阵列感应测井研究中起着非常重要的作用,因此有必要开发阵列感应数值模拟软件。
实现数值计算的主流平台是CompaqVisualFortran6.x,但它却不适合作为应用系统的集成开发平台,大部分Fortran程序是一个没有图形界面的命令行程序,独立运行时会出现一个命令行窗口,直到程序运行结束,参数的输入及计算结果查看非常不方便。为了克服以上缺点,Fortran程序可以“组件”(主流组件为DLL)形式融入到其它语言工具开发的应用系统中。在32位Windows操作系统中,VisualC++为应用系统的集成主流开发平台[2]。因此,本文重点探讨在VisualFortran6.x中编译生成 Win32DLL,以及在Visual C++对生成DLL文件中过程实施调用的混合编程实现阵列感应测井数值模拟软件的开发。
阵列感应响应计算技术在阵列感应测井研究中起着非常重要的作用,它是仪器设计,信号合成处理,反演和测井响应异常解释的基础。目前为止,阵列感应响应计算已发展了很多方法,主要可分为解析解法、数值模式匹配法和有限元法三种方法。三种方法的特点是,解析解法可以计算一维纵向、径向轴对称旋转地层,计算速度快;数值模式匹配法可以计算二维纵向、径向轴对称旋转地层,计算速度较快;有限元法可以计算一般复杂地层,如倾斜地层等,其计算速度与网格剖分疏密有关。本文中计算阵列感应响应Fortran程序主要按数值模式匹配法编写的。
混合语言编程涉及一种语言对用另一种语言编写的函数、过程或者子过程的调用。本文中C/C++和Fortran混合编程主要是C/C++程序调用Fortran的过程或函数。为保证混合编程程序的正确运行主要解决以下几方面问题:
(1)调用约定一致性;
(2)函数命名的一致性;
(3)参数的正确传递,标量参数和矢量参数;
(4)VC++调用Fortran生成的动态链接库(DLL)。
调用约定决定程序对函数如何调用,如何传递参数,如何命名目标函数名。在一种语言的编译环境中,由编译系统统一协调函数的调用方式,因此不存在调用约定不一致的问题[3]。但在混合编程中,由于在C/C++和Fortran混合编程中,不同的语言和编译环境,加之各自的默认调用约定又不完全一致,这就有可能导致程序链接错误或执行错误。所以,调用约定的匹配是混合编程所要解决的关键问题。
CompaqVisualFortran6.x使用的三种调用约定(缺省约定(Default)、C约定和STDCALL约定)的参数传递方式、堆栈管理、可选参数等影响,见表1。
表1 CompaqVisualFortran6.x调用约定
表1中,name为程序中所定义的函数名,n为参数类型所占字节数,十进制表示。
函数是通过关键字DLLEXPORT实现,三种调用约定根据实际需求选择其中一种。
由于C/C++语言字母区分大小写,Fortran不区分标示符大小写,C++编译后目标标识符添加特定的修饰,使目标标识符发生改变。为避免连接失败,必须协调C/C++和Fortran的命名约定,使编译后目标标识符保持一致。而不同的调用约定,其命名约定也不相同。函数编译后的命名有三种情况:大写、小写和大小写混合。
C/C++和Fortran混合编程中参数传递主要包括:数据类型对应和参数传递方式。数据类型见表2。在Fortran和VisualC++过程之间参数的传递方式有值传递和引用传递两种方式,前者将参数值压入堆栈,后者将参数地址压入堆栈。为避免链接错误,在混合语言编程中必须保证参数传递方式的一致性。Fortran参数传递方式取决于调用约定,其默认参数传递方式为引用,如采用C和STDCALL约定,标量参数(单个参数)采用值传递,数组采用引用传递。除采用调用约定约束外,还可以通过属性VALUE和REFERENCE使参数分别以值和引用传递,并忽略调用约定约束。数组参数只能通过引用方式传递,且通过数组名传递数组首地址。在混合编程中,应通过属性VALUE和REFERENCE明确参数传递方式,本文不推荐通过调用约定约束参数的传递方式。
表2 Fortran与C/C++对应数据类型[3]
在数值计算编程中,类型相同的数据常常利用数组。和其它语言相比,Fortran90/95中对数组的操作非常方便。但在Fortran与C/C++语言的混合编程中,数组参数比较特殊,在Fortran中,数组是按列优先在内存中连续排列的,而C/C++中,数组是按行优先在内存中连续排列的。对于一维数组,两种语言没有任何区别。对于大于二维的数组需要特别对待,在传递多维数组参数时,若两种语言的数组存储方式不同,需要在调用前后对数组形状进行调整,即C/C++中数组行与列交换。以上述函数QPROG中第三个参数WK(2,4)为例讨论大于二维的数组参数传递。由于两种语言的数组排列方式不同,C/C++中需对数组WK行列交行 ,如floatWK[2、4]。列出 C/C++和 Fortran 中数组 WK行列交换后的对应关系,见表3。
表3 C/C++和Fortran中数组WK行列交换后的对应关系
不管数组是按列存放还是按行存放,数组在内存中都占据一串连续的存储单元。因此,虽然两种语言的数组下标规定不同,但在数组参数传递时可以通过数组名和取数组首元素的地址传递,其后续元素就一一被传递。
链接DLL到应用程序中有两种方式:显式链接(ExplicitLink)和隐式链接(ImplicitLink)。由于显式链接比隐式链接更具灵活性,并可及时释放内存的特点,所以一般采用显式链接方式。在该方式中,VC++通过函数调用显式装载和卸载DLL,并通过函数指针来调用DLL的导出函数。使用显式链接的基本方式调用LoadLibrary或AfxLoadLibrary装载DLL并得到模块句柄;调用GetProcAddress获得导出函数指针;在使用完毕时,调用FreeLibrary或AfxFreeLibrary释放DLL。
阵列感应正演计算是用Fortran语言编写的。对有关的界面与图形系统的开发部分用VisualC++语言来编写,对阵列感应正演数值计算部分用Fortran语言来编写,在VisualC++中对Fortran中的函数进行调用实现阵列感应正演数值模拟计算软件。
在C/C++和Fortran混合编程中,有两种具体的实现形式:(1)静态库连接方式:将Fortran程序用CompaqVisualFortran6.x编译器进行编译,产生静态目标文件 (lib文件),在VisualC++调用函数生成可执行文件;(2)动态库连接方式:将Fortran程序用CompaqVisualFortran6.x编译器进行编译,生成动态连接库(DLL)文件。在需要调用Fortran代码时,由VisualC++对其动态调用。
笔者采用第二种连接方式实现C/C++和Fortran混合编程,具体实现过程如下。
(1)生成动态连接库
对阵列感应正演计算Fortran程序需作以下修改:
再用CompaqVisualFortran6.x进行编译,分别形成动态连接库(DLL)与静态连接库 (LIB)。
(2)VisualC++中定义Fortran函数接口
首先将第一步生成的态连接库(DLL)与静态连接库 (LIB)文件拷贝到工程所在文件夹中,其次在C++代码中对静态库作如下声明:
#pragmacomment(lib,”dipping.lib”)
最后在C++中定义Fortran函数接口,声明如下:
extern”C”{void_stdcalldipping(intisub,intnsamp,int&nlayer,float&topft,intieo,floatfreq,floatdelft,float&rho,float&bedft,float&realrho,float&rxrho,float&sigmabm);}
(3)VisualC++中调用Fortran函数完成计算
计算结果如图1中给出三层电阻率分别为1.0Ω·m、15.0Ω·m和1.0Ω·m的地层模型的高分辨率阵列感应(HDIL)仪器的响应结果。
图1 HDIL模拟结果
VisualC++可以快速进行界面和绘图显示开发,而Fortran在数值运算中具有优势。利用两者混合编程避免资源的浪费和重复编程,提高了程序开发效率。在实际工程分析中取得良好的应用效果。
[1] 张建华,刘振华,仵 杰.电法测井原理与应用[M].西安:西北大学出版社,2002
[2] 周振红,杨国录,周洞汝,等.FORTRAN 与 VISUALBASIC混合编程的研究[J].武汉水利电力大学学报,1999,42(2)
[3] 周振红,李 强.Fortran90/95高级程序设计[M].黄河水利出版社,1998
P631.8+1
B
1004-9134(2010)03-0079-03
2010-03-15 编辑:梁保江)
胡亚鹏,男,1981年生,助理工程师,2004年毕业于西安石油大学电子工程学院测控技术及仪器专业,目前在河南南阳油田测井公司从事测井工作。邮编:473132