return funktion gibt nur eine Variable aus

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Krackerer
User
Beiträge: 5
Registriert: Freitag 4. Januar 2019, 18:49

Hallo,

in meinen Programm ignoriert Python einfach die zweite Variable die ausgegeben werden sollte. Die np.size ist bei u_gs und u_jacobi 100. Warum wird der Iterationszähler i nicht ausgegeben?

Code: Alles auswählen

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d

def jacobi(u,itmax):
    [Nx,Ny] = np.shape(u)
    u2      = np.zeros([Nx,Ny]);u2[:,0]=u[:,0];u2[:,Ny-1]=u[:,Ny-1];u2[0,:]=u[0,:];u2[Nx-1,:]=u[Nx-1,:]
    i=0
    while i<itmax:
        #calc u2=u(k+1)
        for j in range(1,Nx-1):
            for l in range(1,Ny-1):
                u2[j,l] = 0.25* (u[j+1,l]+u[j-1,l]+u[j,l-1]+u[j,l+1])
        #print(u2)
        if np.allclose(u,u2,atol=1e-2):
            return(u2)
        i+=1
        u=u2
    print("convergence criterion not met after %i iterations" %i)
    return u2

def gs(u,itmax):
    [Nx,Ny] = np.shape(u)
    u2      = np.zeros([Nx,Ny]);u2[:,0]=u[:,0];u2[:,Ny-1]=u[:,Ny-1];u2[0,:]=u[0,:];u2[Nx-1,:]=u[Nx-1,:]
    i=0
    while i<itmax:
        #calc u2=u(k+1)
        for j in range(1,Nx-1):
            for l in range(1,Ny-1):
                u2[j,l] = 0.25* (u[j+1,l]+u2[j-1,l]+u2[j,l-1]+u[j,l+1])
        #print(u2)
        if np.allclose(u,u2,atol=1e-2):
            return(u2)
        i+=1
        u=u2
    print("convergence criterion not met after %i iterations" %i)
    return i,u2

def 


#initialisation and boundary conditions
itmax = 1000
Nx=10
Ny=10
x=np.linspace(-1,1,num=Nx,endpoint=True)
y=np.linspace(-1,1,num=Ny,endpoint=True)
u=np.zeros([Nx,Ny]) ; u_exact = np.zeros([Nx,Ny])# ; u_jacobi=np.zeros([Nx,Ny])
u[:,0]=x**2-1 ; u[:,Ny-1]=x**2-1 ; u[0,:]=1-y**2 ; u[Nx-1,:]=1-y**2

#calc exact solution
for j in range(Nx):
    u_exact[j,:] = x[j]**2 - y**2

#calc numeric solutions
u_jacobi = jacobi(u,itmax)
u_gs     = gs(u,itmax)
print(np.size(gs(u,itmax)))
Benutzeravatar
__blackjack__
User
Beiträge: 13111
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Krackerer: Das ist alles ein bisschen lang um das mal eben so zu verstehen und zu sehen wo Du denn etwas anderes erwartest was passiert und was genau Du wo erwartest und was da stattdessen passiert. Zumal das auch gar nicht lauffähig ist, weil da mitten drin ein ``def`` steht was syntaktisch falsch ist.

Was beim schnellen drüber schauen auffällt ist das `gs()` entweder nur `u2` zurück gibt, falls die ``if``-Bedingung in der Schleife zutrifft, oder ein Tupel aus `i` und `u2` falls die Bedingung der ``while``-Schleife zutrifft. Das ist eine komische API, denn der Aufrufer muss dann ja unterscheiden welchen Fall er da zurück bekommt. Solche Asymmetrien sollte man vermeiden.

``return`` ist übrigens keine Funktion und man sollte das deshalb auch nicht so schreiben als wäre es eine. Nach dem Schlüsselwort sollte ein Leerzeichen stehen und Klammern sollte man nur setzen wenn das die Lesbarkeit fördert. Also beispielsweise wenn es mehrere längere Ausdrücke sind die Elemente eines literalen Tupel bilden und man die Kommas leicht übersehen kann. Sicher nicht wenn da einfach nur ``return u2`` steht.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Zu dem was __blackjack__ schon geschrieben hat: ; sollte man nicht benutzen, sondern jede Anweisung in eine neue Zeile schreiben. `l` ist ein sehr schlechter Variablenname, weil man ihn sehr leicht mit 1 verwechseln kann, was mir beim Lesen öfter passiert ist. Statt der for-Schleifen würde man besser mit slices arbeiten. So ganz verstanden habe ich aber nicht, wie Dein gewünschtes Ergebnis vom aktuellen abweicht.
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

wenn eine Funktion mehr als einen Wert zurück gibt, du den Rückgabewert aber nur an eine Variable bindest, erhältst du automatisch ein Tupel:

Code: Alles auswählen

>>> def foo():
...     return 3, 'bar'
... 
>>> a = foo()
>>> a
(3, 'bar')
>>>
Auf die Elemente des Tupels kannst du per Index zugreifen.

Aber, wie von __blackjack__ schon gesagt: ein _oder_ zwei Werte zurück liefern ist schlecht, weil inkonsistent. Es sollten im gegebenen Fall dann immer zwei Werte sein. Der eine könnte ja auch `None` sein, damit kann man dann wenigsten arbeiten.

Gruß, noisefloor
Benutzeravatar
__blackjack__
User
Beiträge: 13111
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@noisefloor: In diesem Fall gibt es den Wert für das erste Element ja aber auch in dem Fall wo im Code kein Tupel zurückgegeben wird.

@Krackerer: Wobei mir gerade auffällt, dass die beteiligten ``while``-Schleifen eigentlich ``for``-Schleifen sein sollten. Und ``u=u2`` dürfte ein Fehler sein, denn dadurch kommt die Schleife nie über die zweite Iteration hinaus, weil danach beide Namen für das selbe Array stehen und die Abbruchbedingung in dem ``if`` damit natürlich immer wahr ist, denn die Werte in einem Array sind natürlich immer gleich wenn man es mit sich selbst vergleicht. ;-) An der Stelle möchtest Du vielleicht lieber eine Kopie erstellen und die dann an `u` binden.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Krackerer
User
Beiträge: 5
Registriert: Freitag 4. Januar 2019, 18:49

Vielen Dank für die ganzen Antworten!

Ich habe sehr lange nicht verstanden warum es nicht funktioniert aber wie @_blackjack_ angemerkt hat, liegt es daran, dass Bedingung immer erfüllt wird und ich ernsthaft immer übersehen habe, dass dort nur u2 steht. Habe diesen Fehler tagelang gesucht...

ja stimmt an der Bedingung muss ich noch feilen, die stimmt nicht. (das mit dem u=u2). Warum meine while schleife eine for schleife sein sollte verstehe ich allerdings nicht.

EDIT: aber warum ist die bedingung schon bei i=2 erfült? ich ändere u2 ja vor dem vergleich. und wenn die beiden Arrays ähnlich genug sind soll es ja abbrechen..
EDIT2: achso, wenn ich schreibe u=u2 dann sind diese variablen die selben? wie mach ich das wenn ich nur den wert hineinschreiben soll? mit u=np.array(u2)
Zuletzt geändert von Krackerer am Montag 7. Januar 2019, 17:39, insgesamt 1-mal geändert.
Benutzeravatar
__blackjack__
User
Beiträge: 13111
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Krackerer: Weil man dafür ``for``-Schleifen nimmt. Das spart zwei Zeilen Code und man sieht auch gleich das `i` tatsächlich nur von der Schleife abhängt ohne den Code im Schleifenkörper zu kennen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Krackerer
User
Beiträge: 5
Registriert: Freitag 4. Januar 2019, 18:49

__blackjack__ hat geschrieben: Montag 7. Januar 2019, 17:37 @Krackerer: Weil man dafür ``for``-Schleifen nimmt. Das spart zwei Zeilen Code und man sieht auch gleich das `i` tatsächlich nur von der Schleife abhängt ohne den Code im Schleifenkörper zu kennen.
Ich muss zugeben den unterschied der beiden Schleifen nicht wirklich zu kennen. Das muss ich mir wohl mal anschauen. Vielen Dank an alle, sieht so aus als würde es jetzt funktionieren!
Antworten