Autonomní rovnice a systémy

Tento zápisník obsahuje výpočty k cvičení z Aplikované matematiky věnované autonomním systémům.

  • Příklady s velikostmi populací a se syntézou kolagenu jsou převzaty nebo silně inspirovány knihou Alan Garfinkel, Jane Shevtsov, Yina Guo: Modeling Life, The Mathematics of Biological Systems.

  • Příklad se skladováním stavebního materiálu je inspirovaný okolím vlakového nádraží, ze kterého jezdím na fakultu.

import matplotlib.pyplot as plt   # knihovna pro statické grafy, grafy budeme kreslit sem do zápisníku
%matplotlib inline               


import numpy                      # knihovna pro numerické výpočty
from scipy.integrate import solve_ivp  # řešení diferenciálních rovnic

import bokeh.io                   # knihovna pro kreslení interaktivních grafů
import bokeh.plotting             # knihovna pro kreslení interaktivních grafů
bokeh.io.output_notebook()        # grafy kreslit sem do zápisníku

colors = 10*bokeh.palettes.Greens5  # paleta barev
Copy to clipboard
BokehJS 2.3.0 successfully loaded.

Skladování stavebního recyklátu

Hromada sypkého materiálu má tvar kužele. Úhel u vrcholu je konstantní, daný mechanickými vlastnostmi materiálu a je nezávislý na objemu.

  • Předpokládejme, že personál stavebnin přisypává na hromadu materiál konstantní rychlostí (v jednotkách objemu za jednotku času).

  • Tato hromada je však v poměrně otevřené krajině a vítr rozfoukává materiál po okolí. Je rozumné předpokládat, že rozfoukávání (opět v jednotkách objemu za jednotku času) se děje rychlostí úměrnou povrchu návětrné strany pláště.

Diferenciální rovnice popisující růst hromady je dVdt=Rk0S a po vyjádření pomocí objemu dVdt=RkV23, kde R a k jsou konstanty. Vhodnou volbou jednotky objemu můžeme docílit toho, že jsou tyto konstanty numericky stejné a vhodnou volbou jednotky času poté toto, že tato společná hodnota je rovna jedné. Budeme tedy modelovat rovnici pro R=k=1. Na obrázku vidíme jediné stabilní řešení, které je globálně atraktivní.

tspan = numpy.linspace(0, 10, 1000)            # Definice časových značek
p = bokeh.plotting.figure(title="Skladování recyklátu", x_axis_label='čas', y_axis_label='výška hromady',plot_width=1000)

for i in range(0,15):                          # Cyklus přes počátečnmí podmínky
    sol = solve_ivp(lambda t, y: 1-y**(2/3), [tspan[0], tspan[-1]], [i/10], t_eval=tspan)  # Vyřešení rovnice pro danou počáteční podmínku
    p.line(sol.t, sol.y[0], color=colors[i], legend_label="V(0)=%s"%str(i/10), width=3)    # Vykreslení řešení

p.legend.click_policy="hide"                   # Skrývat křivky po kliknutí na legendu
bokeh.plotting.show(p)                         # Vykreslení řešení
Copy to clipboard

Propeptid kolagenu

Kolagen je klíčový protein pojivových tkání. Jeden z kroků při syntéze kolagenu spočívá v reakci tří molekul propeptidu kolagenu, zkráceně propeptidu. Tento propeptid se formuje konstantní rychlostí a kromě toho, že je surovinou pro produkci kolagenu, se ještě rozpadá rychlostí úměrnou koncentraci. Modelem je rovnice dPdt=k1P3+k2k3P, kde ki jsou konstanty. Rovnici je možno přepsat do tvaru dPdt=(k2k3P)(k1P3) s rozdílem klesající a rostoucí funkce na pravé straně. Tyto funkce mají jediný průsečík a proto má rovnice jediný stacionární bod. Tento bod je stabilní, protože pro vysoké hodnoty P je pravá strana rovnice k1P3 záporná (dominantní člen je ) a pro malé hodnoty je pravá strana k2k3P kladná (v nule je rovna konstantě k2).

tspan = numpy.linspace(0, 10, 1000)           # Časy, ve kterých se bude počítat řešení
plt.figure(figsize=(12,6))                    # Inicializace obrázku, rozměry
for podminka in numpy.linspace(0,2,20):       # Cyklus pro počáteční podmínky
    sol = solve_ivp(lambda t, P: -0.5*P**3+1-P, [tspan[0], tspan[-1]], [podminka], t_eval=tspan)
    plt.plot(sol.t, sol.y[0])
plt.title("Časový vývoj množství propeptidu kolagenu")    # 
plt.xlabel('čas')
plt.ylabel('množství propeptidu')
None
Copy to clipboard
_images/Autonomni_rovnice_a_systemy_5_0.png

Jelen a los

Uvažujme populaci jelenů a losů. Tyto populace spolu soupeří o potravu. Bez konkurence by populace jelena rostla rychlostí 3 a populace losa rychlostí 2 na jeden kus. Vnitrodruhová konkurence se projevuje v obou populacích stejně a je rovna druhé mocnině příslušné velikosti populace. Mezidruhová konkurence je vyjádřena členem rovným součinu velikosti populací a tato konkurence se projeví s koeficientem 0.5 v populaci losa a s koeficientem 1 v populaci jelena.

Sestavte matematický model a otestujte jej numerickým experimentem na stabilitu stacionárních bodů. Poté zdvojnásobte parametry mezidruhové konkurence a sledujte změnu odezvy.

Modelem je následující autonomní systém. dxdt=3xxyx2dydt=2y0.5xyy2

def jelen_a_los(t, z, parametry):   # Definice interakce mezi jeleny a losy
    x, y = z
    a, b, c, d, e, f = parametry
    return [a*x - b*x*y - c*x**2, d*y - e*x*y - f*y**2]

sol=[None,None]                                        # pole pro reseni
par = [ [3, 1, 1, 2, 0.5, 1] , [3, 2, 1, 2, 1  , 1] ]  # pole pro nastavení parametrů
# vyřešení rovnice pro jednotlivé hodnoty parametrů, u každého nastavení řešíme dvě počáteční úlohy a budeme kreslit dvě trajektorie
sol[0] = [ solve_ivp(jelen_a_los, [0, 20], pocatek, args=([par[0]]), dense_output=True) for pocatek in [[2,2],[1,0.5]] ]
sol[1] = [ solve_ivp(jelen_a_los, [0, 20], pocatek, args=([par[1]]), dense_output=True) for pocatek in [[2,2],[1,0.5]] ]
Copy to clipboard
import warnings
warnings.filterwarnings('ignore')              # ignorovat chyby při dělení nulou při dělení délkou vektoru

fig, ax = plt.subplots(4, 2, figsize=(15,15))  # nastavenní velikosti obrázku a počtu podobrázků
t = numpy.linspace(0, 20, 1000)                # nastavení časových značek

colors=['red','orange','green']                # pole pro střídání barev

for j in [0,1]:                                # cyklus pro nastavení parametrů, vždy kreslí do dvou řad
    for i in [0,1]:                            # cyklus přes počáteční podmínky s daným nastavením parametrů
        reseni=sol[j][i].sol(t)                # uložení odpovídajícího řešení
        ax[2*j,0].plot(t,reseni[0], color=colors[i])  # vykreslení časovového průběhu první komponenty řešení, jeleni, obrázek vlevo nahoře
        ax[2*j,1].plot(t,reseni[1], color=colors[i])  # vykreslení časovového průběhu druhé komponenty řešení, losi, obrázek vpravo nahoře
        ax[2*j+1,1].plot(reseni[0],reseni[1], color=colors[i], linewidth=4) # vykreslení trajektorie do obou obrázků v dolní řadě čtveřice
        ax[2*j+1,0].plot(reseni[0],reseni[1], color=colors[i], linewidth=4) 

    y, x = numpy.mgrid[0:3:20j, 0:3:20j]                       # mřížka pro vykreslení směrového pole a trajektorií
    U,V = jelen_a_los(t,[x,y],par[j])                          # směrové pole
    ax[2*j+1,0].streamplot(x, y, U, V, color='blue')           # trajektorie do obrázku vlevo dole
    U, V =U/numpy.sqrt(U**2+V**2), V/numpy.sqrt(U**2+V**2)     # směrové pole s normalizovanou délkou vektoru
    ax[2*j+1,1].quiver(x, y, U, V, color='blue', lw=.01)       # vykreslení směrového pole

    ax[2*j,0].set_title("Model %s. Populace jelenů"%str(j+1))  # nadpis v grafu nahoře vlevo
    ax[2*j,1].set_title("Model %s. Populace losů"%str(j+1))    # nadpis v grafu nahoře vpravo
    ax[2*j,0].set_ylim([0,None])                               # svislou osu zacinat od nuly v grafu nahoře vlevo
    ax[2*j,1].set_ylim([0,None])                               # svislou osu zacinat od nuly v grafu nahoře vpravo
    ax[2*j+1,0].set_title("Model %s. Trajektorie v prostoru jelenů a losů"%str(j+1))
    ax[2*j+1,1].set_title("Model %s. Fázový portrét v prostoru jelenů a losů"%str(j+1))
None
Copy to clipboard
_images/Autonomni_rovnice_a_systemy_8_0.png

Puštík obecný

Puštík obecný se téměř výhradně živí malými hlodavci. Předpokládejme následující vztahy.

  • Populace hlodavců má porodnost 0.1 na jedince a úmrtnost 0.025 na jedince za jednotku času.

  • Rychlost s jakou jeden puštík konzumuje hlodavce je úměrná počtu hlodavců s konstantou úměrnosti 0.01. Porodnost v populaci puštíka je úměrná množství zkonzumované potravy s konstantou úměrnosti 0.05.

  • Úmrtnost v populaci puštíka je 0.1 na jedince za jednotku času.


Uvedné vztahy je možné modelovat následující soustavou diferenciálních rovnic. dxdt=0.1x0.025x0.01xydydt=0.1y+0.05xy

def pustik_a_hlodavec(t, z):
    x, y = z
    a, b, c, d, e = 0.1, 0.025, 0.01, 0.1, 0.05
    return [a*x - b*x - c*x*y, -d*y + e*x*y]

xmax, ymax=5, 20

y, x = numpy.mgrid[0:ymax:20j, 0:xmax:20j]
U,V = pustik_a_hlodavec(t,[x,y])

pocatek = [2,10]
sol = solve_ivp(pustik_a_hlodavec, [0, 200], pocatek, dense_output=True)  
t = numpy.linspace(0, 200, 1000)
reseni=sol.sol(t)
Copy to clipboard
fig = plt.figure(figsize=(10,10))
plt.streamplot(x, y, U, V, color='blue')
plt.plot(reseni[0],reseni[1], color='red', linewidth=2)
plt.title("Trajektorie v prostoru hrabošů a puštíků")
plt.xlabel('Populace hraboše')
plt.ylabel('Populace puštíka')
None
Copy to clipboard
_images/Autonomni_rovnice_a_systemy_11_0.png

Vidíme oscilatorický průběh. Ten je dán tím, že puštík sám bez sebe bez potravy nepřežije. V období hojnosti puštík má dostatek potravy, jeho populace roste. Tím však spotřebovává stále více hlodavců a od určitého limitu začne hlodavců ubývat. Tento vývoj trvá, dokud není populace puštíka zredukována natolik, že již nebrání hlodavcům v růstu jejich populace. Tím se populace hlodavců namnoží a začne období hojnosti pro puštíka, čímž se uzavře cyklus.

fig = plt.figure(figsize=(10,10))                 # definice obrazku
ax = fig.add_subplot(1, 1, 1)                     # zpristupneni manipulace s osami
plt.plot(t,reseni[1], color='red', linewidth=2)   # nakresleni druhe komponenty reseni (Python indexuje od nuly)
plt.title("Časový vývoj populace puštíka")        # nadpis
ax.set_ylim([0,None])                             # osa y začne na nule
ax.set_xlabel("čas")                              # popisek na ose x
ax.set_ylabel("populace puštíka")                 # popisek na ose y
None  
Copy to clipboard
_images/Autonomni_rovnice_a_systemy_13_0.png

Kůň Převalského

Kůň Převalského je divoký kůň ze střední Asie, jediný druh koně, který nebyl domestikován. V divočině jsou tyto koně loveni vlky. Napište matematický model založený na následujících předpokladech. Porodnost v populaci koní je 0.15 na jedince. Úmrtnost v populaci koní je 0.01 na jedince. Vlci se živí i jinou potravou, mají tedy kladnou porodnost. Ta je 0.1 na jedince. Vlci mají konstantní úmrtnost 0.05 na jedince. Pravděpodobnost s jakou je kůň uloven vlkem je úměrná počtu vlků s konstantou úměrnosti 0.02.

Matematickým modelem je následující dvojice rovnic. dxdt=0.15x0.01x0.05xydydt=0.1y0.05y

def kun_a_vlk(t, z):
    x, y = z
    return [0.15*x - 0.01*x - 0.05*x*y, 0.1*y -0.05*y]

xmax, ymax=20, 20
y, x = numpy.mgrid[0:ymax:20j, 0:xmax:20j]
U, V = kun_a_vlk(t,[x,y])

fig = plt.figure(figsize=(10,10))
plt.streamplot(x, y, U, V, color='blue')
plt.title("Trajektorie v prostoru koní a vlků")
plt.xlabel('Populace koní')
plt.ylabel('Populace vlků')
None
Copy to clipboard
_images/Autonomni_rovnice_a_systemy_15_0.png

Populace vlků stále roste. Populace koní má při malých hodnotách vlků prostor pro růst (v dolní části obrázku trajektorie směřují doprava), ale tento růst je časově omezený a populace koní tedy koexistenci s populací vlků nepřežije, pokud se vzájemná interakce bude řídit uvedenými předpoklady. Podle Wikipedie kůň Převalského přežil jenom díky péči zoologických zahrad a z rodokmenu je zřejmé, že 70 procent jedinců tohoto druhu má původní předky ze zoologické zahrady v Praze.

Systém, vlastní čísla a vlastní směry

Úloha ze cvičení. Nakreslíme si do obrázku vlastní vektory a trajektorie v okolí stacionárního bodu. Stacionární bod je nestabilním uzlem. dxdt=4x2y+y35dydt=3xy23y

def system(t, z):
    x, y = z
    return [4*x**2*y+y**3-5, 3*x*y**2-3*y]

def Jacobi(z):
    x, y = z
    return [[8*x*y, 4*x**2 + 3*y**2],[3*y**2, 6*x*y-3]]    
Copy to clipboard
from numpy import linalg as LA
x0, y0 = 1, 1
J=Jacobi([x0,y0])
vlastni_cisla, vlastni_smery = LA.eig(J)
e1=vlastni_smery[:,0]
e2=vlastni_smery[:,1]
Copy to clipboard

Do jednoho obrázku nakreslíme trajektorie a vlastní vektory Jacobiho matice. Je vidět, že v okolí stacionárního bodu se trajektorie řídí vypočtenými vlastními směry. Vlastně jenom jedním, protože vlastní hodnoty jsou 10 a 0.3 a v exponenciální závislosti jasně dominuje vyšší hodnota. Proto trajektorie “drží” směr vlastního vektoru příslušného vyšší vlastní hodnotě, tj. červený směr.

fig = plt.figure(figsize=(10,10))

xmin, xmax, ymin, ymax = 0.9, 1.1, 0.9, 1.1
y, x = numpy.mgrid[ymin:ymax:20j, xmin:xmax:20j]
U, V = system(t,[x,y])
plt.streamplot(x, y, U, V, color='blue')

krok = 0.04
plt.title("Trajektorie a vlastní směry")
plt.plot([x0-krok*e1[0],x0+krok*e1[0]],[y0-krok*e1[1],y0+krok*e1[1]], color='red', lw=3, label=str(vlastni_cisla[0]))
plt.plot([x0-krok*e2[0],x0+krok*e2[0]],[y0-krok*e2[1],y0+krok*e2[1]], color='green', lw=3, label=str(vlastni_cisla[1]))
plt.legend()

# Ukazka recyklace kodu. Az na nastaveni xmin, xmax, ... je vse stejne jako vyse
# Neni to uplne optimalni postup, pro kod u ktereho se predpoklada kratka zivotnost 
# (kod vznikly behem uceni nebo pro jednorazove vyuziti) to muze byt akceptovatelne

fig = plt.figure(figsize=(10,10))

xmin, xmax, ymin, ymax = 0, 5, 0, 5
y, x = numpy.mgrid[ymin:ymax:20j, xmin:xmax:20j]
U, V = system(t,[x,y])
plt.streamplot(x, y, U, V, color='blue')

krok = 0.04
plt.title("Trajektorie a vlastní směry")
plt.plot([x0-krok*e1[0],x0+krok*e1[0]],[y0-krok*e1[1],y0+krok*e1[1]], color='red', lw=3, label=str(vlastni_cisla[0]))
plt.plot([x0-krok*e2[0],x0+krok*e2[0]],[y0-krok*e2[1],y0+krok*e2[1]], color='green', lw=3, label=str(vlastni_cisla[1]))
plt.legend()


None
Copy to clipboard
_images/Autonomni_rovnice_a_systemy_21_0.png _images/Autonomni_rovnice_a_systemy_21_1.png