Основной поток для численного решения дифференциальных уравнений:

  1. Найти дифференциальные уравнения для решения
  2. Применение аппроксимации, такой как метод центрированных разностей
  3. Установить граничные условия
  4. Решите систему линейных уравнений (Матричная задача)

Меня очень увлек численный метод. Когда я впервые узнал об этом, было не так просто понять, как это работает. Я надеюсь, что эта статья разрушит барьер численного метода дифференциальных уравнений, пока я улучшаю свои навыки JavaScript.

Я также написал статью, делая то же самое, но в двух измерениях.

Вот дифференциальное уравнение 2-го порядка

Общая форма дифференциального уравнения 2-го порядка:

Теперь есть способ сделать это уравнение в приближенной форме. Метод центрированных разностей - это один, и в точке xₙ метод дает следующую форму:

Пожалуйста, смотрите ссылки в конце моего поста для более подробной информации!

Основная идея состоит в том, чтобы использовать разложение в ряд Тейлора для аппроксимации уравнения, в данном случае до второго порядка. Я всегда скептически относился к использованию аппроксимации, но обнаружил, что аппроксимация весьма хороша.

Уравнение Лапласа

Теперь это общая форма. Давайте сделаем это проще! Простейшая форма уравнения называется уравнением Лапласа, где p(x), q(x) и r(x) равны 0. Таким образом, оно будет выглядеть

мы будем игнорировать большой член O, откуда исходит приближение, поэтому правая часть равна 0. Для уравнения Лапласа это можно еще упростить до

Уравнение Пуассона

Для уравнения Пуассона r(x) постоянно. Таким образом, умножение rΔx² дает

Разница между ними только с правой стороны.

Начнем с уравнения Лапласа в одном измерении, потому что оно самое простое из простейших, а затем с уравнения Пуассона в одном измерении.

Строительная матрица — уравнение Лапласа 1D

Установить граничное условие

Поскольку это дифференциальные уравнения 2-го порядка, существует множество решений, если не установлены граничные условия. Существуют типы граничных условий, такие как граничные условия Дирихле и Неймана. Рассмотрим граничное условие Дирихле, так как оно проще. Позволять

что означает, что в точке сетки 0 для u устанавливается значение a, а в точке сетки n для u устанавливается значение b.

Построить матрицу

следовательно, начиная с u₀ = a, применяя приведенное выше уравнение, необходимо решить n + 1 уравнение. Представьте, что есть точки сетки слева направо, начиная с точки 0 и заканчивая n. В точке 0 получается u₀=a, в точке 1 получаем u₀–2u₁+u₂=0 и так далее. Следовательно

Это можно записать в матричной форме,

Или просто напишите в Матричной форме

Эта форма распространена и есть способы решения. Все, что мне нужно, это построить матрицу A и вектор b. В math.js есть отличная функция под названием lusolve, которая решит линейную систему.

Для одномерного случая я использовал lusolve, потому что его легко реализовать. В качестве альтернативы для решения линейной системы можно использовать численные методы, такие как метод Гаусса-Зейделя, который я использовал для двумерного случая.

Прежде чем начать, начало работы с JavaScript

HTML-файл должен выглядеть так, как показано ниже.

<!DOCTYPE HTML>
<html>
<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/5.0.0/math.min.js"></script>
  <script src="https://cdn.plot.ly/plotly-2.0.0.min.js"></script>
</head>
<body>
  <div id="myDiv" style="width:603px; height:500px"></div>
  <script src="scratch.js"></script>
</body>
</html>

Я использую две библиотеки: Math.js для решения матриц и Plotly.js для построения графиков. Внутри тега body был подготовлен тег div с идентификатором «myDiv», чтобы Plotly мог рисовать. Мы будем писать основной код в файлеcratch.js.

Кодирование

Рассмотрим такие условия, что:

  • n = 10 (так что точка сетки от 0 до 10)
  • u(x0 = 0) = b0 = 0
  • u(xn = 10) = bn = 10

Следовательно,

let n= 10;
let x0 = 0;
let xn = 10;
let b0 = 0;
let bn = 10;

Значения x каждого узла можно найти по номеру узла и Δx или dx.

let dx = (xn - x0) / n;
let x = new Array(n + 1);
for (i = 0; i < x.length; i++) { x[i] = x0 + i * dx };

Функция lusolve требует параметров A и b, где A — матрица [n x n], а b — вектор-столбец [n]. Затем нужно решить 11 уравнений (от n = 0 до n = 10, как объяснялось выше). Матрица A и вектор b могут быть созданы как таковые

let A = [];
A.push(new Array(n + 1).fill(0));
A[0][0] = 1;
for (i = 1; i < n; i++) {
  A.push(new Array(n + 1).fill(0));
  A[i][i - 1] = 1;
  A[i][i] = -2;
  A[i][i + 1] = 1;
}
A.push(new Array(n + 1).fill(0));
A[n][n] = 1; 
let b = new Array(n + 1).fill(0);
b[0] = b0;
b[b.length - 1] = bn;

В этот момент, если вы откроете index.html из проводника (в Windows), браузер запустит скрипт и должен вывести белый экран. Ctrl+Shift+I откроет инструмент разработчика для браузера Chrome, на вкладке консоли введите console.log(A) и console.log(b). Он покажет содержимое массивов.

console.log(A)
(11) [Array(11), Array(11), Array(11), Array(11), Array(11), Array(11), Array(11), Array(11), Array(11), Array(11), Array(11)]
0: (11) [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
1: (11) [1, -2, 1, 0, 0, 0, 0, 0, 0, 0, 0]
2: (11) [0, 1, -2, 1, 0, 0, 0, 0, 0, 0, 0]
3: (11) [0, 0, 1, -2, 1, 0, 0, 0, 0, 0, 0]
4: (11) [0, 0, 0, 1, -2, 1, 0, 0, 0, 0, 0]
5: (11) [0, 0, 0, 0, 1, -2, 1, 0, 0, 0, 0]
6: (11) [0, 0, 0, 0, 0, 1, -2, 1, 0, 0, 0]
7: (11) [0, 0, 0, 0, 0, 0, 1, -2, 1, 0, 0]
8: (11) [0, 0, 0, 0, 0, 0, 0, 1, -2, 1, 0]
9: (11) [0, 0, 0, 0, 0, 0, 0, 0, 1, -2, 1]
10: (11) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
length: 11
__proto__: Array(0)
console.log(b)
(11) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10] 

Это выглядит хорошо. Матрица A и вектор b созданы по назначению. Используйте lusolve, чтобы получить решение u

let u = math.lusolve(A, b);

Давайте визуализируем решение. Я обнаружил, что plotly.js — хорошая библиотека для построения графиков. Теперь для построения нам нужно создать объект

let trace_u = { x: [], y: [] }

затем добавьте значения x к x, решение u к массиву y. Единственное, решение u дано в виде массива размера 1 в массиве размера n. Так,

for (let i = 0; i < n+1; i++) {
  trace_u.x.push(x[i]);  
  trace_u.y.push(u[i][0]);
}

для построения, указывая на объект div с id=’myDiv’ и только что созданный массив trace_u,

Plotly.newPlot('myDiv', [trace_u])

Это даст прямую линию, проходящую через координаты (0, 0) и (10, 10). Уравнение Лапласа в 1D, как и ожидалось, представляет собой прямую линию.

Уравнение Пуассона в 1D

Оказалось, что кодирование части уравнения Пуассона довольно простое. Но прежде чем начать, давайте посмотрим на разницу.

Установите граничное условие и постройте матрицу

Зададим граничное условие как

Учитывая граничное условие и применяя уравнение, необходимо решить n + 1 уравнение

можно записать систему уравнений в матричной форме,

Давайте реализуем это в коде.

Кодирование

Рассмотрим такие условия, что:

  • n = 18
  • r = 2
  • u(x = 0) = b0 =4
  • u(x = 4) = bn = 4

Слегка измените код из уравнения Лапласа

let n= 18;
let r = 2;
let x0 = 0;
let xn = 4;
let b0 = 4;
let bn = 4;

Теперь помните, что для уравнения Лапласа массив b был заполнен 0. Вместо этого заполните rΔx²

let b = new Array(n + 1).fill(r * dx ** 2);

Это оно. Нарисуй и увидишь

Аналитическое решение уравнения Пуассона:

где C1​ и C2​ являются постоянными. Поскольку r = 2 и применяя граничное условие, вы будете иметь

Параболическая кривая, минимум 0 при x=2, и она удовлетворяет граничному условию.

использованная литература