Для продолжения нажмите любую клавишу

Задача 5.2

Постановка задачи

Функцияu(x), являющаяся решением краевой задачи

описывает стационарное распределение тепла в одномерном стержне, совпадающем с отрезком .

Рассчитать стационарное поле температур на отрезке . Предусмотреть возможность задания произвольных граничных условий. Для проверки работы программы построить и рассчитать тестовый пример.

5.2.11 2.2

 

 

Решение

1. Построим тестовый пример.

 

Выберем в качестве точного решения некоторую непрерывную функцию: u(x)=1-x2. Очевидно, что значение u(a)=u(0)= -1. Это значит, что в тестовом примере ua=1. Аналогично, ub=-3.84.

Построим правую часть тестового примера. Для этого найдем левую часть уравнения при выбранной функции u(x).

g(x) = -u”(x) + q(x)*u(x) = 2 + (2+x)^(1/2)*(1-x2) = 2+(2+x)^(1/2)-(x^2)* *(2+x)^(1/2).

Этому же должна быть равна и правая часть уравнения, составляющая сейчас:

f(x) = (u(x)^2 + u(x)) = 2 – 3*x^2 + x^4.

Ясно, что равенства можно добиться, добавляя в правую часть слагаемое

s(x) = g(x) – f(x) =(2+x)^(1/2) - (x^2)*(2+x)^(1/2) + 3*x^2 - x^4

Таким образом, построен тестовый пример:

-u”+xu = u^2+u + (2+x)^(1/2) - (x^2)*(2+x)^(1/2) + 3*x^2 - x^4 x (0, 2.2),

u(0) = 1,

u(2.3) = -3.84.

 

Решением построенной задачи является функция u(x)=1-x2.

2. Проверим правильность работы программы на тестовом примере.

 

Посчитаем значения функции u(x) в точках 0.575, 1.15, 1.725.

u(0.55) = 1-0.552 = 0.6975,

u(1.1) = 1 - 1.12 = -0.21,

u(1.65) = 1 - 1.652 = -1.7225.

Результаты программы совпадают с вычислениями, значит, программа работает корректно.

 

Введите количество разбиений отрезка [a,b]

Введите точность эпсилон

0.00001

Введите значение в точке а

Введите значение в точке b

-3.84

Ua: 1, Ub: -3.84

Деления отрезка:

0 0.55 1.1 1.65 2.2

Матрица производных:

1 0 0 0 0

-1 2.78555 -1 0 0

0 -1 2.83511 -1 0

0 0 -1 2.88043 -1

0 0 0 0 1

Наддиагональ:

0 -1 -1 -1 0

Поддиагональ:

0 -1 -1 -1 0

Главная диагональ:

1 2.78555 2.83511 2.88043 1

Правая часть:

0 3.06682 1.07594 -3.02901 0

Начальное значение:

1 -1 -1 -1 -3.84

Ответ:

1 0.6975 -0.21 -1.7225 -3.84

Для продолжения нажмите любую клавишу . . .

 

3. Решим данную задачу. Граничные условия зададим такие: u(0) = -1, u(2.2) = -11.

 

Введите количество разбиений отрезка [a,b]

Введите точность эпсилон

0.000001

Введите значение в точке а

-1

Введите значение в точке b

-11

Ua: -1, Ub: -11

Деления отрезка:

0 0.244444 0.488889 0.733333 0.977778 1.22222 1.46667 1.71111 1.95556 2.2

Матрица производных:

1 0 0 0 0 0 0 0 0 0

-1 2.14927 -1 0 0 0 0 0 0 0

0 -1 2.15402 -1 0 0 0 0 0 0

0 0 -1 2.15854 -1 0 0 0 0 0

0 0 0 -1 2.16286 -1 0 0 0 0

0 0 0 0 -1 2.16701 -1 0 0 0

0 0 0 0 0 -1 2.17101 -1 0 0

0 0 0 0 0 0 -1 2.17486 -1 0

0 0 0 0 0 0 0 -1 2.17859 -1

0 0 0 0 0 0 0 0 0 1

Наддиагональ:

0 -1 -1 -1 -1 -1 -1 -1 -1 0

Поддиагональ:

0 -1 -1 -1 -1 -1 -1 -1 -1 0

Главная диагональ:

1 2.14927 2.15402 2.15854 2.16286 2.16701 2.17101 2.17486 2.17859 1

Правая часть:

0 0.0895189 0.0942677 0.0987886 0.103111 0.10726 0.111254 0.11511 -9.88116 0

Начальное значение:

-1 -1 -1 -1 -1 -1 -1 -1 -1 -11

Ответ:

-1 -0.958525 -1.00048 -1.13678 -1.39467 -1.82925 -2.55068 -3.79223 -6.10301 -11

Для продолжения нажмите любую клавишу . . .

 

4. Листинг программы (только существенные части):

 

// Значения, стоящие в матрице производных на главной диагонали

void diagElem(double mas[], double z[], double x[], int N)

{

double a = 0; // левая граница стержня

double b = 2.2; // правая граница стержня

double h = (b - a) / N; // шаг

 

for (int i = 0; i <= N; i++)

{

mas[0] = 1;

if ((i != 0) & (i != N))

mas[i] = (2 + h*h*(sqrt(2 + x[i]))) - h*h*(2 * z[i] + 1);

mas[N] = 1;

}

}

 

 

// Функция (правая часть м.Ньютона)

void F(double mas[], double z[], double x[], int N, double grA, double grB)

{

double a = 0; // левая граница стержня

double b = 2.2; // правая граница стержня

double h = (b - a) / N; // шаг

 

mas[0] = -z[0] + grA;

for (int i = 1; i < N; i++)

{

 

mas[i] = -(-z[i - 1] + 2 * z[i] - z[i + 1] + sqrt(2 + x[i])*z[i] * h*h - h*h*(z[i] * z[i] + z[i]));

}

mas[N] = -z[N] + grB;

}

// Метод прогонки

void solveProgonka(double x[], double a[], double b[], double c[], double d[], int n)

{

double alpha[nmax], betta[nmax];

 

alpha[0] = -c[0] / b[0];

betta[0] = d[0] / b[0];

 

for (int i = 1; i < n; i++)

{

alpha[i] = -c[i] / (b[i] + a[i] * alpha[i - 1]);

betta[i] = (d[i] - a[i] * betta[i - 1]) / (b[i] + a[i] * alpha[i - 1]);

}

 

betta[n] = (d[n] - a[n] * betta[n - 1]) / b[n] + a[n] * alpha[n - 1];

x[n] = betta[n];

 

for (int i = n - 1; i >= 0; i--)

{

x[i] = alpha[i] * x[i + 1] + betta[i];

}

}

 

// Первая норма вектора

double norm1(double x[], int n)

{

double sum;

 

sum = 0.0;

for (int i = 0; i <= n; i++)

sum = sum + abs(x[i]);

return sum;

}

 

// Цикл поиска решения

 

while (norma>eps)

{

// сохраняем старое значение

for (inti = 0; i<= N; i++)

temp[i] = z[i];

 

// изменяем матрицу производных

diagElem(mainDiag, z, setka, N);

 

// изменяем правую часть

F(funcF, z, setka, N, ua, ub);

 

solveProgonka(delta, podDiag, mainDiag, nadDiag, funcF, N);

norma = norm1(delta,N);

 

//обновляем вектор решения

for (inti = 0; i<= N; i++)

{

z[i]=delta[i]+temp[i];

}

 

}