2016-01-14 13 views
6

Ho una funzione generale che definisce una forma di ODE che progetto integrare usando scipy.integrate.odeint, ad esempio:Passando parametrizzato maniglia funzione in Python

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

Ho parecchi oggetti nel mio codice che hanno tutti dinamiche del modulo definito in my_ode, ma con parametri univoci K e tau. Mi piacerebbe essere in grado di passare un handle unico a my_ode con quei parametri già impostati quando inizializzo i miei oggetti, in modo che quando aggiorno i miei oggetti, tutto ciò che devo fare è qualcosa come per qualche tempo di simulazione t.

Per esempio, se io definisco una classe:

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) 

Posso fare qualcosa con Lambda quando ho inizializzare istanze di MyThing assegnare fondamentalmente parametri K e tau in fase di inizializzazione e mai bisogno di passare di nuovo? Sono un po 'bloccato.

+3

Forse si dovrebbe dare un'occhiata a Il [ 'partial'] (https://docs.python.org/3/library/functools .html # functools.partial) funzione del modulo 'functools', potrebbe essere utile nel tuo caso. – mgc

+0

Posso solo inizializzare il mio oggetto con 'thing = MyThing (lambda t, y, u: my_ode (K1, tau1, t, y, u), y0)', fornendo i valori per 'K1' e' tau1' all'inizializzazione? Questi valori persisteranno? Non sono ancora in un posto dove posso testarlo nel mio codice. – Engineero

risposta

0

Soluzione con lambda

Sembra che posso fare questo lavoro utilizzando lambda per generare funzione unica gestisce quando ho inizializzo miei oggetti. Per compatibilità con odeint, devo definire le funzioni in modo che i primi due argomenti sono tempo e stato iniziale:

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

Successivo posso inizializzare oggetti di MyThing utilizzando lambda per impostare K e tau come:

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

L'handle di funzione assegnato a thing1.ode è ora l'handle di funzione restituito da lambda (questo potrebbe non essere il modo corretto per dirlo) con i valori per K e tau impostato. Ora, in thing1.update, ho bisogno di apportare alcune modifiche per farlo funzionare con odeint:

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 

Una cosa che mi ha scattato un po 'è che qualsiasi argomento extra al vostro ODE hanno bisogno di essere passato come una tupla a odeint . Questo sembra funzionare abbastanza bene per quello che voglio.

C'è anche l'approccio più orientato agli oggetti usando scipy.integrate.ode, che consente l'integrazione graduale della funzione ed è ottimo per i miei scopi di simulazione.Per questo, ho impostato ODE dell'oggetto e aggiornarlo con qualcosa di simile:

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

Se si dispone di:

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

è possibile definire qualcosa come:

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

e dovrebbe essere in grado di inizializzare MyThing con:

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

allora si potrebbe chiamare questo helper con soli parametri y e u:

someresult = ode_helper(y, u) 
+0

Potrei quindi chiamare 'self.ode (y, u)' come mostrato nell'esempio, poiché la funzione lambda restituita da 'make_ode_helper' sarà assegnata a questo attributo della mia classe? Penso che questo sia quello che sto cercando, se è così! – Engineero

+1

Molto probabilmente sì, provalo. – Ashalynd

Problemi correlati