AdamátorZápiskyHlášky

Cvičení z Numerické matematiky 2

  1. Metoda konečných diferencí
    1. Cauchyho úloha a Rungovy-Kuttovy metody
      1. Rungova-Kuttova metoda pro n=1
        1. Rungova-Kuttova metoda pro n=2
          1. Cauchyho úloha vyššího řádu
          2. Objektově orientované programování
            1. Řešení okrajových úloh

              Materiály

              Metoda konečných diferencí

              Oberhuberova prezentace

              Definice Nechť x0∈ℝ, Hx0 je jeho okolí a f,g:Hx0→ℝ. f aproximuje g s přesností řádu r∈ℕ, pokud existuje C∈ℝ+ takové, že
              limx→x0|f(x)−g(x)||x−x0|r=C
              Definice Nechť x0∈ℝ, Hx0 je jeho okolí, f:Hx0→ℝ, h∈ℝ+ a l1,l2∈ℕ. Potom budeme značit
              Věta Nechť f∈𝒞2((x0,x1)). Potom
              f1−f0h=f′(x0)+𝒪(h)
              Věta Nechť f∈𝒞2((x−1,x0)). Potom
              f0−f−1h=f′(x0)+𝒪(h)
              Věta Nechť f∈𝒞2((x−1,x1)). Potom
              f1−f−12h=f′(x0)+𝒪(h)
              Věta Nechť f∈𝒞3((x−1,x1)). Potom
              f1−f−12h=f′(x0)+𝒪(h2)
              Věta Nechť f∈𝒞4((x−1,x1)). Potom
              f1−2f0+f−1h2=f″(x0)+𝒪(h2)
              Věta Nechť f∈𝒞n+1((x−l1,xl2)). Potom pro každé k∈n^ lze k-tou derivaci aproximovat pomocí konečných diferencí s přesností řádu n+1−k.

              Cauchyho úloha a Rungovy-Kuttovy metody

              Oberhuberova prezentace

              Mějme obyčejnou diferenciální rovnici s počáteční podmínkou:

              x′(t)=f(t,x(t)),t∈(0,T)
              x(0)=x0

              Zkusíme ji vyřešit „simulací“ s diskrétními časovými intervaly. Zvolíme si časový krok τ, tedy budeme mít N≔Tτ kroků. Budeme počítat:

              xi+1≔xi+Δx(iτ,τ)

              Otázkou je, jak zvolit vhodné Δx. Chtěli bychom, aby platilo:

              Δx(t,τ)=x(t+τ)−x(t)=Taylorτx′(t)+τ22x″(t)+⋯

              První derivaci si můžeme spočítat přímo ze zadání. S druhou už to bude horší:

              x″(t)=∂1f(t,x(t))+∂2f(t,x(t))⋅x′(t)=∂1f(t,x(t))+∂2f(t,x(t))⋅f(t,x(t))

              K tomu už potřebujeme znát derivace f. A s dalšími derivacemi by to bylo ještě horší. Pokud se vykašleme na všechny derivace kromě první, dostaneme známou Eulerovu metodu. Ale tento postup je obecně dost numericky nestabilní. Radši použijeme Rungovu-Kuttovu metodu. Ta funguje tak, že přírůstky budeme hledat ve tvaru:

              Δx(t,τ)=∑i=1npiki(t,τ)
              k1(t,τ)≔τf(t,x(t))
              ki(t,τ)≔τf(t+αiτ,x(t)+∑j=1i−1βi,jkj(t,τ)),i>1

              Teď je samozřejmě otázkou, jak vhodně zvolit koeficienty pi,ai,βi,j. Obecně je chceme zvolit tak, aby se přírůstek shodoval s Taylorem do co nejvyššího stupně. Detaily viz prezentace.

              Rungova-Kuttova metoda pro n=1

              Δx(t,τ)=p1k1(t,τ)=p1τf(t,x(t))
              φ1(τ)=x(t+τ)−x(t)−p1τf(t,x(t))=τx′(t)+τ22x″(s)−p1τf(t,x(t))=(1−p1)τf(t,x(t))+τ22x″(s)
              φ1′(τ)=(1−p1)f(t,x(t))+τx″(s)
              φ1′(0)=(1−p1)f(t,x(t))=0⟹p1=1
              Δx(t,τ)=τf(t,x(t))

              Tím jsme opět dostali známou Eulerovu metodu.

              Rungova-Kuttova metoda pro n=2

              Δx(t,τ)=p1k1(t,τ)+p2k2(t,τ)=p1τf(t,x(t))+p2τf(t+α2τ,x(t)+β2,1k1(t,τ))
              φ2(τ)=τx′(τ)+τ22x″(t)+(τ36x‴(s))⏟z−p1τf(t,x(t))−p2τf(t,x(t)+β2,1k1(t,τ))=τf(t,x(t))+τ22(∂tf(t,x(t))+∂xf(t,x(t))f(t,x(t)))+z−p1τf(r,x(t))−p2τf(t,x(t)+β2,1τf(t,x(t)))
              φ2′(τ)=f(t,x(t)) + τ(∂tf(t,x(t))+∂xf(t,x(t))f(t,x(t))) − p1f(t,x(t)) − p2f(t,x(t)+β2,1τf(t,x(t))) − p2τ(∂tf(⋯)α2+∂xf(⋯)β2,1f(t,x(t)))
              φ2″(τ)=∂τf(t,x(t))+∂xf(t,x(t))f(t,x(t))−2p2(∂tf(⋯)α2+∂xf(⋯)β2,1f(t,x(t)))−p2τ∂t(⋯)
              φ2′(0)=⋯=♡0∴1−p1−p2=0
              φ2″(0)=⋯=♡0∴1−2α2p2=1−2β2,1p2=0
              První možnost:
              p1=p2=12,α2=β2,1=1
              Druhá možnost:
              p1=0,p2=1,α2=β2,1=12
              Vidíme, že pro každý řád se to počítá výrazně pracněji.

              Cauchyho úloha vyššího řádu

              xn(t)=f(t,x(t),…,xn−1t)

              Použijeme substituci, čímž to převedeme na soustavu:

              ui(t)≔xi(t)
              un′(t)=f(t,u0(t),…,un−1(t))
              u(i−1)′(t)=ui(t)

              Musíme znát počáteční podmínky pro každé u, tedy počáteční derivace až do řádu n−1.

              Runge-Kuttovy metody můžeme přepsat do vektorového tvaru:

              Δu→(t,τ)=∑i=1npik→i(t,τ)
              k→i(t,τ)=τF→(t+∑j=2iαjτ,u→(t)+∑j=1i−1βi,jk→j(t,τ))

              Objektově orientované programování

              Oberhuberova prezentace

              Když chceme v C++ vykreslit graf funkce, normální člověk by napsal něco takového:

              void drawFunction(std::function<double(double)> f, double left, double right, double step) {
                for (double x = left; x <= right; x += step) {
                  std::cout << x << " " << f(x) << "\n";
                }
              }
              
              int main() {
                drawFunction([](double x) { return (2 * x + 3) * x + 1; }, 0.0, 1.0, 0.1);
                drawFunction([](double x) { return 2 * sin(5 * x + 1); }, 0.0, 1.0, 0.1);
              }

              Ale Oberhuber radši napíše tohle:

              struct Function
              {
                  virtual double getFx( double x );
              }
              
              struct Quadratic : public Function    // !!!!
              {
                  double a, b, c;
              
                  double getFx ( double x )
                  {
                      return ( a * x + b ) * x + c;
                  }
              }
              
              struct Sinus : public Function    // !!!!
              {
                  double A, f, p;
              
                  double getFx ( double x )
                  {
                      fx = A * sin ( f * x + p );
                  }
              }
              
              void drawFunction( Function * function ,
                                 double left , double right , double step )
              {
                  for ( double x = left ; x <= right ; x += step )
                  {
                      printf( " %f %f \n", x, function−>getFx( x ) );
                  }
              }
              
              int main ( int argc , char * argv[] )
              {
                      /****
                       * Evaluate f (x) = 2 x^2 + 3 x + 1 on <0,1>
                       */
                       Quadratic f1;
                       f1.a = 2.0;
                       f1.b = 3.0;
                       f1.c = 1.0;
                       drawFunction ( &f1, // WE DO NOT NEED TO CARE ABOUT FUNCTION TYPE
                                      0.0, 1.0,     // on interval <0, 1>
                                      0.1,          // we draw it with resolution 0.1
                                                    //    −> 11 points on the interval
                                       );
              
                      /****
                       * Evaluate f(x) = 2 sin( 5 *x + 1 ) on <0,1>
                       */
                       Sinus f2;
                       f2.A = 2.0;
                       f2.f = 5.0;
                       f2.p = 1.0;
                       drawFunction ( &f2, // WE DO NOT NEED TO CARE ABOUT FUNCTION TYPE
                                      0.0, 1.0,     // on interval <0, 1>
                                      0.1,          // we draw it with resolution 0.1
                                                    //    −> 11 points on the interval
                                       );
              
              }

              Řešení okrajových úloh

              Oberhuberova prezentace

              Mame-li úlohu se dvěma stupni volnosti, potřebujeme dvě počáteční podmínky. Místo toho ale často máme zadané okrajové podmínky. Z přednášky známe metodu střelby, ale ta nejde zobecnit do více dimenzí (parciální diferenciální rovnice). Místo toho použijeme metodu sítí: provedeme diskretizaci a vyřešíme soustavu lineárních rovnic. Detaily viz prezentace a přednáška.