exponenta event banner

Решение нелинейной ОДУ с граничным слоем путем коллокации

В этом примере показано, как использовать команды сплайна из команды Фитинг кривой (Curve Fitting) Toolbox™ решения нелинейного обыкновенного дифференциального уравнения (ОДУ).

Проблема

Мы рассматриваем нелинейную проблему с единичным возмущением

epsilon D^2g(x) + (g(x))^2 = 1 on [0..1]

Dg(0) = g(1) = 0.

Эта проблема уже довольно сложная для epsilon = .001, поэтому мы выбираем скромный

epsilon = .1;

Пространство аппроксимации

Мы ищем приблизительное решение путем коллокации из кусочных кубиков C ^ 1 с заданной последовательностью разрывовbreaks, следовательно, требуется заказ k быть 4.

breaks = (0:4)/4;
k = 4;

Получаем соответствующую последовательность узлов как

knots = augknt(breaks,k,2)
knots = 1×14

         0         0         0         0    0.2500    0.2500    0.5000    0.5000    0.7500    0.7500    1.0000    1.0000    1.0000    1.0000

Независимо от выбора порядка и узлов, соответствующее сплайновое пространство имеет размер

n = length(knots) - k
n = 10

Дискретизация

Число степеней свободы, 10, хорошо вписывается в тот факт, что мы рассчитываем на совместное размещение в двух местах на полиномиальную часть, в общей сложности 8 условий, что приводит нас к 10 условиям в целом, как только мы добавляем два побочных условия.

Мы выбираем два сайта Гаусса для каждого интервала. Для «стандартного» интервала [-1/2.. 1/2] единичной длины, это две площадки

gauss = .5773502692*[-1/2; 1/2];

Из этого мы получаем всю коллекцию сайтов коллокации по

ninterv = length(breaks)-1;
temp = (breaks(2:ninterv+1)+breaks(1:ninterv))/2;
temp = temp([1 1],:) + gauss*diff(breaks);
colsites = temp(:).';

Числовая проблема

Численная задача, которую мы хотим решить - найти кусочный многочлен (или pp) y данного порядка и с заданными узлами, что удовлетворяет нелинейной системе

Dy(0) = 0

(y(x))^2 + epsilon D^2y(x) = 1 for x in colsites

y(1) = 0

Линеаризация

Если y является ли наше текущее приближение к решению, то линейная задача к лучшему (?) решению z методом Ньютона читает

Dz(0) = 0

w_0(x)z(x) + epsilon D^2z(x) = b(x) for x in colsites

z(1) = 0

с w_0(x) := 2y(x) и b(x) := (y(x))^2 + 1.

Фактически, выбирая w_0(1) := 1, w_1(0) := 1, и

w_2(x) := epsilon, w_1(x) := 0 for x in colsites

и выбор всех других значений w_0, w_1, w_2, и b еще не указано, чтобы быть нулевым, мы можем придать нашей системе однородную форму

w_0(x)z(x) + w_1(x)Dz(x) + w_2(x)D^2z(x) = b(x) for x in sites

где

sites = [0,colsites,1];

Решаемая линейная система

Эта система преобразуется в единицу для коэффициентов B-сплайна ее решения z. Для этого нам нужна нулевая, первая и вторая производная в каждом x в sites и для каждого соответствующего B-сплайна. Эти значения предоставляются spcol команда.

Вот существенная часть документации для spcol:

SPCOL B-spline collocation matrix.

COLLOC = SPCOL(KNOTS,K,TAU) is the matrix

[ D^m(i)B_j(TAU(i)) : i=1:length(TAU), j=1:length(KNOTS)-K ],

with D^m(i)B_j the m(i)-fold derivative of B_j,

B_j the j-th B-spline of order K for the knot sequence KNOTS,

TAU a sequence of sites,

both KNOTS and TAU are assumed to be nondecreasing, and

m(i) is the integer #{ j<i : TAU(j) = TAU(i) }, i.e., the

'cumulative' multiplicity of TAU(i) in TAU.

Мы используем spcol для подачи матрицы

colmat = spcol(knots,k, brk2knt(sites,3));

с brk2knt используется здесь для утроения каждой записи sites, и, таким образом, мы входим colmat, для каждого x в sites, значение и первая и вторая производные при x всех соответствующих B-сплайнов.

Из этого мы получим матрицу коллокации, объединив тройку строк, связанную с x с использованием весов w_0(x), w_1(x), w_2(x) чтобы получить строку, соответствующую x матрицы нашей линейной системы.

Требуется начальное предположение для Y

Нам также нужно текущее приближение y из сплайнового пространства. Первоначально мы получаем его путем интерполяции некоторой разумной начальной догадки из нашего pp-пространства на sites. Для этого мы используем параболу

x^2 - 1

которая удовлетворяет конечным условиям и лежит в нашем сплайновом пространстве. Мы получаем его B-форму интерполяцией на sites. Выберите соответствующую матрицу интерполяции из полной матрицы. colmat. Вот несколько осторожных шагов:

intmat = colmat([2 1+(1:(n-2))*3,1+(n-1)*3],:);
coefs = intmat\[0 colsites.*colsites-1 0].';
y = spmak(knots,coefs.');

Мы строим график результата, чтобы быть уверенным - это должно быть именно x^2-1.

fnplt(y,'g');
legend('Initial Guess (x^2-1)','location','NW');
axis([-0.01 1.01 -1.01 0.01]);
hold on

Figure contains an axes. The axes contains an object of type line. This object represents Initial Guess (x^2-1).

Повторение

Теперь мы можем завершить построение и решение линейной системы для улучшенного приблизительного решения z из нашего текущего предположения y. На самом деле, с первоначальным предположением y доступно, теперь мы настраиваем итерацию, которая будет прервана при изменении z-y меньше указанного допуска.

tolerance = 6.e-9;

Максимальные нормы изменения z-y на каждой итерации показаны выходные данные ниже, а на рисунке показана каждая из итераций.

while 1
   vtau = fnval(y,colsites);
   weights = [0 1 0;
            [2*vtau.' zeros(n-2,1) repmat(epsilon,n-2,1)];
            1 0 0];
   colloc = zeros(n,n);
   for j = 1:n
      colloc(j,:) = weights(j,:)*colmat(3*(j-1)+(1:3),:);
   end
   coefs = colloc\[0 vtau.*vtau+1 0].';
   z = spmak(knots,coefs.');
   fnplt(z,'k');
   maxdif = max(max(abs(z.coefs-y.coefs))); 
   fprintf('maxdif = %g\n',maxdif)
   if (maxdif<tolerance), break, end
   
   % now reiterate
   y = z;
end
maxdif = 0.206695
maxdif = 0.01207
maxdif = 3.95151e-05
maxdif = 4.43216e-10
legend({'Initial Guess (x^2-1)' 'Iterates'},'location','NW');

Figure contains an axes. The axes contains 5 objects of type line. These objects represent Initial Guess (x^2-1), Iterates.

Это выглядит как квадратичная сходимость, как и ожидалось из итерации Ньютона.

Готовьтесь к более мелкому эпсилону

Если мы сейчас уменьшим epsilon, мы создаем больше граничного слоя рядом с правой конечной точкой, и это требует неоднородной сетки. Мы используем newknt для построения соответствующей (более тонкой) сетки из текущего приближения.

knots = newknt(z, ninterv+1); 
breaks = knt2brk(knots);
knots = augknt(breaks,4,2);
n = length(knots)-k;

Сайты коллокации для новых перерывов

Далее мы получим сайты коллокации, соответствующие новому breaks

ninterv = length(breaks)-1;
temp = ((breaks(2:ninterv+1)+breaks(1:ninterv))/2);
temp = temp([1 1], :) + gauss*diff(breaks);
colsites = temp(:).';
sites = [0,colsites,1];

а затем новая матрица словосочетания.

colmat = spcol(knots,k, brk2knt(sites,3));

Начальное предположение

Мы получаем начальное предположение y в качестве интерполятора из текущего сплайнового пространства в вычисленное решение z. Мы построим график результирующего интерполятора, чтобы быть уверенными - он должен быть близок к нашему текущему решению.

intmat = colmat([2 1+(1:(n-2))*3,1+(n-1)*3],:);
y = spmak(knots,[0 fnval(z,colsites) 0]/intmat.');
fnplt(y,'c');
ax = gca;
h = ax.Children;
legend(h([6 5 1]),{'Initial Guess (x^2-1)' 'Iterates' ...
                   'New Initial Guess for New Value of epsilon'}, ...
                   'location','NW');

Figure contains an axes. The axes contains 6 objects of type line. These objects represent Initial Guess (x^2-1), Iterates, New Initial Guess for New Value of epsilon.

Итерация с меньшим эпсилоном

Теперь мы делим epsilon на 3 и повторите вышеуказанную итерацию. Сходимость снова квадратична.

epsilon = epsilon/3;
while 1
   vtau = fnval(y,colsites);
   weights = [0 1 0;
            [2*vtau.' zeros(n-2,1) repmat(epsilon,n-2,1)];
            1 0 0];
   colloc = zeros(n,n);
   for j = 1:n
      colloc(j,:) = weights(j,:)*colmat(3*(j-1)+(1:3),:);
   end
   coefs = colloc\[0 vtau.*vtau+1 0].';
   z = spmak(knots,coefs.');
   fnplt(z,'b');
   maxdif = max(max(abs(z.coefs-y.coefs)));
   fprintf('maxdif = %g\n',maxdif)
   if (maxdif<tolerance), break, end
   
   % now reiterate
   y = z;
end
maxdif = 0.237937
maxdif = 0.0184488
maxdif = 0.000120467
maxdif = 4.78115e-09
ax = gca;
h = ax.Children;
legend(h([10 9 5 4]), ...
       {'Initial Guess (x^2-1) for epsilon = .1' 'Iterates' ...
        sprintf('Initial Guess for epsilon = %.3f',epsilon) ...
        'Iterates'}, 'location','NW');

Figure contains an axes. The axes contains 10 objects of type line. These objects represent Initial Guess (x^2-1) for epsilon = .1, Iterates, Initial Guess for epsilon = 0.033.

Очень маленький эпсилон

Для гораздо меньшего epsilon, мы просто повторяем эти вычисления, деля epsilon на 3 каждый раз.

for ee = 1:4
   knots = newknt(z, ninterv+1); 
   breaks = knt2brk(knots);
   knots = augknt(breaks,4,2); 
   n = length(knots)-k;

   ninterv = length(breaks)-1;
   temp = ((breaks(2:ninterv+1)+breaks(1:ninterv))/2);
   temp = temp([1 1], :) + gauss*diff(breaks);
   colsites = temp(:).';
   sites = [0,colsites,1];

   colmat = spcol(knots,k, brk2knt(sites,3));

   intmat = colmat([2 1+(1:(n-2))*3,1+(n-1)*3],:);
   y = spmak(knots,[0 fnval(z,colsites) 0]/intmat.');
   fnplt(y,'c')

   epsilon = epsilon/3;
   while 1
      vtau = fnval(y,colsites);
      weights = [0 1 0;
               [2*vtau.' zeros(n-2,1) repmat(epsilon,n-2,1)];
               1 0 0];
      colloc = zeros(n,n);
      for j = 1:n
       colloc(j,:) = weights(j,:)*colmat(3*(j-1)+(1:3),:);
      end
      coefs = colloc\[0 vtau.*vtau+1 0].';
      z = spmak(knots,coefs.');
      fnplt(z,'b');
      maxdif = max(max(abs(z.coefs-y.coefs)));
      if (maxdif<tolerance), break, end
      
      % now reiterate
      y = z;
   end
end
ax = gca;
h = ax.Children;
legend(h([30 29 25 24]), ...
       {'Initial Guess (x^2-1) for epsilon = .1' 'Iterates' ...
        'Initial Guesses for epsilon = .1/3^j, j=1:5' ...
        'Iterates'},'location','NW');

Figure contains an axes. The axes contains 30 objects of type line. These objects represent Initial Guess (x^2-1) for epsilon = .1, Iterates, Initial Guesses for epsilon = .1/3^j, j=1:5.

Печать разрывов, используемых для наименьшего эпсилона

Вот окончательное распределение breaks, показ newknt чтобы хорошо сработать в этом случае.

breaks = fnbrk(fn2fm(z,'pp'),'b');
bb = repmat(breaks,3,1);
cc = repmat([0;-1;NaN],1,length(breaks));
plot(bb(:),cc(:),'r');
hold off
ax = gca;
h = ax.Children;
legend(h([31 30 26 25 1]), ...
       {'Initial Guess (x^2-1) for epsilon = .1' 'Iterates' ...
        'Initial Guesses for epsilon = .1/3^j, j=1:5' ...
        'Iterates' 'Breaks for epsilon = .1/3^5'},'location','NW');

Figure contains an axes. The axes contains 31 objects of type line. These objects represent Initial Guess (x^2-1) for epsilon = .1, Iterates, Initial Guesses for epsilon = .1/3^j, j=1:5, Breaks for epsilon = .1/3^5.

График остатка для наименьшего эпсилона

Напомним, что мы решаем ОДУ

epsilon D^2g(x) + (g(x))^2 = 1 on [0..1]

В качестве проверки вычисляем и строим график остатка для вычисленного решения для наименьшего эпсилона. Это тоже выглядит удовлетворительно.

xx = linspace(0,1,201);
plot(xx, 1 - epsilon*fnval(fnder(z,2),xx) - (fnval(z,xx)).^2)
title('Residual for the Computed Solution for Smallest epsilon');

Figure contains an axes. The axes with title Residual for the Computed Solution for Smallest epsilon contains an object of type line.