Fysiikan lakeja, joita virtaava neste tottelee

Kirjoitetaan fysiikan lakeja kuvaavien matemaattisten yhtälöiden perusteella python-funktio, jota tarvitaan numeerisessa simuloinnissa.

Jalo tarkoitukseni oli kirjoittaa tämä juttu niin, että se antaa yleisvaikutelman tämäntapaisesta ohjelmoinnista, vaikka koodiosuudet ja yhtälöt ohittaisi pikaisella silmäyksellä.

(Tällaiset ohjelmakoodit ovat yleensä vaikeita lukea. Luulenpa, että jos vuoden päästä palaan tämän koodin pariin, joudun pitkään hämmästelemään, mitä tässä tapahtuu ja miksi olen sen näin koodannut.)

Ohjelmoinnin perusteita olen yrittänyt esitellä toisaalla Ohjelmointia, matematiikkaa, fysiikka


Alla luetellaan valmiit python-modulit, joita tässä ohjelmassa käytetään.

Olennainen osa ohjelmointia on perehtyä, mitä moduleja on tarjolla ja miten niitä käytetään. Kokemuksen myötä oppii, millaisilla hauilla löytää webistä parhaat ohjeet ja esimerkit modulien soveltamiseen.

Allaolevia määrittelyjä tarvitaan symbolisessa laskennassa. Toisin kuin tavalliset muuttujat, symbolisen laskennan muuttujat pitää näin esitellä.

Aina kun alkaa ratkaista uudenlaista ongelmaa ohjelmoimalla, joutuu perehtymään uusiin asioihin. Uuden opettelu on olennainen osa ohjelmointia. Uuden opettelu toki edellyttää, että omaa perusymmärryksen ohjelmoinnista. Samalla lailla kuin matemaattinen ongelmanratkaisu edellyttää, että on omaksunut 'matemaattisen ajattelun', ohjelmoinnissa tarvitaan 'ohjelmoinnillista ajattelua'. Sitä on yhtä vaikea määritellä kuin matemaattista ajattelua.


Syrjähyppy menneeseen

Tietokoneeni käyttöliittymä on hyvin erilainen kuin se, mihin totuin -70 ja -80 -luvuilla.

Tämä on ohjelmoitu python-ohjelmointikielellä, jonka ensimmäinen versio julkaistiin 1991 ja, jolla opettelin ohjelmoimaan muutama vuosi sitten. Symboliseen laskentaan käyttämäni sympy-kirjaston ensimmäinen versio julkaistiin 2007. Tämä dokumentti on Jupyter-notebook, jonka on kehittänyt vuonna 2015 perustettu project Jupyter. Numeeriseen laskentaan käyttämäni numpy-kirjaston ensimmäinen versio on julkaistu 1995.

Kaikkia ylläolevia ja paljon muuta olen opetellut soveltamaan vasta viime vuosina harrastusmielessä. Kovin vaikeaa se ei ole ollut, koska olen tehnyt samanlaisia hommia -70 ja -80 -luvuilla. Minulle on kai silloin kehittynyt 'ohjelmoinnillinen ajattelu'.

Web-selaimen ja web-palvelimen välisen kommunikoinnin ohjelmointia tuskin jaksaisin opetella. Tietokannat, käyttäjien autentikointi web-sovelluksissa yms. ovat mysteereitä, joihin perehtymiseen en tunne houkutusta. Tuskin oppisin, koska siinä ei nuorena opittu auttaisi.

Tekoäly kuulostaa mielenkiintoiselta, mutta pelkkä ajatus opetella sen soveltamista alkaa ahdistaa. Meille opetettiin neuroverkkojen periaatteita -70 -luvulla, mutta niillä eväin ei pitkälle pötkitä.

Symbolinen laskenta

Yhtälöitä on vaikea syöttää näppäimistöltä niin, että ne miellyttäisivät matemaatikon silmää. Siksi on kehitetty tapoja kirjoittaa yhtälöt helposti näppäiltävässä muodossa ja sen jälkeen erillisellä komennolla tulostaa ne muotoon, josta näkee, mitä tuli näppäiltyä.

Näissä kommenteissa käytän 80-luvulla kehitettyä LaTeX syntaksia. Esimerkiksi $$\nabla \cdot \overrightarrow{V} = \frac{\partial}{\partial x} u(x,y) + \frac{\partial}{\partial y} v(x,y)$$

kirjoitetaan

\nabla \cdot \overrightarrow{V} = \frac{\partial}{\partial x} u(x,y) + \frac{\partial}{\partial y} v(x,y)

Lähes kaikki matemaattisluonnontieteelliset tutkimusartikkelit kirjoitetaan LaTeXilla

LaTeX kuitenkin osaa pelkästään sommitella matemaattisia lausekkeita helposti luettavaan muotoon. Jotta yhtälöitä voisi käsitellä matematiikan sääntöjen mukaisesti, kirjoitan ne sympy-modulin vaatimaan muotoon.

(On olemassa muitakin symbolisen laskennan työkaluja. Sympyn esitystapa ei ehkä ole matemaattikkojen mielestä kaikista kaunein, mutta sympyn etuna on, että se on kiinteä osa python-ohjelmointikieltä.)

Tarvittaessa sympy-lausekkeet voi tulostaa helposti luettavassa muodossa display-komennolla, joka perustuu LaTeXiin:

Kaasujen ja nesteiden (= fluidien) virtausten simuloinnin perusidea

Tarvittavien yhtälöiden johtamiseksi tarkastellaan pienen pientä fluidin mukana kulkevaa fluidi-kuutiota. Kuution tilan kertovat sen nopeus ja siinä olevan fluidin tiheys ja paine. (http://www.eng.auburn.edu/~tplacek/courses/fluidsreview-1.pdf)

Säilymislait

Tarpeeksi pitkään tuollaista kuution kuvaa tuijotettuaan pari tyyppiä päätyi kirjoittamaan yhtälöt kuution massan, liikemäärän ja energian säilymiselle ( navier-Stokes yhtälöt )

Koska on jokseenkin mahdoton tehdä ohjelmaa, jossa tuollaiset fluidi-elementit vaeltelevat ympäriinsä, matemaattiselle tempulla liikkuvan fluidin yhtälöt (non-conservation form) voidaan vääntää yhtälöiksi, jotka kertovat, mitä paikallaan olevassa kuutiossa tapahtuu (conservation form).

(Saattaa olla, etten ole kovin syvällisesti ymmärtänyt eri muotojen perimmäistä eroa. Sori siitä)

Navier-Stokes yhtälöt näyttävät niin luotaantyöntäviltä, että arvelin helpommaksi suoraan fysiikan peruslaeista lähtien kirjoittaa tarvittavat yhtälöt kuutioille, joista järveni rakennan. Muutaman päivän ja muutaman kymmenen yritys-erehdys kierroksen jälkeen nöyrryin selvittämään, miten Navier-Stokes yhtälöt on tapana ratkaista. Jälleen kerran sain muistutuksen siitä, ettei pahankaan näköinen yhtälö ole pohjimmiltaan ilkeä. Niiden kanssa tulee mukavasti juttuun, kunhan varaa kylliksi aikaa rauhalliseen tutustumiseen.

Massan säilyminen

Järvessäni massan säilyminen tarkoittaa, että vesi ei lisäänny eikä vähene, ellen laita puroja tuomaan tai viemään siitä vettä.

Miten noinkin pieni yhtälö voi näyttää noin ilkeältä? Minun matemaattinen intuitioni ei riitä niin pitkälle, että suoraan ymmärtäisin, mitä tuo tarkoittaa. Helpottaa, kun ymmärtää, että yhtälö on tiivistelmä pitkän johdattelun lopputuloksesta.

Toisaalta, näin taiteen tekemisessä ei haittaa, vaikkei intuitio kertoisikaan yhtälön merkitystä. Sen voi kopioida järveäni kuvaavien yhtälöiden sekaan ja antaa tietokoneen laskea, mitä siitä seuraa.

$\rho$: fluidin (= kaasun tai nesteen) tiheys, (järvessäni tämän voi tulkita vesikerroksen paksuudeksi.)

$\overrightarrow{V}$: fluidin nopeus. Nuoli tarkoittaa, että nopeudella on sekä suunta että suuruus

$\nabla: \overrightarrow{i}\frac{\partial}{\partial x} + \overrightarrow{j}\frac{\partial}{\partial y}$, lyhennysmerkintä derivoinnille paikan suhteen. Jos vuorenrinteellä korkeus merenpinnasta on h(x,y) niin $\nabla h$ on rinteen jyrkkyys

Jos $\overrightarrow{V} = u(x,y)\overrightarrow{i} + v(x,y)\overrightarrow{j}$ niin $\nabla \cdot \overrightarrow{V} = \frac{\partial}{\partial x} u(x,y) + \frac{\partial}{\partial y} v(x,y)$

Massan säilyminen sympy-muodossa

Kirjoitetaan yo. kuvan Eq. (2.27) sympy-muotoon

rho(x,y,t) ($\rho(,x,y,t$: Pinnankorkeus

u(x,y,t): veden nopeuden itä-länsi -suuntainen komponentti

v(x,y,t): veden nopeuden etelä-pohjois -suuntainen komponentti

'Väriaineiden' leviäminen nesteeseen

Simuloinnin alussa järveen roiskitaan kahta väriainetta. Lisäksi rannoilta liukenee veteen samoja väriaineita. Diffuusio levittää niitä veteen, vaikka vesi pysyisi paikallaan, mutta lisäksi värinaineet kulkevat nesteen virtauksen mukana.

Väriaineen massa on niin vähäinen, ettei se vaikuta nesteen virtaukseen.

Sekoittuessaan väriaineet neutraloivat toisiaan.

Diffuusio

Diffuusio on esimerkiksi sitä, että vaikka miten varovasti tiputtaisit tilkan maitoa teehesi, ajan myötä maito värjää teen kauttaaltaan. Jos tipautat maidon korkealta tai sekoitat teetä, maito sekoittuu nopeammin, koska diffuusion lisäksi nesteen virtaus levittää maitoa kuppiin.


Fick's second law tells how diffusion causes the concentration to change with respect to time. It is a partial differential equation which in one dimension reads:

$$ \frac {\partial \varphi }{\partial t} = D\,{\frac {\partial ^{2}\varphi }{\partial x^{2}}} $$

where

$ \varphi $ is the concentration;

$ \varphi = \varphi (x,t) $ is a function that depends on location x and time t

D is the diffusion coefficient

In two or more dimensions we must use the Laplacian Δ = ∇2, which generalises the second derivative, obtaining the equation

$$ \frac {\partial \varphi }{\partial t} = D\Delta \varphi $$

https://en.wikipedia.org/wiki/Fick%27s_laws_of_diffusion#Fick's_second_law

D_pnt: diffuusiokerroin paint(x,y,t): väriaineen konsentraatio

Simulaatiossa on vain yhtä väriainetta. Jos sen konsentraatio on negatiivinen, se piirretään vihertävänsävyisenä, jos positiivinen, punertavana. Kun punainen ja vihertävä kohtaavat ja sekoittuvat, summaksi tulee lähellä nollaa oleva luku, jonka väri on vaaleahko.

Alla Ficksin laki 2-ulotteisessa tapauksessa kirjoitettuna sympy-muodossa

Väriaineelle pätee sama massan säilymisen yhtälö kuin vedellekin lisättynä diffuusion vaikutuksella.

Olen koodannut tämän muutama viikko sitten. Miksi olen laittanut miinus-merkin diffuusion vaikutuksen eteen? Nyt allaoleva väriaineen massan säilymisen yhtälö kertoo, että pisteessä (x,y) virta vie ja diffuusio tuo väriainetta. Ehkä olen kopioinut yhtälöt mitään miettimättä. Mitä suotta miettimään, valmiita yhtälöitä ;-)

Entä jos vaihtaisi diffuusion merkin? Väriaine ei leviäisi itsestään vaan päinvastoin kerääntyisi pienten tiivistymien ympärille. Eli virta veisi, mutta diffuusio taistelisi vastaan. Pakko kokeilla!

(Kokeilinkin. Ei näyttänyt hyvältä)

Liikemäärän säilyminen

Kiinteälle kappaleelle pätee: $voima = massa\cdot kiihtyvyys$ eli kappaleen vauhti kiihtyy, kun siihen kohdistuu voima. Mitä suurempi kappaleen massa, sitä enemmän pitää työntää, että sen saa kunnolla vauhtiin.

Sama pätee fluideihin, mutta liikeyhtälöitä johdettaessa tarkastellaan pienen fluidikuution liikettä.

Fluidikuution kohdistuvat voimat

Seuraavat yhtälöt kertovat, miten viereiset kuutiot työntävät ja vetävät toisiaan ja millaisia voimia viereisten kuutioiden välinen 'kitka' aiheuttaa.

Jos ketä kiinnostaa, voi kaivaa webistä selityksen kuvalle ja yhtälöille

Pääosin ymmärrän selityksen, mutta silti tuntuu oudolta mallintaa kaasua tai nestettä kuutioina. Itse en olisi rohjennut muista ehdottaa. Vähän helpottaa, kun ajattelee, että kuutio on 'infinitesimally small'. Siis pienempi kuin pieni.

Fluidin liikemäärän säilymisen yhtälöt

Ensivilkaisulla allaolevan yhtälöt näyttivät niin pahoilta, että kuvittelin helpommaksi miettiä itse, mitä kuutioille tapahtuu. En kuitenkaan onnistunut, joten jouduin nöyrtymään ja perehtymään, mitä nuo yhtälöt tarkoittavat.

Eipä tuossa loppujen lopuksi paljoa tarvinnut ymmärtää. Kopioin yhtälöt ja ratkaisin ne :-)

Liike-energian säilyminen

Kaasut ovat kokoonpuristuvia eli massaa varastoituu tiheyden vaihteluihin. Kaasun paine, tiheys ja lämpötila riippuvat toisistaan, joten kaasuja simuloidessa pitää osata laskea, miten energiaa varastoituu lämmöksi. Sitä varten olisi pitänyt ottaa mukaan allaolevat yhtälöt.

En jaksanut perehtyä ja olisi ollut tyhmää tehdä 'järvivedestä' kokoonpuristuvaa,koska nesteet ovat yleensä käytännössä kokoonpuristumattomia, eli massaa ei varastoidu mihinkään.

Aloin kuitenkin epäillä, että taiteellisen vaikutelman kannalta ajatellen kokoonpuristumaton liemi saattaa käyttäytyä kovin tylsästi. Jos fluidi puristuu kokoon, muutokset etenevät aaltona. Kokoonpuristumattomassa nesteessä muutoksen vaikutus leviää silmänräpäyksessä koko systeemiin.

Ehkä ihan väärin luulin. Olisi kannattanut kokeilla yksinkertaisempaa ilmiötä, mutta halusin heti ekalla yrityksellä mukaan kaiken mahdollisen.

Keksin, että järvessä nestettä voi ajatella varastoituvan pinnankorkeuden vaihteluihin jolloin yhtälöissä esiintyvä paine voisi olla suoraan verrannollinen pinnankorkeuteen. Minun ei tarvitsisi opetella ymmärtämään ylläolevia energiayhtälöitä ja kuitenkin saisin simulointiin varastoitumisen!

Aluksi olin huolissani, toimiiko vesistöni vallan luonnottomasti, ellen vaadi energiaa säilymään. Koska kuitenkin yhtälöitä syntyi yhtä monta kuin tuntemattomia, matemaattisesti ajatellen tilanne oli ok. Toisinaan, kun luottaa matematiikan lakeihin, ei tarvitse ajatella eikä ymmärtää.

Virtausvastus, kitka

Jos kappaleeseen kohdistuu voima, sen vauhti kiihtyy äärettömäksi, ellei mikään voima sitä jarruta. Järvessäni vesi virtaa ikuisesti alamäkeen, joten ylinopeus oli vaarana. Aluksi veden virtausnopeus kasvoikin niin suureksi, että algoritmini sekosi.

Koska järveni on 2-dimensioinen, yhtälöissä ei esiinny ylä- eikä alapuolen vaikutusta. Nehän olisivat kolmatta dimensiota, jota ei kerta kaikkiaan ole olemassa. Lisäsin silti virtausnopeuteen verrannollisen jarruttavan voiman kuvaamaan järven pohjaa. Nopeus ei enää kasvanut liian suureksi.

Myöhemmin oivalsin 'loiventaa alamäkiä' ja tehdä vedestä 'paksumpaa' niin, että rantojen vastus riitti pitämään virtausnopeuden aisoissa.

Liikemäärän säilyminen sympy-muodossa

Differentiaaliyhtälöistä differenssiyhtälöiksi

Ylläoleva yhtälöt ovat differentiaaliyhtälöitä, eli ne kertovat, mitä äärettömän pienet muutokset ajassa tai paikassa vaikuttavat. Tietokoneeni muistiin ei sovi ääretön määrä isoja eikä pieniä muutoksia eikä tietokoneeni erota äärettömän pientä nollasta.

Tietokoneella simuloitaessa maailma jaetaan pieniksi kuutioiksi ja lasketaan, mitä millekin kuutiolle tapahtuu. Pienin mahdollinen siirtymä on hyppy kuutiosta viereiseen tai $\Delta T$:n suuruinen hyppy ajassa. Yhtälöt pitää muuttaa kuvaamaan tuollaisia hyppyjä.

Wikipediasta löytyi tähänkin ongelmaan allaolevan mukainen valmis ratkaisu.

Esimerkiksi allaolevista ylimmän yhtälön mukaisesti pinnankorkeuden osittaisderivaatta itä-länsi suunnassa voidaan approksimoida laskemalla yhteen pinnankorkeus kahdessa viereisessä kuutiossa ja jakamalla kuutioiden keskipisteiden etäisyydellä.

Yksinkertaisimmat allaolevista kaavoista johdetaan kaiketi jo lukiomatikassa, mutta pahimpia en ehkä olisi itse osannut johtaa — siis saada oikeaa tulosta.


Finite differences can be considered in more than one variable. They are analogous to partial derivatives in several variables.

Some partial derivative approximations are:

$$ \begin{aligned}f_{x}(x,y)&\approx {\frac {f(x+h,y)-f(x-h,y)}{2h}}\\f_{y}(x,y)&\approx {\frac {f(x,y+k)-f(x,y-k)}{2k}}\\f_{xx}(x,y)&\approx {\frac {f(x+h,y)-2f(x,y)+f(x-h,y)}{h^{2}}}\\f_{yy}(x,y)&\approx {\frac {f(x,y+k)-2f(x,y)+f(x,y-k)}{k^{2}}}\\f_{xy}(x,y)&\approx {\frac {f(x+h,y+k)-f(x+h,y-k)-f(x-h,y+k)+f(x-h,y-k)}{4hk}}\end{aligned} $$

/https://en.wikipedia.org/wiki/Finite_difference#multivariate_finite_differences/


Alla ensin yksi esimerkki diskretoinnista sympyn avulla ja sitten kaikki yo. säännöt sympy-muodossa

Koska ylläolevia korvaussääntöjä lienee vaikea lukea, tein esimerkin niiden soveltamisesta. Kirjoitin listallisen derivaattojen lausekkeita ja ...



Järvi kuutioiksi

Allaolevan kuvan on tarkoitus auttaa ymmärtämään, miten sovelsin ylläolevia diskretointisääntöjä.

Pari kappaletta numeerisesta integroinnista. Ellei numeerinen integrointi kiinnosta, tämän kappaleen voi ohittaa.

Ensimmäisellä yrityksellä tein ylläolevan kaltaisen korvauksen myös derivaatoille ajan suhteen. Sain yhtälöt, joista saattoi ratkaista muuttujien arvot hetkellä $t + \Delta t$ kun tiesi muuttujien arvot hetkellä $t$. Menetelmää kutsutaan Eulerin menetelmäksi. Tiesin sen epätarkaksi, mutten pitänyt sitä ongelmana. Enhän ole suunnittelemassa lentokoneita.

Eulerin menetelmä on kuitenkin epätarkka tavalla, jonka takia muuttujien arvot karkasivat äärettömyyksiin, joten jouduin turvautumaan pikkuisen monimutkaisempaan Heunin algoritmiin. Siitä lisää myöhemmin numeerista laskentaa esittelevässä luvussa.

Heunin algoritmi varten tässä ratkaistaan muuttujien aikaderivaatat.

Reunaehdot

Ylläolevat säilymislait pätevät keskellä 'järveä', mutta rannoilla pätee omat ehtonsa. Pienellä kaistaleella rannan tuntumassa vesi ei virtaa — ei rannan suuntaisesti, eikä kohtisuoraan rantaan nähden. (Oikeissa järvissä vesi loiskuaa edes takaisin rannalla, mutta eipä siinäkään taida mitään nettovirtausta olla.)

Eli mitä tehdään, kun ylläolevissa yhtälöissä viereinen ruutu onkin maalla?

Simulointiohjelmassani järvi on iso taulukko. Simuloinnin alussa nopeudet laitetaan nolliksi koko taulukossa, myös 'maalla', eikä 'maalla' olevia arvoja käydä sen jälkeen muuttamassa, joten nopeuksien reunaehto toteutuu itsestään. Sama pätee väriaineen konsetraatioon.

Pieni syrjähyppy: Muuttamalla virtauksen nopeutta rantaviivalla simulaatioon voi lisätä puron, josta vesi laskee järveen.

'Reunoilla' ei ole paine-eroa kerrottiin eräässä artikkelissa. Kuulosti järkevältä, vaan miten nollata paine-ero?

Ohjelmani laskee uusia arvoja vain järvellä oleville ruuduille, muttei erota, ovatko laskennassa käytettävät naapuriruudut maalla vai järvellä. Niinpä kopioin järveltä pinnankorkeuden arvon viereiselle rantaviivalle jokaisella aika-askelella. Jos maalla ja rannassa pinnakorkeus on sama, paine-ero on nolla. Selitän tarkemmin myöhemmin.

Ratkaistaan aikaderivaattojen lausekkeet

Ratkaistaan pinnankorkeuden, itä-länsi ja pohjois-etelä suuntaisten nopeuksien ja väriaineen määrän derivaatat ajan suhteen

Ratkaistaan ylläolevasta derivaatat ajan suhteen (Ei onnistuisi ainakaan minulta käsityönä)

Koodin generointia

Muutetaan symboliset lausekkeet python-koodiksi ja kirjoitetaan python-funktio, joka laskee pinnankorkeuden ja nopeuksien derivaattojen arvot kullekin järveäni edustavalla taulukon ruudulle.

Tähän en keksinyt mitään eleganttia ratkaisua, joten tuskin ketään kiinnostaa, miten tämän tein.

Tehdään ylläesitellyt korvaukset systeemiyhtälöihin.

Onnistuu pythonilla aika näppärästi. Toisaalta pythonia tuntemattoman lienee vaikea ymmärtää, mitä alla tapahtuu.

(sympy.Solve antaa ratkaisun yhtälöryhmälle dictionaryna, jonka kelaan lävitse)

Simuloinnin kompleksisuus

Videon tekemistä varten joudun simuloimaan ehkä 10000 aika-askelta. Myöhemmin esiteltävä Heunin algoritmi edellyttää, että ylläolevaa funktiolla lasketaan 'järven' jokaisen ruudun pinnankorkeudelle, virtausnopeudelle ja maalin määrälle uusi arvo kaksi kertaa jokaisella aika-askeleella. Taulukossa on 240x200 ruutua, joista enintään puolet on 'maalla'. Uudet arvot lasketaan siis noin N kertaa.

Herää kysymys, eikö funktiota dfdt(...) voisi formuloida vektorioperaatioiksi, jotka voisi toteuttaa numpyn avulla. Laskenta nopeutuisi ties kuinka paljon. 10-kertaiseksi? 100-kertaiseksi?

Kysymys herää, mutta onneksi ei sentään herää into koodata. Olisi monen päivän työ päästä selville edes siitä, onnistuuko mokoma.