从ctypes访问通用块变量 [英] Access Common Block variables from 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()
$ c
$ 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屋!