Metody numeryczne rozwiązywania równania adwekcji
Transkrypt
Metody numeryczne rozwiązywania równania adwekcji
UNIWERSYTET MARII CURIE-SKŁODOWSKIEJ W LUBLINIE WYDZIAŁ MATEMATYKI FIZYKI I INFORMATYKI Marcin Roman Metody numeryczne rozwiązywania równania adwekcji Numerical methods for solving advection equation Praca licencjacka wykonana pod kierunkiem prof. dra hab. Krzysztofa Murawskiego Lublin 2009 Składam serdeczne podziękowania Panu prof. dr. hab. Krzysztofowi Murawskiemu za poświęcony czas, cenne wskazówki, cierpliwość i wszelką pomoc okazaną podczas pisania niniejszej pracy. Spis treści Wstęp iv 1. Podstawowe pojęcia 1.1. Równania różniczkowe zwyczajne . . . . . . . . . . . . . . . . . . . . 1.2. Równania różniczkowe cząstkowe . . . . . . . . . . . . . . . . . . . . 1.3. Równanie adwekcji . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2. Metody numeryczne rozwiązywania 2.1. Metody różnic skończonych . . . . . 2.2. Metoda Laxa-Friedrichsa . . . . . . 2.3. Metoda Laxa-Wendroffa . . . . . . 2.4. Metoda niejawna Wendroffa . . . . 2.5. Metoda Beama-Warminga . . . . . 2.6. Metoda MacCormacka . . . . . . . 2.7. Metody objętości skończonych . . . 2.8. Metoda Godunowa . . . . . . . . . 2.9. Metody wyższych rzędów . . . . . . równań różniczkowych . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3. Projekt własny - program komputerowy adwekcji 3.1. Interfejs użytkownika . . . . . . . . . . . . 3.2. Szczegóły implementacyjne . . . . . . . . . 3.3. Symulacje numeryczne . . . . . . . . . . . Podsumowanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1 3 7 10 12 14 15 15 16 16 17 18 19 rozwiązujący równanie 23 . . . . . . . . . . . . . . . 23 . . . . . . . . . . . . . . . 24 . . . . . . . . . . . . . . . 28 31 iii Wstęp Wiele zjawisk daje się opisać w naturalny i intuicyjny sposób jako zależności funkcji i ich pochodnych. Jako przykład rozważmy prosty model ruchu swobodnie spadającego ciała puszczonego z pewnej wysokości. Działają na niego siła grawitacji i siły tarcia związane z ruchem. Siła tarcia kinetycznego jest proporcjonalna do prędkości. Związek ten możemy zapisać następująco: y 00 = g − ky 0 , jest prędkością ciała, a k jest współczynnikiem proporcjonalności. gdzie y 0 = dy dt Mając tak postawiony problem chcielibyśmy znaleźć taką funkcję y(t), która będzie spełniała powyższe równanie. Stosując teorię równań różniczkowych możemy także badać wiele innych, bardziej złożonych zjawisk, takich jak rozpad promieniotwórczy, rozwój populacji, rozchodzenie się fal na wodzie, czy też kształtowanie się zjawisk atmosferycznych. W informatyce równania różniczkowe stosuje się między innymi do modelowania ruchu w sieciach komputerowych, przetwarzania obrazów oraz do estymacji i kompensacji ruchu (ang. optical flow ). W tej pracy zostaną omówione metody numeryczne rozwiązywania hiperbolicznych równań różniczkowych na przykładzie równania adwekcji, które modeluje procesy unoszenia i stanowi najprostsze równanie hiperboliczne. W pierwszym rozdziale zostaną krótko przedstawione niezbędne pojęcia oraz model analityczny adwekcji. Rozdział drugi jest poświęcony problemowi konstrukcji schematów numerycznych. W ostatniej części zostały opisane przeprowadzone przez autora pracy symulacje numeryczne przy użyciu zaimplementowanych schematów. iv Rozdział 1 Podstawowe pojęcia 1.1. Równania różniczkowe zwyczajne Równanie różniczkowe to równanie, w którym występują pochodne funkcji szukanej [2]. W ujęciu formalnym: Równanie różniczkowe. Niech F będzie funkcją ciągłą na zbiorze otwartym U , x : t 7→ x(t) szukaną funkcją n-krotnie różniczkowalną. Równanie w postaci uwikłanej: F (t, x(t), x0 (t), . . . , x(n) (t)) = 0 nazywamy równaniem różniczkowym zwyczajnym (ang. Ordinary Differential Equation, ODE ) rzędu n. Postać normalna powyższego równania to: F (t, x(t), x0 (t), . . . , x(n−1) (t)) = x(n) (t). (1.1) Ze względu na częstą fizyczną interpretację zmienna niezależna t nazywana jest czasem. Jeśli F jest wielomianem zmiennej x, to jego stopień nazywamy stopniem odpowiadającego mu równania. Na przykład równania pierwszego stopnia nazywamy równaniami różniczkowymi liniowymi. Definicja 1. Niech X będzie przestrzenią wektorową, S ⊂ R×X zbiorem otwartym, s : S 7→ X, a ∆ przedziałem. Mówimy, że funkcja s : ∆ 7→ R jest rozwiązaniem (całką) równania (1.1), jeśli: 1. s jest n-krotnie różniczkowalna w przedziale ∆, 2. V (t, s(t)) ∈ S, t∈∆ 1 3. po podstawieniu s do równania (1.1) otrzymujemy tożsamość. Ponieważ równanie (1.1) jest równoważne układowi równań rzędu pierwszego, będziemy dalej rozważali równanie x0 = f (t, x), które zapisane w postaci różniczek wygląda następująco: dx = f (t, x)dt. Równanie różniczkowe wraz z warunkiem początkowym x(t0 ) = x0 nazywamy problemem początkowym lub problemem Cauchy’ego. Jeśli nie weźmiemy pod uwagę warunku początkowego i żadnych innych ograniczeń, to rozwiązanie będzie zależeć od pewnych stałych. Jest to tzw. rozwiązanie ogólne równania. Mając rozwiązanie ogólne możemy otrzymać z niego wszystkie rozwiązania szczególne poprzez wyznaczenie stałych [6]. Zauważmy, że rozwiązanie może nie istnieć. Zgodnie z definicją 1 ma to miejsce, jeśli f nie jest ciągła. Aby można było udowodnić istnienie rozwiązania, trzeba poczynić pewne założenia o funkcji f . Twierdzenie Peano (o istnieniu rozwiązania). Jeśli funkcja f jest ciągła w otoczeniu punktu (t0 , x0 ) ∈ D = {(t, x) : |t0 − t| < a, |x0 − x| < b}, wtedy problem Cauchy’ego ma rozwiązanie dla |t0 − t| 6 min(a, Mb ), gdzie M = supD |f (t, x)|. Problem początkowy może mieć wiele rozwiązań. Jego jednoznaczność możemy udowodnić na przykład dla funkcji f spełniających nierówność Lipschitza: |f (x1 ) − f (x2 )| 6 L|x1 − x2 |. Twierdzenie Picarda (o jednoznaczności rozwiązania). Jeśli funkcja f spełnia twierdzenie Peano o istnieniu rozwiązania oraz warunek Lipschitza względem zmiennej x dla pewnej stałej L, to problem Cauchy’ego ma jednoznaczne rozwiązanie dla |t0 − t| 6 min(a, Mb , L1 ) [5]. Oczywiście rozwiązanie może istnieć (i być jednoznaczne) w szerszych przedziałach od tych podanych w powyższych twierdzeniach [1]. Przykład 1. Jako przykład rozważmy model zmian rozmiaru okna TCP zaproponowany w [10]. Do ważnych cech TCP należą unikanie przeciążeń i kontrola przepływu danych. Aby to osiągnąć, można, bazując na obserwacji strat pakietów, tak dostosowywać rozmiar okna, aby wykrywać przeciążenia albo ich unikać. Jednocześnie chcielibyśmy uzyskać jak najlepszą efektywność transmisji. W praktyce nie znamy rzeczywistego obciążenia poszczególnych węzłów, dlatego ważna jest dobra technika aproksymacji. W zaproponowanym modelu rozmiar okna jest opisany 2 za pomocą stochastycznego równania różniczkowego: dW = dt −W +( )dNT D + (1 − W )dNT O . RT T 2 (1.2) Tutaj W oznacza rozmiar okna, RT T czas powrotu (ang. Round Trip Time), NT D i NT O są zmiennymi losowymi w procesie Poissona, odpowiadającymi odpowiednio liczbie strat spowodowanych pominięciem potwierdzenia (Triple Duplicate ACK) i nie nadejściem potwierdzenia w określonym czasie (Timeout). Wyjaśnijmy charakter pierwszego rodzaju strat. Jeśli pakiet z wyższym numerem sekwencyjnym nadejdzie do odbiorcy przed pakietem wcześniejszym, wówczas emitowane jest potwierdzenie wskazujące, że odbiorca oczekuje na ten wcześniejszy pakiet (Duplicate ACK ). W ten sposób nadawca dowiaduje się, że nieodebrany pakiet został utracony albo dotrze później. Otrzymanie kilku potwierdzeń Duplicate ACK może wskazywać z dużym prawdopodobieństwem, że pakiet został utracony (Triple Duplicate ACK ). Wówczas nie czekając na timeout nadawca dokonuje retransmisji. Pierwszy składnik powyższego równania symuluje zwiększanie rozmiaru okna, a dwa pozostałe są związane z multiplikatywnym zmniejszaniem rozmiaru. Ten prosty model pomija zachowanie powolnego startu i kilka innych mniej istotnych problemów, jednak nie wpływa to znacząco na wyniki. Jeśli obliczymy wartość oczekiwaną, otrzymamy: 1 λT D dE[W ] =( + λT O ) − ( + λT O )E(W ). dt RT T 2 Jest to niejednorodne równanie autonomiczne ze względu na E[W ]. Niech A i B będą odpowiednimi stałymi. Przekształcając i całkując to równanie otrzymujemy: dE[W ] = A − B ∗ E(W ), dt A B ln ( dE[W ] = Bdt, − E(W ) A − E(W )) = −Bt − C, B E(W )(t) = 1 RT T λT D 2 λT D + λT O + C 0 e−( 2 +λT O )t . + λT O 1.2. Równania różniczkowe cząstkowe Równanie opisujące zależności między kilkoma zmiennymi niezależnymi, wieloargumentową funkcją u tych zmiennych i jej pochodnymi cząstkowymi 3 nazywamy równaniem różniczkowym cząstkowym (ang. Partial Differential Equation, PDE ). Rząd tego równania jest równy najwyższemu rzędowi pochodnej cząstkowej występującej w równaniu. W pracy będziemy stosować nomenklaturę dla . pochodnych cząstkowych np. ux = ∂u ∂x Niech u : U 7→ R będzie funkcją szukaną, a [x1 , . . . , xn ] = x ∈ U . Oznaczmy przez Dj u zbiór pochodnych cząstkowych j-tego rzędu [7]. Ogólnie równanie k-tego rzędu ma postać: F (x, u, D1 u, . . . , Dk u) = 0. (1.3) Jeśli funkcja u będzie przyjmowała wartości w przestrzeni Rn , czyli u = [u1 , . . . , un ], to zapis (1.3) będzie oznaczał układ równań funkcji składowych. Analiza równań wyższych rzędów jest dużo bardziej skomplikowana. Rozwiązywanie ich można jednak sprowadzić do rozwiązywania układu PDE rzędu pierwszego poprzez odpowiednie zastąpienie pochodnych cząstkowych nowymi funkcjami. Dlatego w dalszej części skupimy się głównie na równaniach drugiego i pierwszego rzędu. Postać ogólna równania dwóch zmiennych drugiego rzędu jest następująca: ∂u ∂u ∂ 2 u ) = 0. F (x, y, u, , , ∂x ∂y ∂x∂y Dla PDE definiuje się analogicznie pojęcie rozwiązania równania i wiele innych twierdzeń odnoszących się do równań różniczkowych zwyczajnych. Na przykład dla równania pierwszego rzędu F (x, y, u, ux , uy ) = 0 zagadnienie Cauchy’ego definiujemy podając warunek początkowy u(x0 , y) = f (y) lub u(x, y0 ) = g(x). Równanie postaci: aux + buy = c, (1.4) gdzie a, b i c są funkcjami x i y, nazywamy równaniem liniowym niejednorodnym. Jeśli c ≡ 0, wówczas mówimy o równaniu jednorodnym. Natomiast, jeśli któraś z funkcji a, b i c zależy od u, to mamy do czynienia z równaniem quasi-liniowym. Zauważmy, że rozwiązanie równania quasi-liniowego można sprowadzić do problemu rozwiązania równania liniowego. 1.2.1. Charakterystyki Załóżmy, że mamy dane równanie pierwszego rzędu: F (x, u, Du) = 0. 4 (1.5) Tutaj x = [x1 , . . . , xn ]. Metoda charakterystyk pozwala nam na sprowadzenie rozwiązania (1.5) wzdłuż pewnej krzywej w przestrzeni Rn do problemu rozwiązania układu równań zwyczajnych. Szukaną krzywą x(s) : R 7→ Rn będziemy zapisywać w postaci parametrycznej. Niech p(s) = [ux1 (x(s)), . . . , uxn (x(s))]. Zróżniczkujmy (1.5) po zmiennej xi : n X ∂F ∂F (p(s), u(x(s)), x(s))uxj xi + (p(s), u(x(s)), x(s))uxi ∂u j=1 ∂pj + ∂F (p(s), u(x(s)), x(s)) = 0. ∂xi Przyjmując zatem d ∂F xj (s) = (p(s), u(x(s)), x(s)) ds ∂xj d i zapisując sumę jako ds pi pozbywamy się pochodnych cząstkowych drugiego rzędu szukanej funkcji u. Wzdłuż krzywej x = x(s) spełnia ona równanie: n n X X d ∂F d uxi (s) xi (s) = pi u(x(s)) = (p(s), u(x(s)), x(s)). ds ds ∂xj i=1 i=1 Otrzymujemy w ten sposób układ ODE, zwany układem charakterystyk [7]: d ∂F − ds pi + ∂F (p(s), u(x(s)), x(s))pi + ∂x (p(s), u(x(s)), x(s)) = 0 (i = 1 . . . n), ∂u i P ∂F d (p(s), u(x(s)), x(s)), u(x(s)) = ni=1 pi ∂x ds j d ∂F (i = 1 . . . n). x (s) = ∂xi (p(s), u(x(s)), x(s)) ds i Krzywe będące jego rozwiązaniem nazywamy charakterystykami. Zatem jeśli dla (1.5) zdefiniujemy warunek początkowy wzdłuż krzywej, która nie jest charakterystyką, będzie można wyznaczyć rozwiązanie w punktach, przez które przechodzi jakaś charakterystyka. W przypadku równania quasi-liniowego: F (x, u, Du) = n X ai ux1 + b = 0, i=1 gdzie ai (i = 1 . . . n) i b są funkcjami x i u, mamy: d u(x(s)) = −b, = ai (i = 1 . . . n). ds d x (s) ds i Widzimy więc, że przy zastosowaniu metody charakterystyk ważne są również metody stosowane do równań zwyczajnych. 5 1.2.2. Hiperboliczne równania różniczkowe Zapiszmy równanie quasi-liniowe drugiego rzędu auxx + buxy + cuyy + e = 0, (1.6) przyjmując p = ux i q = uy , wzdłuż krzywej określonej wzorami: x = x(s), y = y(s). d d p i ds q oraz wyznaczmy z nich pochodne cząstkowe [1]: W tym celu obliczmy ds uxx = dp dy − uxy dx dx uyy = dy dq − uxy . dy dx i symetrycznie: Po podstawieniu ich do (1.6) otrzymamy: −uxy [a( dy 2 dy dp dy dq dy ) − b + c] + a +c +e = 0. dx dx dx dx dx dx (1.7) Określmy krzywą (x, y), tak aby zniknęła pochodna mieszana uxy : dy a dx !2 −b dy + c = 0. dx (1.8) Ze względu na symetrię postaci ogólnej (1.7) względem x i y, jeśli a ≡ 0, to równanie kwadratowe (1.8) możemy pomnożyć przez ( dx )2 . W zależności od wyróżnika ∆ = dy b2 − 4ac wprowadzamy podział na równania: 1. hiperboliczne, dla ∆ > 0, 2. paraboliczne, dla ∆ = 0, 3. eliptyczne, dla ∆ < 0. W tej pracy skupimy się na równaniach rzędu pierwszego postaci: qt + f (q)x = 0. (1.9) Tutaj q : R × R 7→ Rm jest szukaną funkcją, natomiast f : Rm 7→ Rm . Jeśli f jest przekształceniem liniowym, to równanie (1.9) również nazywamy liniowym i możemy je zapisać jako qt + Aqx = 0, (1.10) gdzie A jest macierzą Jacobiego tego przekształcenia [3]. 6 Definicja 2. Równanie (1.10) nazywamy hiperbolicznym, jeśli macierz A jest diagonalizowalna i ma rzeczywiste wartości własne. Jeśli dodatkowo widmo A jest proste, to mówimy, że równanie to jest ściśle hiperboliczne. Warunek diagonalizowalności pozwala na zapisanie macierzy A = RA0 R−1 . Tutaj A0 jest macierzą diagonalną z wartościami własnymi na przekątnej, R jest macierzą przejścia, a jej kolumny są odpowiednimi wektorami własnymi macierzy A. Podstawiając tą zależność do (1.10) i mnożąc otrzymane równanie lewostronnie przez R−1 , otrzymamy: R−1 qt + A0 R−1 qx = 0. Teraz przyjmijmy p = R−1 q. Widzimy więc, że znalezienie rozwiązania sprowadza się do rozwiązania m niezależnych równań - jak się przekonamy w następnym paragrafie, są to równania adwekcji. Funkcję q można wyrazić jako kombinację znalezionych funkcji (tzw. zmiennych charakterystycznych) p1 , . . . , pm , które są składowymi p: q(x, t) = Rp(x, t), q(x, t) = m X ri pi (x, t). i=1 Tutaj ri są wektorami własnymi A, czyli kolumnami macierzy R. Wynik ten sugeruje, że równania hiperboliczne opisują fale rozchodzące się ze skończoną prędkością [4]. 1.3. Równanie adwekcji Z punktu widzenia zastosowań fizycznych ważną klasę PDE stanowią równania uzyskane z praw zachowania [3]. Rozważmy pewien ograniczony obszar U ∈ Rn . Niech wewnątrz tego obszaru znajduje się pewna substancja, której gęstość określa funkcja q : U 7→ R. Ilość tej substancji możemy obliczyć poprzez scałkowanie q po tym obszarze: Z MU = qdU . U Wielkość MU może się zmieniać jedynie wskutek przepływu substancji przez brzeg ∂U tego obszaru. W tej pracy zajmiemy się przypadkiem jednowymiarowym (n = 1), ze względu na jego prostotę przy analizie metod numerycznych. Tak więc U jest odcinkiem (x1 , x2 ) ∈ R. Funkcję strumienia zwykle chcielibyśmy uzależnić od gęstości substancji na końcach odcinka: f (q, t, x). Zatem zmianę MU w czasie wyraża 7 zależność: Z x1 ∂ Z x2 ∂ f (q, t, x)dx. q(t, x)dx = f (q, t, x1 ) − f (q, t, x2 ) = ∂t x1 x2 ∂x (1.11) Zależność to znana jest jako postać całkowa prawa zachowania. Zakładając odpowiednią regularność funkcji podcałkowych możemy zapisać równoważnie prawo zachowania w postaci różniczkowej: ∂ ∂ q(t, x) + f (q, t, x) = 0. ∂t ∂x Adwekcja (łac. advectio - transport) jest zjawiskiem przenoszenia pewnej substancji związanym z przepływem pewnej cieczy. W ogólności może być unoszona pewna zachowywana własność jak masa, pęd, energia, zasolenie, czy wilgotność (w przypadku gdy ośrodkiem jest powietrze) i możemy rozpatrywać kilka tych własności (być może powiązanych ze sobą) jednocześnie: q : U 7→ Rm . Przenoszona substancja nie powinna znacząco wpływać na ruch ośrodka. W naszym jednowymiarowym przypadku możemy modelować np. transport zanieczyszczeń w wodzie w pewnej rurce. W przypadku adwekcji funkcja strumienia zależy od prędkości cieczy: f (x, t) = u(x, t)q. Najprostszy przypadek zachodzi, gdy u = const. Wtedy równanie adwekcji można zapisać jako: qt + uqx = 0. (1.12) Zauważmy, że nie uwzględnia ono takich zjawisk jak dyfuzja, czy zmiana ilości substancji w wyniku reakcji oraz występowania źródeł i ujść. Zapiszmy wzór na pochodną kierunkową q, w pewnym kierunku l określonym przez kąty α, β między l i osiami współrzędnych: ∂ q = qt cos α + qx cos β. ∂l Znormalizujmy wektor v = [1, u]: ṽ = 1 u v √ = [√ , ]. kvk 1 + u2 1 + u2 Widzimy więc, że pochodna kierunkowa wzdłuż osi ṽ = [cos α, cos β] się zeruje [7]. To oznacza, że q jest stała na prostych o równaniu x = u(t − t0 ) + x0 . Stąd też bierze się nazwa równania (1.12): profil funkcji jest „przenoszony” z czasem. Zwykle warunek początkowy mamy dany dla t = 0: q(0, x) = g(x), x ∈ R. Jeśli g jest dana na przedziale ograniczonym, to powinny zostać także określone warunki brzegowe. Pozwala nam to na znalezienie rozwiązania równania (1.12). 8 Jeśli prędkość cieczy u(x, t) zmienia się wzdłuż osi x, to dla równania: qt + uqx = −ux q układ charakterystyk ma postać: d t(s) ds = 1, d x(s) = u, ds d q(s) = −ux q. ds Szczególnym przypadkiem tego równania jest nielepka postać równania Burgersa: przyjmujemy, że prędkość u = 12 q [4]. Otrzymujemy w ten sposób równanie nieliniowe: qt + qqx = 0. Krzywe charakterystyk spełniają zależność: x0 (t) = q(x(t)). Natomiast szukana funkcja: d ∂ ∂ q(x(t), t) = q(x(t), t) + q(x(t), t)x0 (t) = 0 dt ∂t ∂x jest stała wzdłuż tych charakterystyk, z czego wynika, że są one prostymi o nachyleniu zależnym do wartości q w danym punkcie. Znajomość dokładnych rozwiązań analitycznych równania adwekcji pozwala na porównanie i analizę zachowania schematów numerycznych dla funkcji początkowych o szczególnych własnościach. 9 Rozdział 2 Metody numeryczne rozwiązywania równań różniczkowych Metody analityczne rozwiązywania równań różniczkowych prowadzą często do rozwiązań bardzo skomplikowanych i trudnych do analizy, co utrudnia lub nawet uniemożliwia poznanie istoty oraz specyficznych własności danego zagadnienia. Co więcej, w wielu przypadkach może nie być możliwe przedstawienie rozwiązania przy użyciu skończonej liczby funkcji elementarnych. Tutaj z pomocą przychodzą metody numeryczne. Ich użycie pozwala przede wszystkim na symulację zjawiska. Oczywiście podobnie jak w przypadku metod analitycznych nie istnieje jedna metoda badania równań różniczkowych, tak też pewien algorytm numeryczny stosowany z powodzeniem do problemów jednej klasy może dać dalekie od rzeczywistości wyniki dla innego, nawet z pozoru podobnego równania. Z wykorzystaniem schematów numerycznych wiąże się dyskretyzacja. Prowadzi ona do błędów przybliżeń charakterystycznych dla danej metody. Błąd globalny jest różnicą między rozwiązaniem dokładnym a przybliżonym. Natomiast jeśli dla zadanych danych obliczymy błąd, jaki powstaje w pojedynczym kroku czasowym, wówczas mamy do czynienia z błędem lokalnym. Z użyciem cyfrowych maszyn liczących wiąże się też błąd zaokrąglenia [1]. Pewną intuicją przy dokonywaniu dyskretyzacji równania jest przybliżenie pochodnych różnicami skończonymi. Rozwińmy szukaną funkcję f (x) w szereg Taylora: f (n−1) (x0 ) n−1 f 00 (x0 ) 2 h + ... + h + O(hn ). f (x0 + h) = f (x0 ) + f (x0 )h + 2! (n − 1)! 0 10 Dla n = 2 mamy: f (x0 + h) − f (x0 ) + O(h). (2.1) h Widzimy, że błąd jest rzędu O(h). Aby go zminimalizować, moglibyśmy na przykład zmniejszyć h. Jednak ze względu na błędy zaokrągleń nie zawsze prowadzi to do poprawy. Obliczona tą metodą pochodna cos0 (2) przy użyciu 64-bitowego typu double wynosi dla danych wartości: f 0 (x0 ) = h = 2−8 : −0.90848232860788868947565788403153419494628906250000, h = 2−20 : −0.90929722838336601853370666503906250000000000000000, h = 2−47 : −0.90625000000000000000000000000000000000000000000000. Widzimy więc, że dla małych h licznik i mianownik użytego przybliżenia mają mało cyfr znaczących, przez co dokładność maleje wraz z h począwszy od pewnej wartości granicznej [1]. Obliczmy teraz szereg Taylora dla n = 3 w punktach x0 − h i x0 + h oraz odejmijmy je stronami: f 0 (x0 ) = f (x0 + h) − f (x0 − h) + O(h2 ). 2h (2.2) Jest to tzw. iloraz różnicowy centralny stosowany do oszacowania pochodnej f 0 (x0 ). Jego błąd jest rzędu O(h2 ). Innym często używanym przybliżeniem pochodnej f 00 (x0 ) jest: f (x0 + h) − 2f (x0 ) + f (x0 − h) + O(h2 ). (2.3) f 00 (x0 ) = h2 Ważnym krokiem przy dokonywaniu dyskretyzacji jest określenie dla jakich punktów będziemy dokonywać obliczeń. Zwykle mając zadany warunek początkowy dla t0 = 0, będziemy aproksymować rozwiązania w tych punktach po upływie czasu ∆t. Oczywiście punkty początkowe mogą być rozmieszczone nierównomiernie. Można wtedy dokonać interpolacji. Rozrzedzenie siatki może być celowe, jeśli w pewnych obszarach nie interesują nas dokładne wyniki. Zajmiemy się przypadkiem jednorodnym. Punkty będą znajdować się na n-wymiarowej kracie wyznaczonej przez wektory postaci ki = [0, . . . , ki , . . . , 0]. Dodatkowym wymiarem, który możemy uwzględniać jest czas. Ograniczając się do przypadku jednowymiarowego współrzędne punktów kraty numerycznej mają postać: (xp + i∆x, n∆t) : n = 0, 1, . . . ; 11 i = 0, 1, . . . , ie . Przy analizie metody numerycznej istotna jest stabilność. Oznacza ona, że błędy obliczeń nie wpłyną znacząco na rozwiązanie i nie będzie ono się zasadniczo różniło od rozwiązania dokładnego. Widzieliśmy, że rozwiązanie hiperbolicznego PDE (1.10) jest kombinacją liniową funkcji, które są rozwiązaniami równań adwekcji. Dla każdego z nich prędkością unoszenia jest odpowiednia wartość własna λi macierzy A. Prędkości te wyznaczają zbiór punktów dla tp < t, od których zależy rozwiązanie w danym punkcie. W ten sposób definiuje się dziedzinę zależności rozwiązania analitycznego Dtp (x, t) = {xd : |x − xd | < max (λi )(t − td )}. Dla skalarnego równania adwekcji należy do niej 1 punkt: Dtp (x, t) = {x − u(t − tp )}. Jednak w przypadku równania przewodnictwa cieplnego jest to cała przestrzeń. Analogicznie definiuje się dziedzinę zależności dla metody numerycznej jako zbiór punktów z poprzednich kroków, mających wpływ na obliczenia dla danego punktu. Wiąże się z tym warunek konieczny stabilności metody (znany jako warunek CFL): dziedzina zależności rozwiązania analitycznego powinna zawierać się w dziedzinie zależności metody numerycznej [3]. Wpływa to na dobór siatki i ogranicza w pewien sposób iloraz: u∆t (2.4) ζ= ∆x zwany liczbą Couranta. O schematach dla równań zwyczajnych zapisanych w postaci ogólnej: xn + αk−1 xn−1 + . . . + α0 xn−k = h(βk fn + . . . + β0 fn−k ) mówimy, że są wielokrokowe, jeśli k > 1 [5]. W przypadku, gdy βk = 0, schemat nazywamy jawnym, w przeciwnym razie - niejawnym. Podobnie możemy scharakteryzować schematy dla PDE: jeśli do obliczenia wartości w punkcie siatki (xj , tk ) wykorzystujemy wyniki z k > 1 poprzednich kroków, to schemat jest wielokrokowy. Schemat będzie niejawny, jeśli wyznaczenie wartości dla czasu tk wymaga rozwiązania równania wiążącego nieobliczone dotąd wartości z tego kroku. 2.1. Metody różnic skończonych Metody różnic skończonych (ang. finite-difference methods) polegają na zastąpieniu pochodnych występujących we wzorze analitycznym ilorazami 12 różnicowymi i przybliżeniami wyznaczonymi ze wzoru Taylora. W związku z tym ważne jest założenie o istnieniu pochodnych odpowiedniego rzędu poszukiwanej funkcji. W przypadku równania adwekcji można skorzystać z faktu, że: k ∂kq ∂kq k∂ q = −u = . . . = (−u) . ∂tk ∂tk−1 ∂x1 ∂xk Związek ten pozwala zastąpić pochodne czasowe pochodnymi przestrzennymi. Podejście to sprowadza się do poszukiwania rozwiązań w punktach qin = q(xn , ti ) siatki. Zwykle pomijamy przy tym analizę zachowania funkcji pomiędzy tymi punktami. Nasuwa się pomysł zastąpienia w równaniu adwekcji (1.12) pochodnych: czasowej - ilorazem różnicowym wprzód i przestrzennej - ilorazem centrowanym (nie chcielibyśmy wyróżniać któregoś kierunku). Prowadzi to do schematu FTCS (Forward-Time Central-Space): n n qi+1 − qi−1 qin+1 − qin +u = 0. ∆t 2∆x (2.5) Niestety otrzymany w ten sposób schemat jest niestabilny dla równań hiperbolicznych [3]. 2.1.1. Metoda pod wiatr Innym podobnym pomysłem rozwiązania równania adwekcji (1.12) jest użycie przybliżeń pierwszego rzędu. Jeśli substancja o gęstości q porusza się w kierunku zgodnym ze wzrostem współrzędnej przestrzennej (u > 0), wtedy przy obliczaniu ilorazu dla qx (xi , tn ) uwzględnimy wartości z „lewej” strony (od tej strony substancja napływa): n q n − qi−1 qin+1 − qin +u i = 0, u > 0. (2.6) ∆t ∆x n W przeciwnym razie wykorzystamy qi+1 . Niesymetryczność tych oszacowań jest zgodna z sensem fizycznym adwekcji. Z tego też względu schemat ten jest określany jako dyskretyzacja pod wiatr (ang. upwind ). Uwzględnienie innych punktów jest zbędne i wprowadziłoby „wygładzanie” funkcji. Schemat ten jest stabilny dla 0 ¬ | u∆t | ¬ 1. Wzór (2.6) możemy zapisać w sposób ogólny: ∆x qin+1 = qin − ∆t(min (u, 0)qx+ + max (u, 0)qx− ), 13 gdzie: n n − qin qi+1 qin − qi−1 − = , qx = . ∆x ∆x Możliwe jest też użycie lepszych przybliżeń (np. drugiego rzędu dokładnych): qx+ qx+ = n n − 3qin + 4qi+1 −qi+2 , 2∆x (2.7) n n 3qin − 4qi−1 + qi−2 . 2∆x (2.8) qx− = 2.1.2. Schemat skoku żaby Jeśli wykorzystamy przybliżenie pochodnymi centrowanymi zarówno w czasie, jak i w przestrzeni, otrzymamy schemat skoku żaby (ang. leap-frog): qin+1 = qin−1 − u∆t n n (q − qi−1 ). ∆x i+1 (2.9) 2.2. Metoda Laxa-Friedrichsa Jeśli do schematu Eulera (2.5) dodamy czynnik dyspersyjny, to otrzymamy metodę Laxa-Friedrichsa [4]. Modyfikacja sprowadza się do zastąpienia qin przez średnią sąsiednich punktów: n q n + qi+1 . qin ≈ i−1 2 Uzyskujemy w ten sposób: qin+1 = n n n qi+1 + qi−1 q n − qi−1 − u∆t i+1 . 2 2∆x Zauważmy jeszcze, że dyskretyzując równanie adwekcji z dyfuzją: qt + uqx = qxx w sposób następujący: n n q n − qi−1 q n − 2qin + qi+1 qin+1 − qin + u i+1 = i−1 ∆t 2∆x (∆x)2 otrzymamy (2.10), jeśli przyjmiemy: = (∆x)2 . 2∆t 14 (2.10) Dzięki wprowadzeniu członu dyfuzyjnego otrzymujemy metodę stabilną dla: u∆t ∆x ¬ 1. 2.3. Metoda Laxa-Wendroffa Zapiszmy rozwinięcie Taylora dla qin+1 uwzględniając 3 pierwsze wyrazy oraz zastępując pochodne czasowe przestrzennymi: q(x, t + ∆t) = q − u∆tqx + 1 (u∆t)2 qxx . 2 Używając pochodnych centralnych otrzymujemy schemat Laxa-Wendroffa [3]: qin+1 = qin 1 u∆t n 1 n − (qi+1 − qi−1 )+ 2 ∆x 2 u∆t ∆x !2 n n (qi+1 − 2qin + qi−1 ). (2.11) Innym sposobem uzyskania tego schematu jest wyznaczenie ze schematu Laxan+1/2 n+1/2 Friedrichsa wartości qi−1/2 oraz qi+1/2 przyjmując o połowę mniejsze ∆x i ∆t. Dla drugiego z szukanych przybliżeń otrzymamy wyrażenie: n+1/2 qi+1/2 = n q n − qin + qin qi+1 − u∆t i+1 . 2 2∆x Drugim krokiem jest użycie wyników do obliczenia qin+1 : n+1/2 n+1/2 qi+1/2 − qi−1/2 qin+1 − qin = −u . ∆t ∆x Po uproszczeniu dostaniemy (2.11). To podejście jest jednak ogólniejsze i można je zastosować dla innej funkcji strumienia. 2.4. Metoda niejawna Wendroffa Zapiszmy ilorazy pochodnych czasowych w punktach (i, n + 0.5) i (i + 1, n + 0.5) [1]. Jeśli funkcja jest regularna, to uśrednienie ich przybliża pochodną w punkcie (i+0.5, n+0.5). Podobnie postępujemy z pochodnymi przestrzennymi. Podstawiając wyniki do (1.12) otrzymujemy schemat niejawny (Rys. 2.1): 1 2 n+1 n − qi+1 qin+1 − qin qi+1 + ∆t ∆t ! u + 2 15 n+1 n qi+1 − qin qi+1 − qin+1 + ∆x ∆x ! = 0. Błąd metody Wendroffa wynosi O((∆x)2 + (∆t)2 ). (i,n+1) (i+1,n+1) (i+0.5,n+0.5) Rysunek 2.1: Wykorzystywane węzły w niejawnej metodzie Wendroffa. 2.5. Metoda Beama-Warminga Metodę Beama-Warminga otrzymujemy w podobny sposób jak metodę LaxaWendroffa [8]. Modyfikacja polega za zastąpieniu pierwszej pochodnej przestrzennej wyrażeniem (2.7) lub (2.8), np.: qin+1 = qin n n + qi−2 3q n − 4qi−1 1 + − u∆t i 2∆x 2 u∆t ∆x !2 n n (qin − 2qi−1 + qi−2 ). (2.12) 2.6. Metoda MacCormacka Metoda ta dotyczy w ogólności wyrażenia (1.9), ale dla zagadnienia liniowego jest równoważna metodzie Laxa-Wendroffa [8]. Można wyodrębnić następujące kroki: • etap przewidywania (ang. predictor step) - proste przybliżenie: q̃in+1 = qin − ∆t n fi+1 − fin . ∆x • etap korekcji (ang. corrector step) n+1/2 qin+1 − qi ∆t/2 = n+1 f˜in+1 − f˜i−1 , ∆x gdzie f˜in+1 = f (q̃in+1 ). • postać końcowa otrzymana po zastosowaniu przybliżenia n+1/2 qi ≈ 16 q̃in+1 − qin 2 w rezultacie wynosi: qin+1 = (qin + q̃in+1 − ∆t ˜n+1 ˜n+1 (f − fi−1 ))/2. ∆x i 2.7. Metody objętości skończonych Zamiast przybliżać rozwiązanie szukanej funkcji w punktach możemy przestrzeń X, T podzielić na komórki, dla których będziemy obliczać średnią wartość q w przedziale: Ii = [xi−1/2 , xi+1/2 ]. Będziemy ją zapisywać następująco: Qni 1 Z = q(x, tn )dx, ∆x Ii gdzie ∆x = xi+1/2 − xi−1/2 jest rozmiarem i-tej komórki numerycznej. Całkując (1.11) względem czasu otrzymujemy: Qn+1 i = Qni 1 + ∆x Z tn+1 tn f (xi−1/2 , t)dt − Z tn+1 tn f (xi+1/2 , t)dt . Będziemy rozpatrywać zmianę Qni w wyniku przepływów przez brzegi komórki [3]. Ponieważ nie wiemy jak zmienia się q(xi , t ∈ (tn , tn+1 )), nie możemy wyznaczyć dokładnych całek ze strumienia, występujących w powyższym wyrażeniu. Metody objętości skończonych (ang. Finite Volume Methods) sprowadzają się zatem do znalezienia dla nich przybliżeń Fin . Otrzymane schematy mają postać ogólną: Qn+1 = Qni − i ∆t n n (F − Fi−1/2 ). ∆x i+1/2 (2.13) Takie podejście pozwala na uwzględnienie własności zachowawczych przy konstrukcji metod numerycznych oraz umożliwia poszerzenie klasy rozwiązań o rozwiązania nieróżniczkowalne, zwane rozwiązaniami słabymi [3]. Ponieważ (2.13) można zapisać w równoważnej postaci: n n Fi+1/2 − Fi−1/2 Qn+1 − Qni i =− , ∆t ∆x metody objętości skończonych można traktować jako metody różnic skończonych. 17 Dla przykładu metodę Laxa-Friedrichsa możemy uzyskać przyjmując: " n Fi+1/2 # ∆t 1 = f (Qni ) + f (Qni+1 ) − (f (Qni+1 ) − f (Qni )) . 2 ∆x 2.8. Metoda Godunowa W przypadku metod objętości skończonych zdyskretyzowana funkcja q w kroku ti , była przedziałami stała. Nieciągłości mogły się pojawić jedynie na brzegach komórek numerycznych. Idea zaproponowana przez Godunowa polega na obserwacji, że funkcję przepływu numerycznego można wyznaczyć rozwiązując problem Riemanna dla nieciągłości między komórkami [4]. Problem Riemanna. Zagadnienie znalezienia rozwiązania (1.9), mając zadany problem początkowy z pojedynczą nieciągłością postaci: q(x, 0) = ql : x < 0, qr : x > 0 nazywamy problemem Riemanna. Wektory ql i qr możemy zapisać jako kombinację wektorów własnych: ql = m X vil ri , qr = m X vir ri , i=1 i=1 gdzie: vil (x, t) : x − λi t < 0, vi (x, t) = r vi (x, t) : x − λi t > 0. Korzystając z konwencji Iversona rozwiązanie możemy zapisać następująco: q(x, t) = m X (vil + (vir − vil )[x − λi t > 0])ri . i=1 Oznacza to, iż rozwiązanie sprowadza się do przedstawienia skoku qr − ql w postaci kombinacji liniowej wektorów własnych A. Dla problemu adwekcji poszczególne „składowe” przemieszczają się z prędkościami charakterystycznymi λi . Metoda Godunowa polega na wyrażeniu przepływu w punkcie xi+1/2 poprzez rozwiązanie problemu Riemanna. Dla najprostszego przypadku skalarnego równania adwekcji mamy: n Fi+1/2 = [u > 0]uQni + [u < 0]uQni+1 . 18 Jest to jeszcze jeden sposób na uzyskanie metody pod wiatr. Z opisanym schematem postępowania wiąże się ograniczenie na rozmiar komórki: nieciągłości niesione przez fale z jednego brzegu xi+1/2 nie mogą dotrzeć do sąsiednich w czasie ∆t. Ze względu na warunek stabilności schematu numerycznego liczba Couranta ζ jest ograniczona następująco: u∆t ζ= ¬ 1. ∆x 2.9. Metody wyższych rzędów Metoda Godunowa zakłada rekonstrukcję q w komórce funkcjami stałymi. Aby osiągnąć lepszą dokładność, należy skonstruować wielomiany wyższego stopnia na postawie wartości w sąsiednich komórkach. Następnymi krokami dla adwekcji będzie translacja otrzymanej funkcji oraz jej uśrednienie. Częstą praktyką jest wykorzystanie funkcji liniowych: q̃ n (x) = Qni + σin (x − xi ), x ∈ Ii . (2.14) Tutaj współczynnik kierunkowy σin jest funkcją nachylenia. Otrzymujemy schemat ogólny postaci [3]: Qn+1 = Qni − i u∆t u∆t n n (Qi − Qni−1 ) − (∆x − u∆t)(σin − σi−1 ). ∆x 2∆x (2.15) W zależności od doboru funkcji nachylenia uzyskujemy różne metody. Przedstawia to Tabela 2.1. Tabela 2.1: Sposoby doboru nachylenia σin . σin 0 n Qn i+1 −Qi−1 2∆xn Qn i −Qi−1 ∆x n Qn i+1 −Qi ∆x n Qn Qn −Qn i+1 −Qi minmod( ∆x , i ∆xi−1 ) 19 metoda metoda Godunowa metoda Fromma metoda Beama-Warminga metoda Laxa-Wendroffa metoda minmod Funkcja minmod zdefiniowana jest następująco: min (xi ) : xi > 0, i minmod(x1 , . . . , xn ) = max (xi ) : V V xi < 0, i wpp. 0: Metody drugiego rzędu mogą prowadzić do powstania oscylacji w pobliżu nieciągłości [3]. Z tego względu chcielibyśmy tak połączyć metody pierwszego i drugiego rzędu, aby wykorzystać zalety obu metod. Aby zapewnić, że schemat nie wprowadza oscylacji, trzeba nałożyć pewne ograniczenia. Korzysta się w tym celu z pojęcia całkowitej wariancji, która jest zdefiniowana następująco [9]: T V (Q) = X |Qi − Qi−1 |. i Jeśli wartość ta w kolejnych krokach nie rośnie, to można pokazać, że oscylacje nie powstaną. Strumień F możemy otrzymać całkując q̃ n (x) po czasie na brzegu komórki. Dla równania adwekcji mamy [3]: n Fi−1/2 = [u > 0]uQni−1 + [u < 0]uQni ! u∆t |u| σin ∆x. 1− + ∆x 2 Zapisując ogranicznik nachylenia jako: σin n qi+1 − qin φ(θin ), = ∆x gdzie θin jest pewną miarą gładkości, używamy funkcji ogranicznika strumienia (zwanej też filtratorem) φ. Zwykle przyjmuje się θin = qn − qn−1 . qn+1 − qn Tabela 2.2 przedstawia kilka wybranych ograniczników. Szary obszar na wykresach został zdefiniowany przez Sweby - zawarte w nim funkcje ograniczników zachowują warunek zmniejszania ogólnej wariancji (TVD) oraz są dokładne drugiego rzędu. 20 Tabela 2.2: Ograniczniki strumienia. Ogranicznik van Leera Ogranicznik van Albada (1) 2 2 1 1 1 φ= 2 1 r+|r| 1+|r| φ= 2 r2 +r r2 +1 Ogranicznik van Albada (2) Ogranicznik UMIST 2 2 1 1 1 φ= 2 1 2r 1+|r| 2 φ = max(0, min(2r, 0.25 + 0.75r, 0.75 + 0.25r, 2)) Ogranicznik Sweby Ogranicznik superbee 2 2 1 1 1 2 1 φ = max(0, min(βr, 1), min(r, β)) 2 φ = max(0, min(2r, 1), min(r, 2)) Ogranicznik smart Ogranicznik ospre 2 2 1 1 1 2 1 2 φ = 1.5(r2 + r)/(r2 + r + 1) φ = max(0, min(2r, 0.25 + 0.75r, 4)) 21 Tabela 2.2: Ograniczniki strumienia. Ogranicznik Osher Ogranicznik MC 2 2 1 1 1 2 1 φ = max(0, min(r, β)) φ = max(0, min(2r, 0.5(1 + r), 2)) Ogranicznik minmod Ogranicznik Koren 2 2 1 1 1 2 2 1 2 φ = max(0, min(1, r)) φ = max(0, min(2r, (1 + 2r)/3, 2)) Ogranicznik HQUICK Ogranicznik HCUS 2 2 1 1 1 φ= 2 1 2(r+|r|) r+3 φ= 22 1.5(r+|r|) r+2 2 Rozdział 3 Projekt własny - program komputerowy rozwiązujący równanie adwekcji Przedstawione w poprzednim rozdziale metody rozwiązywania równania adwekcji zostały zaimplementowane przez autora pracy w języku C++. Do stworzenia interfejsu użytkownika został wykorzystany framework Qt. Dzięki temu aplikacja jest przenośna. Program został przetestowany na systemach Mac OS X i GNU/Linux. Jednak możliwe jest uruchomienie go również w innych środowiskach prawdopodobnie bez konieczności wprowadzenia zmian w kodzie. Jednym z ważnych założeń projektowych Qt jest użycie mechanizmu slotów i sygnałów. Wprowadza to pewną dynamikę w komunikacji między obiektami oraz znacznie upraszcza tworzenie interfejsu użytkownika. W dalszej części pracy zostanie omówiony interfejs graficzny oraz aspekty implementacyjne. Następnie zostaną opisane wyniki zastosowania wybranych metod do rozwiązania równania adwekcji (1.12). 3.1. Interfejs użytkownika Oprócz głównego okna, na którym rysowany jest wykres funkcji, do sterowania obliczeniami służą osobne palety. Do zadania warunku początkowego służy paleta Initial Problem (Rys. 3.1a). Można w niej wybrać funkcję (sin, sinc, Gaussa, impuls trójkątny oraz prostokątny) oraz ustawić jej parametry takie jak amplituda i okres. Następnym krokiem jest określenie, w ilu punktach funkcja ma zostać spróbkowana oraz podanie innych 23 parametrów siatki numerycznej. Ponieważ niektóre wielkości są ze sobą powiązane, zmiana jednej z nich powoduje automatyczne dostosowanie innych wartości. (a) Zadanie problemu początkowego. (b) Sterowanie rozwiązaniem. Rysunek 3.1: Palety programu. Paleta Solver (Rys. 3.1b) pozwala na wybranie schematu numerycznego oraz na uruchomienie i zatrzymanie obliczeń. Aby rozpocząć obliczenia od początku, należy najpierw kliknąć w przycisk stop. Możliwe jest też przyspieszenie obliczeń przy użyciu suwaka, przy czym minimalny odstęp pomiędzy kolejnymi krokami wynosi 1 ms. 3.2. Szczegóły implementacyjne Do najważniejszych klas w programie należą: • GraphWidget Ta klasa dziedziczy po klasie QWidget i jest odpowiedzialna za rysowanie wykresu, co jest zrealizowane w metodzie paintEvent. Do tego celu jest wykorzystywany silnik graficzny Qt. • InitialProblem Obiekt tej klasy przechowuje parametry problemu początkowego, które są wykorzystywane do generowania funkcji początkowej oraz do inicjacji obiektów rozwiązujących równanie. • FunctionVector Przechowuje wartości w punktach siatki, które są wykorzystywane do 24 rysowania wykresu i do obliczeń. Może przechowywać k wektorów z wynikami obliczeń z k ostatnich kroków czasowych. • AdvectionSolverThread Jest klasą wątku, który steruje obliczeniami. Po wykonaniu każdego kroku czasowego wysyła on komunikat do obiektu klasy GraphWidget o konieczności odświeżenia wykresu. • ThreadTimer Stanowi realizację licznika czasu (ang. timer ) przy użyciu wątku. Takie rozwiązanie pozwala uniezależnić sterowanie wątkiem obliczeń AdvectionSolverThread od wątku związanego z interfejsem użytkownika. • AdvectionSolver Jest to klasa abstrakcyjna. Dziedziczą po niej inne klasy implementujące konkretny schemat numeryczny. Wszystkie zaimplementowane metody są jednokrokowe z wyjątkiem schematu leap-frog. Przy jego inicjacji została wykorzystana metoda upwind do wykonania obliczeń w pierwszym kroku. Ze względu na symetrię zagadnienia zakłada się dodatnią prędkość u w równaniu adwekcji (1.12). Również aby obserwować zachowanie się rozwiązania w większym przedziale czasu, zostały przyjęte okresowe warunki brzegowe, tzn. wartości z prawej strony wektora (. . . , xn−1 , xn ) są traktowane jako (. . . , x−2 , x−1 ) i wykorzystywane (w zależności od metody) do obliczeń w punktach z lewej strony (x0 ,x1 ,. . . ). Na systemach wieloprocesorowych możemy uzyskać przyspieszenie w naturalny sposób poprzez uruchomienie obliczeń w oddzielnym wątku. W szczególności przedstawione w pracy schematy można w bardzo prosty sposób zaimplementować tak, aby obliczenia były wykonywane w kilku wątkach. Mimo, iż w programie jest użyty tylko jeden wątek do obliczeń, wszystkie metody można z łatwością uogólnić na większą ich liczbę. Przy czym można się sugerować wartością funkcji QThread::idealThreadCount(), której zwracana (zgodnie z dokumentacją) wartość jest związana z liczbą rdzeni w systemie. Alternatywnym rozwiązaniem, które zostało użyte przy implementacji, jest wykorzystanie biblioteki OpenMP. Pozwoliło to w prosty sposób na zrównoleglenie obliczeń bez wprowadzania jednocześnie dodatkowych konstrukcji związanych z zarządzaniem wątkami. Jednym z założeń projektowych było zapobieżenie modyfikacji danych przez wątek liczący podczas rysowania wykresu. Do synchronizacji jest stosowana blokada klasy QMutex. Algorytmy synchronizacyjne (zaimplementowane w klasie 25 FunctionVector ) sprowadzają się do pomijania wektora „odczytywanego” podczas wyboru wektora do zapisu. Pole składowe readVector wskazuje na wektor aktualnie odczytywany, a zmiany tego pola dokonywane są w sekcjach krytycznych. Synchronizacja realizowana jest w czasie jednostkowym. Mimo to moglibyśmy chcieć nie dopuścić do sytuacji, w której wątek liczący czeka na uzyskanie blokady w funkcji updateReadableVector(). Rozważmy następującą realizację synchronizacji dla schematów jednokrokowych: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 double *FunctionVector::getReadersVector(){ // metoda pozwalająca na uzyskanie wektora do odczytu // wywoływana na początku rysowania wykresu if (readVectorDirty) return freeVector; readersVectorLock.lock(); return readVector; } void FunctionVector::finishReading(){ // metoda wywoływana po zakończeniu odczytu przez wątek rysujący readersVectorLock.unlock(); } void FunctionVector::updateReadableVector(){ // metoda wywoływana przez wątek sterujący obliczeniami // w celu ustawienia nowego wektora ’’do odczytu’’ double *swapVector=writeVector; 16 readVectorDirty=false; if (readersVectorLock.tryLock()){ writeVector=readVector; readVector=swapVector; readersVectorLock.unlock(); } else { writeVector=freeVector; freeVector=swapVector; readVectorDirty=true; } 17 18 19 20 21 22 23 24 25 26 27 } Wątek rysujący działa następująco: 1 2 3 functionVector->getReadersVector(); // rysuj functionVector->finishReading(); Wątek obliczeń wykonuje następujące operacje: 26 1 2 3 4 pobierz pobierz wykonaj wywołaj wektor do odczytu bez blokowania wektor do zapisu obliczenia functionVector->finishReading(), aby uaktualnić wskazania na wektory Zmienna readVectorDirty określa, czy wektor wskazywany przez readVector zawiera wyniki obliczeń z ostatniego kroku. Jeśli tak nie jest, to wskazuje na nie zmienna freeVector. Aby wykazać poprawność powyższych algorytmów, wystarczy pokazać, że wektor uzyskany poprzez wywołanie getReadersVector() nie jest modyfikowany przez wątek obliczeń. Istotnie, jeśli został zwrócony freeVector, to powiedzie się uzyskanie blokady w updateReadableVector i nie będzie on modyfikowany. Natomiast jeśli został zwrócony readVector, to readersVectorLock.tryLock() zwróci false i nie będzie on również modyfikowany. Ustawienie readVectorDirty=false przed próbą uzyskania blokady zabezpiecza przed sytuacją, kiedy readVectorDirty=true, tryLock() zwróci false, wątek rysujący zwolni blokadę i wywoła getReadersVector() (otrzymując freeVector ) i dopiero teraz nastąpi wymiana wskaźników writeVector i freeVector. Łatwo się przekonać, że nie może do tego dojść, jeśli zapewnimy, że readVectorDirty=false przed próbą uzyskania blokady. Niestety teraz wątek rysujący może uzyskać nieaktualny wektor do odczytu. Można temu zapobiec stosując np. dodatkowy semafor. Możemy z łatwością uogólnić powyższy algorytm na przypadek metod wielokrokowych. Istotną kwestią konieczną do poprawności powyższego rozumowania jest fakt, że Qt (podobnie jak niektóre inne biblioteki do konstrukcji GUI) wykonuje procedury odświeżające w sposób sekwencyjny w jednym wątku. Dzięki temu bez wprowadzania modyfikacji możemy użyć np. kilku instancji GraphWidget do wyświetlania tego samego wektora. Ważne jest również, że mamy tylko jednego „pisarza” (nie potrzebujemy więcej). Powszechnie spotykanym rozwiązaniem jest użycie licznika czasu zaimplementowanego przy użyciu wątków. Oczywiście ze zbyt dużą liczbą wątków wiążą się dodatkowe koszty związane z zarządzaniem nimi. Klasa QTimer jest jednak związana z pętlą zdarzeń (ang. event loop) i podobnie jak w przypadku wielu klas frameworku Qt nie jest bezpiecznym używanie jej w kilku wątkach. Z tego względu została zaimplementowana klasa ThreadTimer. Steruje ona wątkiem obliczeń klasy AdvectionSolverThread poprzez wykonywanie operacji release() na semaforze. Natomiast wątek liczący po wykonaniu kolejnego etapu wywołuje metodę acquire(). Metoda release() nie jest wykonywana częściej niż co 1 ms. 27 3.3. Symulacje numeryczne Wizualizacja wyników obliczeń pozwala na porównanie zachowania się konkretnych schematów dla specyficznych funkcji początkowych. W przeprowadzonych symulacjach funkcje początkowe były określone na przedziale (0, 10), miały amplitudę równą 2, okres (w przypadku funkcji Gaussa jest to współczynnik skali osi X) tak dobrany, aby widoczne było charakterystyczne zachowanie dla poszczególnych metod. Liczba Couranta wynosiła 0.9, prędkość u = 1, a liczba punktów siatki została ustawiona na 1000. Należy podkreślić, iż już podczas generowania funkcji początkowej pojawiają się błędy związane z dyskretyzacją, arytmetyką komputera i skończoną reprezentacją funkcji. Szara linia na wykresach odpowiada amplitudzie funkcji początkowych. 3.3.1. Schemat skoku żaby Schemat skoku żaby (2.9) dawał stosunkowo dobre wyniki dla funkcji gładkich (Rys. 3.2 (a) i (b)). W przypadku punktów nieróżniczkowalnych (np. dla impulsu trójkątnego) pojawiły się delikatne oscylacje po stronie lewej (Rys. 3.2 (c)). Natomiast w punktach nieciągłości pojawiają się znaczne oscylacje, zmieniające całkowicie kształt funkcji (nie pokazano). (a) (b) (c) Rysunek 3.2: Wyniki symulacji wykonanych za pomocą schematu skoku żaby: dla funkcji Gaussa (a), impulsu trójkątnego (b) i zaburzenia typu zęby piły (c). W przypadku impuls trójkątnego widoczna jest dyfuzja numeryczna prowadząca do obniżenia amplitudy. 3.3.2. Schematy pod wiatr i Laxa-Friedrichsa Schematy pod wiatr (2.6) i Laxa-Friedrichsa (2.10) dawały podobne rezultaty w ekstremach funkcje zostały istotnie rozmyte (Rys. 3.3). 28 (a) (b) Rysunek 3.3: Wyniki symulacji dla schematów Laxa-Friedrichsa (a) i pod wiatr (b) dla impulsu typu zęby piły. 3.3.3. Oscylacje w punktach nieciągłości Zastosowanie metod Beama-Warminga (2.12), Laxa-Wendroffa (2.11) i Fromma prowadzi do powstania oscylacji w punktach nieciągłości (Rys. 3.4 i 3.5). Przy tym schemat Beama-Warminga prowadzi do oscylacji przed nieciągłością, a schematy Laxa-Wendroffa i Fromma generują oscylacje po przeciwnej stronie. Oscylacje te są wynikiem dyspersyjnych błędów numerycznych. Dyspersja numeryczna powoduje, że krótkie fale poruszają się szybciej (wolniej) w przypadku schematu BeamaWarminga (Laxa-Wendroffa i Fromma). (a) Beam-Warming (b) Lax-Wendroff (c) Fromm Rysunek 3.4: Oscylacje w punktach nieciągłości dla impulsu prostokątnego. (a) Beam-Warming (b) Lax-Wendroff Rysunek 3.5: Oscylacje w punktach nieciągłości dla impulsu typu zęby piły. 29 3.3.4. Metody wyższych rzędów Zgodnie z opisem analitycznym przedstawionym w rozdziale 2.9 metody wyższych rzędów są tak skonstruowane, aby nie tworzyły się błędne oscylacje nie mające interpretacji fizycznej (Rys. 3.4 i 3.5). Z rysunków 3.6 i 3.7 wynika, że bardzo dobre rezultaty otrzymamy stosując ogranicznik superbee. Jednak w przypadku tego ogranicznika zauważalne jest „spłaszczenie” funkcji w ekstremach. Dość znaczne wygładzanie występuje przy stosowaniu ogranicznika minmod. (a) minmod (b) superbee (c) van Leer Rysunek 3.6: Działanie wybranych ograniczników zastosowanych dla impulsu prostokątnego. (a) monotonized central (b) minmod (c) smart (d) superbee Rysunek 3.7: Działanie wybranych ograniczników zastosowanych dla impulsu typu zęby piły. Większość przedstawionych ograniczników bardzo dobrze się sprawdza dla gładkich funkcji początkowych. 30 Podsumowanie W tej pracy zostały zaprezentowane dwa główne podejścia do konstruowania metod numerycznych dla równia adwekcji: metoda różnic skończonych oraz metoda objętości skończonych. Omówiliśmy również krótko niezbędne podstawy analityczne. Należy podkreślić, że mimo swojej prostoty równanie adwekcji ma zasadnicze znaczenie dla zagadnień hiperbolicznych. Również wiele technik i spostrzeżeń związanych z wyprowadzeniem schematów numerycznych ma charakter uniwersalny. Ważną częścią pracy jest napisany przez autora pracy program, który pozwala na sprawdzenie przedstawionych zagadnień w praktyce. Z przeprowadzonych obserwacji wynika, że zwykle najlepsze rezultaty przy tworzeniu metody otrzymamy, jeśli uwzględnimy zarówno charakter modelowanego zjawiska jak i konkretny problem, który chcemy rozwiązać. W symulacjach przeprowadzonych w rozdziale 3.3 szczególnie dobrze sprawdził się ogranicznik superbee, również w punktach nieciągłości. 31 Bibliografia [1] D. Kincaid, W. Cheney, Analiza numeryczna, Wydawnictwa Naukowo-Techniczne, Warszawa 2006. [2] J. Ombach, Wykłady z równań różniczkowych wspomagane komputerowo – Maple, Wydawnictwo Uniwersytetu Jagiellońskiego, Kraków 1999. [3] R. J. LeVeque, Finite-Volume Methods for Hiperbolic Problems, Cambridge University Press, Cambridge 2002. [4] R. J. LeVeque, Computational Methods for Astrophysical Fluid Flow, Springer-Verlag, 1998. [5] A. Palczewski, Równania różniczkowe zwyczajne, Wydawnictwa Naukowo-Techniczne, Warszawa 2004. [6] S. Łanowy, F. Przybylak, B. Szlęk, Równania różniczkowe, Wydawnictwo Politechniki Śląskiej, Gliwice 2002. [7] L. C. Evans, Równania różniczkowe cząstkowe, PWN, Warszawa 2008. [8] K. Murawski, Analytical and numerical methods for wave propagation in fluids, World Scientific, 2002. [9] E. F. Toro, Riemann Solvers and Numerical Methods for Fluid Dynamics: A practical Introduction, Springer-Verlag, 1999 [10] V. Misra, W. Gong, D. Towsley, Stochastic Differential Equation Modeling and Analysis of TCP-Windowsize Behavior. [11] http://wazniak.mimuw.edu.pl/index.php?title=Analiza matematyczna 2 [12] Dokumentacja Qt, http://doc.qtsoftware.com/ 32