1. Неявные методы

Методы численного решения ОДУ, с которыми мы познакомились в первом разделе этого курса (метод Эйлера, метод средней точки и т. п.), называются «явными» методами. Однако иногда система ОДУ может стать «жесткой», а решать такие системы явными методами неудобно. В этом случае желательно изменить формулировку задачи так, что не пришлось иметь дело с жесткой системой. Но это не всегда возможно, поэтому вы должны уметь решать жесткие ОДУ. Для этого, как правило, используют методы решения, которые называются «неявными».

2. Пример жесткого ОДУ

Во-первых, в чем смысл и причина появления жестких уравнений? Давайте рассмотрим пример, который часто возникает в динамике. Предположим, что у нас есть частица, с координатами \((x(t),y(t))\), и предположим, что мы хотим, чтобы ее \(y\)-координата всегда оставалась равной нулю. Один из способов добиться этого — добавить слагаемое \(-ky(t)\), к производной \(\dot{y}(t)\), где \(k\) — большая положительная постоянная. Если \(k\) достаточно велико, то частица никогда не уйдет далеко от \(y(t)=0\), так как слагаемое \(-ky(t)\) всегда приведет \(y(t)\) обратно к нулю. Предположим далее, что мы хотим, чтобы пользователь мог перемещать частицу как угодно вдоль оси \(x\). Дифференциальное уравнение, описывающее движение данной системы, будет иметь вид

\begin{equation} \dot{\textbf{X}}(t) = \frac{d}{d t} \left( \begin{array}{c} x(t) \\ y(t) \end{array} \right) = \left( \begin{array}{c} -x(t) \\ -ky(t) \end{array} \right) . \label{stiff2} \end{equation}

(Кроме того, мы предполагаем, что частица не запускается из \(y_0=0\)). В результате частица будет сильно притягиваться к прямой \(y = 0\), и менее сильно — к \(x = 0\). Если решать ОДУ на достаточно продолжительном интервале времени, то частица рано или поздно попадет в точку \((0, 0)\) и останется в ней.

Теперь предположим, что для решения уравнения мы используем метод Эйлера. Если сделать шаг размера \(h\), то получим

$$ \textbf{X}_{new} = \textbf{X}_0 + h \dot{\textbf{X}}(t_0) = \left( \begin{array}{c} x_0 \\ y_0 \end{array} \right) + h\left( \begin{array}{c} -x_0 \\ -ky_0 \end{array} \right) $$

или

$$ \textbf{X}_{new} = \left( \begin{array}{c} x_0 - h x_0 \\ y_0 - h k y_0 \end{array} \right) = \left( \begin{array}{c} (1-h)x_0 \\ (1-hk)y_0 \end{array} \right) . $$

Если мы посмотрим на \(у\)-компоненту этого уравнения, то увидим, что при \(|1-hk|>1\), вычисленное нами \(y_{new}\) будет по модулю больше, чем \(|у_0|\). Другими словами, при \(|1-hk|>1\) метод Эйлера будет неустойчив: каждый шаг приводит к увеличению \(y_{new}\) по сравнению с предыдущим значением и приближенное решение будут все дальше отклоняться от нуля. Таким образом, для обеспечения устойчивости метода нужно, чтобы \(1-hk>-1\) или \(hk<2\). Самый большой шаг, который мы можем сделать не нарушив устойчивости, должен быть меньше \(2/k\).

Теперь, если \(k\) – большое число, мы вынуждены делать очень маленькие шаги. Это означает, что частица будет двигаться к \((0,0)\) мучительно медленно. Даже если взять \(y_0\) очень близким к нулю, то придется делать настолько маленькие шаги, что изменение \(x\)-координаты будет практически незаметно. Вот так выглядит жесткое ОДУ. В данном случае жесткость возникает из-за слишком большого \(k\), призванного удержать частицу возле прямой \(у = 0\). Позже, когда мы будем рассматривать частицы, соединенные пружинами, мы увидим то же самое явление: от жесткости пружины и происходит термин «жесткое» ОДУ. Даже если мы используем более совершенный численный метод, такой как метод Рунге-Кутта 4-го порядка, это лишь слегка улучшит ситуацию с выбором величины шага, но мы все равно будем иметь серьезные вычислительные проблемы.

Теперь, как мы уже говорили выше, нужно попытаться переформулировать свою задачу так, чтобы избежать появления жесткого ОДУ. Если же это не получится, то нужно использовать неявный метод решения ОДУ. Метод, который мы покажем ниже, является самым простым из неявных методов. Он основан на том, что шаг обычного метода Эйлера выполняется «наоборот».

3. Решение жесткого ОДУ

Пусть дано дифференциальное уравнение

$$ \frac{d}{dt}\textbf{X}(t) = f(\textbf{X}(t)). $$

Формула явного метода Эйлера

$$ \textbf{X}_{new} = \textbf{X}_0 + h f(\textbf{X}(t_0)) $$

продвигает систему вперед на шаг \(h\) во времени. Для жестких систем, однако, удобнее заменить эту формулу на следующую

\begin{equation} \textbf{X}_{new} = \textbf{X}_0 + h f(\textbf{X}(t_{new})). \label{backward} \end{equation}

То есть, нам нужно вычислить \(f\) в точке, в которую мы стремимся попасть (\(\textbf{X}_{new}\)), а не в исходной (\(\textbf{X}_0\)). (Если представить, что время может двигаться в обратном направление, то смысл этого уравнения очевиден. Оно говорит: «если вы находитесь в \(\textbf{X}_{new}\), и сделаете шаг \(-hf (\textbf{X}_{new})\), то попадете в \(\textbf{X}_0\)». Так что если ваше ДУ представляет собой систему, движущуюся вспять во времени, то этот шаг имеет смысл. Это просто поиск точки \(\textbf{X}_{new}\) такой, что если запустить время вспять, вы в конечном итоге окажетесь в \(\textbf{X}_0\).) Таким образом, мы ищем точку \(\textbf{X}_{new}\) такую, что \(f\), вычисленная в ней и умноженная на \(h\), приводит к исходной точке \(\textbf{X}_0\). К сожалению, найти \(\textbf{X}_{new}\) из уравнения \eqref{backward} в общем случае невозможно, если только \(f\) не является линейной функцией.

Чтобы справиться с этим, заменим \(f (\textbf{X}_{new})\) линейной аппроксимацией, основанной на разложении \(f\) в ряд Тейлора. Введем обозначение \(\Delta\textbf{X}=\textbf{X}_{new}-\textbf{X}_0\). Подставив его в уравнение \eqref{backward}, получим

$$ \textbf{X}_0 + \Delta\textbf{X} = \textbf{X}_0 + hf(\textbf{X}_0 + \Delta\textbf{X}) $$

или просто

$$ \Delta\textbf{X} = hf(\textbf{X}_0 + \Delta\textbf{X}). $$

Теперь заменим \(f(\textbf{X}_0 + \Delta\textbf{X})\) следующим приближением

$$ f(\textbf{X}_0) + f^{\prime}(\textbf{X}_0)\Delta\textbf{X}. $$

(Заметим, что поскольку \(f(\textbf{X}_0)\) является вектором, то производная \(f^\prime(\textbf{X}_0)\) является матрицей.) Используя это приближение, мы можем записать \(\Delta\textbf{X}\) как

$$ \Delta\textbf{X} = h(f(\textbf{X}_0) + f^{\prime}(\textbf{X}_0)\Delta\textbf{X}) $$

или

$$ \Delta\textbf{X} - hf^{\prime}(\textbf{X}_0)\Delta\textbf{X} = hf(\textbf{X}_0). $$

Разделим обе части последнего соотношения на \(h\) и перепишем результат в виде

$$ \left( \frac{1}{h}\textbf{I} - f^{\prime}(\textbf{X}_0) \right)\Delta\textbf{X} = f(\textbf{X}_0), $$

где \(I\) — единичная матрица.

Разрешая это соотношение относительно \(\Delta\textbf{X}\), получим

\begin{equation} \Delta\textbf{X} = \left( \frac{1}{h}\textbf{I} - f^{\prime}(\textbf{X}_0) \right)^{-1} f(\textbf{X}_0). \label{DeltaX} \end{equation}

Вычисление \(\textbf{X}_{new}=\textbf{X}_0+\Delta\textbf{X}\) для неявного метода очевидно требует больших вычислительных затрат, чем при использовании явного метода, так как мы должны решать систему линейных уравнений на каждом шаге. Хотя это может показаться серьезным недостатком (в вычислительном плане), не отчаивайтесь (пока). Для многих классов задач, матрица \(f^\prime\) будет разреженной — например, для «решетки» частиц, соединенных пружинами, \(f^\prime\) будет иметь структуру, которая соответствует связям между частицами. (Обсуждение разреженности и методов решений, применимых в этом случае, см. Baraff и Witkin [1]. Основной материал в Press et al. [2] также будет полезен.) В результате, как правило, можно решить уравнение \eqref{DeltaX} в линейном времени (т. е. за время, пропорциональное размерности \(\textbf{X}\)). Выигрыш в таких случаях будет весьма существенным: мы, как правило, можем делать большие шаги по времени без потери устойчивости (т. е. без расхождения, как это происходит для явного метода, если длина шага слишком велика). Время, необходимое для решения каждой линейной системы, таким образом, более чем компенсируется тем, шагов можно зачастую сделать на порядки больше, чем при использовании явных методов. (Конечно, код, необходимый для реализации всего этого, гораздо сложнее, чем в явном случае; как мы уже говорили: переделывайте свои задачи в нежесткие, а если не получается, то платите положенную цену.)

Применим теперь неявный метод для решения уравнения \eqref{stiff2}. В нашем случае \(f(\textbf{X}(t))\) равно

$$ f(\textbf{X}(t)) = \left( \begin{array}{c} -x(t) \\ -ky(t) \end{array} \right) . $$

Дифференцирование по \(\textbf{X}\) дает

$$ f^\prime(\textbf{X}(t)) = \frac{\partial}{\partial\textbf{X}} f(\textbf{X}(t)) = \left( \begin{array}{cc} -1 & 0 \\ 0 & -k \end{array} \right) . $$

Тогда матрица \((1/h)\textbf{I} - f^{\prime}(\textbf{X}_0)\) будет равна

$$ \left( \begin{array}{cc} \frac{1}{h}+1 & 0 \\ 0 & \frac{1}{h}+k \\ \end{array} \right) = \left( \begin{array}{cc} \frac{1+h}{h} & 0 \\ 0 & \frac{1+kh}{h} \end{array} \right) . $$

Обращая эту матрицу и умножая на \(f(\textbf{X}_0)\), получим

$$ \Delta\textbf{X} = \left( \begin{array}{cc} \frac{1+h}{h} & 0 \\ 0 & \frac{1+kh}{h} \end{array} \right)^{-1} \left( \begin{array}{c} -x_0 \\ -ky_0 \end{array} \right) = \left( \begin{array}{cc} \frac{h}{1+h} & 0 \\ 0 & \frac{h}{1+kh} \end{array} \right) \left( \begin{array}{c} -x_0 \\ -ky_0 \end{array} \right) = - \left( \begin{array}{c} \frac{h}{1+h}x_0 \\ \frac{h}{1+kh}ky_0 \end{array} \right) . $$

Какова же предельная длина шага в этом случае? Ответ: нет предела! Если позволить \(h\) расти до бесконечности, мы получаем следующее

$$ \lim_{h\to\infty} \Delta\textbf{X} = \lim_{h\to\infty} -\left( \begin{array}{c} \frac{h}{1+h}x_0 \\ \frac{h}{1+kh}ky_0 \end{array} \right) = - \left( \begin{array}{c} x_0 \\ \frac{1}{k}ky_0 \end{array} \right) = - \left( \begin{array}{c} x_0 \\ y_0 \end{array} \right) . $$

Это означает, что мы достигнем \(\textbf{X}_{new}=\textbf{X}_0 + (-\textbf{X}_0)=0\) за один шаг! В общем случае для жесткого ОДУ мы не сможем сделать шаг произвольного размера, но мы сможем сделать его гораздо большим, чем если бы использовали явный метод. Дополнительные расходы на решение системы линейных уравнений компенсируются экономией, возникающий благодаря возможности сделать меньше шагов.

4. Решение уравнений второго порядка

Большинство задач динамики записывается в виде ДУ 2-го порядка

\begin{equation} \ddot{\textbf{x}}(t) = f( \textbf{x}(t), \dot{\textbf{x}}(t) ) . \label{secorder} \end{equation}

Это уравнение легко преобразуется систему ДУ 1-го порядка, добавлением новых переменных. Если мы определим \(\textbf{v}=\dot{\textbf{x}}\), то сможем переписать уравнение \eqref{secorder} в виде

\begin{equation} \frac{d}{dt} \left( \begin{array}{c} \textbf{x}(t) \\ \textbf{v}(t) \end{array} \right) = \left( \begin{array}{c} \textbf{v}(t) \\ f(\textbf{x}(t), \textbf{v}(t)) \end{array} \right) , \label{firstordersys} \end{equation}

что представляет собой систему ДУ 1-го порядка. Однако, применяя обратный (неявный) метод Эйлера к уравнению \eqref{firstordersys}, получим линейную систему размера \(2n \times 2n\) где \(n\) — размерность \(\textbf{x}\). Простое преобразование позволяет уменьшить размер линейной системы до \(n \times n\). Важно отметить, что обе системы — исходная и преобразованная — будут иметь одинаковую степень разреженности. Таким образом, решение системы меньшего размера будет выполняться быстрее.

Система \(n \times n\), которая должна быть решена, получается следующим образом. Введем для краткости следующие обозначения \(\textbf{x}_0=\textbf{x}(t_0)\) и \(\textbf{v}_0=\textbf{v}(t_0)\). Определяем \(\Delta\textbf{x}\) и \(\Delta\textbf{v}\) как \(\Delta\textbf{x} = \textbf{x}(t_0+h)-\textbf{x}(t_0)\) и \(\Delta\textbf{v} = \textbf{v}(t_0+h)-\textbf{v}(t_0)\). Очередное приближение по неявному методу Эйлера, примененному к уравнению \eqref{firstordersys}, дает в результате

\begin{equation} \left( \begin{array}{c} \Delta\textbf{x} \\ \Delta\textbf{v} \end{array} \right) = h \left( \begin{array}{c} \textbf{v}_0 + \Delta\textbf{v} \\ f(\textbf{x}_0 + \Delta\textbf{x}, \textbf{v}_0 + \Delta\textbf{v}) \end{array} \right) . \label{delta} \end{equation}

Применяя к \(f\) разложение в ряд Тейлора, которое в данном контексте является функцией и \(\textbf{x}\) и \(\textbf{v}\), получим приближение 1-го порядка

$$ f(\textbf{x}_0 + \Delta\textbf{x}, \textbf{v}_0 + \Delta\textbf{v}) = f_0 + \frac{\partial f}{\partial\textbf{x}}\Delta\textbf{x} + \frac{\partial f}{\partial\textbf{v}}\Delta\textbf{v} . $$

В этом уравнении, производная \(\partial f / \partial\textbf{x}\) оценивается в точке \((\textbf{x}_0, \textbf{v}_0)\) и аналогично вычисляется \(\partial f / \partial\textbf{v}\). Подставляя это приближение в уравнение \eqref{delta}, получим линейную систему

\begin{equation} \left( \begin{array}{c} \Delta\textbf{x} \\ \Delta\textbf{v} \end{array} \right) = h \left( \begin{array}{c} \textbf{v}_0 + \Delta\textbf{v} \\ f_0 + \frac{\partial f}{\partial\textbf{x}}\Delta\textbf{x} + \frac{\partial f}{\partial\textbf{v}}\Delta\textbf{v} \end{array} \right) . \end{equation}

Подставив во вторую строку последнего равенства соотношение \(\Delta\textbf{x} = h(\textbf{v}_0 + \Delta\textbf{v})\) (т. е. первую строку того же равенства), придем к

$$ \Delta\textbf{v} = h \left( f_0 + \frac{\partial f}{\partial\textbf{x}}h(\textbf{v}_0 + \Delta\textbf{v}) + \frac{\partial f}{\partial\textbf{v}}\Delta\textbf{v} \right) . $$

Вводя единичную матрицу \(I\) и перегруппировав члены, получим соотношение

\begin{equation} \left( \textbf{I} - h \frac{\partial f}{\partial\textbf{v}} - h^2 \frac{\partial f}{\partial\textbf{x}} \right) \Delta\textbf{v} = h\left( f_0 + h\frac{\partial f}{\partial\textbf{x}}\textbf{v}_0 \right) \label{DeltaV} \end{equation}

из которого находим \(\Delta\textbf{v}\). А зная \(\Delta\textbf{v}\) легко вычислить \(\Delta\textbf{x} = h(\textbf{v}_0 + \Delta\textbf{v})\).

Выше, мы предполагали, что функция \(f\) не зависит явно от времени. Если же \(f\) зависит от времени явно (например, если \(f\) описывает изменяющиеся во времени внешние силы), то в уравнение \eqref{DeltaV} добавляется член, позволяющий учесть эту зависимость

\begin{equation} \left( \textbf{I} - h \frac{\partial f}{\partial\textbf{v}} - h^2 \frac{\partial f}{\partial\textbf{x}} \right) \Delta\textbf{v} = h\left( f_0 + h\frac{\partial f}{\partial\textbf{x}}\textbf{v}_0 + \frac{\partial f}{\partial t} \right) . \label{implicit} \end{equation}

Ссылки

  1. D. Baraff and A. Witkin. Large steps in cloth simulation. Computer Graphics (Proc. SIGGRAPH), 1998.
  2. W.H. Press, B.P. Flannery, S.A. Teukolsky, and W.T. Vetterling. Numerical Recipes. Cambridge University Press, 1986.


Комментарии

comments powered by Disqus