program ALG115;
{
   PIECEWISE LINEAR RAYLEIGH-RITZ METHOD

   To approximate the solution of the boundary-value problem

        -D(P(X)Y')/DX + Q(X)Y = F(X), 0 <= X <= 1,
               Y(0) = Y(1) = 0,

   with a piecewise linear function:

   INPUT:   integer N; mesh points X(0) = 0 < X(1) < ...
            < X(N) < X(N+1) = 1

   OUTPUT:  coefficients C(1),...,C(N) of the basis functions
}
var
   X : array [ 0..26 ] of real;
   H : array [ 0..25 ] of real;
   A,B,ALPHA,BETA,ZETA,Z,C : array [ 1..25 ] of real;
   Q : array [ 1..6, 1..26 ] of real;
   HQ,HC : real;
   N1,J1,FN,N,J,FLAG : integer;
   OK : boolean;
   AA : char;
   NAME : string [ 14 ];
   INP,OUP : text;
{  Change functions P, QQ and F for a new problem                      }
function P( X : real ) : real;
   begin
      P := 1.0
   end;
function QQ( X : real ) : real;
   begin
      QQ := PI * PI
   end;
function F( X : real ) : real;
   begin
      F := 2.0 * PI * PI * sin( PI * X )
   end;
procedure INPUT;
   begin
      writeln('This is the Piecewise Linear Rayleigh-Ritz Method.');
      writeln ('This program requires functions P, QQ, F to be created and ');
      writeln ('X(0), ..., X(N+1) to be supplied. ');
      writeln ('Are the preparations complete? Answer Y or N. ');
      readln ( AA );
      if ( ( AA = 'Y' ) or ( AA = 'y' ) ) then
         begin
            OK := false;
            while ( not OK ) do
               begin
                  writeln('Input integer N where X(0) = 0, X(N+1) = 1.');
                  readln ( N );
                  if ( N < 1 ) then writeln ('N must be greater than one. ')
                  else OK := true
               end;
            X[0] := 0.0;
            X[N+1] := 1.0;
            writeln ('Choice of method to input X(1), ..., X(N): ');
            writeln ('1.  Input from keyboard at the prompt ');
            writeln ('2.  Equally spaced nodes to be calculated ');
            writeln ('3.  Input from text file ');
            writeln ('Please enter 1, 2, or 3. ');
            readln ( FLAG );
            if ( FLAG = 2 ) then
               begin
                  HC := 1.0 / ( N + 1.0 );
                  for J := 1 to N do
                     begin
                        X[J] := J * HC;
                        H[J-1] := HC
                     end;
                  H[N] := HC
               end
            else
               begin
                  if ( FLAG = 3 ) then
                     begin
                        writeln ('Enter the input file name using the format ');
                        writeln (' - drive:name.ext, ');
                        writeln('for example:   A:DATA.DTA');
                        readln ( NAME );
                        assign ( INP, NAME );
                        reset ( INP );
                        for J := 1 to N do read ( INP, X[J] );
                        for J := 0 to N do H[J] := X[J+1] - X[J];
                        close ( INP )
                     end
                  else
                     begin
                        for J := 1 to N do
                           begin
                              writeln ('Input X(',J,'). ');
                              readln ( X[J] );
                              H[J-1] := X[J] - X[J-1]
                           end;
                        H[N] := X[N+1] - X[N]
                     end
               end
         end
      else
         begin
            writeln ('The program will end so that the functions ');
            writeln ('can be created. ');
            OK := false
         end
   end;
function SIMPSON( FN : integer; A,B : real ) : real;
   var
      Z : array [ 0..4 ] of real;
      Y,H : real;
      I : integer;
   begin
      H := ( B - A ) / 4.0;
      for I := 0 to 4 do
         begin
            Y := A + I * H;
            case FN of
               1: Z[I] := ( 4.0 - I ) * I * sqr( H ) * QQ( Y );
               2: Z[I] := sqr( I * H ) * QQ( Y );
               3: Z[I] := sqr( H * ( 4.0 - I ) ) * QQ( Y );
               4: Z[I] := P( Y );
               5: Z[I] := I * H * F( Y );
               6: Z[I] := ( 4.0 - I ) * H * F( Y )
            end
         end;
      SIMPSON := ( Z[0] + Z[4] + 2.0 * Z[2] + 4.0 * ( Z[1] + Z[3] ) ) *
                 H / 3.0
   end;
procedure OUTPUT;
   begin
      writeln ('Choice of output method: ');
      writeln ('1. Output to screen ');
      writeln ('2. Output to text file ');
      writeln ('Please enter 1 or 2. ');
      readln ( FLAG );
      if ( FLAG = 2 ) then
         begin
            writeln ('Input the file name in the form - drive:name.ext, ');
            writeln('for example:   A:OUTPUT.DTA');
            readln ( NAME );
            assign ( OUP, NAME )
         end
      else assign ( OUP, 'CON' );
      rewrite ( OUP );
      writeln(OUP,'PIECEWISE LINEAR RAYLEIGH-RITZ METHOD');
      writeln(OUP);
      writeln ( OUP,'I':3,'X(I-1)':12,'X(I)':12,'X(I+1)':12,'C(I)':14);
      writeln ( OUP );
      for J := 1 to N do
         writeln(OUP,J:3,X[J-1]:12:8,X[J]:12:8,X[J+1]:12:8,C[J]:14:8);
      close ( OUP )
   end;
   begin
      INPUT;
{     Step 1 is done within the input procedure                        }
      if ( OK ) then
         begin
            N1 := N - 1;
{           STEP 3                                                     }
            for J := 1 to N1 do
               begin
                  Q[1,J] := SIMPSON( 1, X[J], X[J+1] ) / sqr( H[J] );
                  Q[2,J] := SIMPSON( 2, X[J-1], X[J] ) / sqr( H[J-1] );
                  Q[3,J] := SIMPSON( 3, X[J], X[J+1] ) / sqr( H[J] );
                  Q[4,J] := SIMPSON( 4, X[J-1], X[J] ) / sqr( H[J-1] );
                  Q[5,J] := SIMPSON( 5, X[J-1], X[J] ) / H[J-1] ;
                  Q[6,J] := SIMPSON( 6, X[J], X[J+1] ) / H[J]
               end;
            Q[2,N] := SIMPSON( 2, X[N-1], X[N] ) / sqr( H[N-1] );
            Q[3,N] := SIMPSON( 3, X[N], X[N+1] ) / sqr( H[N] );
            Q[4,N] := SIMPSON( 4, X[N-1], X[N] ) / sqr( H[N-1] );
            Q[4,N+1] := SIMPSON( 4, X[N], X[N+1] ) / sqr( H[N] );
            Q[5,N] := SIMPSON( 5, X[N-1], X[N] ) / H[N-1] ;
            Q[6,N] := SIMPSON( 6, X[N], X[N+1] ) / H[N] ;
{           STEP 4                                                     }
            for J := 1 to N1 do
               begin
                  ALPHA[J] := Q[4,J]+Q[4,J+1]+Q[2,J]+Q[3,J];
                  BETA[J] := Q[1,J]-Q[4,J+1];
                  B[J] := Q[5,J]+Q[6,J]
               end;
{           STEP 5                                                     }
            ALPHA[N] := Q[4,N]+Q[4,N+1]+Q[2,N]+Q[3,N];
            B[N] := Q[5,N]+Q[6,N];
{           STEP 6                                                     }
            A[1] := ALPHA[1];
            ZETA[1] := BETA[1] / ALPHA[1];
{           STEP 7                                                     }
            for J := 2 to N1 do
               begin
                  A[J] := ALPHA[J] - BETA[J-1] * ZETA[J-1];
                  ZETA[J] := BETA[J] / A[J]
               end;
{           STEP 8                                                     }
            A[N] := ALPHA[N] - BETA[N-1] * ZETA[N-1];
{           STEP 9                                                     }
            Z[1] := B[1] / A[1];
{           STEP 10                                                    }
            for J := 2 to N do
               Z[J] := ( B[J] - BETA[J-1] * Z[J-1] ) / A[J];
{           STEP 11                                                    }
            C[N] := Z[N];
{           STEP 12                                                    }
            for J := 1 to N1 do
               begin
                  J1 := N - J;
                  C[J1] := Z[J1] - ZETA[J1] * C[J1+1]
               end;
            OUTPUT
         end
{        STEP 13                                                       }
   end.



