Seite 1 von 1

Fortran 77 dll importieren + function aufrufen

Verfasst: Montag 5. März 2012, 16:22
von liddokun88
Hallo alle zusammen :D

Habe da ein Problem, was wie ich finde auf den meisten Seiten nicht wirklich gelöst wurde, daher dachte ich mir ich frage hier mal.
Ich habe ein .dll welche unter Fortran 77 compiliert wurde. Ich möchte diese in Python importieren, und eine Funktion in dieser .dll aufrufen. Die .dll hat den Namen Eth.dll und ich möchte gerne die Funktion CP_ABC_Eth(A,B,C) aus dieser aufrufen.

Hier vielleicht mal kurz was ich bisher habe:

from ctypes import *

# give location of dll
Eth = cdll.LoadLibrary("Eth.dll")

# call the functions in the dll
A=1
B=1
C=-1000
CP= Eth.CP_ABC_Eth(A,B,C)

print "CP"


wenn ich das versuche zu rechnen, erhalte ich folgende Fehlermeldung:

Traceback (most recent call last):
File "C:\...\testfile", line 11, in <module>
CP= Eth.CP_ABC_Eth(A,B,C)
WindowsError: exception: access violation reading 0x00000001

Hoffe mir kann einer weiterhelfen.

Vielen Dank im Voraus :mrgreen:

Re: Fortran 77 dll importieren + function aufrufen

Verfasst: Montag 5. März 2012, 17:49
von lunar
@liddokun88: Versuche einmal, die Signatur dieser Funktion so wie in der ctypes-Dokumentation angegeben zu spezifizieren. Ohne wird implizit angenommen, dass die Argumente von C-Typ "int" sind.

Re: Fortran 77 dll importieren + function aufrufen

Verfasst: Dienstag 6. März 2012, 09:18
von liddokun88
Viellen Dank erstmal für die Anwort.

Irgendwie stehe ich da auf dem Schlauch. Die dll an sich wird bei mir eingelesen, aber der Aufruf der Funktion klappt ja nicht. Aber in der Docu finde ich unter ctypes nicht unbedingt wie du das meinst mit dem deklarieren als andere Datentyp. Für die Inputvariablen A,B,C ist das kein Problem, aber für die Funktion finde ich nichts direkt.

Re: Fortran 77 dll importieren + function aufrufen

Verfasst: Dienstag 6. März 2012, 09:32
von BlackJack

Re: Fortran 77 dll importieren + function aufrufen

Verfasst: Mittwoch 7. März 2012, 09:40
von liddokun88
Hallo alle zusammen.

Bin der Sache näher gekommen. Ich kann nun die dll einlesen und die Funktion darin aufrufen.
Es rechnet zwar noch nicht richtig, aber denke das bekommt man auch noch hin.
Vom Syntax her sieht das nun wie folgt aus:

Code: Alles auswählen

from ctypes import *

# give location of dll
Eth = windll.LoadLibrary("Eth.dll");

# call the functions in the dll
def CP_ABC(A,B,C):
    A =c_double()
    B=c_double()
    C =c_double()
    CP_ABC= Eth.CP_AB_Eth(byref(A),byref(B),byref(C))
Wenn ich nun die definierte Funktion CP_ABC aufrufe,die entsprechenden inputparameter eingebe, dann rechnet er mir aber noch unsinn aus. wenn ich also z.B.

Code: Alles auswählen

print CP_ABC(10,100,-1000)
eingebe, erhalte ich als Lösung None . Es sollte aber eigentlich ein double heraus kommen. Hat da einer eine Ahnung woran das liegen kann?

Re: Fortran 77 dll importieren + function aufrufen

Verfasst: Mittwoch 7. März 2012, 09:50
von deets
1. Bitte benutz Python code-tags, damit man das lesen kann
2. Du hast das immer noch nicht verstanden, wie du einer Funktion eine Signatur verpasst. Damit kann das ganze dann nicht funktionieren. Bitte erzaehl uns doch mal, wie genau die Funktion deklariert ist. Also in C zb sowas wie

Code: Alles auswählen

int do_somenthing(int a, int *b);
Anhand dieser Signatur musst du dann ctypes mitteilen, wie die Parameter der Funktion auszusehen haben.

Re: Fortran 77 dll importieren + function aufrufen

Verfasst: Mittwoch 7. März 2012, 11:21
von liddokun88
Die Funktion ist wie gesagt Fortran 77 und vom Typ

Code: Alles auswählen


REAL*8 FUNCTION CP_ABC_ETH (REAL*8 A,REAL*8 B, REAL*8 C)

es handelt sich also hierbei beim In- und Output um double Werte.

Re: Fortran 77 dll importieren + function aufrufen

Verfasst: Mittwoch 7. März 2012, 11:57
von BlackJack
@liddokun88: Deine `CP_ABC()`-Funktion gibt `None` zurück weil das alle Python-Funktionen machen, bei denen man nicht explizit etwas zurück gibt. Dafür gibt es die ``return``-Anweisung. Stell Dir einfach ein ``return None`` am Ende von jeder Funktionsdefinition vor. An der Stelle solltest Du vielleicht ein Python-Tutorial durcharbeiten für die Grundlagen.

Laut Fortran-Signatur erwartet die Funktion Argumente vom C-Typ `double`, Du übergibst in Deiner Funktion aber Werte vom C-Typ *Pointer auf `double`*.

Damit `ctypes` weiss wie die Argumente übergeben werden müssen und welchen Typ das Ergebnis hat, musst Du wie schon gesagt diese Informationen an die dafür vorgesehenen Attribute des Funktionsobjektes binden, das Du von der DLL abfragst. Siehe den Abschnitt in der Dokumentation, den ich weiter oben verlinkt habe und auch den darauf folgenden Abschnitt für den Typ des Rückgabewertes.

Re: Fortran 77 dll importieren + function aufrufen

Verfasst: Donnerstag 8. März 2012, 10:47
von liddokun88
Ich habe mal versucht aus ctypes schlau zu werden. Wahrscheinlich ist das aber auch wieder total falsch.
Wäre nett wenn einer mal sagen könnte wie das den nun in meinem bsp. aussehen muss.

Code: Alles auswählen


# call the functions in the dll
def CP_ABC(A,B,C):
        CP = Eth.CP_ABC_Eth  #name of function
        CP.restype = c_double   #deklaration output
        CP.argtypes= [c_double,c_double,c_double]   #deklaration input
        CP = CP(p,t,x)
        return CP

bei der Variante erhalte ich ebenfalls einen Fehler und zwar:

Code: Alles auswählen

  File "C:\...\testfile", line 12, in CP_ABC
    CP = CP(A,B,C)
WindowsError: exception: access violation reading 0x00000000

Re: Fortran 77 dll importieren + function aufrufen

Verfasst: Donnerstag 8. März 2012, 11:56
von BlackJack
@liddokun88: Das sollte eigentlich richtig sein. Jetzt könnte es noch sein, dass die DLL eine andere Aufrufkonvention verwendet. Also das man sie mit `windll` statt `cdll` laden muss.

Oder die Parameterübergabe funktioniert bei Fortran ganz anders als bei C. Dann wäre ich ein wenig ratlos.

Bei Deinem Beispiel ist die Python-Funktion relativ nutzlos, weil man das erstellen des C-Types-Funktionsobjektes auch aus der Funktion heraus ziehen kann — das muss man ja nicht jedes mal aufs neue bei jedem Aufruf machen. Dann besteht die Python-Funktion nur noch aus einem weiterreichen der Argumente.

Etwas ungünstig ist es auch den selben Namen (`CP`) innerhalb einer Funktion für so grundverschiedene Dinge zu verwenden.

Re: Fortran 77 dll importieren + function aufrufen

Verfasst: Donnerstag 8. März 2012, 12:17
von BlackJack
@liddokun88: Kurze Suche im Netz nach der Aufrufkonvention von Fortran (Suchanfrage „fortran77 library calling convention from c”) ergab als ersten Treffer folgende Seite: http://www.math.utah.edu/software/c-wit ... ence-diffs

Demnach muss man immer Pointer übergeben, auch auf skalare Werte. Ungetestet:

Code: Alles auswählen

c_double_p = POINTER(c_double)

eth_lib = windll.LoadLibrary('Eth.dll') # oder `cdll`...

_cp_ab = eth_lib.CP_AB_Eth
_cp_ab.argtypes = [c_double_p, c_double_p, c_double_p]
_cp_ab.restype = c_double

def cp_abc(a, b, c):
    a = c_double(a)
    b = c_double(b)
    c = c_double(c)
    return _cp_ab(byref(a), byref(b), byref(c))

Re: Fortran 77 dll importieren + function aufrufen

Verfasst: Donnerstag 8. März 2012, 13:53
von liddokun88
Danke für die schnelle Nachricht. Hab das mal geändert so dass es nun wie folgt aussieht.

Code: Alles auswählen


# import all functions from ctypes
from ctypes import *

# deklaration of double in/output
c_double_p = POINTER(c_double)    

# give location of dll
Eth = windll.LoadLibrary("Eth.dll");

# call the functions in the dll
def CP_ABC(A,B,C):
    _cp_ptx = Eth.CP_ABC_Eth     #select function in dll
    _cp_ptx.argtypes = [c_double_p,c_double_p,c_double_p] # input to double
    _cp_ptx.restype = c_double_p       
#   change imput implicit to double
    A = c_double(A)
    B = c_double(B)
    B = c_double(C)
#   return value to console
    return _cp_ptx(byref(A), byref(B), byref(C))
Als Rückgabewert erhalte ich

Code: Alles auswählen

_main__.LP_c_double object at 0x02983260>
Was sagt mir das jetzt ?

Re: Fortran 77 dll importieren + function aufrufen

Verfasst: Donnerstag 8. März 2012, 14:21
von BlackJack
@liddokun88: Das sagt Dir dass `ctypes` versucht den Rückgabewert als „Pointer auf double” zu interpretieren, weil Du das fälschlicherweise so angegegen hast. `restype` muss nur `c_double` sein.

Und ich hätte ja einen `NameError` erwartet, weil den Namen `p`, `t`, und `x` nirgends etwas zugewiesen wird.

Re: Fortran 77 dll importieren + function aufrufen

Verfasst: Donnerstag 8. März 2012, 14:28
von liddokun88
ahhh endlich funktioniert es :D :D :D :D

Hattest recht mit dem c_double bei restype. Habe das geändert und alles geht.

Viellen Dank für die Hilfe :D

Re: Fortran 77 dll importieren + function aufrufen

Verfasst: Freitag 6. April 2012, 14:13
von liddokun88
als nachtrag nochmal eine Frage,

wie kann ich dem Algorithmus sagen, das der input C z.B. ein Array sein muss ?

Also angenommen C ist ein double Array mit 8 Argumenten, wie müsste ich das Argument C dann ändern?

Re: Fortran 77 dll importieren + function aufrufen

Verfasst: Freitag 6. April 2012, 14:21
von BlackJack
@liddokun88: Arraytypen werden bei `ctypes` mit dem ``*``-Operator erzeugt.

Code: Alles auswählen

In [1]: import ctypes as ct

In [2]: ct.c_double * 8
Out[2]: <class '__main__.c_double_Array_8'>

Re: Fortran 77 dll importieren + function aufrufen

Verfasst: Freitag 6. April 2012, 14:55
von liddokun88
Ich stehe heute auf dem Schlauch, wie soll das nun aussehen?

Code: Alles auswählen

from ctypes import *
c_double_p = POINTER(c_double)    
test = windll.LoadLibrary("test.dll");

# call the functions in the dll
def A(B,C):        # wobei C ein double array mit 8 argumenten ist
     A = test.A_BC     #select function in dll
     A.argtypes = [c_double_p,ctypes.c_double * 8] # input to double
     A.restype = c_double_p       

     B = c_double(B)

#   return value to console
    return A(byref(B), byref(class '__main__.c_double_Array_8'))
 
meinst du das so in der Richtung?

Re: Fortran 77 dll importieren + function aufrufen

Verfasst: Freitag 6. April 2012, 18:03
von deets
Das ist doch noch nicht mal gueltiges Python.

Es steht in der ctypes-Doku wie man Array-Typen anlegt, und damit arbeitet um konkrete Arrays und Referenzen darauf zu erzeugen.

http://python.net/crew/theller/ctypes/t ... tml#arrays