2017-01-17 11 views
1

Ich schreibe einen numerischen numerischen Löser in Fortran. Ich habe ein Modul für das gleiche erstellt, das aus dem Hauptprogramm aufgerufen wird. Ich habe external für den Aufruf der unbekannten Funktion verwendet, als ich für Ode erster Ordnung schrieb. Doch auf die Replikation des Ergebnisses für mehr als eine Dimension external mit bekomme ich folgende FehlerVerwendung einer externen Funktion in einem Modul

Error: EXTERNAL attribute conflicts with DIMENSION attribute in 'f_x' 

Das bedeutet, mein Compiler keine externe Funktion mit Array-Ausgang verarbeiten kann.

ich versuchte, einen Schnittstellenblock unter Verwendung der Parameter der Funktion mit festen Abmessungen vordefinieren und I mit diesem Fehler am Ende

Error: PROCEDURE attribute conflicts with INTENT attribute in 'f_x' 

Gibt es eine Möglichkeit in Fortran eine externe Funktion der Rückkehr zu einem Array initialisiert wird, um eine Verwendung von Dummy-Funktion in einem Unterprogramm.

Hier ist der Code, den ich verwendet habe.

module int_adaptive 
implicit none 
contains 

subroutine RK4nd(f_x, norder, nvar, x_0, t_0, t_f, x_out, t_out) 
    INTERFACE 
     FUNCTION f_x (x_0, t_0) 
      integer, parameter :: dp=kind(0.d0) 
      REAL(dp), INTENT(IN) :: x_0(2, 3), t_0 
      REAL, intent(out) :: f_x(2,3) 
     END FUNCTION f_x 
    END INTERFACE 


    integer, parameter :: dp=kind(0.d0) 
    integer    :: norder, i, nvar 
    external   :: f_x 
    real(dp), intent(in):: x_0(norder, nvar), t_0, t_f 
    real(dp)   :: x_out(norder, nvar), t_out, k1(norder, nvar), y1(norder, nvar), y(norder, nvar) 
    real(dp)   :: k2(norder, nvar), k3(norder, nvar), k4(norder, nvar),& 
          y2(norder, nvar), y3(norder, nvar), y4(norder, nvar)!, f_x(norder, nvar) 
    real(dp)   :: h_min, h_0, h_max, tol, err_est, h, t 

    if (h_0<h) then 
     h = h_0 
    end if 
    if ((t_f - t_0) < 0.0) then 
     h = -h 
    end if 
    t = t_0 
    y = x_0 

    do while (t .NE. t_f) 
     k1 = f_x(y, t) 
     y1 = y + k1*h/2.0 

     k2 = f_x(y1, t+h/2.0) 
     y2 = y + k2*h/2.0 

     k3 = f_x(y2, t+h/2.0) 
     y3 = y + k3*h 

     k4 = f_x(y3, t+h) 
     y4 = y + (k1+ 2*k2 + 2*k3 +k4)*h/6.0 

     t = t + h 
     y = y4 

    end do 

    x_out = y 
    t_out = t 

end subroutine 
end module 

Ich könnte einen Standard-Integrator mit festen Funktionseingang innerhalb eines Moduls definieren und direkt beim Namen nennen, aber da mich mit ODE des verschiedenen Aufträge befassen wird es jedes Mal kompliziert sein ich die Reihenfolge bin zu ändern, ich werde Sie müssen dieses Modul ebenfalls aktualisieren.

Antwort

3

Sie haben hier zwei unterschiedliche Probleme.

Die erste ist, dass Ihre Angabe der expliziten Schnittstelle für die Funktion f_xincorrect ist: das Funktionsergebnis f_x müssen das intent(out) Attribut nicht haben. Dies deckt die zweite Fehlermeldung ab.

Die erste Fehlermeldung auf die spätere Verwendung von

external f_x 

Diese external Anweisung verwendet wird, gibt f_x das external Attribut. Was gut ist, weil die Dummy-Prozedur eine externe Funktion ist. Sie haben dieser Prozedur jedoch auch eine explizite Schnittstelle mit dem (jetzt korrigierten) Schnittstellenblock gegeben. Dieser Schnittstellenblock gibt auch an, dass die Prozedur das Attribut external hat.

Dadurch haben Sie eine Einschränkung verletzt, dass eine Entität in einem Scoping-Block nicht zweimal dasselbe Attribut erhält. Um dieses Problem zu beheben, sollten Sie eine der Spezifikationen entfernen. Da die Funktion ein Array-Ergebnis zurückgibt, muss ihre Schnittstelle in der Subroutine, in der sie referenziert wird, explizit sein, so dass der Schnittstellenblock beibehalten werden muss. Das heißt, entfernen Sie die external Anweisung.

Aus Gründen der Klarheit sollten Sie auch die auskommentierte real(dp) f_x(norder, nvar) Deklaration entfernen. Eine solche Deklaration ist für eine Funktion fehlerhaft.

+0

Ich habe den Punkt auf dem Entfernen der externen Block, aber es war der Vorsatz, der den Trick getan hat. Kein Compilerfehler. Brauchen Sie es zu testen. Vielen Dank – Astroynamicist

1

Wie Francescalus bereits darauf hingewiesen, sollte eine Funktion entweder explizit INTERFACEd oder als EXTERNAL deklariert werden - nicht beides. Die Verwendung von EXTERNAL ist ein altmodischer Fortran, da die Funktionsschnittstelle in Fortran 90 eingeführt wurde, um die Notwendigkeit von EXTERNAL zu ersetzen, was ein ziemlich veraltetes Merkmal ist, das immer noch für die Rückwärtskompatibilität gültig ist.

Darüber hinaus kann ein Funktionsergebnis kein INTENT-Attribut haben. Eine Funktion soll ein Ergebnis mit "seinem eigenen Namen" zurückgeben, wie in y=f_x(...).Daher sollten Sie entweder f_x selbst als REAL deklarieren (ohne ein INTENT-Attribut), oder noch besser das RESULT-Attribut, sowohl in der Funktionsdeklaration als auch in seiner Schnittstelle. Das Verwenden des RESULT-Attributs ist tatsächlich in rekursiven Funktionen erforderlich, es ist jedoch eine gute Vorgehensweise, dies auch dann zu tun, wenn die Funktion nicht rekursiv ist. So sollte die Schnittstelle für Ihre Funktion als

INTERFACE 
    FUNCTION f_x (x_0, t_0) RESULT(res) 
     INTEGER, PARAMETER :: dp=kind(0.d0) 
     REAL(kind=dp), DIMENSION(2,3), INTENT(IN) :: x_0 
     REAL(kind=dp), INTENT(IN) :: t_0 
     REAL, DIMENSION(2,3) :: res 
    END FUNCTION f_x 
END INTERFACE 

In Ihrer tatsächlichen f_x Implementierung geschrieben werden, sollten Sie res (oder was auch immer Sie das Ergebnis nennen) als die Variable das Ergebnis hält diese Funktion zurückkehren.

Beachten Sie, dass ich auch ein paar Modifikationen vorgenommen habe, die nicht unbedingt notwendig sind, aber sehr zu empfehlen: wie Sie, REAL(dp), INTENT(IN) :: x_0(2, 3) ist auch altmodisch Fortran (das DIMENSION-Attribut wurde eingeführt, um die Dinge klarer zu machen). Auch einige Fortran-Implementierungen, insbesondere der F-Standard, akzeptieren REAL(dp) nicht und benötigen stattdessen REAL(kind=dp).

+0

Ich werde nicht auf den Stil Punkt der Bevorzugung "Ergebnis" kommentieren, aber es gibt etwas zu sagen. Die Verwendung von 'result' (kein Attribut) ist im Schnittstellenblock für eine rekursive Funktion nicht notwendig. Der Name des Funktionsergebnisses ist kein Merkmal (des Funktionsergebnisses oder der Funktion), und da es keine ausführbare Anweisung zum Verweisen auf die Funktion und nicht auf das Funktionsergebnis gibt, ist kein eindeutiger Name erforderlich. Die Implementierung muss ein Mittel haben, zwischen ihnen zu unterscheiden, aber die Namen der Funktion ergeben sich in der Implementierung und die Schnittstelle muss nicht übereinstimmen. – francescalus

+0

@francescalus: Nach dem F-Standard mit 'result' (was ein Funktionsattribut zu sein scheint für mich, egal wie es offiziell heißt) ist auch für nicht-rekursive Funktionen zwingend erforderlich. In diesem speziellen Fall kann die Verwendung von "result" aus einem anderen Grund erforderlich sein: Das tatsächliche Ergebnis der Funktion ist ein Array, und einige Compiler akzeptieren nicht "real, dimension (2,3) :: f_x". Natürlich müssen die Namen der Funktion in der Schnittstelle und die tatsächliche Implementierung nicht übereinstimmen, so dass man 'result (res)' in der Schnittstelle und 'result (foo)' in der Funktionsimplementierung verwenden könnte. – Pap

+0

@Pap Danke für die Info, werde mit mehr Details in das Ergebnis schauen, aber ich dachte, dass die explizite Angabe von Dimensionen früher praktiziert wurde, da Skalarvariablen separat deklariert werden müssen, weshalb ich nach Angabe der Variablen Dimensionen angegeben habe. Etwas Neues habe ich gelernt. – Astroynamicist

Verwandte Themen