2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу 1, 2  След.
 
 Численное решение волнового уравнения
Сообщение10.08.2015, 23:04 


18/05/14
71
Здравствуйте. Я пытаюсь сделать простую задачу - решить однородное линейное волновое уравнение

$$u_{tt} = v^2 u_{xx}$$,

где $v$ - скорость распространяющейся волны.
В качестве начальных условий я использую

$$u(x, 0) = \sin(x)$$
$$u_t(x, 0) = -v \sin(x) $$
что соответствует волне с профилем $\sin(x-vt)$.

В течение первых двух-трех итераций полученное решение с помощью метода Эйлера (Рунге-Кутты 2го порядка точности) совпадает с аналитическим ($\sin(x-vt)$), но далее происходит резкий "выстрел" - значение решения уходит на отметку около 128. В чем причина - я не могу понять.

Привожу код, написанный на C++.

Код:
//2nd derivative function

    float z2der(int n, int i, int j, float* x, float** zx) {
   float h = x[2] - x[1];
   float zr, zl, zm, zrr, zll;

   zm = -30.0*zx[i][j];
   if (i<n - 1)
      zr = 16.0*zx[i + 1][j];
   else
      zr = 16.0;
   if (i>0)
      zl = 16.0*zx[i - 1][j];
   if (i<n - 2)
      zrr = -zx[i + 2][j];
   if (i>1)
      zll = -zx[i - 2][j];
   
   if (i>1 && i<n-2)
      return (zll + zrr + zl + zr + zm) / (12.0 * h * h);
   if (i == 1)
      return (15 / 4 * zx[i][j] - 77 / 6 * zx[i + 1][j] - 107 / 6 * zx[i + 2][j] - 13 * zx[i + 3][j] - 61 / 12 * zx[i + 4][j]) / (h*h);
   if (i==n-2)
      return (15 / 4 * zx[i][j] - 77 / 6 * zx[i - 1][j] - 107 / 6 * zx[i - 2][j] - 13 * zx[i - 3][j] - 61 / 12 * zx[i - 4][j]) / (h*h);
   if (i == 0 || i == n - 1)
      return 0;
}


//PARAMETERS

    float tmin = 0.0;
   float tmax = 12.0;
   int nt = 37000;
   float dt = (tmax - tmin) / float(nt);
   float *time = new float[nt];
   for (int j = 0; j<nt; j++)
      time[j] = tmin + dt*float(j);

   float xmin = -30.0;
   float xmax = 30.0;
   int nx = 901;
   float *x = new float[nx];
   for (int i = 0; i<nx; i++)
      x[i] = xmin + (xmax - xmin)*float(i) / float(nx);

   float v = -0.1; // velocity

    float** wave = new float*[nx];
   for (int i = 0; i < nx; i++)
      wave[i] = new float[nt];

   float** waved = new float*[nx];
   for (int i = 0; i < nx; i++)
      waved[i] = new float[nt];

   for (int i = 0; i<nx; i++) {
      xx = x[i];
      wave[i][0] = sin(xx);
      waved[i][0] = -v*v*sin(xx);
   }

   float* wavedd = new float[nx];
   float* waveddot = new float[nx];

   for (int i = 0; i<nx; i++) { //j=0;
      wavedd[i] = z2der(nx, i, 0, x, wave);
      waveddot[i] = v*v*wavedd[i];
   }

   for (int j = 0; j<nt - 1; j++) {
      for (int i = 0; i<nx; i++) {
         waved[i][j + 1] = waved[i][j] + dt * waveddot[i];
         wave[i][j + 1] = wave[i][j] + dt * waved[i][j];

         wavedd[i] = z2der(nx, i, j + 1, x, wave);
         waveddot[i] = v*v*wavedd[i];
      }
   }

 Профиль  
                  
 
 Re: Численное решение волнового уравнения
Сообщение10.08.2015, 23:27 
Заслуженный участник


09/05/12
25179
Ну, помимо того, что код в целом ужасен... Как Вы думаете, чему равно, например, 15 / 4 * zx[i][j]?

(Ответ)

А вот и не угадали, 3 * zx[i][j]. :D

 Профиль  
                  
 
 Re: Численное решение волнового уравнения
Сообщение11.08.2015, 03:01 
Заслуженный участник
Аватара пользователя


31/01/14
11053
Hogtown
Кстати, явная схема для волнового уравнения условно устойчива

 Профиль  
                  
 
 Re: Численное решение волнового уравнения
Сообщение11.08.2015, 06:26 
Аватара пользователя


31/10/08
1244
Red_Herring
Red_Herring в сообщении #1044247 писал(а):
Кстати, явная схема для волнового уравнения условно устойчива

Что вы имеете в виду? Просто я не знаю не одного признака устойчивости который бы зависел от схемы. Вернее знаю одну особенность, но она относится к неявным схемам.


PS. На самом деле у меня тоже затык с численным решением. Но пока ещё сам по разбираюсь.

 Профиль  
                  
 
 Re: Численное решение волнового уравнения
Сообщение11.08.2015, 06:45 
Заслуженный участник
Аватара пользователя


31/01/14
11053
Hogtown
Pavia в сообщении #1044344 писал(а):
Что вы имеете в виду?

Ну то что если шаги по времени и пространству $\tau,h$ то при $v\tau >h$ устойчивость в явной (естественной) схеме теряется.

 Профиль  
                  
 
 Re: Численное решение волнового уравнения
Сообщение11.08.2015, 09:05 
Аватара пользователя


31/10/08
1244
Red_Herring
Обычно даётся условие устойчивости в общем виде. И оно работает для любой разностной схемы (явной, не явной).
$\frac{v^2\tau^2}{h^2} <1$
Если у нас явная схема, то $h>0$, $\tau>0$, но упростить всё равно не получится из-за скорости. Хотя если её взять по модулю, то можно.

Red_Herring в сообщении #1044247 писал(а):
Кстати, явная схема для волнового уравнения условно устойчива

У автора в коде есть следующие параметры.
Код:
   float tmin = 0.0;
   float tmax = 12.0;
   int nt = 37000;
   float dt = (tmax - tmin) / float(nt);

Код:
   float xmin = -30.0;
   float xmax = 30.0;
   int nx = 901;

Код:
float v = -0.1; // velocity


Откуда имеем, данные:
$\tau=3,24 \cdot 10^{-4}$
$h=0,066$
$v=-0.1$

$\frac{0.01 \cdot 1,049 \cdot 10^{-7}}{0.0044}=2.385 \cdot 10^{-8}<1$
Условие верно.

 Профиль  
                  
 
 Re: Численное решение волнового уравнения
Сообщение11.08.2015, 10:19 


18/05/14
71
Pphantom в сообщении #1044137 писал(а):
Ну, помимо того, что код в целом ужасен... Как Вы думаете, чему равно, например, 15 / 4 * zx[i][j]?

(Ответ)

А вот и не угадали, 3 * zx[i][j]. :D

Данная ошибка у меня сделана только в определении производной на границе. Сейчас я ее исправил, но все равно результат аналогичный - на третьей итерации решение "взлетает".

P.S. В чем ужасность кода?

 Профиль  
                  
 
 Re: Численное решение волнового уравнения
Сообщение11.08.2015, 12:45 
Аватара пользователя


31/10/08
1244
lv00 в сообщении #1044362 писал(а):
P.S. В чем ужасность кода?

Ваш код понять стороннему человеку просто невозможно.
Разве из вашего кода можно понять вы используете метод Эйлера или метод Рунге-Кутты?
Много к чему можно придраться
1) Функций мало.
2) Комментариев мало.
3) Имена переменных непонятны.
4) Большинство констант не понятно откуда взялись.
Код:
zm = -30.0*zx[i][j];
Откуда тут -30?


Код:
  zm = -30.0*zx[i][j];
   if (i<n - 1)
      zr = 16.0*zx[i + 1][j]; // ';' - лишняя
   else
      zr = 16.0;


Много if в первой функции. За ними теряется суть. Их надо вынести из цикла.
Что-бы не писать много if для обработки границ,
надо просто увеличив массив с каждой стороны. И заполнить приближенными значениями, к примеру просто продублировать крайние значения.

 Профиль  
                  
 
 Re: Численное решение волнового уравнения
Сообщение11.08.2015, 13:50 
Заслуженный участник


09/05/12
25179
Red_Herring в сообщении #1044346 писал(а):
Ну то что если шаги по времени и пространству $\tau,h$ то при $v\tau >h$ устойчивость в явной (естественной) схеме теряется.
Тут есть конкретные параметры, для них это условие выполняется. Для распада на 2-3 шаге это не причина.

Больше похоже на проявление немонотонности, но ввиду жуткого и при этом неполного кода это и глазами проверить трудно, и запустить и посмотреть нельзя.

lv00 в сообщении #1044362 писал(а):
P.S. В чем ужасность кода?
Из него совершенно непонятно, что и как Вы делаете. Комментариев нет, расшифровки названий переменных нет, везде напиханы "магические константы"...

 Профиль  
                  
 
 Re: Численное решение волнового уравнения
Сообщение11.08.2015, 15:18 
Заслуженный участник


27/04/09
28128
Pavia в сообщении #1044397 писал(а):
// ';' - лишняя
Ничего не лишняя. Она входит в оператор выражение ; и не входит в оператор if ( выражение ) оператор else оператор.

 Профиль  
                  
 
 Re: Численное решение волнового уравнения
Сообщение11.08.2015, 15:23 
Аватара пользователя


28/01/12
467
lv00 в сообщении #1044362 писал(а):
на третьей итерации решение "взлетает".

Я тут быстро поправил огрехи и скомпилировал ваш код, получил данные
для первых 5 итераций:
Код:
i=0; sinus(-30)=0.988032; -v*v*sin(xx)=-0.00988032
i=1; sinus(-29.9334)=0.996106; -v*v*sin(xx)=-0.00996106
i=2; sinus(-29.8668)=0.999765; -v*v*sin(xx)=-0.00999765
i=3; sinus(-29.8002)=0.998992; -v*v*sin(xx)=-0.00998992
i=4; sinus(-29.7336)=0.99379; -v*v*sin(xx)=-0.0099379
i=5; sinus(-29.667)=0.984183; -v*v*sin(xx)=-0.00984183

i=0; wavedd[0] = 0
i=1; wavedd[1] = -10110.2
i=2; wavedd[2] = -0.999792
i=3; wavedd[3] = -0.999039
i=4; wavedd[4] = -0.993842
i=5; wavedd[5] = -0.984128

i=0, j=0; waveddot[0] = 0
i=1, j=0; waveddot[1] = 8.42366
i=2, j=0; waveddot[2] = -2.827
i=3, j=0; waveddot[3] = -2.81316
i=4, j=0; waveddot[4] = -2.78684
i=5, j=0; waveddot[5] = -2.74817
i=0, j=1; waveddot[0] = 0
i=1, j=1; waveddot[1] = 8.42355
i=2, j=1; waveddot[2] = -2.82702
i=3, j=1; waveddot[3] = -2.81314
i=4, j=1; waveddot[4] = -2.78683
i=5, j=1; waveddot[5] = -2.74817
i=0, j=2; waveddot[0] = 0
i=1, j=2; waveddot[1] = 8.42344
i=2, j=2; waveddot[2] = -2.82704
i=3, j=2; waveddot[3] = -2.81313
i=4, j=2; waveddot[4] = -2.78682
i=5, j=2; waveddot[5] = -2.74816
i=0, j=3; waveddot[0] = 0
i=1, j=3; waveddot[1] = 8.42333
i=2, j=3; waveddot[2] = -2.82705
i=3, j=3; waveddot[3] = -2.81312
i=4, j=3; waveddot[4] = -2.78681
i=5, j=3; waveddot[5] = -2.74815
Скажите о каких взлетах вы говорите?

 Профиль  
                  
 
 Re: Численное решение волнового уравнения
Сообщение11.08.2015, 23:16 


18/05/14
71
Привожу исправленный код. If-ы не изменял, добавил комментарии под переменные. Константы - такие как 30.0, 16.0 и пр. - это коэффициенты для аппроксимации второй производной конечной разностью 4го порядка точности.

Код:

    float 2der(int n, int i, int j, float* x, float** func) { //Second Der. of func
   float h = x[2] - x[1];
   float zr, zl, zm, zrr, zll;

   zm = -30.0*func[i][j];
   if (i<n - 1)
      zr = 16.0*func[i + 1][j];
   if (i>0)
      zl = 16.0*func[i - 1][j];
   if (i<n - 2)
      zrr = -func[i + 2][j];
   if (i>1)
      zll = -func[i - 2][j];
   
   if (i>1 && i<n-2)
      return (zll + zrr + zl + zr + zm) / (12.0 * h * h);
   if (i == 1)
      return (15.0 / 4.0 * func[i][j] - 77.0 / 6.0 * func[i + 1][j] - 107.0 / 6.0 * func[i + 2][j] - 13.0 * func[i + 3][j] - 61.0 / 12.0 * func[i + 4][j]) / (h*h);
   if (i==n-2)
      return (15.0 / 4.0 * func[i][j] - 77.0 / 6.0 * func[i - 1][j] - 107.0 / 6.0 * func[i - 2][j] - 13.0 * func[i - 3][j] - 61.0 / 12.0 * func[i - 4][j]) / (h*h);
   if (i == 0 || i == n - 1)
      return 0;
}


//PARAMETERS

    float tmin = 0.0;
   float tmax = 12.0;
   int nt = 37000; //number of points for time
   float dt = (tmax - tmin) / float(nt);
   float *time = new float[nt];
   for (int j = 0; j<nt; j++)
      time[j] = tmin + dt*float(j);

   float xmin = -30.0;
   float xmax = 30.0;
   int nx = 901; //number of points for x-coordinate
   float *x = new float[nx];
   for (int i = 0; i<nx; i++)
      x[i] = xmin + (xmax - xmin)*float(i) / float(nx);

   float v = -0.1; // velocity of wave

//SOLUTION

    float** wave = new float*[nx]; //array of solution
   for (int i = 0; i < nx; i++)
      wave[i] = new float[nt];

   float** waved = new float*[nx]; //array of 1st derivative of solution
   for (int i = 0; i < nx; i++)
      waved[i] = new float[nt];

   for (int i = 0; i<nx; i++) { //initial conditions
      xx = x[i];
      wave[i][0] = sin(xx);
      waved[i][0] = -v*v*sin(xx);
   }

   float* wavedd = new float[nx]; //auxiliary variables
   float* waveddot = new float[nx];

   for (int i = 0; i<nx; i++) { //j=0;
      wavedd[i] = 2der(nx, i, 0, x, wave);
      waveddot[i] = v*v*wavedd[i];
   }

   for (int j = 0; j<nt - 1; j++) { // Euler method solution
      for (int i = 0; i<nx; i++) {
         waved[i][j + 1] = waved[i][j] + dt * waveddot[i];
         wave[i][j + 1] = wave[i][j] + dt * waved[i][j];

         wavedd[i] = 2der(nx, i, j + 1, x, wave);
         waveddot[i] = v*v*wavedd[i];
      }
   }


Pavia в сообщении #1044397 писал(а):
lv00 в сообщении #1044362 писал(а):
P.S. В чем ужасность кода?

Откуда тут -30?


-30 тут, т.к. это коэффициент для разностной схемы, аппроксимирующий вторую производную. Там должно быть -$5/2$, как раз $-30/12 = -5/2$.

NT2000 в сообщении #1044455 писал(а):
lv00 в сообщении #1044362 писал(а):
на третьей итерации решение "взлетает".

Скажите о каких взлетах вы говорите?

Вы написали итерации по координате (соответствует i). Я же говорю про итерации по времени (как раз работа алгоритма численного решения Рунге-Кутты), они соответствуют j.

 Профиль  
                  
 
 Re: Численное решение волнового уравнения
Сообщение12.08.2015, 08:39 
Аватара пользователя


31/10/08
1244
lv00 в сообщении #1044677 писал(а):
if (i == 1)
return (15.0 / 4.0 * func[i][j] - 77.0 / 6.0 * func[i + 1][j] - 107.0 / 6.0 * func[i + 2][j] - 13.0 * func[i + 3][j] - 61.0 / 12.0 * func[i + 4][j]) / (h*h);
if (i==n-2)
return (15.0 / 4.0 * func[i][j] - 77.0 / 6.0 * func[i - 1][j] - 107.0 / 6.0 * func[i - 2][j] - 13.0 * func[i - 3][j] - 61.0 / 12.0 * func[i - 4][j]) / (h*h);


Вот тут ошибка. Если проверить по норме.
$5.0 / 4.0 * 1 - 77.0 / 6.0 * 1 - 107.0 / 6.0 * 1 - 13.0 * 1 - 61.0 / 12.0 *1=-47,5$
А должен быть 0.

Цитата:
if (i == 0 || i == n - 1)
return 0;

Не лучшее решение.

 Профиль  
                  
 
 Re: Численное решение волнового уравнения
Сообщение12.08.2015, 11:17 


18/05/14
71
Pavia в сообщении #1044750 писал(а):
lv00 в сообщении #1044677 писал(а):
if (i == 1)
return (15.0 / 4.0 * func[i][j] - 77.0 / 6.0 * func[i + 1][j] - 107.0 / 6.0 * func[i + 2][j] - 13.0 * func[i + 3][j] - 61.0 / 12.0 * func[i + 4][j]) / (h*h);
if (i==n-2)
return (15.0 / 4.0 * func[i][j] - 77.0 / 6.0 * func[i - 1][j] - 107.0 / 6.0 * func[i - 2][j] - 13.0 * func[i - 3][j] - 61.0 / 12.0 * func[i - 4][j]) / (h*h);

Вот тут ошибка. Если проверить по норме.
$5.0 / 4.0 * 1 - 77.0 / 6.0 * 1 - 107.0 / 6.0 * 1 - 13.0 * 1 - 61.0 / 12.0 *1=-47,5$
А должен быть 0.

Я поправил. Правильные коэффициенты: $15.0/4.0, -77.0/6.0, 107.0/6.0, -13.0, 61.0/12.0, -5.0/6.0$
Цитата:
Цитата:
if (i == 0 || i == n - 1)
return 0;

Не лучшее решение.

Почему?

После исправления все равно наблюдаются "взлеты". Привожу данные.
Код:
i=0: wave[0][0] = 0.988032, wave[0][1] = 0.988028, wave[0][2] = 0.988025, wave[0][3] = 0.988022
i=1: wave[1][0] = 0.996106, wave[1][1] = 0.996103, wave[1][2] = 0.9961, wave[1][3] = 384.915
i=2: wave[2][0] = 0.999765, wave[2][1] = 0.999762, wave[2][2] = 0.999758, wave[2][3] = -126.973
i=3: wave[3][0] = 0.998992, wave[3][1] = 0.998989, wave[3][2] = 0.998985, wave[3][3] = -126.974

и так далее.

 Профиль  
                  
 
 Re: Численное решение волнового уравнения
Сообщение12.08.2015, 14:40 


18/05/14
71
UPD: заметил еще опечатку в начальном условии для производной по времени - должно быть $v \cos(xx)$, а не $-v^2 \sin(xx)$, но это не влияет на ситуацию - ровно такой же рост в том же месте.

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 28 ]  На страницу 1, 2  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group