Jdi na navigaci předmětu

3. Domácí úkol: Kulečník

Úvod

V teorii chaosu se studuje chování tzv. dynamických kulečníků (dynamical billiards). Jde o jednoduché modely popisující pohyb kuličky zanedbatelných rozměrů v rovině omezený překážkami, na kterých dochází k dokonale pružnému odrazu. Ve volném prostoru se kulička pohybuje rovnoměrně přímočaře (po přímce) a směr pohybu se mění jenom při odrazu na překážce podle známého zákona odrazu (úhel dopadnu je shodný s úhlem odrazu).

Teoretický background

Odraz na překážkách

V našem simulátoru se zaměříme pouze na dva typy překážek, z kterých bude možné okraj kulečníku sestavit:

  • úsečky spojující dva zadané body,
  • části kružnice.

Naše kulička bude popsána polohou (bod v rovině) a vektorem rychlosti. Zřejmě si stačí zaznamenávat pouze body, kdy dochází k odrazu (viz níže).

Odraz v obou případech probíhá podobně. Dojde pouze k změně velikosti rychlosti vR2v \in \mathbb{R}^2 podle následujícího pravidla: je-li sR2s \in \mathbb{R}^2 vektor udávající směrnici tečny k překážce a nR2n \in \mathbb{R}^2 odpovídající normálový směr, oba normalizované na jedničku (délky 1), pak nový směr kuličky po odrazu je

s,vsn,vn,\langle s, v \rangle s - \langle n, v \rangle n,

kde ,\langle,\rangle označuje standardní skalární součin. Vektory ss a vv uvedené výše v případě jednotlivých překážek určíme snadno:

  • v případě úsečky: směrovým vektorem ss je směrový vektor přímky, na které úsečka leží, normálový vektor nn je pak libovolný vektor kolmý na ss s jednotkovou délkou,
  • v případě kružnice: normálový vektor nn je vektor spojující bod dopadu a střed kružnice, směrový vektor ss je pak libovolný vektor kolmý na mm s jednotkovou délkou.

Poincarého řezy

Jedním z vizuálních nástrojů pro pozorování chaosu jsou tzv. Poincarého řezy.

Stav kuličky v našem kulečníku je dán její polohou (bod v rovině) a směrem rychlosti (velikost nehraje roli). Libovolný stav kuličky je proto prvek množiny R2×π,π\mathbb{R}^2 \times \langle -\pi, \pi \rangle (tzv. fázový prostor). Prvky této množiny, ale i trajektorie v rovině, sice jde vizualizovat, ale výsledek je značně nepřehledný.

Poincarého myšlenka spočívá v "řezu" této množiny. V našem případě konkrétně zafixujeme úsečku (podél které kulečník rozřízneme) a zaznamenáme si pouze průsečíky trajektorií s touto úsečkou a směr rychlosti. Jsou-li krajní body řezu AA a BB a trajektorie prochází bodem XX ležícím na úsečce spojující tyto dva body, tj. X=A+t(BA)X = A + t (B - A), kde t0,1t \in \langle 0, 1\rangle, pak zobrazíme bod o souřadnicích t,φt, \varphi, kde φ\varphi je úhel, který vektor rychlosti svírá s kladným směrem osy xx, tj. hodnota mezi π-\pi a π\pi. K rozlišení trajektorií použijeme rozdílné barvy (tj. body v řezu odpovídající jedné trajektorii jsou jedné barvy).

Implementační pokyny

V souboru src/billiard.jl doplňte implementaci modulu Billiard, který bude umožňovat vytvoření hranice kulečníku z dvou primitivních překážek:

  • úsečka zadaná svými krajními body (typ Segment, podrobněji níže),
  • oblouk kružnice zadaný středem a poloměr kružnice a dvěma úhly (typ Arc, podrobněji níže).

Celou implementaci pro jednoduchost a rychlost provedeme ve strojových číslech (tj. vektory a různé hodnoty budou uvažovány pouze typu Float64).

Tento úkol vytvořte jako projekt, tj. bude možné ho aktivovat a doinstalovat závislosti, které použijete na vykreslování.

Typy

Abstraktní typ Obstacle modeluje libovolnou překážku a má dva podtypy, typ Segment a typ Arc.

Typ Segment představuje úsečku a k vytvoření objektu jednoduše vyžaduje dva body dané úsečky. Body chápeme jako Vector{Float64} o dvou složkách. Nelze vytvořit úsečku mezi body, které jsou u sebe moc blízko nebo jsou dokonce si rovny (blízkost bodů ověřujte pomocí metody isapprox)

Typ Arc představuje část oblouku kružnice se středem v bodě (Vector{Float64}) a poloměrem (Float64) a dále dvěma úhly (oba Float64). První úhel musí být menší než druhý a ukazují (proti směru hodinových ručiček od kladného směru osy xx) začátek a konec oblouku. Tj. pokud bychom měli jednotkovou kružnici, tak s úhly 00 a π\pi mluvíme pouze o její části nad osou xx.

Střed kružnice musí být svousložkový vektor (jsme v rovině), poloměr musí být nezáporný, první úhel musí být menší než druhý a musí být možné je zadat i jako násobky π\pi (v Julia existuje abstraktní konstanta pi, její použití je pohodlné pro uživatele).

Posledním použitým vlastním typem je typ Table, který jednoduše modeluje kulečník sestavený z překážek z dvou výše uvedených typů. Tyto překážky jednoduše ukládá/dostává v poli typu Vector{Obstacle}.

Funkce simulate!

Tato metoda počítá postupně body odrazu na okraji kulečníku, který jí předáme v prvním argumentu (table). Druhý argument (path) obsahuje matici Float64 hodnot rozměru 4×n4 \times n, kde v prvním sloupci jsou uloženy počáteční podmínky: popořadě souřadnice polohy a složky vektoru rychlosti (nemusí být jednotkový). Metoda z této počáteční podmínky poté vyplní zbývající sloupce pole hodnotami souřadnic dopadů na hranici a novými složkami rychlosti (po odrazu).

Počet odrazů, které algoritmus napočítá je tedy n1n-1.

Hodnota nn musí být alespoň 22. Matice path musí mít právě čtyři řádky. Pokud algoritmus nenajde další dopadu ("děravý" kulečník, nebo špatné počáteční podmínky vně kulečníku), dojde k výjimce RuntimeError.

Vizualizační funkce draw_path a draw_poincare

Konečně budou k dispozici dvě vizualizační metody:

  • draw_path přijme minimálně kulečník table a trajektorii path, které vykreslí.
  • draw_poincare přijme minimálně pole trajektorií paths, dva body P1 a P2 určující koncové body řezu a vykreslí Poincarého řez popsaný výše.

Testy

Vaši implementaci prověříte spuštěním testů (automaticky se spouštějí i na Gitlabu) příkazem julia --project=@. test/runtests.jl.

Řešení a odevzdání

Opět vytvořte větev odvozenou z větve assignment/03-billiard a nezvěte ji solution/03-billiard. Do solution/03-billiard vložte své řešení, což zde znamená vytvoření projektu a primárně editaci src/billiard.jl. Zdrojový kód ale můžete rozdělit na více souboru, případně přidat testy do složky test. Až budete se svým řešením spokojeni, vytvořte MR (to můžete i dříve, aspoň uvidíte výsledek testů, pokud je nespouštíte lokálně) a přiřaďte mě k němu jako assignee. Tímto aktem úkol odevzdáte.