2016-09-16 81 views
1

我想從Python腳本訪問存儲在Fortran 77公共塊中的數據。問題是我不知道這些數據存儲在哪裏。 我正在開發的Python應用程序使用不同的庫。這些庫包含功能用下面的指令:訪問來自ctypes的公共塊變量

#include <tcsisc_common.inc> 

公共塊包含:

C 
     INTEGER*4 IDEBUG 
C 
C.... ARRAY DIMENSIONS 
     DIMENSION IDEBUG(10) 
C 
C.... COMMON BLOCK 
     COMMON /TCSD/ IDEBUG 
C 

在Python的部分(上我已經使用IPython的示例中),I加載庫:

In [1]: import ctypes 
In [2]: _libtcsisc= /home/jfreixa/project/bin/libtcsisc.so 
In [3]: _tcsisc = ctypes.CDLL(_libtcsisc, ctypes.RTLD_GLOBAL) 

問題是我不知道如何獲得IDEBUG。我曾嘗試以下,但我只是得到TCSD作爲c_long初始化爲0

In [4]: tcsd = ctypes.c_int.in_dll(_tcsisc, "TCSD_") 
In [5]: tcsd 
Out[5]: c_long(0) 
In [6]: idebug = ctypes.c_int.in_dll(_tcsisc, "IDEBUG_") 
--------------------------------------------------------------------------- 
ValueError        Traceback (most recent call last) 
<ipython-input-6-ee5018286275> in <module>() 

----> 1 idebug = ctypes.c_int.in_dll(_tcsisc,'IDEBUG_') 

ValueError: ld.so.1: python2.7: fatal: IDEBUG_: can't find symbol 

任何想法正確地獲得變量?

+2

爲什麼不寫fortran函數python可以調用來訪問這些變量。 – innoSPG

+0

由於這些庫很早就開發出來了,我想避免嘗試翻譯經過驗證的基礎架構。訪問通用塊中的變量將允許我在Python中使用它們(需要更新的部分),並且在Fortran上保留數百個不需要更新的函數。 – Jfreixa

+0

編寫一個包裝並不意味着更新任何東西!您只需編寫一個Fortran setter和getter,即可完成全新的過程。完全沒有改變!您的數百個功能可以保持不變。 –

回答

3

根據this page(特別是如何從C訪問Fortran的公共塊)和一些Q/A page有關如何從Python中訪問C結構,我們似乎如下可以訪問公共塊(儘管這可能不是很便攜,看下文):

mylib.f90

subroutine fortsub() 
    implicit none 
    integer n 
    common /mycom/ n 
    print *, "fortsub> current /mycom/ n = ", n 
end 

編譯:

$ gfortran -shared -fPIC -o mylib.so mylib.f90 

test.py

from __future__ import print_function 
import ctypes 

class Mycom(ctypes.Structure): 
    _fields_ = [ ("n", ctypes.c_int) ] 

mylib = ctypes.CDLL("./mylib.so") 

mycom = Mycom.in_dll(mylib, "mycom_") 

print(" python> modifying /mycom/ n to 777") 

mycom.n = 777 

fortsub = mylib.fortsub_ 
fortsub() 

測試:

$ python test.py 
python> modifying /mycom/ n to 777 
fortsub> current /mycom/ n =   777 

在這裏,請注意,公共塊(在這裏,mycom)的名稱由小寫字母和一個下劃線連接(假設gfortran)。因爲這個約定是依賴於編譯器的,所以編寫新的Fortran例程來設置/獲取公共塊中的值(特別是在iso_c_binding的幫助下)並且從Python調用那些例程(如在@innoSPG中建議的那樣)第一評論)。


又如包括不同類型和陣列可以是這樣的:

mylib.f90

subroutine initcom() 
    implicit none 
    integer   n(2), w !! assumed to be compatible with c_int 
    real    f(2)  !!      ... with c_float 
    double precision d(2)  !!      ... with c_double 
    common /mycom/ n, f, d, w 

    print *, "(fort) initializing /mycom/" 
    n(:) = [ 1, 2 ] 
    f(:) = [ 3.0, 4.0 ] 
    d(:) = [ 5.0d0, 6.0d0 ] 
    w = 7 
    call printcom() 
end 

subroutine printcom() 
    implicit none 
    integer   n(2), w 
    real    f(2) 
    double precision d(2) 
    common /mycom/ n, f, d, w 

    print *, "(fort) current /mycom/" 
    print *, "  n = ", n 
    print *, "  f = ", f 
    print *, "  d = ", d 
    print *, "  w = ", w 
end 

test.py

from __future__ import print_function 
import ctypes 

N = 2 

class Mycom(ctypes.Structure): 
    _fields_ = [ ("x", ctypes.c_int * N), 
       ("y", ctypes.c_float * N), 
       ("z", ctypes.c_double * N), 
       ("w", ctypes.c_int  ) ] 

mylib = ctypes.CDLL("./mylib.so") 

mycom = Mycom.in_dll(mylib, "mycom_") 

initcom = mylib.initcom_ 
initcom() 

print(" (python) current /mycom/") 
print("   x = ", mycom.x[:]) 
print("   y = ", mycom.y[:]) 
print("   z = ", mycom.z[:]) 
print("   w = ", mycom.w ) 

print(" (python) modifying /mycom/ ...") 
for i in range(N): 
    mycom.x[ i ] = (i + 1) * 10 
    mycom.y[ i ] = (i + 1) * 100 
    mycom.z[ i ] = (i + 1) * 0.1 
mycom.w = 777 

printcom = mylib.printcom_ 
printcom() 

測試:

$ python test.py 

(fort) initializing /mycom/ 
(fort) current /mycom/ 
     n =   1   2 
     f = 3.0000000  4.0000000  
     d = 5.0000000000000000  6.0000000000000000  
     w =   7 
(python) current /mycom/ 
      x = [1, 2] 
      y = [3.0, 4.0] 
      z = [5.0, 6.0] 
      w = 7 
(python) modifying /mycom/ ... 
(fort) current /mycom/ 
     n =   10   20 
     f = 100.00000  200.00000  
     d = 0.10000000000000001  0.20000000000000001  
     w =   777 
+0

當出現有關公共變量對齊的備註或警告時,可能需要在編譯Fortran源代碼時添加一些選項(例如,對於ifort使用-align)。這也是依賴於編譯器的,所以爲了避免這種情況,可能會更方便(最終)爲必要的公共變量編寫getter/setter例程,而不是直接從python訪問它們。 – roygvib