2017-08-15 76 views
2

將ode與scipy集成時,ode接受的函數參數比t和y更多。例如:scipy ode update set_f_params函數內部設置爲set_solout

def fun(t, y, param1, param2):

以及這些參數的值可以使用set_f_params方法設置。

但是,如果還使用set_solout方法並嘗試在此函數內更新set_f_params的參數,則集成將保持不變,就像參數未被修改一樣。

如何使用sol_out修改參數? 我想受益於dopri5密集輸出,但我需要在每個時間步驟更新非均勻項。

一個簡單的例子如下所示。

import numpy as np 
import matplotlib.pyplot as plt 
from scipy.integrate import ode 

def fun(t, x, param): 
    return x - param 

def f_param(t): 
    return t 

ode1 = ode(fun).set_integrator('dopri5').set_initial_value([10.0]) 
ode1.set_f_params(f_param(0)) 
results1 = ([], []) 

ode2 = ode(fun).set_integrator('dopri5').set_initial_value([10.0]) 
ode2.set_f_params(f_param(0)) 
results2 = ([], []) 

def callback1(t, x): 
    results1[0].append(t) 
    results1[1].append(x.copy()) 

def callback2(t, x): 
    results2[0].append(t) 
    results2[1].append(x.copy()) 
    ode2.set_f_params(f_param(t)) 

ode1.set_solout(callback1) 
ode2.set_solout(callback2) 

ode1.integrate(3) 
ode2.integrate(3) 

plt.plot(results1[0], results1[1], 'o-', alpha=0.7, label='ode1') 
plt.plot(results2[0], results2[1], '.--', label='ode2') 
plt.legend() 

,結果如下所示:

image

+2

請注意,您最有可能通過完全不使用參數來解決此問題,而是在計算導數時執行您需要執行的任何操作來獲取時間相關參數。在你的例子中,你可以使用'def fun(t,x):return x - f_param(t)'。顧名思義,'set_solout'就是在每個自適應整合步驟之後想要類似輸出的東西。另請注意,每個集成步驟都包含不同時間的多個功能評估。因此,使用'set_solout'會比我建議的選擇更少地改變你的參數。 – Wrzlprmft

+0

你說得對,使用'set_solout'來更新參數並不是最好的選擇,因爲它們將被固定用於自適應集成步驟。但是,直接調用函數來設置要整合的函數內的參數並不總是一個選項。不過,該函數可以作爲參數本身傳遞,並且永遠不需要更新! –

回答

2

這是一個如何與the new ODE solvers做將在SciPy 1.0中發佈:

from functools import partial 

import numpy as np 
from scipy.integrate import solve_ivp 

import matplotlib.pyplot as plt 


def fun_fixed(t, x, param): 
    return x - param 

sol_fixed = solve_ivp(
    partial(fun_fixed, param=0), (0, 3), [10.0], dense_output=True) 

def fun_param(t, x, fun): 
    return -x + fun(t) 

def f_param(t): 
    return t 

sol_param = solve_ivp(
    partial(fun_param, fun=f_param), (0, 3), [10.0], dense_output=True) 

t = np.linspace(0, 3, num=16) 

plt.figure(figsize=(8, 5)) 
plt.plot(t, sol_fixed.sol(t)[0], 'o-', alpha=0.7, label='ode1') 
plt.plot(t, sol_param.sol(t)[0], 's-.', label='ode3') 
plt.legend() 

Two solutions

+1

更容易和功能!大!謝謝@astrojuanlu –

+0

@astrojuanlu是否可以使用此解算器進行頌歌系統? –

+0

當然,也是舊的求解器。您必須以矢量/數組形式編寫它們,查看文檔。 – astrojuanlu

1

通過@Wrzlprmft的評論的啓發,它是安全不,如果他們不是恆定的,並呼籲該更新功能使用PARAMS直接在你想要更新的函數中傳遞參數。正如他所說,這意味着:

def fun(t, x): 
    return x - f_param(t) 

然而,該函數(f_param在這種情況下)可能無法在該函數的命名空間訪問集成(在本例中fun以上)。因此,將函數設置爲要集成的函數的參數更爲方便,並且在開始時只使用set_f_params來指定該函數。

正如代碼中的問題的延續:

def fun3(t, x, fun): 
return -x + fun(t) 

def fun4(t, x): 
    return -x + t 

ode3 = ode(fun3).set_integrator('dopri5').set_initial_value([10.0]) 
ode3.set_f_params(f_param) 
results3 = ([], []) 

ode4 = ode(fun4).set_integrator('dopri5').set_initial_value([10.0]) 
results4 = ([], []) 

def callback3(t, x): 
    results3[0].append(t) 
    results3[1].append(x.copy()) 

def callback4(t, x): 
    results4[0].append(t) 
    results4[1].append(x.copy()) 

ode3.set_solout(callback3) 
ode4.set_solout(callback4) 

ode3.integrate(3) 
ode4.integrate(3) 

plt.figure(figsize=(8, 5)) 
plt.plot(results1[0], results1[1], 'o-', alpha=0.7, label='ode1') 
plt.plot(results2[0], results2[1], '.--', label='ode2') 
plt.plot(results3[0], results3[1], 's-.', label='ode3') 
plt.plot(results4[0], results4[1], '^-.', label='ode3') 
plt.legend() 

表明ODE3和ode4提供相同的解決方案:

solutions