Zapomeňte na e-shopy: Python umí modelovat realitu (3. díl) – co je divergence?

Co je divergence a jak poznat, kde se v poli něco „rodí“ nebo zaniká? Na intuitivním příkladu s dýmem a čističkou vzduchu si ukážeme, jak číst tok vektorového pole a jak ho jednoduše spočítat i vizualizovat v Pythonu.

Zapomeňte na e-shopy: Python umí modelovat realitu (3. díl) – co je divergence?

V minulém článku jsem ukázal, co je to gradient a jak ho můžeme pochopit i vizualizovat pomocí Pythonu. Viděli jsme, že gradient není jen abstraktní matematický pojem, ale velmi praktický nástroj, který nám říká, jak rychle se veličina mění a kterým směrem tato změna probíhá nejrychleji.

Tím jsme ale otevřeli širší téma. Gradient je jen jeden ze způsobů, jak z pole „číst“ informace o dění v prostoru. Pokud chceme realitu popisovat systematicky, potřebujeme se podívat i na další nástroje, které nám umožní zachytit strukturu a dynamiku polí.

Zapomeňte na e-shopy: Python umí modelovat realitu (2. díl) – co je gradient?
V minulém článku jsme si ukázali, co je pole a jak ho vizualizovat v Pythonu. Teď jdeme dál – pochopíme gradient, tedy jak se pole v prostoru mění a jak z něj číst informace o reálných jevech.

Divergence

Než budeme pokračovat podívejte se prosím na toto video.

Ve videu vidíme zapálenou dýmovnici a vedle ní čističku vzduchu, která nasává okolní vzduch a filtruje ho. Z hlediska analýzy polí je to velmi pěkný a názorný experiment.

Dýmovnice uvolňuje do prostoru velké množství prachových částic. Ty se začnou pohybovat vzduchem a v každém bodě prostoru mají určitou rychlost a směr pohybu. Jinými slovy, můžeme si představit, že v každém bodě existuje vektor rychlosti, který popisuje pohyb částic v daném místě. Vzniká tak vektorové pole proudění částic.

Jakmile zapneme čističku vzduchu, situace se změní. Částice jsou nasávány směrem k čističce, kde jsou zachyceny filtrem. V okolí dýmovnice se tedy částice rodí (jsou do prostoru uvolňovány), zatímco u čističky zanikají (jsou pohlceny filtrem).

Pokud to chceme popsat přesněji jazykem vektorové analýzy, pak nás nezajímá přímo vznik nebo zánik jednotlivých částic, ale to, jak se chová tok vektorů v prostoru. V některých místech se vektory rozbíhají do okolí, jinde se naopak sbíhají do jednoho bodu.

Právě tuto vlastnost pole popisuje divergence. Divergence v každém bodě říká, zda se tok vektorů v daném místě rozbíhá (zdroj), sbíhá (odtok, propad), nebo zda jím pouze protéká bez změny.

Slovo divergence pochází z latinského divergere. Je složené ze dvou částí: předpony dis- / di-, která znamená „od sebe“, a slovesa vergere, tedy „směřovat“ nebo „naklánět se“. Doslovný význam slova divergence je tedy rozbíhání se od sebe. To velmi dobře odpovídá matematickému významu: vektorové pole se v daném místě rozbíhá do okolí.

Opakem divergence je konvergence. Toto slovo pochází z latinského convergere, kde předpona con- znamená „spolu“ nebo „dohromady“. Konvergence tedy doslova znamená sbíhání se k sobě. V kontextu vektorových polí to znamená, že tok směřuje do jednoho bodu, kde se „shromažďuje“.

V matematice tyto dva pojmy souvisejí také se znaménkem divergence. Pokud je divergence kladná, vektory se z daného místa rozbíhají a můžeme mluvit o zdroji pole. Pokud je divergence záporná, vektory se naopak sbíhají do jednoho bodu – pole má v tomto místě pohlcovač (někdy se používá také termín propad). Pokud je divergence nulová, tok vektoru daným místem pouze protéká, aniž by zde vznikal nebo zanikal.

Navážu tak, aby přechod z intuice (dýmovnice, pohlcovač, rozbíhání toků) k definici byl přirozený a ne formální.

Intuitivní představu tedy máme: divergence nám říká, zda se tok vektorů v daném místě rozbíhá, sbíhá, nebo zda jím pouze protéká. Jak ale tuto myšlenku vyjádřit matematicky?

Představme si malý uzavřený objem prostoru, například malou krychli. Sledujeme, kolik toku do této krychle vstupuje a kolik z ní vystupuje. Pokud z krychle vystupuje více toku, než do ní vstupuje, znamená to, že se tok v tomto místě rozbíhá – máme kladnou divergenci. Pokud naopak více toku do krychle vstupuje, než z ní vystupuje, tok se zde sbíhá – divergence je záporná.

Divergence tedy v podstatě měří rozdíl mezi tokem, který z malého objemu vystupuje, a tokem, který do něj vstupuje.

Pozitivní divergence, negativní divergence (konvergence), nulová divergence. zdroj

Matematicky tuto myšlenku zapisujeme pomocí parciálních derivací. Pokud máme vektorové pole

$$ \mathbf{F}(x,y,z) = (F_x(x,y,z), F_y(x,y,z), F_z(x,y,z))$$

pak jeho divergence je definována jako

$$ \nabla \cdot \mathbf{F} = \frac{\partial F_x}{\partial x} + \frac{\partial F_y}{\partial y} + \frac{\partial F_z}{\partial z}.$$

Každý člen tohoto výrazu říká, jak se mění příslušná složka vektorového pole ve svém směru. Když tyto změny sečteme, dostaneme informaci o tom, zda se pole v daném místě lokálně rozbíhá, nebo sbíhá.

Tato definice má jednu velmi pěknou interpretaci: divergence říká, kolik toku z malého objemu prostoru „odtéká“ ven. Proto se s ní setkáváme v mnoha fyzikálních zákonech – například při popisu proudění tekutin, difuze látek nebo elektrického pole.

Python ukázka divergence

V hodinách fyziky na základní nebo střední škole jste se určitě setkali s elektrickým polem. Jedno z nejjednodušších polí je pole, kde jsou dva náboje. Jeden kladný a druhý záporný. Mezi těmito náboji vzniká elektrické pole, což je velmi hezký příklad pro vizualizaci v Pythonu.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import TwoSlopeNorm

# mřížka prostoru
x = np.linspace(-2, 2, 200)
y = np.linspace(-2, 2, 200)
X, Y = np.meshgrid(x, y)

# pozice nábojů
q1 = 1
q2 = -1
x1, y1 = -1, 0
x2, y2 = 1, 0

# vzdálenosti od nábojů
eps = 0.05
r1 = np.sqrt((X - x1)**2 + (Y - y1)**2 + eps**2)
r2 = np.sqrt((X - x2)**2 + (Y - y2)**2 + eps**2)

# elektrické pole
Ex = q1 * (X - x1) / r1**3 + q2 * (X - x2) / r2**3
Ey = q1 * (Y - y1) / r1**3 + q2 * (Y - y2) / r2**3

# divergence
dx = x[1] - x[0]
dy = y[1] - y[0]
dExdx = np.gradient(Ex, dx, axis=1)
dEydy = np.gradient(Ey, dy, axis=0)
div = dExdx + dEydy

# ořez extrémních hodnot pro lepší vizualizaci
limit = np.percentile(np.abs(div), 98)
div_clipped = np.clip(div, -limit, limit)

# barevná normalizace se středem v nule
norm = TwoSlopeNorm(vmin=-limit, vcenter=0, vmax=limit)

# vykreslení
plt.figure(figsize=(9, 7))

plt.contourf(
    X, Y, div_clipped,
    levels=40,
    cmap="RdBu_r",
    norm=norm
)
plt.colorbar(label="Divergence")

plt.streamplot(X, Y, Ex, Ey, color="black", density=1.2, linewidth=1)

plt.scatter(x1, y1, color="red", s=120, label="Positive charge")
plt.scatter(x2, y2, color="blue", s=120, label="Negative charge")

plt.title("Electric field and divergence")
plt.xlabel("x")
plt.ylabel("y")
plt.legend()
plt.show()

Vytvoření prostoru

Nejprve si vytvoříme dvourozměrnou mřížku bodů, ve které budeme elektrické pole počítat.

x = np.linspace(-2, 2, 200)
y = np.linspace(-2, 2, 200)
X, Y = np.meshgrid(x, y)

Funkce linspace vytvoří rovnoměrně rozložené body mezi -2 a 2. Funkce meshgrid z nich sestaví síť bodů v rovině. Každý bod této sítě odpovídá jednomu místu v prostoru, kde budeme pole vyhodnocovat.

Definice nábojů

Potom definujeme dva bodové náboje:

q1 = 1
q2 = -1
x1, y1 = -1, 0
x2, y2 = 1, 0

První náboj je kladný a leží vlevo, druhý je záporný a leží vpravo. Tím vytvoříme klasickou dvojici, u které elektrické pole vychází z kladného náboje a vstupuje do záporného.

Vzdálenosti od nábojů

Abychom mohli spočítat pole v každém bodě, potřebujeme znát vzdálenost daného bodu od každého náboje.

eps = 0.05
r1 = np.sqrt((X - x1)**2 + (Y - y1)**2 + eps**2)
r2 = np.sqrt((X - x2)**2 + (Y - y2)**2 + eps**2)

Zde používáme běžný vzorec pro eukleidovskou vzdálenost. Malá konstanta eps slouží k tomu, aby ve výpočtu nevznikla singularita přímo v místě náboje. V ideální fyzice by bylo pole bodového náboje v jeho středu nekonečné, ale při numerickém výpočtu potřebujeme tuto singularitu mírně zjemnit.

Výpočet elektrického pole

Nyní spočítáme složky elektrického pole v každém bodě.

Ex = q1 * (X - x1) / r1**3 + q2 * (X - x2) / r2**3
Ey = q1 * (Y - y1) / r1**3 + q2 * (Y - y2) / r2**3

Tento zápis odpovídá tomu, že elektrické pole bodového náboje míří radiálně od náboje a jeho velikost klesá s rostoucí vzdáleností. Výsledné pole dostaneme jako součet polí obou nábojů.

Pole tedy v každém bodě reprezentujeme dvojicí hodnot:

$$\mathbf{E}(x,y) = (E_x(x,y), E_y(x,y))$$

Výpočet divergence

Divergence vektorového pole ve dvou rozměrech je definována jako

$$\nabla \cdot \mathbf{E} = \frac{\partial E_x}{\partial x} + \frac{\partial E_y}{\partial y}.$$

V Pythonu ji spočítáme numericky pomocí funkce np.gradient.

dx = x[1] - x[0]
dy = y[1] - y[0]
dExdx = np.gradient(Ex, dx, axis=1)
dEydy = np.gradient(Ey, dy, axis=0)
div = dExdx + dEydy

Nejprve si spočítáme krok mřížky ve směru os $x$ a $y$. Potom určujeme parciální derivace obou složek elektrického pole. Jejich součtem získáme divergenci.

Proč je potřeba oříznout extrémní hodnoty

V okolí bodových nábojů jsou hodnoty divergence numericky velmi vysoké. Kdybychom je zobrazili bez úprav, barevná mapa by byla téměř nečitelná a většina zajímavých struktur by zanikla.

Proto extrémní hodnoty ořízneme:

limit = np.percentile(np.abs(div), 98)
div_clipped = np.clip(div, -limit, limit)

Tím si ponecháme většinu informace, ale zabráníme tomu, aby několik extrémních bodů zničilo celou škálu.

Barevná škála se středem v nule

Protože divergence může být kladná i záporná, chceme, aby nulová hodnota ležela přesně uprostřed barevné škály.

norm = TwoSlopeNorm(vmin=-limit, vcenter=0, vmax=limit)

To je důležité, protože:

  • kladná divergence odpovídá zdroji pole,
  • záporná divergence odpovídá pohlcovači,
  • nula znamená, že pole místem jen protéká.

Vykreslení výsledku

Nejprve zobrazíme divergenci jako barevné pole.

plt.contourf(
    X, Y, div_clipped,
    levels=40,
    cmap="RdBu_r",
    norm=norm
)
plt.colorbar(label="Divergence")

Použili jsme barevnou mapu RdBu_r, protože je vhodná pro veličiny se zápornými i kladnými hodnotami. Jedna barva reprezentuje kladné hodnoty, druhá záporné.

Potom přes tepelnou mapu vykreslíme proudnice elektrického pole:

plt.streamplot(X, Y, Ex, Ey, color="black", density=1.2, linewidth=1)

Díky tomu na jednom obrázku vidíme zároveň:

  • vektorové pole elektrického pole,
  • skalární pole jeho divergence.

Nakonec vykreslíme samotné náboje:

plt.scatter(x1, y1, color="red", s=120, label="Positive charge")
plt.scatter(x2, y2, color="blue", s=120, label="Negative charge")

Jak výsledek interpretovat

Na výsledném obrázku uvidíme, že:

  • v okolí kladného náboje je divergence kladná, protože odtud pole vychází,
  • v okolí záporného náboje je divergence záporná, protože tam pole vstupuje,
  • ve většině ostatního prostoru je divergence blízká nule.

To velmi dobře odpovídá fyzikální intuici i Gaussovu zákonu:

$$ \nabla \cdot \mathbf{E} = \frac{\rho}{\varepsilon_0} $$

Divergence elektrického pole je tedy nenulová právě tam, kde se nachází elektrický náboj.


V tomto článku jsme se posunuli o další krok. Zatímco gradient nám říká, jak se veličina mění a kterým směrem roste nejrychleji, divergence nám umožňuje dívat se na pole úplně jinak – jako na tok.

Ukázali jsme si, že vektorové pole není jen soubor šipek v prostoru, ale že v sobě nese informaci o tom, kde něco vzniká, kde naopak zaniká a kde pouze „protéká“. Ať už jde o dým šířící se vzduchem, proudění tekutin nebo elektrické pole mezi náboji, divergence nám umožňuje tyto jevy přesně popsat a kvantifikovat.

Zároveň jsme viděli důležitý princip: z lokální informace (malý objem prostoru) dokážeme odvodit globální chování systému. Právě to je jeden ze základních stavebních kamenů fyziky i matematického modelování – schopnost číst z jednoduchých rovnic strukturu celého děje.

Tím se ale náš příběh vektorových polí ještě neuzavírá. Kromě toho, že pole může růst (gradient) a mít zdroje nebo propady (divergence), může se také „otáčet“ – vytvářet víry a cirkulace.

Právě tuto poslední vlastnost popisuje rotace. V dalším díle se podíváme na to, jak poznat, že se pole v nějakém místě „točí“, a jak tento jev souvisí například s vířením tekutin, magnetickými poli nebo atmosférickými jevy.


Pokud chcete vidět celý obraz a jak to všechno zapadá dohromady, tady je kompletní článek:

Zapomeňte na e-shopy: Python umí modelovat realitu – vektorová pole, tok a Stokesova věta
Jak gradient, divergence, rotace, tok pole a Stokesova věta souvisí s modelováním reality? Intuitivní vysvětlení vektorového počtu doplněné o experimenty a vizualizace v Pythonu.