从ctypes访问通用块变量 [英] Access Common Block variables from ctypes

查看:181
本文介绍了从ctypes访问通用块变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图从Python脚本访问存储在Fortran 77公共块中的数据。问题是我不知道这些数据存储在哪里。
我正在开发的Python应用程序使用不同的库。这些库包含以下指令的函数:

  #include< tcsisc_common.inc> 

常用的块包含:

<$ p $
$ C
INTEGER * 4 IDEBUG
C
C ....阵列尺寸
DIMENSION IDEBUG(10)
C
C .... COMMON BLOCK
COMMON / TCSD / IDEBUG
C

在Python部分(在我使用iPython的例子中),我加载了库:

  In [1]:import ctypes 
在[2]中:_libtcsisc = /home/jfreixa/project/bin/libtcsisc.so
在[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(最近的最后一次调用)
< ipython-input-6-ee5018286275> in< module>()

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

ValueError:ld.so.1:python2.7:fatal:IDEBUG_:找不到符号
code>

任何想法都可以正确地获得变量?

解决方案

根据此页面(特别是如何访问Fortran常见块从C)和一些 Q / A关于如何从Python访问C结构体,我们似乎可以像下面那样访问公共块(尽管这可能不是很便携,见下面):



< ()







$ / 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>修改/ mycom / n到777)

mycom.n = 777

fortsub = mylib.fortsub_
fortsub()


$ b

测试:

  $ python test .py 
python>修改/ mycom / n至777
fortsub> current / mycom / n = 777

这里请注意,公共块的名称(这里是 mycom )是小写字母和一个下划线(假设gfortran)。这个约定是依赖于编译器的,它可能更强大/更方便编写新的Fortran例程来设置/获取公共块中的值(特别是在 iso_c_binding 的帮助下)和调用那些来自Python的例程(如第一条评论中的@innoSPG所建议的那样)。




另一个包含不同类型和数组的例子可能看起来像这样:

mylib.f90

$ p $ 子程序initcom()
隐式无
整数n( 2),w !!假定与c_int
real f(2)兼容! ...用c_float
双精度d(2)!! ... with c_double
common / mycom / n,f,d,w
$ b $ print *,(fort)initializing / mycom /
n(:) = [1 ,2]
f(:) = [3.0,4.0]
d(:) = [5.0d0,6.0d0]
w = 7
call printcom()
end

子程序printcom()
隐式无
整数n(2),w
实数f(2)
双精度d(2)
common / mycom / n,f,d,w
$ b 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)modify / 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)初始化/ 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)modify / mycom / ...
(fort)current / mycom /
n = 10 20
f = 100.00000 200.00000
d = 0.10000000000000001 0.20000000000000001
w = 777


I am trying to access the data stored in a Fortran 77 common block from a Python script. The question is that I don't know where this data is stored. The Python application that I am developing makes use of different libraries. These libraries contain functions with the following directives:

#include <tcsisc_common.inc>

The common block contains:

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

On the Python part (on the example I have used iPython), I load the library:

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

The problem is that I don't know how to get IDEBUG. I have tried the following, but I just get tcsd as a c_long initialized to 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

Any idea to correctly get the variable?

解决方案

According to this page (particularly how to access Fortran common blocks from C) and some Q/A page about how to access C struct from Python, it seems that we could access common blocks as follows (though this may be not very portable, see below):

mylib.f90

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

compile:

$ 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()

Test:

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

Here, please note that the name of the common block (here, mycom) is made lowercase and one underscore attached (by assuming gfortran). Because this convention is compiler-dependent, it may be more robust/portable to write new Fortran routines for setting/getting values in common blocks (particularly with the help of iso_c_binding) and call those routines from Python (as suggested by @innoSPG in the first comment).


Another example including different types and arrays may look like this:

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()

Test:

 $ 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

这篇关于从ctypes访问通用块变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆