Вычислительные методы: разностная схема и метод прогонки (Delphi)

program Lab7_3;

{$APPTYPE CONSOLE}

{ Описание задания по вычислительным методам.

 Дана разностная схема
   A[I]*Y[I+1]+B[I]*Y[I]+C[I]*Y[I-1] = 12*H^2*F(x[I]) + H^4*F''(x[I]), где
      I = 1,...n-1
      F'' - вторая производная
   Y[0] = 0
   Y[n] = 0
   H = 1/n
   x[I] = I * H, где I = 1,...n-1

   A[I] = H^2 - 12, I = 1,...n-1
   B[I] = -(10*H^2 + 24), I = 1,...n-1
   C[I] = A[I], I = 1,...n-1

 аппроксимирующая задачу -d^2 u/dx^2 + u = F(x), где
     d - знак дифференциала
     x принадлежит отрезку [0, 1]
     u(0) = 0
     u(1) = 0
 с четвертым порядком.


 Полагаем u(x) = Sin(2*Pi*x).

 Необходимо решить разностную схему методом прогонки и сравнить
 полученные значения с истинными
}

uses
  SysUtils;

type
  TFloat = Extended;
  TFloatArray = array of TFloat;

function Progonka(A, B, C, F: TFloatArray; var Y: TFloatArray): Boolean;
// Решение системы уравнений с трехдиагональной матрицей
// методом правой прогонки.
//
// Обозначим за X[i] - Х с индексом i.
//   A[i] * Y[I+1] - B[I] * Y[I] + C[I] * Y[I-1] = F[I], где I от 1 до N-1,
//                                                       A[I] <> 0
//                                                       C[I] <> 0
//   Y[0] = A[0] * Y[1] + F[0]
//   Y[N] = C[N] * Y[N-1] + F[N]
//
// Т.о. данная система уравнений на Y-итые образует трехдиагональную матрицу.
// Решить данную систему можно используя следующие формулы:
//   K[0]:= A[0]
//   L[0]:= F[0]
//
//   K[I]:= A[I] / (B[I] - K[I-1]*C[I]), где I от 1 до N-1
//   L[I]:= (C[I]*L[I-1] - F[I]) / (B[I} - K[I-1]*C[I]), где I от 1 до N-1
//
//   Y[N]:= (F[N] + C[N]*L[N-1]) / (1 - C[N]*K[N-1])
//   Y[I]:= K[I]*Y[I+1] + L[I], где I от N-1 до 0
var
  n, I: Integer;
  K, L: TFloatArray;
begin
  if Length(A) < 3 then
  begin
    Result:= False;
    Exit;
  end;

  n:= Length(A) - 1;
  if (Length(B) <> n + 1) or (Length(C) <> n + 1) or (Length(F) <> n + 1) then
  begin
    Result:= False;
    Exit;
  end;

  try
    SetLength(K, n);
    SetLength(L, n);
    SetLength(Y, n + 1);

    K[0]:= A[0];
    L[0]:= F[0];

    for I:= 1 to n - 1 do
    begin
      K[I]:= A[I] / (B[I] - K[I-1] * C[I]);
      L[I]:= (C[I] * L[I-1] - F[I]) / (B[I] - K[I-1] * C[I]);
    end;

    Y[n]:= (F[n] + C[n] * L[n-1]) / (1 - C[n] * K[n-1]);
    for I:= n - 1 downto 0 do
      Y[I]:= K[I] * Y[I+1] + L[I];

    Result:= True;
  except
    Result:= False;
  end;
end;

procedure DoWork(A, B: TFloat; n: Integer);
// Функция выполняет задание
//   A, B - концы отрезка
//   n - кол-во интервалов на отрезке
var
  _a, _b, _c: TFloatArray; // коэффициенты в левой части
  _f: TFloatArray;         // значения правой части в узлах
  Y: TFloatArray;          // приближенное решение полученное
                           // методом прогонки
  H: TFloat;               // шаг
  I: Integer;
  Err: TFloat;
begin
  if A >= B then
    Exit;

  if n < 3 then
    Exit;

  H:= Abs(B-A) / n;

  try
    SetLength(_a, n + 1);
    SetLength(_b, n + 1);
    SetLength(_c, n + 1);
    SetLength(_f, n + 1);

    for I:= 0 to n do
    begin

      // Задаем коэффициенты разностной схемы

      if I = 0 then
        _a[I]:= 0 // следует из нашей разностной схемы
      else
        _a[I]:= H*H-12;

      _b[I]:= -(10*H*H+24);

      if I = n then
        _c[I]:= 0 // следует из нашей разностной схемы
      else
        _c[I]:= H*H-12;


      // Задаем правую часть в разностной схеме

      if I = 0 then
        _f[I]:= 0 // следует из нашей разностной схемы
      else if I = n then
        _f[I]:= 0 // следует из нашей разностной схемы
      else
        _f[I]:= Sqr(H)*(1+4*Sqr(Pi))*Sin(2*Pi*(A+I*H))*(12 - Sqr(H*2*Pi));
    end;

    // Решаем полученную систему методом прогонки

    if Progonka(_a, _b, _c, _f, Y) then
    begin
      Err:= 0;
      for I:= 0 to n do
      begin

        // Сравнимаем полученное решение с истинным решением

        Write('Y[', I, '] = ', Y[I]);
        Write('':10, 'U[', I, '] = ', Sin(2*Pi*(A+I*H)));

        // Вычисляем точность, как максимум модуля разности
        // между полученным (приближенным) решением и истинным решением

        if Abs(Y[I] - Sin(2*Pi*(A+I*H))) > Err then
          Err:= Abs(Y[I] - Sin(2*Pi*(A+I*H)));

        WriteLn;
      end;

      WriteLn('Mistake: ', Err);

    end else
     WriteLn(ErrOutput, 'Unexpected error!!!');
  except
    on E: Exception do
      WriteLn(ErrOutput, E.Message);
  end;
end;

begin
  DoWork(0, 1, 10);
  ReadLn;
end.
 
Слава Антонов © 2002 — August 13, 2008
Индекс цитирования 197-577-902 ICQ-статус
Hosted by uCoz