5. Diferenciální rovnice 2#
5.1. Exponenciální růst#
Namodelujeme exponenciální růst
Nejprve růst pro tři různé hodnoty koeficientu \(k\). Vidíme, že čím vyšší je \(k\), tím rychleji velikost populace roste v čase.
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from scipy.integrate import solve_ivp
### Příprava funkcí a parametrů
pocatecni_podminka = np.array([0.1]) # počáteční podmínka
meze = np.array([0,10]) # interval, na kterém hledáme řešení
parametry = [1,1.5,2] # seznam parametrů
n = 100
def rovnice(t, x, k=1):
return k*x
### Řešení modelu
t=np.linspace(*meze, n) # definiční obor, v těchto bodech budeme hledat řešení
df = pd.DataFrame() # tabulka pro výstup
df.index = t # sloupec s časem
for parametr in parametry:
reseni = solve_ivp(
lambda t,x:rovnice(t,x,k=parametr),
meze,
pocatecni_podminka,
t_eval=t
)
df[parametr] = reseni.y.T # další sloupec tabulky
# lambda funkce viz https://www.w3schools.com/python/python_lambda.asp
# (dočasná nepojmenovaná funkce)
df
1.0 | 1.5 | 2.0 | |
---|---|---|---|
0.00000 | 0.100000 | 0.100000 | 1.000000e-01 |
0.10101 | 0.110629 | 0.116360 | 1.223884e-01 |
0.20202 | 0.122390 | 0.135402 | 1.497941e-01 |
0.30303 | 0.135402 | 0.157551 | 1.833156e-01 |
0.40404 | 0.149792 | 0.183314 | 2.243435e-01 |
... | ... | ... | ... |
9.59596 | 1469.825225 | 178046.326900 | 2.159632e+07 |
9.69697 | 1626.028660 | 207190.044520 | 2.643182e+07 |
9.79798 | 1798.852275 | 241143.463018 | 3.234832e+07 |
9.89899 | 1990.068781 | 280661.211823 | 3.958971e+07 |
10.00000 | 2201.608767 | 326591.822323 | 4.845406e+07 |
100 rows × 3 columns
### Vizualizace řešení
ax = df.plot()
ax.set(
ylim = (0,1000),
title = "Model exponenciálního růstu",
xlabel="čas",
ylabel="velikost populace",
)
plt.legend(title="Hodnoty parametru")
<matplotlib.legend.Legend at 0x7fcc68258200>
5.1.1. Volitelná část#
Po transformaci do bezrozměrného času by měly křivky splynout. Abychom to viděli graficky, budeme postupně snižovat jejich tloušťku a nastavíme částečnou průhlednost. To zajistíme volbami lw
(zkratka za linewidth
) a alpha
.
for k,lw in zip(parametry,[8,5,2]):
plt.plot(t*k,df[k],lw=lw,label=k,alpha=0.5) # Na vodorovne ose neni cas ale bezrozmerny cas
ax = plt.gca()
ax.set(
ylim=(0,100),
xlim=(0,10),
xlabel="bezrozměrný čas",
ylabel="velikost populace",
title="Růst rychlostí úměrnou velikosti v bezrozměrném čase"
)
plt.legend(title=r"Hodnota $k$");
Poznámka: Provnávání grafů je poměrně primitivní metoda. Lepší a jednoznačnější by bylo vypočítat hodnoty v časech, které si odpovídají a poté ukázat, že rozdíl je blízký nule.
5.2. Exponenciální růst k vodorovné asymptotě#
5.2.1. Úkol#
Nakreslete řešení rovnice růstu k vodorovné asymptotě (von Bertalanffyho růst)
Po splnění modifikujte kód některým z následujících způsobů. Můžete využít umělou inteligenci. Například zápisníky na Anaconda cloud
Legendu upravte tak, aby obsahovala Vámi zadaný nadpis a popisky křivek nebyla čísla, ale řetězce „k=x“, kde x je příslušná hodnota parametru.
Upravte rozsah tak, aby svislá osa začínala na nule.
Upravte graf tak, aby kreslil křivky pro různé hodnoty \(M\).
# Sem vložte řešení.
5.3. Logistický růst - pro případné samostatně pracující studenty#
5.3.1. Úkol#
Vykreslete řešení logistické rovnice
# Sem vložte řešení. Můžete jej rozdělit do více buněk, které si sem vložíte.
5.3.2. Logistická rovnice v bezrozměrném tvaru#
Nyní si ukážeme, že v určitém smyslu stačí bez újmy na obecnosti studovat případ \(K=1\) a \(r=1\). Na rovnici
pocatecni_podminka = np.array([0.1])
meze = np.array([0,10])
def rovnice(t, x, r=1, K=1):
return r*x*(1-x/K)
# r a K budou náhodná čísla z intervalu (0,0.2) a (0,10).
K,r = np.array([10,0.2])*np.random.random(2)
print(f"r={r}, K={K}")
t = np.linspace(*meze,12)
reseni_plne_rovnice = solve_ivp(
lambda t,x:rovnice(t,x,r=r,K=K),
meze,
pocatecni_podminka,
t_eval=t
)
reseni_bezrozmerne_rovnice = solve_ivp(
rovnice,
r*meze, # převod mezí na bezrozměrný čas
pocatecni_podminka/K, # převod na bezrozměrnou velikost populace
t_eval=r*t # vyhodnoceni v bezrozmernem case
)
df = pd.DataFrame()
df.index = t
df["plnohodnotna"] = reseni_plne_rovnice.y[0]
df["bezrozmerna"] = K*reseni_bezrozmerne_rovnice.y[0]
df["rozdil"] = np.abs(df["bezrozmerna"]-df["plnohodnotna"])
df["relativni rozdil"] = df["rozdil"]/df["plnohodnotna"]
df
r=0.05326698626509379, K=0.8770402780683362
plnohodnotna | bezrozmerna | rozdil | relativni rozdil | |
---|---|---|---|---|
0.000000 | 0.100000 | 0.100000 | 0.000000e+00 | 0.000000e+00 |
0.909091 | 0.104371 | 0.104371 | 4.032880e-11 | 3.863979e-10 |
1.818182 | 0.108907 | 0.108907 | 1.662413e-11 | 1.526457e-10 |
2.727273 | 0.113610 | 0.113610 | 9.308351e-09 | 8.193239e-08 |
3.636364 | 0.118485 | 0.118485 | 1.042345e-08 | 8.797241e-08 |
4.545455 | 0.123536 | 0.123536 | 5.503706e-09 | 4.455137e-08 |
5.454545 | 0.128766 | 0.128766 | 1.247267e-09 | 9.686328e-09 |
6.363636 | 0.134177 | 0.134177 | 6.939976e-09 | 5.172245e-08 |
7.272727 | 0.139774 | 0.139774 | 9.999059e-09 | 7.153748e-08 |
8.181818 | 0.145558 | 0.145558 | 1.016328e-08 | 6.982301e-08 |
9.090909 | 0.151532 | 0.151532 | 8.485545e-09 | 5.599837e-08 |
10.000000 | 0.157699 | 0.157699 | 7.332868e-09 | 4.649928e-08 |
df.rozdil.max()
1.042345194879335e-08
df["relativni rozdil"].max()
8.7972410305879e-08
np.isclose(df["bezrozmerna"],df["plnohodnotna"], rtol=0.0001).all()
True