home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 9 / 09.iso / l / l042 / 2.ddi / CHAP8.ARC / INITVAL2.INC < prev    next >
Encoding:
Text File  |  1987-12-30  |  42.2 KB  |  1,111 lines

  1. {----------------------------------------------------------------------------}
  2. {-                                                                          -}
  3. {-     Turbo Pascal Numerical Methods Toolbox                               -}
  4. {-     Copyright (c) 1986, 87 by Borland International, Inc.                -}
  5. {-                                                                          -}
  6. {----------------------------------------------------------------------------}
  7.  
  8. procedure InitialConditionSystem{(NumEquations  : integer;
  9.                                  LowerLimit     : Float;
  10.                                  UpperLimit     : Float;
  11.                                  InitialValues  : TNvector;
  12.                                  NumReturn      : integer;
  13.                                  NumIntervals   : integer;
  14.                              var SolutionValues : TNmatrix;
  15.                              var Error          : byte;
  16.                                  Vector         : FuncVect)};
  17. type
  18.   Ptr = ^Data;
  19.  
  20.   Data = record
  21.            Values : TNvector;
  22.            Next : Ptr;
  23.          end;
  24.  
  25. var
  26.   ValuesStack : Ptr;                     { Pointer to the stack  }
  27.   Spacing, HalfSpacing : Float;           { Size of each subinterval  }
  28.   Index : integer;
  29.   Term : integer;
  30.   F1 : TNvector;
  31.   F2 : TNvector;
  32.   F3 : TNvector;
  33.   F4 : TNvector;
  34.   CurrentValues : TNvector;
  35.   TempValues : TNvector;
  36.  
  37. procedure InitializeStack(var ValuesStack : Ptr);
  38. begin
  39.   ValuesStack := nil;
  40. end; { procedure InitializeStack }
  41.  
  42. procedure Push(var ValuesStack   : Ptr;
  43.                var CurrentValues : TNvector);
  44.  
  45. {--------------------------------------}
  46. {- Input: ValuesStack, CurrentValues  -}
  47. {- Output: ValuesStack                -}
  48. {-                                    -}
  49. {- Push data onto the Stack           -}
  50. {--------------------------------------}
  51.  
  52. var
  53.   NewNode : Ptr;
  54.  
  55. begin
  56.   New(NewNode);
  57.   NewNode^.Values := CurrentValues;
  58.   NewNode^.Next := ValuesStack;
  59.   ValuesStack := NewNode;
  60. end; { procedure Push }
  61.  
  62. procedure Pop(var ValuesStack   : Ptr;
  63.               var CurrentValues : TNvector);
  64.  
  65. {--------------------------------------}
  66. {- Input: ValuesStack, CurrentValues  -}
  67. {- Output: ValuesStack                -}
  68. {-                                    -}
  69. {- Pop data from the Stack            -}
  70. {--------------------------------------}
  71.  
  72. var
  73.   OldNode : Ptr;
  74.  
  75. begin
  76.   OldNode := ValuesStack;
  77.   ValuesStack := OldNode^.Next;
  78.   CurrentValues := OldNode^.Values;
  79. end; { procedure Pop }
  80.  
  81. procedure TestAndInitialize(NumEquations     : integer;
  82.                             LowerLimit       : Float;
  83.                             UpperLimit       : Float;
  84.                             var NumIntervals : integer;
  85.                             NumReturn        : integer;
  86.                         var ValuesStack      : Ptr;
  87.                         var Spacing          : Float;
  88.                         var Error            : byte);
  89.  
  90. {-----------------------------------------------------------------}
  91. {- Input: NumEquations, LowerLimit, UpperLimit,                  -}
  92. {-        NumIntervals, NumReturn                                -}
  93. {- Output: ValuesStack, Spacing, Error                           -}
  94. {-                                                               -}
  95. {- This procedure initializes the above variables. ValuesStack   -}
  96. {- is initialized to NIL. Spacing is initialized to              -}
  97. {-        (UpperLimit - LowerLimit)/NumIntervals.                -}
  98. {- NumEquations, NumIntervals, and NumReturn are checked for     -}
  99. {- errors; they must be greater than zero.                       -}
  100. {-----------------------------------------------------------------}
  101.  
  102. begin
  103.   Error := 0;
  104.   if NumReturn <= 0 then
  105.     Error := 1;
  106.   if NumIntervals < NumReturn then
  107.     Error := 2;
  108.   if NumEquations < 1 then
  109.     Error := 3;
  110.   if LowerLimit = UpperLimit then
  111.     Error := 4;
  112.   if Error = 0 then
  113.   begin
  114.     InitializeStack(ValuesStack);
  115.     Spacing := (UpperLimit - LowerLimit)/NumIntervals;
  116.   end;
  117. end; { procedure TestAndInitialize }
  118.  
  119. procedure GetValues(NumReturn      : integer;
  120.                     NumIntervals   : integer;
  121.                 var ValuesStack    : Ptr;
  122.                 var SolutionValues : TNmatrix);
  123.  
  124. {----------------------------------------------------------}
  125. {- Input: NumReturn, NumIntervals, ValuesStack            -}
  126. {- Output: SolutionValues                                 -}
  127. {-                                                        -}
  128. {- This procedure fills in the matrix SolutionValues      -}
  129. {- with data from the values stack. For example,          -}
  130. {- if there are five times as many items on the stack     -}
  131. {- (NumIntervals) as should be returned (NumReturn) then  -}
  132. {- every fifth value from the stack will be returned.     -}
  133. {----------------------------------------------------------}
  134.  
  135. var
  136.   Index, Term   : integer;
  137.   CurrentValues : TNvector;
  138.  
  139. begin
  140.   Term := NumIntervals;
  141.   for Index := NumReturn downto 0 do
  142.   begin
  143.     Pop(ValuesStack, CurrentValues);
  144.     Term := Pred(Term);
  145.     while (Term / NumIntervals >= Index / NumReturn) and (Term >= 0) do
  146.     begin
  147.       Pop(ValuesStack, CurrentValues);
  148.       Term := Pred(Term);
  149.     end;
  150.     SolutionValues[Index] := CurrentValues;
  151.   end;
  152. end; { procedure GetValues }
  153.  
  154. procedure Step(Spacing       : Float;
  155.            var CurrentValues : TNvector;
  156.            var F             : TNvector);
  157.  
  158. {---------------------------------------------------------}
  159. {- Input: Spacing, CurrentValues                         -}
  160. {- Output: F                                             -}
  161. {-                                                       -}
  162. {- This procedure performs one step in the Runge-Kutta   -}
  163. {- four-step algorithm. By varying CurrentValues, this   -}
  164. {- procedure can be used at all steps in the Runge-      -}
  165. {- Kutta algorithm.                                      -}
  166. {-                                                       -}
  167. {- This procedure assumes that there are no more than    -}
  168. {- ten coupled 1st-order equations.  The F's record      -}
  169. {- information about the 10 (or fewer) independent       -}
  170. {- variables.                                            -}
  171. {---------------------------------------------------------}
  172.  
  173. begin
  174.   F[1] := Spacing * UserFunction3(CurrentValues, Vector[1]);
  175.   F[2] := Spacing * UserFunction3(CurrentValues, Vector[2]);
  176.   F[3] := Spacing * UserFunction3(CurrentValues, Vector[3]);
  177.   F[4] := Spacing * UserFunction3(CurrentValues, Vector[4]);
  178.   F[5] := Spacing * UserFunction3(CurrentValues, Vector[5]);
  179.   F[6] := Spacing * UserFunction3(CurrentValues, Vector[6]);
  180.   F[7] := Spacing * UserFunction3(CurrentValues, Vector[7]);
  181.   F[8] := Spacing * UserFunction3(CurrentValues, Vector[8]);
  182.   F[9] := Spacing * UserFunction3(CurrentValues, Vector[9]);
  183.   F[10] := Spacing * UserFunction3(CurrentValues, Vector[10]);
  184. end; { procedure Step }
  185.  
  186. begin  { procedure InitialConditionSystem }
  187.   TestAndInitialize(NumEquations, LowerLimit, UpperLimit,
  188.                     NumIntervals, NumReturn, ValuesStack, Spacing, Error);
  189.   if Error = 0 then
  190.   begin
  191.     CurrentValues := InitialValues;
  192.     Push(ValuesStack, CurrentValues);
  193.     HalfSpacing := Spacing / 2;
  194.     for Index := 1 to NumIntervals do
  195.     begin
  196.       { First step - calculate F1  }
  197.       Step(Spacing, CurrentValues, F1);
  198.       TempValues[0] := CurrentValues[0] + HalfSpacing;
  199.       for Term := 1 to NumEquations do
  200.         TempValues[Term] := CurrentValues[Term] + 0.5 * F1[Term];
  201.  
  202.       { 2nd step - calculate F2  }
  203.       Step(Spacing, TempValues, F2);
  204.       for Term := 1 to NumEquations do
  205.         TempValues[Term] := CurrentValues[Term] + 0.5 * F2[Term];
  206.  
  207.       { Third step - calculate F3  }
  208.       Step(Spacing, TempValues, F3);
  209.       TempValues[0] := CurrentValues[0] + Spacing;
  210.       for Term := 1 to NumEquations do
  211.         TempValues[Term] := CurrentValues[Term] + F3[Term];
  212.  
  213.       { Fourth step - calculate F4[1]; first equation  }
  214.       Step(Spacing, TempValues, F4);
  215.  
  216.       { Combine F1, F2, F3, and F4 to get  }
  217.       { the solution at this mesh point    }
  218.       CurrentValues[0] := CurrentValues[0] + Spacing;
  219.       for Term := 1 to NumEquations do
  220.         CurrentValues[Term] := CurrentValues[Term] + (F1[Term] + 2 * F2[Term] +
  221.                                2 * F3[Term] + F4[Term]) / 6;
  222.  
  223.       Push(ValuesStack, CurrentValues);
  224.     end;
  225.     GetValues(NumReturn, NumIntervals, ValuesStack, SolutionValues);
  226.   end;
  227. end; { procedure InitialConditionSystem }
  228.  
  229. procedure InitialConditionSystem2{(NumEquations  : integer;
  230.                                   LowerLimit     : Float;
  231.                                   UpperLimit     : Float;
  232.                                   InitialValues  : TNvector2;
  233.                                   NumReturn      : integer;
  234.                                   NumIntervals   : integer;
  235.                               var SolutionValues : TNmatrix2;
  236.                               var Error          : byte;
  237.                                   Vector         : FuncVect)};
  238.  
  239. type
  240.   Ptr = ^Data;
  241.  
  242.   Data = record
  243.            Values : TNvector2;
  244.            Next : Ptr;
  245.          end;
  246.  
  247. var
  248.   ValuesStack : Ptr;                     { Pointer to the stack  }
  249.   Spacing, HalfSpacing : Float;           { Size of each subinterval  }
  250.   Index : integer;
  251.   Term : integer;
  252.   F1 : TNvector2;
  253.   F2 : TNvector2;
  254.   F3 : TNvector2;
  255.   F4 : TNvector2;
  256.   CurrentValues : TNvector2;
  257.   TempValues : TNvector2;
  258.  
  259. procedure InitializeStack(var ValuesStack : Ptr);
  260. begin
  261.   ValuesStack := nil;
  262. end; { procedure InitializeStack }
  263.  
  264. procedure Push(var ValuesStack   : Ptr;
  265.                var CurrentValues : TNvector2);
  266.  
  267. {--------------------------------------}
  268. {- Input: ValuesStack, CurrentValues  -}
  269. {- Output: ValuesStack                -}
  270. {-                                    -}
  271. {- Push data onto the Stack           -}
  272. {--------------------------------------}
  273.  
  274. var
  275.   NewNode : Ptr;
  276.  
  277. begin
  278.   New(NewNode);
  279.   NewNode^.Values := CurrentValues;
  280.   NewNode^.Next := ValuesStack;
  281.   ValuesStack := NewNode;
  282. end; { procedure Push }
  283.  
  284. procedure Pop(var ValuesStack   : Ptr;
  285.               var CurrentValues : TNvector2);
  286.  
  287. {--------------------------------------}
  288. {- Input: ValuesStack, CurrentValues  -}
  289. {- Output: ValuesStack                -}
  290. {-                                    -}
  291. {- Pop data from the Stack            -}
  292. {--------------------------------------}
  293.  
  294. var
  295.   OldNode : Ptr;
  296.  
  297. begin
  298.   OldNode := ValuesStack;
  299.   ValuesStack := OldNode^.Next;
  300.   CurrentValues := OldNode^.Values;
  301. end; { procedure Pop }
  302.  
  303. procedure TestAndInitialize(NumEquations  : integer;
  304.                             LowerLimit    : Float;
  305.                             UpperLimit    : Float;
  306.                             NumIntervals  : integer;
  307.                             NumReturn     : integer;
  308.                         var InitialValues : TNvector2;
  309.                         var ValuesStack   : Ptr;
  310.                         var Spacing       : Float;
  311.                         var Error         : byte);
  312.  
  313. {-----------------------------------------------------------------}
  314. {- Input: NumEquations, LowerLimit, UpperLimit,                  -}
  315. {-        NumIntervals, NumReturn                                -}
  316. {- Output: InitialValues, ValuesStack, Spacing, Error            -}
  317. {-                                                               -}
  318. {- This procedure initializes the above variables. ValuesStack   -}
  319. {- is initialized to NIL. Spacing is initialized to              -}
  320. {-        (UpperLimit - LowerLimit)/NumIntervals.                -}
  321. {- NumEquations, NumIntervals, and NumReturn are checked for     -}
  322. {- errors; they must be greater than zero.                       -}
  323. {-----------------------------------------------------------------}
  324.  
  325. begin
  326.   Error := 0;
  327.   if NumReturn <= 0 then
  328.     Error := 1;
  329.   if NumIntervals < NumReturn then
  330.     Error := 2;
  331.   if NumEquations < 1 then
  332.     Error := 3;
  333.   if LowerLimit = UpperLimit then
  334.     Error := 4;
  335.   if Error = 0 then
  336.   begin
  337.     InitializeStack(ValuesStack);
  338.     Spacing := (UpperLimit - LowerLimit)/NumIntervals;
  339.     InitialValues[0].X := LowerLimit;
  340.   end;
  341. end; { procedure TestAndInitialize }
  342.  
  343. procedure GetValues(NumReturn      : integer;
  344.                     NumIntervals   : integer;
  345.                 var ValuesStack    : Ptr;
  346.                 var SolutionValues : TNmatrix2);
  347.  
  348. {----------------------------------------------------------}
  349. {- Input: NumReturn, NumIntervals, ValuesStack            -}
  350. {- Output: SolutionValues                                 -}
  351. {-                                                        -}
  352. {- This procedure fills in the matrix SolutionValues      -}
  353. {- with data from the values stack. For example,          -}
  354. {- if there are five times as many items on the stack     -}
  355. {- (NumIntervals) as should be returned (NumReturn) then  -}
  356. {- every fifth value from the stack will be returned.     -}
  357. {----------------------------------------------------------}
  358.  
  359. var
  360.   Index : integer;
  361.   Term : integer;
  362.   CurrentValues : TNvector2;
  363.  
  364. begin
  365.   Term := NumIntervals;
  366.   for Index := NumReturn downto 0 do
  367.   begin
  368.     Pop(ValuesStack, CurrentValues);
  369.     Term := Pred(Term);
  370.     while (Term/NumIntervals >= Index/NumReturn) and (Term >= 0) do
  371.     begin
  372.       Pop(ValuesStack, CurrentValues);
  373.       Term := Pred(Term);
  374.     end;
  375.     SolutionValues[Index] := CurrentValues;
  376.   end;
  377. end; { procedure GetValues }
  378.  
  379. procedure Step(Spacing       : Float;
  380.            var CurrentValues : TNvector2;
  381.            var F             : TNvector2);
  382.  
  383. {---------------------------------------------------------}
  384. {- Input: Spacing, CurrentValues                         -}
  385. {- Output: F                                             -}
  386. {-                                                       -}
  387. {- This procedure performs one step in the Runge-Kutta   -}
  388. {- four-step algorithm. By varying CurrentValues, this   -}
  389. {- procedure can be used at all steps in the Runge-      -}
  390. {- Kutta algorithm.                                      -}
  391. {-                                                       -}
  392. {- This procedure assumes that there are no more than    -}
  393. {- ten coupled 2nd-order equations.  The F.X's record    -}
  394. {- information about the 10 (or fewer) independent       -}
  395. {- variables.  The F.xDeriv's record information about   -}
  396. {- their derivatives.                                    -}
  397. {---------------------------------------------------------}
  398.  
  399. begin
  400.   F[1].X := Spacing * CurrentValues[1].xDeriv;
  401.   F[1].xDeriv := Spacing * UserFunction4(CurrentValues, Vector[1]);
  402.  
  403.   F[2].X := Spacing * CurrentValues[2].xDeriv;
  404.   F[2].xDeriv := Spacing * UserFunction4(CurrentValues, Vector[2]);
  405.  
  406.   F[3].X := Spacing * CurrentValues[3].xDeriv;
  407.   F[3].xDeriv := Spacing * UserFunction4(CurrentValues, Vector[3]);
  408.  
  409.   F[4].X := Spacing * CurrentValues[4].xDeriv;
  410.   F[4].xDeriv := Spacing * UserFunction4(CurrentValues, Vector[4]);
  411.  
  412.   F[5].X := Spacing * CurrentValues[5].xDeriv;
  413.   F[5].xDeriv := Spacing * UserFunction4(CurrentValues, Vector[5]);
  414.  
  415.   F[6].X := Spacing * CurrentValues[6].xDeriv;
  416.   F[6].xDeriv := Spacing * UserFunction4(CurrentValues, Vector[6]);
  417.  
  418.   F[7].X := Spacing * CurrentValues[7].xDeriv;
  419.   F[7].xDeriv := Spacing * UserFunction4(CurrentValues, Vector[7]);
  420.  
  421.   F[8].X := Spacing * CurrentValues[8].xDeriv;
  422.   F[8].xDeriv := Spacing * UserFunction4(CurrentValues, Vector[8]);
  423.  
  424.   F[9].X := Spacing * CurrentValues[9].xDeriv;
  425.   F[9].xDeriv := Spacing * UserFunction4(CurrentValues, Vector[9]);
  426.  
  427.   F[10].X := Spacing * CurrentValues[10].xDeriv;
  428.   F[10].xDeriv := Spacing * UserFunction4(CurrentValues, Vector[10]);
  429. end; { procedure Step }
  430.  
  431. begin  {procedure InitialConditionSystem2}
  432.   TestAndInitialize(NumEquations, LowerLimit, UpperLimit, NumIntervals,
  433.                     NumReturn, InitialValues, ValuesStack, Spacing, Error);
  434.   if Error = 0 then
  435.   begin
  436.     CurrentValues := InitialValues;
  437.     Push(ValuesStack, CurrentValues);
  438.     HalfSpacing := Spacing / 2;
  439.     for Index := 1 to NumIntervals do
  440.     begin
  441.  
  442.       { First step - calculate F1  }
  443.       Step(Spacing, CurrentValues, F1);
  444.       TempValues[0].X := CurrentValues[0].X + HalfSpacing;
  445.       for Term := 1 to NumEquations do
  446.       begin
  447.         TempValues[Term].X := CurrentValues[Term].X + 0.5 * F1[Term].X;
  448.         TempValues[Term].xDeriv := CurrentValues[Term].xDeriv +
  449.                                    0.5 * F1[Term].xDeriv;
  450.       end;
  451.  
  452.       { Second step - calculate F2  }
  453.       Step(Spacing, TempValues, F2);
  454.       for Term := 1 to NumEquations do
  455.       begin
  456.         TempValues[Term].X := CurrentValues[Term].X + 0.5 * F2[Term].X;
  457.         TempValues[Term].xDeriv := CurrentValues[Term].xDeriv +
  458.                                    0.5 * F2[Term].xDeriv;
  459.       end;
  460.  
  461.       { Third step - calculate F3  }
  462.       Step(Spacing, TempValues, F3);
  463.       TempValues[0].X := CurrentValues[0].X + Spacing;
  464.       for Term := 1 to NumEquations do
  465.       begin
  466.         TempValues[Term].X := CurrentValues[Term].X + F3[Term].X;
  467.         TempValues[Term].xDeriv := CurrentValues[Term].xDeriv + F3[Term].xDeriv;
  468.       end;
  469.  
  470.       { Fourth step - calculate F4  }
  471.       Step(Spacing, TempValues, F4);
  472.  
  473.       { Combine F1, F2, F3, and F4 to get  }
  474.       { the solution at this mesh point    }
  475.       CurrentValues[0].X := CurrentValues[0].X + Spacing;
  476.       for Term := 1 to NumEquations do
  477.       begin
  478.         CurrentValues[Term].X := CurrentValues[Term].X + (F1[Term].X +
  479.                              2 * F2[Term].X + 2 * F3[Term].X + F4[Term].X) / 6;
  480.         CurrentValues[Term].xDeriv := CurrentValues[Term].xDeriv +
  481.                                       (F1[Term].xDeriv + 2 * F2[Term].xDeriv +
  482.                                     2 * F3[Term].xDeriv + F4[Term].xDeriv) / 6;
  483.       end;
  484.       Push(ValuesStack, CurrentValues);
  485.     end;
  486.     GetValues(NumReturn, NumIntervals, ValuesStack, SolutionValues);
  487.   end;
  488. end; { procedure InitialConditionSystem2 }
  489.  
  490. procedure Shooting{(LowerLimit  : Float;
  491.                    UpperLimit   : Float;
  492.                    LowerInitial : Float;
  493.                    UpperInitial : Float;
  494.                    InitialSlope : Float;
  495.                    NumReturn    : integer;
  496.                    Tolerance    : Float;
  497.                    MaxIter      : integer;
  498.                    NumIntervals : integer;
  499.                var Iter         : integer;
  500.                var XValues      : TNvector;
  501.                var YValues      : TNvector;
  502.                var YDerivValues : TNvector;
  503.                var Error        : byte;
  504.                    FuncPtr      : Pointer)};
  505. type
  506.   Ptr = ^Data;
  507.  
  508.   Data = record
  509.            X, Y, YPrime : Float;
  510.            Next : Ptr;
  511.          end;
  512.  
  513. var
  514.   HeapTop : Ptr;                      { Top of the heap  }
  515.   Values : Ptr;                       { Pointer to the stack  }
  516.   Spacing : Float;                     { Size of sub-intervals  }
  517.   UpperApprox1 : Float;                { Approx to UpperInitial  }
  518.   UpperApprox2 : Float;
  519.   Slope1 : Float;                      { Slope at LowerLimit  }
  520.   Slope2 : Float;
  521.   NewSlope : Float;
  522.   Done : boolean;                     { True  --> algorithm finished  }
  523.                                       { False --> algorithm not finished  }
  524.  
  525. procedure Push(var Values  : Ptr;
  526.                XValue      : Float;
  527.                YValue      : Float;
  528.                YPrimeValue : Float);
  529.  
  530. {----------------------------------}
  531. {- Input: Values, XValue, YValue  -}
  532. {-        YPrimeValue             -}
  533. {- Output: Values                 -}
  534. {-                                -}
  535. {- Push data into the Stack       -}
  536. {----------------------------------}
  537.  
  538. begin
  539.   Values^.X := XValue;
  540.   Values^.Y := YValue;
  541.   Values^.YPrime := YPrimeValue;
  542.   Values := Values^.Next;
  543. end; { procedure Push }
  544.  
  545. procedure Pop(var Values      : Ptr;
  546.               var XValue      : Float;
  547.               var YValue      : Float;
  548.               var YPrimeValue : Float);
  549.  
  550. {----------------------------------}
  551. {- Input: Values, XValue, YValue  -}
  552. {-        YPrimeValue             -}
  553. {- Output: Values                 -}
  554. {-                                -}
  555. {- Pop Data from the Stack        -}
  556. {----------------------------------}
  557.  
  558. var
  559.   OldNode : Ptr;
  560.  
  561. begin
  562.   OldNode := Values;
  563.   Values := OldNode^.Next;
  564.   XValue := OldNode^.X;
  565.   YValue := OldNode^.Y;
  566.   YPrimeValue := OldNode^.YPrime;
  567.   Dispose(OldNode);
  568. end; { procedure Pop }
  569.  
  570. procedure TestAndInitialize(LowerLimit   : Float;
  571.                             UpperLimit   : Float;
  572.                             InitialSlope : Float;
  573.                             NumReturn    : integer;
  574.                             var Spacing  : Float;
  575.                             Tolerance    : Float;
  576.                             MaxIter      : integer;
  577.                         var HeapTop      : Ptr;
  578.                         var Iter         : integer;
  579.                         var Values       : Ptr;
  580.                         var NumIntervals : integer;
  581.                         var Done         : boolean;
  582.                         var Slope1       : Float;
  583.                         var Error        : byte);
  584.  
  585. {---------------------------------------------------------------}
  586. {- Input: LowerLimit, UpperLimit, InitialSlope, NumReturn,     -}
  587. {-        Spacing, Tolerance, MaxIter                          -}
  588. {- Output: Iter, Values1, Values2, Spacing, Done,              -}
  589. {-         Slope1, Slope2, Error                               -}
  590. {-                                                             -}
  591. {- This procedure initializes the above variables.  Values1    -}
  592. {- and Values2 are initialized to NIL. NumIntervals is         -}
  593. {- initialized to  (UpperLimit - LowerLimit)/Spacing.          -}
  594. {- NumReturn, Tolerance, MaxIter and NumIntervals are          -}
  595. {- checked for errors (they must be greater than zero).        -}
  596. {---------------------------------------------------------------}
  597.  
  598. var
  599.   Index : integer;
  600.   Dummy : Ptr;
  601.  
  602. begin
  603.   Error := 0;
  604.   if NumReturn <= 0 then
  605.     Error := 1;
  606.   if NumIntervals < NumReturn then
  607.     Error := 2;
  608.   if ABS(LowerLimit - UpperLimit) < TNNearlyZero then
  609.     Error := 3;
  610.   if Tolerance < TNNearlyZero then
  611.     Error := 4;
  612.   if MaxIter < 1 then
  613.     Error := 5;
  614.   if Error = 0 then
  615.   begin
  616.     Iter := 0;
  617.     New(HeapTop);
  618.     { Create space on the heap  }
  619.     Values := HeapTop;
  620.     for Index := 0 to NumIntervals do
  621.     begin
  622.       New(Dummy);
  623.       Values^.Next := Dummy;
  624.       Values := Dummy;
  625.     end;
  626.     Values := HeapTop;
  627.     Spacing := (UpperLimit - LowerLimit) / NumIntervals;
  628.     Slope1 := InitialSlope;
  629.     Done := false;
  630.   end;
  631. end; { procedure TestAndInitialize }
  632.  
  633. procedure RungeKuttaFour(NumIntervals : integer;
  634.                          Spacing      : Float;
  635.                          LowerLimit   : Float;
  636.                          LowerInitial : Float;
  637.                          Slope        : Float;
  638.                          HeapTop      : Ptr;
  639.                      var Values       : Ptr;
  640.                      var UpperApprox  : Float;
  641.                      var Error        : byte);
  642.  
  643. {--------------------------------------------------------------}
  644. {- Input: NumIntervals, Spacing, LowerLimit, LowerLimit,      -}
  645. {-        Slope, HeapTop                                      -}
  646. {- Output: Values, UpperApprox, Error                         -}
  647. {-                                                            -}
  648. {- This procedure solves a possibly non-linear 2nd order      -}
  649. {- ordinary differential equation with specified initial      -}
  650. {- conditions.                                                -}
  651. {- Given a possibly non-linear function of the form           -}
  652. {-           Y" = TNTargetF(X, Y, Y')                         -}
  653. {- and initial conditions                                     -}
  654. {-           Y[LowerLimit] = LowerInitial                     -}
  655. {-          Y'[LowerLimit] = Slope                            -}
  656. {- the Runge-Kutta one step method for two variables (Y and   -}
  657. {- Y') is used to solve for Y and Y' in the interval          -}
  658. {- [LowerLimit, UpperLimit].  The algorithm uses              -}
  659. {- sub-intervals of length Spacing. The approximation at      -}
  660. {- UpperLimit is returned as UpperApprox.                     -}
  661. {- If the solution to the initial value problem is unstable   -}
  662. {- (i.e. blows up), then Error 7 is returned.                 -}
  663. {--------------------------------------------------------------}
  664.  
  665. var
  666.   Index : integer;
  667.   HalfSpacing : Float;
  668.   F1y, F2y, F3y, F4y, F1yPrime, F2yPrime, F3yPrime, F4yPrime : Float;
  669.   X, Y, YPrime : Float;
  670.  
  671. procedure TestForInstability(LowerLimit   : Float;
  672.                              LowerInitial : Float;
  673.                              X            : Float;
  674.                              Y            : Float;
  675.                          var Error        : byte);
  676.  
  677. {------------------------------------------------------------}
  678. {- Input: LowerLimit, LowerInitial, X, Y                    -}
  679. {- Output: Error                                            -}
  680. {-                                                          -}
  681. {- This procedure determines if the solution to the initial -}
  682. {- value problem is unstable (i.e. if it is blowing up).    -}
  683. {- If the slope between the current point (X, Y) and the    -}
  684. {- initial point (LowerLimit, LowerInitial) is greater than -}
  685. {- 1E20, then the solution is assumed to be blowing up and  -}
  686. {- Error 7 is returned.                                     -}
  687. {------------------------------------------------------------}
  688.  
  689. begin
  690.   if ABS((Y - LowerInitial) / (X - LowerLimit)) > 1E20 then
  691.     Error := 7;   { Convergence not possible  }
  692. end; { procedure TestForInstability }
  693.  
  694. begin { procedure RungeKuttaFour }
  695.   { Clear the heap  }
  696.   Values := HeapTop;
  697.   X := LowerLimit;
  698.   Y := LowerInitial;
  699.   YPrime := Slope;
  700.   Push(Values, X, Y, yPrime);
  701.   HalfSpacing := Spacing / 2;
  702.   Index := 0;
  703.   while (Index < NumIntervals) and (Error = 0) do
  704.   begin
  705.     Index := Succ(Index);
  706.     F1y := Spacing * YPrime;
  707.     F1yPrime := Spacing * UserFunction2(X, Y, YPrime, FuncPtr);
  708.     F2y := Spacing * (YPrime + 0.5 * F1yPrime);
  709.     F2yPrime := Spacing * UserFunction2(X + HalfSpacing, Y + 0.5 * F1y,
  710.                                     YPrime + 0.5 * F1yPrime, FuncPtr);
  711.     F3y := Spacing * (YPrime + 0.5 * F2yPrime);
  712.     F3yPrime := Spacing * UserFunction2(X + HalfSpacing, Y + 0.5 * F2y,
  713.                                     YPrime + 0.5 * F2yPrime, FuncPtr);
  714.     F4y := Spacing * (YPrime + F3yPrime);
  715.     F4yPrime := Spacing * UserFunction2(X + Spacing, Y + F3y,
  716.                                     YPrime + F3yPrime, FuncPtr);
  717.  
  718.     Y := Y + (F1y + 2*F2y + 2*F3y + F4y) / 6;
  719.     YPrime := YPrime + (F1yPrime + 2 * F2yPrime + 2 * F3yPrime + F4yPrime) / 6;
  720.     X := X + Spacing;
  721.     Push(Values, X, Y, YPrime);
  722.     TestForInstability(LowerLimit, LowerInitial, X, Y, Error);
  723.   end;
  724.   UpperApprox := Y;
  725. end; { procedure RungeKuttaFour }
  726.  
  727. procedure ComputeNewSlope(UpperInitial : Float;
  728.                           UpperApprox1 : Float;
  729.                           UpperApprox2 : Float;
  730.                           Slope1       : Float;
  731.                           Slope2       : Float;
  732.                       var NewSlope     : Float;
  733.                       var Done         : boolean;
  734.                       var Error        : byte);
  735.  
  736. {-------------------------------------------------------------}
  737. {- Input: UpperInitial, UpperApprox1, UpperApprox2,          -}
  738. {-        Slope1, Slope2                                     -}
  739. {- Output: NewSlope, Done                                    -}
  740. {-                                                           -}
  741. {- This procedure uses the secant method and information     -}
  742. {- from the last two iterations to interpolate a value       -}
  743. {- for the slope at the left endpoint.                       -}
  744. {-------------------------------------------------------------}
  745.  
  746. begin
  747.   if ABS(UpperApprox2 - UpperApprox1) > TNNearlyZero then
  748.     NewSlope := Slope2 - (UpperApprox2 - UpperInitial) *
  749.                (Slope2 - Slope1)/(UpperApprox2 - UpperApprox1)
  750.   else
  751.     if ABS(UpperApprox1 - UpperInitial) < TNNearlyZero then
  752.       Done := true
  753.     else
  754.       Error := 7     { Convergence not possible  }
  755. end; { procedure ComputeNewSlope }
  756.  
  757. procedure GetValues(NumReturn    : integer;
  758.                     NumIntervals : integer;
  759.                 var HeapTop      : Ptr;
  760.                 var Values       : Ptr;
  761.                 var XValues      : TNvector;
  762.                 var YValues      : TNvector;
  763.                 var YDerivValues : TNvector);
  764.  
  765. {-------------------------------------------------------------}
  766. {- Input: NumReturn, NumIntervals, HeapTop, Values           -}
  767. {- Output: XValues, YValues, YDerivValues                    -}
  768. {-                                                           -}
  769. {- This procedure fills in the arrays XValues, YValues and   -}
  770. {- YDerivValues with data from the Values stack. For         -}
  771. {- example, if there are five times as many items on the     -}
  772. {- stack (NumIntervals) as should be returned (NumReturn)    -}
  773. {- then every fifth value from the stack will be returned.   -}
  774. {-------------------------------------------------------------}
  775.  
  776. var
  777.   Index, Term : integer;
  778.   X, Y, YPrime : Float;
  779.  
  780. begin
  781.   Values := HeapTop;
  782.   Term := 0;
  783.   for Index := 0 to NumReturn do
  784.   begin
  785.     Pop(Values, X, Y, YPrime);
  786.     Term := Succ(Term);
  787.     while (Term / NumIntervals <= Index / NumReturn) and
  788.           (Term <= NumIntervals) do
  789.     begin
  790.       Pop(Values, X, Y, YPrime);
  791.       Term := Succ(Term);
  792.     end;
  793.     XValues[Index] := X;
  794.     YValues[Index] := Y;
  795.     YDerivValues[Index] := YPrime;
  796.   end;
  797. end; { procedure GetValues }
  798.  
  799. begin { procedure Shooting }
  800.   TestAndInitialize(LowerLimit, UpperLimit,  InitialSlope,
  801.                     NumReturn, Spacing, Tolerance, MaxIter,
  802.                     HeapTop, Iter, Values, NumIntervals, Done,
  803.                     Slope1, Error);
  804.   if Error = 0 then
  805.   begin
  806.     Iter := Succ(Iter);
  807.     RungeKuttaFour(NumIntervals, Spacing, LowerLimit, LowerInitial,
  808.                    Slope1, HeapTop, Values, UpperApprox1, Error);
  809.     Done := ABS(UpperApprox1 - UpperInitial) <
  810.             ABS(UpperInitial * Tolerance);
  811.     Slope2 := Slope1 +
  812.               (UpperInitial - UpperApprox1) / (UpperLimit - LowerLimit);
  813.  
  814.     while (Iter < MaxIter) and not Done and (Error = 0) do
  815.     begin
  816.       Iter := Succ(Iter);
  817.       RungeKuttaFour(NumIntervals, Spacing, LowerLimit, LowerInitial,
  818.                      Slope2, HeapTop, Values, UpperApprox2, Error);
  819.       Done := ABS(UpperApprox2 - UpperInitial) <
  820.               ABS(UpperInitial * Tolerance);
  821.       ComputeNewSlope(UpperInitial, UpperApprox1, UpperApprox2,
  822.                       Slope1, Slope2, NewSlope, Done, Error);
  823.       Slope1 := Slope2;
  824.       Slope2 := NewSlope;
  825.       UpperApprox1 := UpperApprox2;
  826.     end;
  827.     GetValues(NumReturn, NumIntervals, HeapTop, Values, XValues,
  828.               YValues, YDerivValues);
  829.     if Iter = MaxIter then
  830.       Error := 6;
  831.   end;
  832. end; { procedure Shooting }
  833.  
  834. procedure LinearShooting{(LowerLimit  : Float;
  835.                          UpperLimit   : Float;
  836.                          LowerInitial : Float;
  837.                          UpperInitial : Float;
  838.                          NumReturn    : integer;
  839.                          NumIntervals : integer;
  840.                      var XValues      : TNvector;
  841.                      var YValues      : TNvector;
  842.                      var YDerivValues : TNvector;
  843.                      var Error        : byte;
  844.                          FuncPtr      : Pointer)};
  845.  
  846. type
  847.   Ptr = ^Data;
  848.  
  849.   Data = record
  850.            X, Y, YPrime : Float;
  851.            Next : Ptr;
  852.          end;
  853.  
  854. var
  855.   Values1, Values2 : Ptr;             { Pointers to the stacks  }
  856.   Spacing : Float;                     { Size of sub-intervals  }
  857.   UpperApprox1, UpperApprox2 : Float;  { Approx to UpperInitial  }
  858.   Slope1, Slope2 : Float;              { Initial slopes of    }
  859.                                       { Iterative solutions  }
  860.  
  861. procedure InitializeStack(var Values : Ptr);
  862. begin
  863.   Values := nil;
  864. end; { procedure InitializeStack }
  865.  
  866. procedure Push(var Values      : Ptr;
  867.                    TValue      : Float;
  868.                    XValue      : Float;
  869.                    yPrimeValue : Float);
  870.  
  871. {----------------------------------}
  872. {- Input: Values, TValue, XValue  -}
  873. {-        yPrimeValue             -}
  874. {- Output: Values                 -}
  875. {-                                -}
  876. {- Push data onto the Stack       -}
  877. {----------------------------------}
  878.  
  879. var
  880.   NewNode : Ptr;
  881.  
  882. begin
  883.   New(NewNode);
  884.   NewNode^.X := TValue;
  885.   NewNode^.Y := XValue;
  886.   NewNode^.YPrime := yPrimeValue;
  887.   NewNode^.Next := Values;
  888.   Values := NewNode;
  889. end; { procedure Push }
  890.  
  891. procedure Pop(var Values      : Ptr;
  892.               var TValue      : Float;
  893.               var XValue      : Float;
  894.               var yPrimeValue : Float);
  895.  
  896. {----------------------------------}
  897. {- Input: Values, TValue, XValue  -}
  898. {-        yPrimeValue             -}
  899. {- Output: Values                 -}
  900. {-                                -}
  901. {- Pop Data from the Stack        -}
  902. {----------------------------------}
  903.  
  904. var
  905.   OldNode : Ptr;
  906.  
  907. begin
  908.   OldNode := Values;
  909.   Values := OldNode^.Next;
  910.   TValue := OldNode^.X;
  911.   XValue := OldNode^.Y;
  912.   yPrimeValue := OldNode^.YPrime;
  913.   Dispose(OldNode);
  914. end; { procedure Pop }
  915.  
  916. procedure TestAndInitialize(LowerLimit   : Float;
  917.                             UpperLimit   : Float;
  918.                             NumReturn    : integer;
  919.                         var Spacing      : Float;
  920.                         var Values1      : Ptr;
  921.                         var Values2      : Ptr;
  922.                         var NumIntervals : integer;
  923.                         var Slope1       : Float;
  924.                         var Slope2       : Float;
  925.                         var Error        : byte);
  926.  
  927. {-------------------------------------------------------------}
  928. {- Input: LowerLimit, UpperLimit, NumReturn, Spacing         -}
  929. {- Output: Values, Spacing, Done, Slope1, Slope2, Error      -}
  930. {-                                                           -}
  931. {- This procedure initializes the above variables.  Values1  -}
  932. {- and Values2 are initialized to NIL. Spacing is            -}
  933. {- initialized to (UpperLimit - LowerLimit)/NumIntervals.    -}
  934. {- NumReturn and NumIntervals are checked for errors (they   -}
  935. {- must be greater than zero).                               -}
  936. {-------------------------------------------------------------}
  937.  
  938. begin
  939.   Error := 0;
  940.   if NumReturn <= 0 then
  941.     Error := 1;
  942.   if NumIntervals < NumReturn then
  943.     Error := 2;
  944.   if ABS(LowerLimit - UpperLimit) < TNNearlyZero then
  945.     Error := 3;
  946.   if Error = 0 then
  947.   begin
  948.     InitializeStack(Values1);
  949.     InitializeStack(Values2);
  950.     if NumIntervals < NumReturn then
  951.       NumIntervals := NumReturn;
  952.     { Adjust the Spacing so there are an integral  }
  953.     { number of sub-intervals in the interval      }
  954.     Spacing := (UpperLimit - LowerLimit) / NumIntervals;
  955.     Slope1 := 1;
  956.     Slope2 := 0;
  957.   end;
  958. end; { procedure TestAndInitialize }
  959.  
  960. procedure RungeKuttaFour(NumIntervals : integer;
  961.                          Spacing      : Float;
  962.                          LowerLimit   : Float;
  963.                          LowerInitial : Float;
  964.                          Slope        : Float;
  965.                      var Values       : Ptr;
  966.                      var UpperApprox  : Float);
  967.  
  968. {--------------------------------------------------------------}
  969. {- Input: NumIntervals, Spacing, LowerLimit, LowerLimit,      -}
  970. {-        Slope                                               -}
  971. {- Output: Values, UpperApprox                                -}
  972. {-                                                            -}
  973. {- This procedure solves a possibly non-linear 2nd order      -}
  974. {- ordinary differential equation with specified initial      -}
  975. {- conditions.                                                -}
  976. {- Given a possibly non-linear function of the form           -}
  977. {-           Y" = TNTargetF(X, Y, Y')                         -}
  978. {- and initial conditions                                     -}
  979. {-           Y[LowerLimit] = LowerInitial                     -}
  980. {-          Y'[LowerLimit] = Slope                            -}
  981. {- the Runge-Kutta one step method for two variables (Y and   -}
  982. {- Y') is used to solve for Y and Y' in the interval          -}
  983. {- [LowerLimit, UpperLimit].  The algorithm uses              -}
  984. {- sub-intervals of length Spacing. The approximation at      -}
  985. {- UpperLimit is returned as UpperApprox.                     -}
  986. {--------------------------------------------------------------}
  987.  
  988. var
  989.   Index : integer;
  990.   HalfSpacing : Float;
  991.   F1y, F2y, F3y, F4y, F1yPrime, F2yPrime, F3yPrime, F4yPrime : Float;
  992.   X, Y, YPrime : Float;
  993.  
  994. begin
  995.   X := LowerLimit;
  996.   Y := LowerInitial;
  997.   YPrime := Slope;
  998.   Push(Values, X, Y, YPrime);
  999.   HalfSpacing := Spacing/2;
  1000.   for Index := 1 to NumIntervals do
  1001.   begin
  1002.     F1y := Spacing * YPrime;
  1003.     F1yPrime := Spacing * UserFunction2(X, Y, YPrime, FuncPtr);
  1004.     F2y := Spacing * (YPrime + 0.5 * F1yPrime);
  1005.     F2yPrime := Spacing * UserFunction2(X + HalfSpacing, Y + 0.5 * F1y,
  1006.                 YPrime + 0.5 * F1yPrime, FuncPtr);
  1007.     F3y := Spacing * (YPrime + 0.5 * F2yPrime);
  1008.     F3yPrime := Spacing * UserFunction2(X + HalfSpacing, Y + 0.5 * F2y,
  1009.                 YPrime + 0.5 * F2yPrime, FuncPtr);
  1010.     F4y := Spacing * (YPrime + F3yPrime);
  1011.     F4yPrime := Spacing * UserFunction2(X + Spacing, Y + F3y,
  1012.                 YPrime + F3yPrime, FuncPtr);
  1013.  
  1014.     Y := Y + (F1y + 2 * F2y + 2 * F3y + F4y) / 6;
  1015.     YPrime := YPrime + (F1yPrime + 2 * F2yPrime + 2 * F3yPrime + F4yPrime) / 6;
  1016.     X := X + Spacing;
  1017.     Push(Values, X, Y, YPrime);
  1018.   end;
  1019.   UpperApprox := Y;
  1020. end; { procedure RungeKuttaFour }
  1021.  
  1022. procedure ComputeActualAnswer(NumIntervals : integer;
  1023.                               NumReturn    : integer;
  1024.                               UpperInitial : Float;
  1025.                               UpperApprox1 : Float;
  1026.                               UpperApprox2 : Float;
  1027.                           var Values1      : Ptr;
  1028.                           var Values2      : Ptr;
  1029.                           var XValues      : TNvector;
  1030.                           var YValues      : TNvector;
  1031.                           var YDerivValues : TNvector;
  1032.                           var Error        : byte);
  1033.  
  1034. {-------------------------------------------------------------------------}
  1035. {- Input: NumIntervals, NumReturn, UpperInitial, UpperApprox1,           -}
  1036. {-        UpperApprox2, Values1, Values2                                 -}
  1037. {- Output: XValues, YValues, YDerivValues, Error                         -}
  1038. {-                                                                       -}
  1039. {- This procedure fills in the arrays XValues, YValues and               -}
  1040. {- YDerivValues with data from the Values stack. For                     -}
  1041. {- example, if there are five times as many items on the                 -}
  1042. {- stack (NumIntervals) as should be returned (NumReturn)                -}
  1043. {- then every fifth value from the stack will be returned.               -}
  1044. {-                                                                       -}
  1045. {- A linear combination of the solutions (Values1 and Values2)           -}
  1046. {- to the two initial value problems will give the solution              -}
  1047. {- to the boundary value problem.  This procedure uses the               -}
  1048. {- equations:                                                            -}
  1049. {-                                                                       -}
  1050. {-   Multiplier1 - LowerInitial +                                        -}
  1051. {-               Multiplier2 - LowerInitial = LowerInitial               -}
  1052. {-                                                                       -}
  1053. {-   Multiplier1 - UpperApprox1 +                                        -}
  1054. {-               Multiplier2 - UpperApprox2 = UpperInitial               -}
  1055. {-                                                                       -}
  1056. {- to compute the Multipliers.  These multipliers are used to            -}
  1057. {- form the linear combination of the two solutions:                     -}
  1058. {-   YValues := Multiplier1 - Values1.Y +                                -}
  1059. {-              Multiplier2 - Values2.Y                                  -}
  1060. {-   YDerivValues := Multiplier1 - Values1.YPrime +                      -}
  1061. {-                   Mulitplier2 - Values2.YPrime                        -}
  1062. {-------------------------------------------------------------------------}
  1063.  
  1064. var
  1065.   Index, Term : integer;
  1066.   Multiplier1, Multiplier2 : Float;
  1067.   X, Y1, yPrime1, Y2, yPrime2 : Float;
  1068.  
  1069. begin
  1070.   if ABS(UpperApprox2 - UpperApprox1) > TNNearlyZero then
  1071.     begin
  1072.       Multiplier2 := (UpperInitial - UpperApprox1) /
  1073.                      (UpperApprox2- UpperApprox1);
  1074.       Multiplier1 := 1 - Multiplier2;
  1075.  
  1076.       Term := NumIntervals;
  1077.       for Index := NumReturn downto 0 do
  1078.       begin
  1079.         Pop(Values1, X, Y1, yPrime1);
  1080.         Pop(Values2, X, Y2, yPrime2);
  1081.         Term := Pred(Term);
  1082.         while (Term / NumIntervals >= Index / NumReturn) and (Term >= 0) do
  1083.         begin
  1084.           Pop(Values1, X, Y1, yPrime1);
  1085.           Pop(Values2, X, Y2, yPrime2);
  1086.           Term := Pred(Term);
  1087.         end;
  1088.         XValues[Index] := X;
  1089.         YValues[Index] := Y1 * Multiplier1 + Y2 * Multiplier2;
  1090.         YDerivValues[Index] := yPrime1 * Multiplier1 + yPrime2 * Multiplier2;
  1091.       end;
  1092.     end
  1093.   else
  1094.     Error := 4;   { Differential equation not linear  }
  1095. end;  { procedure ComputeActualAnswer }
  1096.  
  1097. begin  { procedure LinearShooting }
  1098.   TestAndInitialize(LowerLimit, UpperLimit, NumReturn, Spacing, Values1,
  1099.                     Values2, NumIntervals, Slope1, Slope2, Error);
  1100.   if Error = 0 then
  1101.   begin
  1102.     RungeKuttaFour(NumIntervals, Spacing, LowerLimit, LowerInitial,
  1103.                    Slope1, Values1, UpperApprox1);
  1104.     RungeKuttaFour(NumIntervals, Spacing, LowerLimit, LowerInitial,
  1105.                    Slope2, Values2, UpperApprox2);
  1106.     ComputeActualAnswer(NumIntervals, NumReturn,
  1107.                         UpperInitial, UpperApprox1, UpperApprox2, Values1,
  1108.                         Values2, XValues, YValues, YDerivValues, Error);
  1109.   end;
  1110. end; { procedure LinearShooting }
  1111.