2017-12-02 5 views
2

Ich möchte ein Array variabler Größe zu einer Fortran-DLL übergeben und das Ergebnis (per Referenz) erhalten, so dass ich direkt Wert erhalten kann.Python Ctypes übergeben Zeiger im Strukturfeld zu Fortran-abgeleiteten Typen

Im Fortran-Code verwende ich zuweisbare Variablen, die ich denke, ist wie ein Zeiger, um zugeordnete Adresse zu zeigen.

Ich kann wie folgt tun, aber ich weiß nicht, wie es in der Struktur zu tun:

test = POINTER(c_double)() 

sim.structtest(input, byref(test)) 

die Definition von test in Fortran ist

real(kind=8), allocatable, dimension (:) :: test 

allocate(test(1)) 

Der ursprüngliche Code:

Python-Code (structtest.py):

from ctypes import * 
import sys 
import os 


sim = cdll.LoadLibrary("struct.so") 

class Input(Structure): 
    _fields_ = [("a", c_double * 1), 
       ("b", c_double)] 

class Output(Structure): 
    _fields_ = [("a", c_double), 
       ("b", POINTER(c_double))] #-> don't know how to do 

def main(): 
    input = Input() 
    output = Output() 
    input.a[0] = 1 
    input.b = 2 

    sim.structtest(input, byref(output)) 

Fortran-Code (struct.f90):

subroutine structtest(input, output) bind(c, name='structtest') 

    USE ISO_C_BINDING 
    IMPLICIT NONE 

    !define input structure 
    TYPE T_INPUT 
     !real*8, allocatable :: a(:) 
     real(kind=8) :: a(1) 
     real(kind=8) :: b 
    END TYPE T_INPUT 

    !define output structure 
    TYPE T_OUTPUT 
     real(kind=8) :: a 
     real(kind=8), allocatable, dimension (:) :: b 
    END TYPE T_OUTPUT 


    !define a variable "input" with structure "INPUT" 
    TYPE (T_INPUT), value :: input 

    TYPE (T_OUTPUT) :: output 


    allocate(output%d(1)) 


    output%b(1) = 5 
    PRINT *, output%d(1) 

kompilieren ich die Fortran DLL wie:

python structtest.py 

ich das Ergebnis:

ifort -shared -fPIC -static-intel -o struct.so struct.f90 

ich die Python als ausführen :

*** Error in `python': free(): corrupted unsorted chunks: 0x0000000001f7af00 *** 
======= Backtrace: ========= 
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7fc9027f57e5] 
/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7fc9027fe37a] 
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7fc90280253c] 
/lib/x86_64-linux-gnu/libc.so.6(__open_catalog+0xe8)[0x7fc9027b2008] 
/lib/x86_64-linux-gnu/libc.so.6(catopen+0x4c)[0x7fc9027b1c2c] 
/home/mingster/simGeo.docker/simgeo/lib/struct.so(for__issue_diagnostic+0x11e)[0x7fc90147a77e] 
/home/mingster/simGeo.docker/simgeo/lib/struct.so(for_allocate+0x303)[0x7fc90146b9a3] 
/home/mingster/simGeo.docker/simgeo/lib/struct.so(structtest+0xae)[0x7fc90146b16e] 
/usr/lib/x86_64-linux-gnu/libffi.so.6(ffi_call_unix64+0x4c)[0x7fc901757e40] 
/usr/lib/x86_64-linux-gnu/libffi.so.6(ffi_call+0x2eb)[0x7fc9017578ab] 
/usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so(_ctypes_callproc+0x48f)[0x7fc9019673df] 
/usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so(+0x11d82)[0x7fc90196bd82] 
python(PyObject_Call+0x43)[0x4b0c93] 
python(PyEval_EvalFrameEx+0x602f)[0x4c9f9f] 
python(PyEval_EvalFrameEx+0x5e0f)[0x4c9d7f] 
python(PyEval_EvalCodeEx+0x255)[0x4c2705] 
python(PyEval_EvalCode+0x19)[0x4c24a9] 
python[0x4f19ef] 
python(PyRun_FileExFlags+0x82)[0x4ec372] 
python(PyRun_SimpleFileExFlags+0x191)[0x4eaaf1] 
python(Py_Main+0x6c8)[0x49e208] 
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7fc90279e830] 
python(_start+0x29)[0x49da59] 
======= Memory map: ======== 
00400000-006e9000 r-xp 00000000 08:01 525090        /usr/bin/python2.7 
008e8000-008ea000 r--p 002e8000 08:01 525090        /usr/bin/python2.7 
008ea000-00961000 rw-p 002ea000 08:01 525090        /usr/bin/python2.7 
00961000-00984000 rw-p 00000000 00:00 0 
01f10000-01ff6000 rw-p 00000000 00:00 0         [heap] 
7fc8fc000000-7fc8fc021000 rw-p 00000000 00:00 0 
7fc8fc021000-7fc900000000 ---p 00000000 00:00 0 
7fc901246000-7fc90125c000 r-xp 00000000 08:01 38797837     /lib/x86_64-linux-gnu/libgcc_s.so.1 
7fc90125c000-7fc90145b000 ---p 00016000 08:01 38797837     /lib/x86_64-linux-gnu/libgcc_s.so.1 
7fc90145b000-7fc90145c000 rw-p 00015000 08:01 38797837     /lib/x86_64-linux-gnu/libgcc_s.so.1 
7fc90145c000-7fc901504000 r-xp 00000000 08:01 51643749     /home/mingster/simGeo.docker/simgeo/lib/struct.so 
7fc901504000-7fc901704000 ---p 000a8000 08:01 51643749     /home/mingster/simGeo.docker/simgeo/lib/struct.so 
7fc901704000-7fc90170a000 rw-p 000a8000 08:01 51643749     /home/mingster/simGeo.docker/simgeo/lib/struct.so 
7fc90170a000-7fc901752000 rw-p 00000000 00:00 0 
7fc901752000-7fc901759000 r-xp 00000000 08:01 526635      /usr/lib/x86_64-linux-gnu/libffi.so.6.0.4 
7fc901759000-7fc901958000 ---p 00007000 08:01 526635      /usr/lib/x86_64-linux-gnu/libffi.so.6.0.4 
7fc901958000-7fc901959000 r--p 00006000 08:01 526635      /usr/lib/x86_64-linux-gnu/libffi.so.6.0.4 
7fc901959000-7fc90195a000 rw-p 00007000 08:01 526635      /usr/lib/x86_64-linux-gnu/libffi.so.6.0.4 
7fc90195a000-7fc901978000 r-xp 00000000 08:01 30543353     /usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so 
7fc901978000-7fc901b77000 ---p 0001e000 08:01 30543353     /usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so 
7fc901b77000-7fc901b78000 r--p 0001d000 08:01 30543353     /usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so 
7fc901b78000-7fc901b7c000 rw-p 0001e000 08:01 30543353     /usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so 
7fc901b7c000-7fc901e54000 r--p 00000000 08:01 529135      /usr/lib/locale/locale-archive 
7fc901e54000-7fc901f5c000 r-xp 00000000 08:01 38797852     /lib/x86_64-linux-gnu/libm-2.23.so 
7fc901f5c000-7fc90215b000 ---p 00108000 08:01 38797852     /lib/x86_64-linux-gnu/libm-2.23.so 
7fc90215b000-7fc90215c000 r--p 00107000 08:01 38797852     /lib/x86_64-linux-gnu/libm-2.23.so 
7fc90215c000-7fc90215d000 rw-p 00108000 08:01 38797852     /lib/x86_64-linux-gnu/libm-2.23.so 
7fc90215d000-7fc902176000 r-xp 00000000 08:01 38797934     /lib/x86_64-linux-gnu/libz.so.1.2.8 
7fc902176000-7fc902375000 ---p 00019000 08:01 38797934     /lib/x86_64-linux-gnu/libz.so.1.2.8 
7fc902375000-7fc902376000 r--p 00018000 08:01 38797934     /lib/x86_64-linux-gnu/libz.so.1.2.8 
7fc902376000-7fc902377000 rw-p 00019000 08:01 38797934     /lib/x86_64-linux-gnu/libz.so.1.2.8 
7fc902377000-7fc902379000 r-xp 00000000 08:01 38797927     /lib/x86_64-linux-gnu/libutil-2.23.so 
7fc902379000-7fc902578000 ---p 00002000 08:01 38797927     /lib/x86_64-linux-gnu/libutil-2.23.so 
7fc902578000-7fc902579000 r--p 00001000 08:01 38797927     /lib/x86_64-linux-gnu/libutil-2.23.so 
7fc902579000-7fc90257a000 rw-p 00002000 08:01 38797927     /lib/x86_64-linux-gnu/libutil-2.23.so 
7fc90257a000-7fc90257d000 r-xp 00000000 08:01 38797825     /lib/x86_64-linux-gnu/libdl-2.23.so 
7fc90257d000-7fc90277c000 ---p 00003000 08:01 38797825     /lib/x86_64-linux-gnu/libdl-2.23.so 
7fc90277c000-7fc90277d000 r--p 00002000 08:01 38797825     /lib/x86_64-linux-gnu/libdl-2.23.so 
7fc90277d000-7fc90277e000 rw-p 00003000 08:01 38797825     /lib/x86_64-linux-gnu/libdl-2.23.so 
7fc90277e000-7fc90293e000 r-xp 00000000 08:01 38797811     /lib/x86_64-linux-gnu/libc-2.23.so 
7fc90293e000-7fc902b3e000 ---p 001c0000 08:01 38797811     /lib/x86_64-linux-gnu/libc-2.23.so 
7fc902b3e000-7fc902b42000 r--p 001c0000 08:01 38797811     /lib/x86_64-linux-gnu/libc-2.23.so 
7fc902b42000-7fc902b44000 rw-p 001c4000 08:01 38797811     /lib/x86_64-linux-gnu/libc-2.23.so 
7fc902b44000-7fc902b48000 rw-p 00000000 00:00 0 
7fc902b48000-7fc902b60000 r-xp 00000000 08:01 38797898     /lib/x86_64-linux-gnu/libpthread-2.23.so 
7fc902b60000-7fc902d5f000 ---p 00018000 08:01 38797898     /lib/x86_64-linux-gnu/libpthread-2.23.so 
7fc902d5f000-7fc902d60000 r--p 00017000 08:01 38797898     /lib/x86_64-linux-gnu/libpthread-2.23.so 
7fc902d60000-7fc902d61000 rw-p 00018000 08:01 38797898     /lib/x86_64-linux-gnu/libpthread-2.23.so 
7fc902d61000-7fc902d65000 rw-p 00000000 00:00 0 
7fc902d65000-7fc902d8b000 r-xp 00000000 08:01 38797787     /lib/x86_64-linux-gnu/ld-2.23.so 
7fc902dc5000-7fc902f7b000 rw-p 00000000 00:00 0 
7fc902f86000-7fc902f87000 rw-p 00000000 00:00 0 
7fc902f87000-7fc902f88000 rwxp 00000000 00:00 0 
7fc902f88000-7fc902f8a000 rw-p 00000000 00:00 0 
7fc902f8a000-7fc902f8b000 r--p 00025000 08:01 38797787     /lib/x86_64-linux-gnu/ld-2.23.so 
7fc902f8b000-7fc902f8c000 rw-p 00026000 08:01 38797787     /lib/x86_64-linux-gnu/ld-2.23.so 
7fc902f8c000-7fc902f8d000 rw-p 00000000 00:00 0 
7ffc38bde000-7ffc38bff000 rw-p 00000000 00:00 0       [stack] 
7ffc38cd8000-7ffc38cda000 r--p 00000000 00:00 0       [vvar] 
7ffc38cda000-7ffc38cdc000 r-xp 00000000 00:00 0       [vdso] 
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0     [vsyscall] 
Aborted (core dumped) 
+0

Obwohl Sie der Fortran-Subroutine das 'bind'-Attribut geben, ist es bemerkenswert, dass die Dummy-Argumente nicht C-interoperabel sind (und sie haben nicht das Attribut' bind'). – francescalus

+0

Sehr eng verwandt https://stackoverflow.com/questions/28543180/fortran-derived-types-containing-pinters-to-be-accessible-from-c –

+0

@VladimirF Vielen Dank, das hilft sehr. Über C-Interoperabilität von Intel Fortran's mit C: [Fortran2003_InterOpC.ppt] (https://modelingguru.nasa.gov/servlet/JiveServlet/previewBody/1376-102-5-1827/Fortran2003_InterOpC.ppt) –

Antwort

0

Dank All,

belows ist das Ausführungsbeispiel für Python mehrdimensionale Array passieren

Python-Code FORTRAN:

from ctypes import * 
import ctypes 
import sys 
import os 
import numpy as np 

sim = cdll.LoadLibrary(os.path.dirname(os.path.abspath(__file__)) + "/lib/struct.so") 


class Param(Structure): 
    pass 

class Result(Structure): 
    pass 

def main(): 

    x = 2 
    y = 3 
    z = 4 
    Param._fields_ = [("len_x", c_int), 
       ("len_y", c_int), 
       ("len_z", c_int), 
       ("c", POINTER(c_double)), 
       ("d", POINTER(c_double * x)), 
       ("e", POINTER(c_double * x * y))] 

    Result._fields_ = [("len_x", c_int), 
       ("len_y", c_int), 
       ("len_z", c_int), 
       ("f", POINTER(c_double)), 
       ("g", POINTER(c_double * x)), 
       ("h", POINTER(c_double * x * y))] 

    param = Param() 
    result = Result() 

    cc = (c_double * x)() 
    dd = ((c_double * x) * y)() 
    ee = ((((c_double * x) * y) * z))() 

    #[x]  
    cc[0] = 10.0 
    cc[1] = 20.0 

    #[y][x] 
    dd[0][0] = 10.0 
    dd[1][0] = 20.0 
    dd[2][0] = 30.0 
    dd[0][1] = 40.0 
    dd[1][1] = 50.0 
    dd[2][1] = 60.0 

    #[z][y][x] 
    ee[0][0][0] = 1.0 
    ee[1][0][0] = 2.0 
    ee[2][0][0] = 3.0 
    ee[0][1][0] = 4.0 
    ee[1][1][0] = 5.0 
    ee[2][1][0] = 6.0 


    param.len_x = x 
    param.len_y = y 
    param.len_z = z 

    param.c = cc 
    param.d = dd 
    param.e = ee 

    sim.structtest(byref(param), byref(result)) 

    #[x] 
    print "1D" 
    print result.f[0] 
    print result.f[1] 

    #[y][x] 
    print "2D" 
    print result.g[0][0] 
    print result.g[1][0] 
    print result.g[2][0] 
    print result.g[0][1] 
    print result.g[1][1] 
    print result.g[2][1] 

    #[z][y][x] 
    print "3D" 
    print result.h[0][0][0] 
    print result.h[1][0][0] 
    print result.h[2][0][0] 
    print result.h[0][1][0] 
    print result.h[1][1][0] 
    print result.h[2][1][0] 



if __name__ == "__main__": 
    result = main() 

Fortran-Code:

subroutine structtest(param, result) bind(c, name="structtest") 

    use, intrinsic :: ISO_C_BINDING 
    implicit none 

    type, BIND(C) :: args 
     integer (C_INT) :: len_x 
     integer (C_INT) :: len_y 
     integer (C_INT) :: len_z 
     type (C_PTR) :: c 
     type (C_PTR) :: d 
     type (C_PTR) :: e 
    end type args 

    type, BIND(C) :: output 
     integer (C_INT) :: len_x 
     integer (C_INT) :: len_y 
     integer (C_INT) :: len_z 
     type (C_PTR) :: f 
     type (C_PTR) :: g 
     type (C_PTR) :: h 
    end type output  

    type (args), intent(in):: param 
    type (output), intent(out):: result 

    real (C_DOUBLE), pointer :: arg_array_c(:) 
    real (C_DOUBLE), pointer :: arg_array_d(:,:) 
    real (C_DOUBLE), pointer :: arg_array_e(:,:,:) 
    real (C_DOUBLE), ALLOCATABLE, target, save :: result_array_f(:) 
    real (C_DOUBLE), ALLOCATABLE, target, save :: result_array_g(:,:) 
    real (C_DOUBLE), ALLOCATABLE, target, save :: result_array_h(:,:,:) 

    ! Associate c_array with an array allocated in C 
    call C_F_POINTER (param%c, arg_array_c, [param%len_x]) 
    call C_F_POINTER (param%d, arg_array_d, [param%len_x,param%len_y]) 
    call C_F_POINTER (param%e, arg_array_e, [param%len_x,param%len_y,param%len_z]) 

    ![x] 
    print *,"1D" 
    print *,arg_array_c(1) 
    print *,arg_array_c(2) 

    ![x][y] 
    print *,"2D" 
    print *,arg_array_d(1,1) 
    print *,arg_array_d(1,2) 
    print *,arg_array_d(1,3) 
    print *,arg_array_d(2,1) 
    print *,arg_array_d(2,2) 
    print *,arg_array_d(2,3) 

    ![x][y][z] 
    print *,"3D" 
    print *,arg_array_e(1,1,1) 
    print *,arg_array_e(1,1,2) 
    print *,arg_array_e(1,1,3) 
    print *,arg_array_e(1,2,1) 
    print *,arg_array_e(1,2,2) 
    print *,arg_array_e(1,2,3) 

    ! Allocate an array and make it available in C 

    result%len_x = param%len_x 
    result%len_y = param%len_y 
    result%len_z = param%len_z 

    ALLOCATE (result_array_f(result%len_x)) 
    ALLOCATE (result_array_g(result%len_x, result%len_y)) 
    ALLOCATE (result_array_h(result%len_x, result%len_y, result%len_z)) 


    result%f = c_loc(result_array_f) 
    result%g = c_loc(result_array_g) 
    result%h = c_loc(result_array_h) 

    ![x] 
    result_array_f(1) = arg_array_c(1) 
    result_array_f(2) = arg_array_c(2) 

    ![x][y] 
    result_array_g(1,1) = arg_array_d(1,1) 
    result_array_g(1,2) = arg_array_d(1,2) 
    result_array_g(1,3) = arg_array_d(1,3) 
    result_array_g(2,1) = arg_array_d(2,1) 
    result_array_g(2,2) = arg_array_d(2,2) 
    result_array_g(2,3) = arg_array_d(2,3)   

    ![x][y][z] 
    result_array_h(1,1,1) = arg_array_e(1,1,1) 
    result_array_h(1,1,2) = arg_array_e(1,1,2) 
    result_array_h(1,1,3) = arg_array_e(1,1,3) 
    result_array_h(1,2,1) = arg_array_e(1,2,1) 
    result_array_h(1,2,2) = arg_array_e(1,2,2) 
    result_array_h(1,2,3) = arg_array_e(1,2,3) 

end 

Ausgabe:

1D 
    10.0000000000000 
    20.0000000000000 
2D 
    10.0000000000000 
    20.0000000000000 
    30.0000000000000 
    40.0000000000000 
    50.0000000000000 
    60.0000000000000 
3D 
    1.00000000000000 
    2.00000000000000 
    3.00000000000000 
    4.00000000000000 
    5.00000000000000 
    6.00000000000000 
1D 
10.0 
20.0 
2D 
10.0 
20.0 
30.0 
40.0 
50.0 
60.0 
3D 
1.0 
2.0 
3.0 
4.0 
5.0 
6.0 
+0

Notieren Sie diese Art = 8' existiert nicht für mehrere Fortran-Compiler. Ihr Code wird nicht mit ihnen kompiliert. Es ist nicht tragbar. Wenn Sie bereits 'iso_c_binding' verwenden, verwenden Sie einfach' kind = c_double'? Du kannst das 'kind =' sicher weglassen, wenn du denkst, dass es zu lang ist (ich lasse es immer weg). Oder definiere eine Konstante mit einem kürzeren Namen. Es ist SO VIEL besser ... –

+0

Und auch bitte beachten Sie, dass eine gute Antwort würdig einige upvote einige Beschreibung enthalten sollte, was geändert wurde und warum. Wenn die Antwort von @ IanH Ihnen erheblich geholfen hat, sollten Sie sie akzeptieren oder verbessern. Siehe [Tour] für mehr. –

+0

@VladimirF Verstanden. Upvoted. –

0

Das Layout im Speicher des sogenannten Deskriptors für eine zuweisbare Komponente ist Fortran-Prozessor-spezifisch. Für eine zuweisbare Array-Komponente ist es immer viel mehr als nur eine einzige Speicheradresse. In der Dokumentation Ihres Fortran-Prozessors finden Sie die Details zum Deskriptor. Code, der auf dem Layout des Deskriptors beruht, ist von Natur aus prozessorspezifisch.

Die entsprechende Dokumentation für die aktuelle Version des Intel-Compilers finden Sie im Abschnitt Handling Fortran Array Descriptors.

Der aktuelle Entwurf für Fortran 2018 bietet zusätzliche Funktionen für die Interoperation mit zuweisbaren Dummy-Argumenten, aber es gibt weiterhin plattformspezifische Merkmale.

(Im angezeigten Code verwenden Sie das intrinsische Modul ISO_C_BINDING, aber der Code scheint dann nichts davon zu referenzieren ...)