胡亞鵬朱東華郭小賓李玉芝李 影馮光輝
(1.河南油田測井公司 河南南陽) (2.河南油田通信公司 河南南陽)
VC++和FORTRAN混合編程在陣列感應數(shù)值模擬軟件中的應用
胡亞鵬1朱東華1郭小賓1李玉芝2李 影1馮光輝1
(1.河南油田測井公司 河南南陽) (2.河南油田通信公司 河南南陽)
為了利用已有成熟的FORTRAN程序,避免重復編程和資源浪費,節(jié)省編程時間,在工程與科學研究中C/C++和Fortran混合編程有很大的應用價值。主要論述了VisualC++和Fortran混合編程中動態(tài)鏈接庫方法。闡明了如何通過CompaqVisualFortran6.x生成動態(tài)鏈接庫,VisualC++中如何調(diào)用生成動態(tài)鏈接庫的方法。并通過兩者的混合編程實現(xiàn)陣列感應測井數(shù)值模擬軟件的開發(fā)。
混合編程;動態(tài)鏈接庫;陣列感應響應
隨著石油測井行業(yè)的發(fā)展,由于陣列感應測井[1]在劃分薄層、描述地層電阻率徑向變化、識別油水層等方面體現(xiàn)出的優(yōu)越性,在石油測井行業(yè)中的地位越來越重要。而陣列感應響應計算技術在陣列感應測井研究中起著非常重要的作用,因此有必要開發(fā)陣列感應數(shù)值模擬軟件。
實現(xiàn)數(shù)值計算的主流平臺是CompaqVisualFortran6.x,但它卻不適合作為應用系統(tǒng)的集成開發(fā)平臺,大部分Fortran程序是一個沒有圖形界面的命令行程序,獨立運行時會出現(xiàn)一個命令行窗口,直到程序運行結(jié)束,參數(shù)的輸入及計算結(jié)果查看非常不方便。為了克服以上缺點,Fortran程序可以“組件”(主流組件為DLL)形式融入到其它語言工具開發(fā)的應用系統(tǒng)中。在32位Windows操作系統(tǒng)中,VisualC++為應用系統(tǒng)的集成主流開發(fā)平臺[2]。因此,本文重點探討在VisualFortran6.x中編譯生成 Win32DLL,以及在Visual C++對生成DLL文件中過程實施調(diào)用的混合編程實現(xiàn)陣列感應測井數(shù)值模擬軟件的開發(fā)。
陣列感應響應計算技術在陣列感應測井研究中起著非常重要的作用,它是儀器設計,信號合成處理,反演和測井響應異常解釋的基礎。目前為止,陣列感應響應計算已發(fā)展了很多方法,主要可分為解析解法、數(shù)值模式匹配法和有限元法三種方法。三種方法的特點是,解析解法可以計算一維縱向、徑向軸對稱旋轉(zhuǎn)地層,計算速度快;數(shù)值模式匹配法可以計算二維縱向、徑向軸對稱旋轉(zhuǎn)地層,計算速度較快;有限元法可以計算一般復雜地層,如傾斜地層等,其計算速度與網(wǎng)格剖分疏密有關。本文中計算陣列感應響應Fortran程序主要按數(shù)值模式匹配法編寫的。
混合語言編程涉及一種語言對用另一種語言編寫的函數(shù)、過程或者子過程的調(diào)用。本文中C/C++和Fortran混合編程主要是C/C++程序調(diào)用Fortran的過程或函數(shù)。為保證混合編程程序的正確運行主要解決以下幾方面問題:
(1)調(diào)用約定一致性;
(2)函數(shù)命名的一致性;
(3)參數(shù)的正確傳遞,標量參數(shù)和矢量參數(shù);
(4)VC++調(diào)用Fortran生成的動態(tài)鏈接庫(DLL)。
調(diào)用約定決定程序?qū)瘮?shù)如何調(diào)用,如何傳遞參數(shù),如何命名目標函數(shù)名。在一種語言的編譯環(huán)境中,由編譯系統(tǒng)統(tǒng)一協(xié)調(diào)函數(shù)的調(diào)用方式,因此不存在調(diào)用約定不一致的問題[3]。但在混合編程中,由于在C/C++和Fortran混合編程中,不同的語言和編譯環(huán)境,加之各自的默認調(diào)用約定又不完全一致,這就有可能導致程序鏈接錯誤或執(zhí)行錯誤。所以,調(diào)用約定的匹配是混合編程所要解決的關鍵問題。
CompaqVisualFortran6.x使用的三種調(diào)用約定(缺省約定(Default)、C約定和STDCALL約定)的參數(shù)傳遞方式、堆棧管理、可選參數(shù)等影響,見表1。
表1 CompaqVisualFortran6.x調(diào)用約定
表1中,name為程序中所定義的函數(shù)名,n為參數(shù)類型所占字節(jié)數(shù),十進制表示。
函數(shù)是通過關鍵字DLLEXPORT實現(xiàn),三種調(diào)用約定根據(jù)實際需求選擇其中一種。
由于C/C++語言字母區(qū)分大小寫,Fortran不區(qū)分標示符大小寫,C++編譯后目標標識符添加特定的修飾,使目標標識符發(fā)生改變。為避免連接失敗,必須協(xié)調(diào)C/C++和Fortran的命名約定,使編譯后目標標識符保持一致。而不同的調(diào)用約定,其命名約定也不相同。函數(shù)編譯后的命名有三種情況:大寫、小寫和大小寫混合。
C/C++和Fortran混合編程中參數(shù)傳遞主要包括:數(shù)據(jù)類型對應和參數(shù)傳遞方式。數(shù)據(jù)類型見表2。在Fortran和VisualC++過程之間參數(shù)的傳遞方式有值傳遞和引用傳遞兩種方式,前者將參數(shù)值壓入堆棧,后者將參數(shù)地址壓入堆棧。為避免鏈接錯誤,在混合語言編程中必須保證參數(shù)傳遞方式的一致性。Fortran參數(shù)傳遞方式取決于調(diào)用約定,其默認參數(shù)傳遞方式為引用,如采用C和STDCALL約定,標量參數(shù)(單個參數(shù))采用值傳遞,數(shù)組采用引用傳遞。除采用調(diào)用約定約束外,還可以通過屬性VALUE和REFERENCE使參數(shù)分別以值和引用傳遞,并忽略調(diào)用約定約束。數(shù)組參數(shù)只能通過引用方式傳遞,且通過數(shù)組名傳遞數(shù)組首地址。在混合編程中,應通過屬性VALUE和REFERENCE明確參數(shù)傳遞方式,本文不推薦通過調(diào)用約定約束參數(shù)的傳遞方式。
表2 Fortran與C/C++對應數(shù)據(jù)類型[3]
在數(shù)值計算編程中,類型相同的數(shù)據(jù)常常利用數(shù)組。和其它語言相比,Fortran90/95中對數(shù)組的操作非常方便。但在Fortran與C/C++語言的混合編程中,數(shù)組參數(shù)比較特殊,在Fortran中,數(shù)組是按列優(yōu)先在內(nèi)存中連續(xù)排列的,而C/C++中,數(shù)組是按行優(yōu)先在內(nèi)存中連續(xù)排列的。對于一維數(shù)組,兩種語言沒有任何區(qū)別。對于大于二維的數(shù)組需要特別對待,在傳遞多維數(shù)組參數(shù)時,若兩種語言的數(shù)組存儲方式不同,需要在調(diào)用前后對數(shù)組形狀進行調(diào)整,即C/C++中數(shù)組行與列交換。以上述函數(shù)QPROG中第三個參數(shù)WK(2,4)為例討論大于二維的數(shù)組參數(shù)傳遞。由于兩種語言的數(shù)組排列方式不同,C/C++中需對數(shù)組WK行列交行 ,如floatWK[2、4]。列出 C/C++和 Fortran 中數(shù)組 WK行列交換后的對應關系,見表3。
表3 C/C++和Fortran中數(shù)組WK行列交換后的對應關系
不管數(shù)組是按列存放還是按行存放,數(shù)組在內(nèi)存中都占據(jù)一串連續(xù)的存儲單元。因此,雖然兩種語言的數(shù)組下標規(guī)定不同,但在數(shù)組參數(shù)傳遞時可以通過數(shù)組名和取數(shù)組首元素的地址傳遞,其后續(xù)元素就一一被傳遞。
鏈接DLL到應用程序中有兩種方式:顯式鏈接(ExplicitLink)和隱式鏈接(ImplicitLink)。由于顯式鏈接比隱式鏈接更具靈活性,并可及時釋放內(nèi)存的特點,所以一般采用顯式鏈接方式。在該方式中,VC++通過函數(shù)調(diào)用顯式裝載和卸載DLL,并通過函數(shù)指針來調(diào)用DLL的導出函數(shù)。使用顯式鏈接的基本方式調(diào)用LoadLibrary或AfxLoadLibrary裝載DLL并得到模塊句柄;調(diào)用GetProcAddress獲得導出函數(shù)指針;在使用完畢時,調(diào)用FreeLibrary或AfxFreeLibrary釋放DLL。
陣列感應正演計算是用Fortran語言編寫的。對有關的界面與圖形系統(tǒng)的開發(fā)部分用VisualC++語言來編寫,對陣列感應正演數(shù)值計算部分用Fortran語言來編寫,在VisualC++中對Fortran中的函數(shù)進行調(diào)用實現(xiàn)陣列感應正演數(shù)值模擬計算軟件。
在C/C++和Fortran混合編程中,有兩種具體的實現(xiàn)形式:(1)靜態(tài)庫連接方式:將Fortran程序用CompaqVisualFortran6.x編譯器進行編譯,產(chǎn)生靜態(tài)目標文件 (lib文件),在VisualC++調(diào)用函數(shù)生成可執(zhí)行文件;(2)動態(tài)庫連接方式:將Fortran程序用CompaqVisualFortran6.x編譯器進行編譯,生成動態(tài)連接庫(DLL)文件。在需要調(diào)用Fortran代碼時,由VisualC++對其動態(tài)調(diào)用。
筆者采用第二種連接方式實現(xiàn)C/C++和Fortran混合編程,具體實現(xiàn)過程如下。
(1)生成動態(tài)連接庫
對陣列感應正演計算Fortran程序需作以下修改:
再用CompaqVisualFortran6.x進行編譯,分別形成動態(tài)連接庫(DLL)與靜態(tài)連接庫 (LIB)。
(2)VisualC++中定義Fortran函數(shù)接口
首先將第一步生成的態(tài)連接庫(DLL)與靜態(tài)連接庫 (LIB)文件拷貝到工程所在文件夾中,其次在C++代碼中對靜態(tài)庫作如下聲明:
#pragmacomment(lib,”dipping.lib”)
最后在C++中定義Fortran函數(shù)接口,聲明如下:
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++中調(diào)用Fortran函數(shù)完成計算
計算結(jié)果如圖1中給出三層電阻率分別為1.0Ω·m、15.0Ω·m和1.0Ω·m的地層模型的高分辨率陣列感應(HDIL)儀器的響應結(jié)果。
圖1 HDIL模擬結(jié)果
VisualC++可以快速進行界面和繪圖顯示開發(fā),而Fortran在數(shù)值運算中具有優(yōu)勢。利用兩者混合編程避免資源的浪費和重復編程,提高了程序開發(fā)效率。在實際工程分析中取得良好的應用效果。
[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年畢業(yè)于西安石油大學電子工程學院測控技術及儀器專業(yè),目前在河南南陽油田測井公司從事測井工作。郵編:473132