2016-09-16 3 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を使用している例で)、私は、ライブラリのロード:

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

問題は、IDEBUGの入手方法がわかりません。私は、次のことを試してみましたが、私はちょうど正しく変数を取得するために、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 

任意のアイデアに初期化c_longのようTCSDを取得しますか?

+2

なぜそれらの変数へのアクセスを得るためにpythonが呼び出せるFortran関数を書かないのですか? – innoSPG

+0

ライブラリは長い間開発されていたので、検証済みのインフラストラクチャの翻訳を避けたいと考えています。共通ブロックの変数にアクセスすると、Python(更新が必要な部分)でそれらを使用し、更新する必要のない何百もの関数をFortranに残すことができます。 – Jfreixa

+0

ラッパーの作成は何かを更新することを意味するものではありません! Fortranのセッターとゲッターを書くだけで、まったく新しいプロシージャーになります。全く変更するものはありません!何百もの機能がそのまま残ることができます。 –

答えて

3

this page(特にCからFortranの共通ブロックにアクセスする方法)とQ/A pageではPythonからC structにアクセスする方法については、次のように共通ブロックにアクセスできるようです。以下):

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 

、(仮定のgfortranで)共通ブロック(ここでは、mycom)の名​​前が小文字に行われ、1アンダースコアが添付ことに注意してください。この規約はコンパイラに依存しているため、共通ブロック(特にiso_c_bindingの助けを借りて)で値を設定/取得するための新しいFortranルーチンを作成し、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)を追加する必要があります。これはコンパイラにも依存するので、Pythonから直接アクセスするのではなく、必要な共通変数のgetter/setterルーチンを書く方が便利です(最終的に)。 – roygvib

関連する問題