2016-01-14 7 views
6

ich eine allgemeine Funktion, die eine Form einer ODE definiert, die ich plane, beispielsweise zur Integration scipy.integrate.odeint Verwendung:Passing parametrisierte Funktion Griff in Python

def my_ode(K, tau, y, u): 
    return K*u/tau - y/tau # dydt 

Ich habe mehrere Objekte in meinem Code, der alle Dynamik haben des in my_ode definierten Formulars, jedoch mit eindeutigen Parametern K und tau. Ich würde gerne in der Lage sein, einen einzigartigen Handle zu übergeben my_ode mit diesen Parametern bereits gesetzt, wenn ich meine Objekte initialisieren, so dass, wenn ich meine Objekte aktualisieren, alles was ich tun muss ist etwas wie für einige Simulationszeit t.

Zum Beispiel, wenn ich definiere eine Klasse:

class MyThing: 
    def __init__(self, ode, y0): 
    # I would rather not maintain K and tau in the objects, I just want the ODE with unique parameters here. 
    self.ode = ode 
    self.y = y0 
    self.time = 0.0 

    def update(self, t, u): 
    # I want this to look something like: 
    self.y = scipy.integrate.odeint(self.ode, t, self.y, u) 

Kann ich mit Lambda tue etwas, wenn ich Instanzen MyThing initialisieren, um grundsätzlich Parameter zuweisen K und tau bei der Initialisierung und muß nie wieder passieren? Ich bin ein bisschen fest.

+3

Vielleicht sollten Sie einen Blick nehmen, die [ 'partial'] (https://docs.python.org/3/library/functools .html # functools.partial) Funktion des 'functools' Moduls, kann es in Ihrem Fall nützlich sein. – mgc

+0

Kann ich mein Objekt einfach mit 'thing = MyThing (Lambda t, y, u: mein_ode (K1, tau1, t, y, u), y0)' initialisieren, indem man bei der Initialisierung Werte für 'K1' und' tau1' liefert? Werden diese Werte dann bestehen bleiben? Ich bin noch nicht an einem Ort, wo ich es in meinem Code testen kann. – Engineero

Antwort

0

Lösung mit lambdas

Es sieht aus wie ich diese Arbeit machen kann lambda unter Verwendung der einzigartige Funktion zu erzeugen, behandelt, wenn ich meine Objekte initialisieren. Für die Kompatibilität mit odeint, muss ich meine Funktionen definieren, so dass die ersten beiden Argumente sind Zeit und Anfangszustand:

def my_ode(t, y, u, K, tau): 
    return K*u/tau - y/tau # dydt 

Next I Objekte von MyThing lambdas initialisieren kann unter Verwendung einstellen K und tau als:

thing1 = MyThing(lambda t, y, u: my_ode(t, y, u, 10.0, 0.5), 0.0) 

Das Funktionshandle, das thing1.ode zugewiesen wird, ist jetzt das vom Lambda zurückgegebene Funktionshandle (dies ist möglicherweise nicht der richtige Weg, dies zu sagen) mit Werten für K und tau festgelegt. Jetzt in thing1.update, muss ich einige Änderungen vornehmen, um es mit odeint zu arbeiten:

def update(self, t_step, t_end, u): 
    t_array = np.arange(self.time, t_end, t_step) # time values at which to evaluate ODE 
    response = scipy.integrate.odeint(self.ode, self.y, t_array, (u,)) 
    self.y = response[-1] # current state is the last evaluated state 

Eine Sache, die mich stolperte ein bisschen ist, dass alle zusätzlichen Argumente für Ihre ODE braucht als Tupel zu odeint weitergegeben werden . Das scheint ziemlich gut zu funktionieren für das, was ich will.

Es gibt auch den eher objektorientierten Ansatz mit scipy.integrate.ode, der eine schrittweise Integration der Funktion ermöglicht und sich hervorragend für meine Simulationszwecke eignet.Dazu stelle ich die ODE des Objekts und aktualisieren Sie es mit so etwas wie:

class MyThing(): 
    def __init__(self, ode, y0): 
    self.ode = integrate.ode(ode) # define the ODE 
    self.ode.set_integrator("dopri5") # choose an integrator 
    self.ode.set_initial_value(y0) 

    def update(self, u, t_step): 
    """Update the ODE step-wise.""" 

    self.ode.set_f_params(u) # need to pass extra parameters with this method 
    self.ode.integrate(self.ode.t + t_step) # step-wise update 
    return self.ode.successful() 

    def get_output(self): 
    """Get output from ODE function.""" 

    return self.ode.y 
2

Wenn Sie:

def my_ode(K, tau, y, u): 
    return K*u/tau - y/tau 

Sie so etwas wie definieren könnte:

def make_ode_helper(k, tau): 
    return lambda (y, u): my_ode(K, tau, y, u) 

und sollte initialisiert werden können, Mything mit:

mt = new MyThing(make_ode_helper(k, tau), y0) 

dann könnte man diese Helfer rufen mit nur y- und u-Parametern:

someresult = ode_helper(y, u) 
+0

Könnte ich dann 'self.ode (y, u)' wie im Beispiel gezeigt aufrufen, da die von 'make_ode_helper' zurückgegebene Lambda-Funktion diesem Attribut meiner Klasse zugeordnet wird? Ich denke, das ist es wonach ich suche! – Engineero

+1

Höchstwahrscheinlich ja, versuchen Sie es. – Ashalynd