xref: /csrg-svn/usr.bin/pascal/pdx/test/parall.p (revision 62158)
148082Sbostic(*
2*62158Sbostic * Copyright (c) 1980, 1993
3*62158Sbostic *	The Regents of the University of California.  All rights reserved.
448082Sbostic *
548082Sbostic * %sccs.include.redist.c%
648082Sbostic *
7*62158Sbostic *	@(#)parall.p	8.1 (Berkeley) 06/06/93
848082Sbostic *)
948082Sbostic
1048082Sbosticprogram Parall(input,output);
1148082Sbostic
1248082Sbostic{Declare constants for unit conversions, convergence tests, etc.}
1348082Sbostic
1448082Sbosticconst	SQRT2 = 1.4142136;	{Square root of 2}
1548082Sbostic	TWOPI = 6.2831853;	{Two times pi}
1648082Sbostic	MINALPHA = 0.001;	{Minimum y-step size}
1748082Sbostic	ROUGHLYZERO = 0.001;	{Approximation to zero for convergence}
1848082Sbostic	YTHRESHOLD = 40.0;	{Heuristic constant for thresholding}
1948082Sbostic	N = 8;			{Vector and matrix dimension}
2048082Sbostic
2148082Sbostic
2248082Sbostic{Declare types for circuit elements, vectors, and matrices.}
2348082Sbostic
2448082Sbostictype	VSOURCE = record
2548082Sbostic			ampl: real;	 {Volts (peak)}
2648082Sbostic			freq: real;	 {Radians/second}
2748082Sbostic			xindex: integer;	{Index for x value}
2848082Sbostic			yindex: integer;	{Index for y value}
2948082Sbostic		  end;
3048082Sbostic
3148082Sbostic	RLPAIR = record
3248082Sbostic			r: real;	 {Ohms}
3348082Sbostic			l: real;	 {Henries}
3448082Sbostic			islope: real;	 {Amps/second}
3548082Sbostic			invariant: real; {Trapezoidal invariant}
3648082Sbostic			lasttime: real;  {Most recent time}
3748082Sbostic			xindex: array [1..2] of integer;  {x value indices}
3848082Sbostic			yindex: array [1..2] of integer;  {y value indices}
3948082Sbostic		 end;
4048082Sbostic
4148082Sbostic	CAPACITOR = record
4248082Sbostic			c: real;	 {Farads}
4348082Sbostic			vslope: real;	 {Volts/second}
4448082Sbostic			invariant: real; {Trapezoidal invariant}
4548082Sbostic			lasttime: real;  {Most recent time}
4648082Sbostic			xindex: array [1..2] of integer;  {x value indices}
4748082Sbostic			yindex: array [1..2] of integer;  {y value indices}
4848082Sbostic		    end;
4948082Sbostic
5048082Sbostic	VECTOR = array [1..N] of real;
5148082Sbostic
5248082Sbostic	MATRIX = array [1..N,1..N] of real;
5348082Sbostic
5448082Sbostic
5548082Sbostic{Declare global variables for central simulation information.}
5648082Sbostic
5748082Sbosticvar	ground: VSOURCE;	{Ground -- a fake source}
5848082Sbostic	itcount: integer;	{Main routine iteration count}
5948082Sbostic	update: integer;	{Update loop counter for main}
6048082Sbostic	optimcount: integer;	{Number of optimization steps}
6148082Sbostic	newtoncount: integer;	{Number of Newton steps}
6248082Sbostic	v1: VSOURCE;		{Voltage source V1}
6348082Sbostic	rl1: RLPAIR;		{R1/L1 resistor-inductor pair}
6448082Sbostic	rl2: RLPAIR;		{R2/L2 resistor-inductor pair}
6548082Sbostic	c1: CAPACITOR;		{Capacitor C1}
6648082Sbostic	a: MATRIX;		{Global matrix A}
6748082Sbostic	b: MATRIX;		{Global matrix B}
6848082Sbostic	jac: MATRIX;		{Global Jacobian matrix}
6948082Sbostic	x: VECTOR;		{Global vector of dependents}
7048082Sbostic	xnext: VECTOR;		{Next x-vector for simulation}
7148082Sbostic	y: VECTOR;		{Global vector of independents}
7248082Sbostic	ynext: VECTOR;		{Next y-vector for simulation}
7348082Sbostic	gradient: VECTOR;	{Global gradient vector}
7448082Sbostic	h: real;		{Time step value}
7548082Sbostic	time: real;		{Current time}
7648082Sbostic	lastychange: real;	{YStep's most recent y-change}
7748082Sbostic	timestep: integer;	{Current timestep number}
7848082Sbostic	maxsteps: integer;	{Number of time steps to run}
7948082Sbostic        oldxnorm: real;		{Old one-norm of x-vector}
8048082Sbostic	newxnorm: real;		{New one-norm of x-vector}
8148082Sbostic	closenough: boolean;   	{Flag to indicate convergence}
8248082Sbostic
8348082Sbostic
8448082Sbostic
8548082Sbostic
8648082Sbostic{The following procedure initializes everything for the program based
8748082Sbostic on the little test circuit suggested by Sarosh.  The user is asked
8848082Sbostic to specify the simulation and circuit parameters, and then the matrix
8948082Sbostic and vector values are set up.}
9048082Sbostic
9148082Sbosticprocedure InitializeEverything;
9248082Sbosticvar i,j: integer;
9348082Sbostic    rtemp: real;
9448082Sbosticbegin
9548082Sbostic
9648082Sbostic{Ready the input and output files (almost nil for Berkeley).}
9748082Sbosticwriteln(output);
9848082Sbosticwriteln(output,'*** Simulation Output Record ***');
9948082Sbosticwriteln(output);
10048082Sbosticwriteln(output);
10148082Sbostic
10248082Sbostic{Initialize convergence test/indication variables.}
10348082Sbosticoldxnorm := 0.0;
10448082Sbosticnewxnorm := 0.0;
10548082Sbosticlastychange := 0.0;
10648082Sbostic
10748082Sbostic{Get desired time step size for simulation.}
10848082Sbosticreadln(input,h);
10948082Sbosticwriteln(output,'h (Seconds): ',h:12:7);
11048082Sbostic
11148082Sbostic{Get desired number of time steps for simulation.}
11248082Sbosticreadln(input,maxsteps);
11348082Sbosticwriteln(output,'maxsteps: ',maxsteps:4);
11448082Sbostic
11548082Sbostic{Get parameters for source V1 and initialize the source.}
11648082Sbosticwith v1 do
11748082Sbostic   begin
11848082Sbostic   readln(input,rtemp);
11948082Sbostic   writeln(output,'V1 (Volts RMS): ',rtemp:9:3);
12048082Sbostic   ampl := rtemp * SQRT2;
12148082Sbostic   readln(input,rtemp);
12248082Sbostic   writeln(output,'f (Hertz): ',rtemp:9:3);
12348082Sbostic   freq := rtemp * TWOPI;
12448082Sbostic   xindex := 1;
12548082Sbostic   yindex := 1;
12648082Sbostic   end;
12748082Sbostic
12848082Sbostic{Get parameters for R1/L1 pair and initialize the pair.}
12948082Sbosticwith rl1 do
13048082Sbostic   begin
13148082Sbostic   readln(input,r);
13248082Sbostic   writeln(output,'R1 (Ohms): ',r:9:3);
13348082Sbostic   readln(input,l);
13448082Sbostic   writeln(output,'L1 (Henries): ',l:12:7);
13548082Sbostic   islope := 0.0;
13648082Sbostic   invariant := 0.0;
13748082Sbostic   lasttime := -1.0;        {Negative to force first update}
13848082Sbostic   xindex[1] := 2;
13948082Sbostic   yindex[1] := 2;
14048082Sbostic   xindex[2] := 3;
14148082Sbostic   yindex[2] := 3;
14248082Sbostic   end;
14348082Sbostic
14448082Sbostic{Get parameters for R2/L2 pair and initialize the pair.}
14548082Sbosticwith rl2 do
14648082Sbostic   begin
14748082Sbostic   readln(input,r);
14848082Sbostic   writeln(output,'R2 (Ohms): ',r:9:3);
14948082Sbostic   readln(input,l);
15048082Sbostic   writeln(output,'L2 (Henries): ',l:12:7);
15148082Sbostic   islope := 0.0;
15248082Sbostic   invariant := 0.0;
15348082Sbostic   lasttime := -1.0;	   {Negative to force first update}
15448082Sbostic   xindex[1] := 4;
15548082Sbostic   yindex[1] := 4;
15648082Sbostic   xindex[2] := 5;
15748082Sbostic   yindex[2] := 5;
15848082Sbostic   end;
15948082Sbostic
16048082Sbostic{Get parameters for capacitor C1 and initialize the device.}
16148082Sbosticwith c1 do
16248082Sbostic   begin
16348082Sbostic   readln(input,c);
16448082Sbostic   writeln(output,'C1 (Farads): ',c:12:7);
16548082Sbostic   vslope := 0.0;
16648082Sbostic   invariant := 0.0;
16748082Sbostic   lasttime := -1.0;	   {Negative to force first update}
16848082Sbostic   xindex[1] := 6;
16948082Sbostic   yindex[1] := 6;
17048082Sbostic   xindex[2] := 7;
17148082Sbostic   yindex[2] := 7;
17248082Sbostic   end;
17348082Sbostic
17448082Sbostic{Initialize the ground node.}
17548082Sbosticwith ground do
17648082Sbostic   begin
17748082Sbostic   ampl := 0.0;
17848082Sbostic   freq := 0.0;
17948082Sbostic   xindex := 8;
18048082Sbostic   yindex := 8;
18148082Sbostic   end;
18248082Sbostic
18348082Sbostic{Zero out all the vectors and matrices.}
18448082Sbosticfor i := 1 to N do
18548082Sbostic   begin
18648082Sbostic   x[i] := 0.0;
18748082Sbostic   y[i] := 0.0;
18848082Sbostic   for j := 1 to N do
18948082Sbostic      begin
19048082Sbostic      a[i,j] := 0.0;
19148082Sbostic      b[i,j] := 0.0;
19248082Sbostic      jac[i,j] := 0.0;
19348082Sbostic      end;
19448082Sbostic   end;
19548082Sbostic
19648082Sbostic{Initialize the A matrix.}
19748082Sbostica[1,2] := -1.0;
19848082Sbostica[2,3] := 1.0;
19948082Sbostica[2,4] := -1.0;
20048082Sbostica[3,5] := 1.0;
20148082Sbostica[4,7] := 1.0;
20248082Sbostica[5,1] := 1.0;
20348082Sbostica[7,6] := 1.0;
20448082Sbostica[8,8] := 1.0;
20548082Sbostic
20648082Sbostic{Initialize the B matrix.}
20748082Sbosticb[1,1] := 1.0;
20848082Sbosticb[3,7] := -1.0;
20948082Sbosticb[4,8] := -1.0;
21048082Sbosticb[5,2] := 1.0;
21148082Sbosticb[6,3] := 1.0;
21248082Sbosticb[6,4] := 1.0;
21348082Sbosticb[7,5] := 1.0;
21448082Sbosticb[8,6] := 1.0;
21548082Sbostic
21648082Sbostic{Initialize the Jacobian matrix.}
21748082Sbosticrtemp := h / (2.0 * rl1.l  +  rl1.r * h);
21848082Sbosticjac[2,2] := rtemp;
21948082Sbosticjac[3,3] := rtemp;
22048082Sbosticjac[2,3] := -rtemp;
22148082Sbosticjac[3,2] := -rtemp;
22248082Sbosticrtemp := h / (2.0 * rl2.l  +  rl2.r * h);
22348082Sbosticjac[4,4] := rtemp;
22448082Sbosticjac[5,5] := rtemp;
22548082Sbosticjac[4,5] := -rtemp;
22648082Sbosticjac[5,4] := -rtemp;
22748082Sbosticjac[6,6] := -1.0;
22848082Sbosticjac[7,7] := 1.0;
22948082Sbosticjac[7,6] := h / (2.0 * c1.c);
23048082Sbosticend;
23148082Sbostic
23248082Sbostic
23348082Sbostic
23448082Sbostic
23548082Sbostic{The following procedure solves the equation Ax=b for an N x N system
23648082Sbostic of linear equations, where A is the coefficient matrix, b is the
23748082Sbostic right-hand-side vector, and x is the vector of unknowns.  Gaussian
23848082Sbostic elimination with maximal column pivots is used.                     }
23948082Sbostic
24048082Sbosticprocedure Solve(a: MATRIX; b: VECTOR; var x: VECTOR);
24148082Sbosticvar y,z: real;
24248082Sbostic    i,j,k,k1: integer;
24348082Sbosticbegin
24448082Sbosticfor k := 1 to N-1 do
24548082Sbostic   begin
24648082Sbostic   y := abs(a[k,k]);
24748082Sbostic   j := k;
24848082Sbostic   k1 := k + 1;
24948082Sbostic   for i := k1 to N do
25048082Sbostic      if abs(a[i,k]) > y then
25148082Sbostic         begin
25248082Sbostic         j := i;
25348082Sbostic         y := abs(a[i,k]);
25448082Sbostic         end;
25548082Sbostic   for i := k to N do
25648082Sbostic      begin
25748082Sbostic      y := a[k,i];
25848082Sbostic      a[k,i] := a[j,i];
25948082Sbostic      a[j,i] := y;
26048082Sbostic      end;
26148082Sbostic   y := b[k];
26248082Sbostic   b[k] := b[j];
26348082Sbostic   b[j] := y;
26448082Sbostic   z := a[k,k];
26548082Sbostic   for i := k1 to N do
26648082Sbostic      begin
26748082Sbostic      y := a[i,k] / z;
26848082Sbostic      a[i,k] := y;
26948082Sbostic      for j := k1 to N do a[i,j] := a[i,j]  -  y * a[k,j];
27048082Sbostic      b[i] := b[i] - y * b[k];
27148082Sbostic      end;
27248082Sbostic   end;
27348082Sbosticx[N] := b[N] / a[N,N];
27448082Sbosticfor i := N-1 downto 1 do
27548082Sbostic   begin
27648082Sbostic   y := b[i];
27748082Sbostic   for j := i+1 to N do y := y  -  a[i,j] * x[j];
27848082Sbostic   x[i] := y / a[i,i];
27948082Sbostic   end;
28048082Sbosticend;
28148082Sbostic
28248082Sbostic
28348082Sbostic{The following procedure computes and returns a vector called "deltay",
28448082Sbostic which is the change in the y-vector prescribed by the Newton-Rhapson
28548082Sbostic algorithm.}
28648082Sbostic
28748082Sbosticprocedure NewtonStep(var deltay: VECTOR);
28848082Sbosticvar phi: VECTOR;
28948082Sbostic    m: MATRIX;
29048082Sbostic    i,j,k: integer;
29148082Sbosticbegin
29248082Sbosticfor i := 1 to N do
29348082Sbostic   begin
29448082Sbostic   phi[i] := 0.0;
29548082Sbostic   for j := 1 to N do
29648082Sbostic      begin
29748082Sbostic      phi[i] := phi[i]  +  a[i,j] * y[j]  +  b[i,j] * x[j];
29848082Sbostic      m[i,j] := -a[i,j];
29948082Sbostic      for k := 1 to N do m[i,j] := m[i,j] - b[i,k] * jac[k,j];
30048082Sbostic      end;
30148082Sbostic
30248082Sbostic   end;
30348082SbosticSolve(m,phi,deltay);
30448082Sbosticend;
30548082Sbostic
30648082Sbostic
30748082Sbostic
30848082Sbostic
30948082Sbostic{The following function computes the value of theta, the objective
31048082Sbostic function, given the x and y vectors.}
31148082Sbostic
31248082Sbosticfunction ThetaValue(x,y: VECTOR): real;
31348082Sbosticvar i,j: integer;
31448082Sbostic    phielem: real;
31548082Sbostic    theta: real;
31648082Sbosticbegin
31748082Sbostictheta := 0.0;
31848082Sbosticfor i:= 1 to N do
31948082Sbostic   begin
32048082Sbostic   phielem := 0.0;
32148082Sbostic   for j := 1 to N do
32248082Sbostic      phielem := phielem  +  a[i,j] * y[j]  +  b[i,j] * x[j];
32348082Sbostic   theta := theta  +  phielem * phielem;
32448082Sbostic   end;
32548082SbosticThetaValue := theta;
32648082Sbosticend;
32748082Sbostic
32848082Sbostic
32948082Sbostic{The following function computes the theta value associated with a
33048082Sbostic proposed step of size alpha in the direction of the gradient.}
33148082Sbostic
33248082Sbosticfunction Theta(alpha: real): real;
33348082Sbosticvar ythere: VECTOR;
33448082Sbostic    i: integer;
33548082Sbosticbegin
33648082Sbosticfor i := 1 to N do
33748082Sbostic   ythere[i] := y[i]  -  alpha * gradient[i];
33848082SbosticTheta := ThetaValue(x,ythere);
33948082Sbosticend;
34048082Sbostic
34148082Sbostic
34248082Sbostic{The following procedure computes the gradient of the objective
34348082Sbostic function (theta) with respect to the vector y.}
34448082Sbostic
34548082Sbosticprocedure ComputeGradient;
34648082Sbosticvar i,j,k: integer;
34748082Sbostic    m: MATRIX;
34848082Sbostic    v: VECTOR;
34948082Sbosticbegin
35048082Sbostic{Compute v = Ay + Bx and M = A' + J'B'.}
35148082Sbosticfor i := 1 to N do
35248082Sbostic   begin
35348082Sbostic   v[i] := 0.0;
35448082Sbostic   for j := 1 to N do
35548082Sbostic      begin
35648082Sbostic      v[i] := v[i]  +  a[i,j] * y[j]  +  b[i,j] * x[j];
35748082Sbostic      m[i,j] := a[j,i];
35848082Sbostic      for k := 1 to N do
35948082Sbostic         m[i,j] := m[i,j]  +  jac[k,i] * b[j,k];
36048082Sbostic      end;
36148082Sbostic   end;
36248082Sbostic{Compute gradient = 2Mv.}
36348082Sbosticfor i := 1 to N do
36448082Sbostic   begin
36548082Sbostic   gradient[i] := 0.0;
36648082Sbostic   for j := 1 to N do
36748082Sbostic      gradient[i] := gradient[i]  +  m[i,j] * v[j];
36848082Sbostic   gradient[i] := 2.0 * gradient[i];
36948082Sbostic   end;
37048082Sbosticend;
37148082Sbostic
37248082Sbostic
37348082Sbostic{The following procedure computes the bounds on alpha, the step size
37448082Sbostic to take in the gradient direction.  The bounding is done according
37548082Sbostic to an algorithm suggested in S.W.Director's text on circuits.}
37648082Sbostic
37748082Sbosticprocedure GetAlphaBounds(var lower,upper: real);
37848082Sbosticvar alpha: real;
37948082Sbostic    oldtheta,newtheta: real;
38048082Sbosticbegin
38148082Sbosticif ThetaValue(x,y) = 0.0
38248082Sbostic   then
38348082Sbostic      begin
38448082Sbostic      lower := 0;
38548082Sbostic
38648082Sbostic      upper := 0;
38748082Sbostic      end
38848082Sbostic   else
38948082Sbostic      begin
39048082Sbostic      lower := MINALPHA;
39148082Sbostic      oldtheta := Theta(lower);
39248082Sbostic      upper := MINALPHA * 2.0;
39348082Sbostic      newtheta := Theta(upper);
39448082Sbostic      if newtheta <= oldtheta then
39548082Sbostic         begin
39648082Sbostic         alpha := upper;
39748082Sbostic         repeat
39848082Sbostic            begin
39948082Sbostic            oldtheta := newtheta;
40048082Sbostic            alpha := alpha * 2.0;
40148082Sbostic            newtheta := Theta(alpha);
40248082Sbostic            end
40348082Sbostic         until (newtheta > oldtheta);
40448082Sbostic         lower := alpha / 4.0;
40548082Sbostic         upper := alpha;
40648082Sbostic         end;
40748082Sbostic      end;
40848082Sbosticend;
40948082Sbostic
41048082Sbostic
41148082Sbostic{The following function computes the best value of alpha for the step
41248082Sbostic in the gradient direction.  This best value is the value that minimizes
41348082Sbostic theta along the gradient-directed path.}
41448082Sbostic
41548082Sbosticfunction BestAlpha(lower,upper: real): real;
41648082Sbosticvar alphaL,alphaU,alpha1,alpha2: real;
41748082Sbostic    thetaL,thetaU,theta1,theta2: real;
41848082Sbostic
41948082Sbosticbegin
42048082SbosticalphaL := lower;
42148082SbosticthetaL := Theta(alphaL);
42248082SbosticalphaU := upper;
42348082SbosticthetaU := Theta(alphaU);
42448082Sbosticalpha1 := 0.381966 * alphaU  +  0.618034 * alphaL;
42548082Sbostictheta1 := Theta(alpha1);
42648082Sbosticalpha2 := 0.618034 * alphaU  +  0.381966 * alphaL;
42748082Sbostictheta2 := Theta(alpha2);
42848082Sbosticrepeat
42948082Sbostic   if theta1 < theta2
43048082Sbostic      then
43148082Sbostic         begin
43248082Sbostic         alphaU := alpha2;
43348082Sbostic         thetaU := theta2;
43448082Sbostic         alpha2 := alpha1;
43548082Sbostic         theta2 := theta1;
43648082Sbostic         alpha1 := 0.381966 * alphaU  +  0.618034 * alphaL;
43748082Sbostic         theta1 := Theta(alpha1);
43848082Sbostic         end
43948082Sbostic      else
44048082Sbostic         begin
44148082Sbostic         alphaL := alpha1;
44248082Sbostic         thetaL := theta1;
44348082Sbostic         alpha1 := alpha2;
44448082Sbostic         theta1 := theta2;
44548082Sbostic         alpha2 := 0.618034 * alphaU  +  0.381966 * alphaL;
44648082Sbostic         theta2 := Theta(alpha2);
44748082Sbostic         end
44848082Sbosticuntil abs(thetaU - thetaL) <= ROUGHLYZERO;
44948082SbosticBestAlpha := (alphaL + alphaU) / 2.0;
45048082Sbosticend;
45148082Sbostic
45248082Sbostic
45348082Sbostic{The following procedure computes and returns a vector called "deltay",
45448082Sbostic which is the change in the y-vector prescribed by the steepest-descent
45548082Sbostic approach.}
45648082Sbostic
45748082Sbosticprocedure OptimizationStep(var deltay: VECTOR);
45848082Sbosticvar lower,upper: real;
45948082Sbostic    alpha: real;
46048082Sbostic    i: integer;
46148082Sbosticbegin
46248082SbosticComputeGradient;
46348082SbosticGetAlphaBounds(lower,upper);
46448082Sbosticif lower <> upper then
46548082Sbostic   begin
46648082Sbostic   alpha := BestAlpha(lower,upper);
46748082Sbostic   for i:= 1 to N do deltay[i] := - alpha * gradient[i];
46848082Sbostic   end;
46948082Sbosticend;
47048082Sbostic
47148082Sbostic
47248082Sbostic
47348082Sbostic
47448082Sbostic{The following function computes the one-norm of a vector argument.
47548082Sbostic The length of the argument vector is assumed to be N.}
47648082Sbostic
47748082Sbosticfunction OneNorm(vec: VECTOR): real;
47848082Sbosticvar sum: real;
47948082Sbostic    i: integer;
48048082Sbosticbegin
48148082Sbosticsum := 0;
48248082Sbosticfor i := 1 to N do  sum := sum + abs(vec[i]);
48348082SbosticOneNorm := sum;
48448082Sbosticend;
48548082Sbostic
48648082Sbostic
48748082Sbostic{The following procedure takes a y-step, using the optimization
48848082Sbosticapproach when far from the solution and the Newton-Rhapson approach
48948082Sbosticwhen fairly close to the solution.}
49048082Sbostic
49148082Sbosticprocedure YStep;
49248082Sbosticvar deltay: VECTOR;
49348082Sbostic    ychange: real;
49448082Sbostic    scale: real;
49548082Sbostic    i: integer;
49648082Sbosticbegin
49748082SbosticNewtonStep(deltay);
49848082Sbosticychange := OneNorm(deltay);
49948082Sbosticif ychange > YTHRESHOLD
50048082Sbostic   then
50148082Sbostic{
50248082Sbostic      begin
50348082Sbostic      OptimizationStep(deltay);
50448082Sbostic      ychange := OneNorm(deltay);
50548082Sbostic      if ychange > YTHRESHOLD then
50648082Sbostic}
50748082Sbostic         begin
50848082Sbostic         scale := YTHRESHOLD/ychange;
50948082Sbostic         for i := 1 to N do deltay[i] := scale * deltay[i];
51048082Sbostic	 optimcount := optimcount + 1;
51148082Sbostic	 end	 	{;}
51248082Sbostic{
51348082Sbostic      optimcount := optimcount + 1;
51448082Sbostic      end
51548082Sbostic}
51648082Sbostic   else
51748082Sbostic      begin
51848082Sbostic      newtoncount := newtoncount + 1;
51948082Sbostic      end;
52048082Sbosticfor i := 1 to N do ynext[i] := y[i] + deltay[i];
52148082Sbosticend;
52248082Sbostic
52348082Sbostic
52448082Sbostic
52548082Sbostic
52648082Sbostic{The following procedure updates the output of a voltage source
52748082Sbostic given the current time.}
52848082Sbostic
52948082Sbosticprocedure VsourceStep(vn: VSOURCE);
53048082Sbosticbegin
53148082Sbosticwith vn do
53248082Sbostic   xnext[xindex] := ampl * sin(freq * time);
53348082Sbosticend;
53448082Sbostic
53548082Sbostic
53648082Sbostic{The following procedure updates the outputs of a resistor-inductor
53748082Sbostic pair given the time step to take...that is, this routine takes a
53848082Sbostic time step for resistor-inductor pairs.  The new outputs are found
53948082Sbostic by applying the trapezoidal rule.}
54048082Sbostic
54148082Sbosticprocedure RLPairStep(var rln: RLPAIR);
54248082Sbosticbegin
54348082Sbosticwith rln do
54448082Sbostic   begin
54548082Sbostic   if (time > lasttime) then
54648082Sbostic      begin
54748082Sbostic      lasttime := time;
54848082Sbostic      invariant := xnext[xindex[1]]  +  (h / 2.0) * islope;
54948082Sbostic      end;
55048082Sbostic   islope := (y[yindex[1]]  -  y[yindex[2]]  -  r * xnext[xindex[1]]) / l;
55148082Sbostic   xnext[xindex[1]] := invariant  +  (h / 2.0) * islope;
55248082Sbostic   xnext[xindex[2]] := - xnext[xindex[1]];
55348082Sbostic   end;
55448082Sbosticend;
55548082Sbostic
55648082Sbostic
55748082Sbostic{The following procedure updates the outputs of a capacitor given the
55848082Sbostic time step...it takes the time step using a trapezoidal rule iteration.}
55948082Sbostic
56048082Sbosticprocedure CapacitorStep(var cn: CAPACITOR);
56148082Sbosticvar v: real;
56248082Sbosticbegin
56348082Sbosticwith cn do
56448082Sbostic   begin
56548082Sbostic   if (time > lasttime) then
56648082Sbostic      begin
56748082Sbostic      lasttime := time;
56848082Sbostic      v := xnext[xindex[2]]  -  y[yindex[2]];
56948082Sbostic      invariant := v  +  (h / 2.0) * vslope;
57048082Sbostic      end;
57148082Sbostic   vslope := y[yindex[1]] / c;
57248082Sbostic   v := invariant  +  (h / 2.0) * vslope;
57348082Sbostic   xnext[xindex[1]] := - y[yindex[1]];
57448082Sbostic   xnext[xindex[2]] := y[yindex[2]] + v;
57548082Sbostic   end;
57648082Sbosticend;
57748082Sbostic
57848082Sbostic
57948082Sbostic{The following procedure controls the overall x-step for the
58048082Sbostic specific circuit to be simulated.}
58148082Sbostic
58248082Sbosticprocedure XStep;
58348082Sbosticbegin
58448082SbosticVsourceStep(v1);
58548082SbosticRLPairStep(rl1);
58648082SbosticRLPairStep(rl2);
58748082SbosticCapacitorStep(c1);
58848082SbosticVsourceStep(ground);
58948082Sbosticend;
59048082Sbostic
59148082Sbostic
59248082Sbostic
59348082Sbostic
59448082Sbostic{The following procedure prints out the values of all the voltages and
59548082Sbostic currents for the circuit at each time step.}
59648082Sbostic
59748082Sbosticprocedure PrintReport;
59848082Sbosticbegin
59948082Sbosticwriteln(output);
60048082Sbosticwriteln(output);
60148082Sbosticwriteln(output,'REPORT at Time = ',time:8:5,' seconds');
60248082Sbosticwriteln(output,'Number of iterations used: ',itcount:2);
60348082Sbosticwriteln(output,'Number of truncations: ',optimcount:2);
60448082Sbosticwriteln(output,'Number of Newton y-steps: ',newtoncount:2);
60548082Sbosticwriteln(output,'The voltages and currents are:');
60648082Sbosticwriteln(output,'  V1 = ',x[1]:12:7,'   I1 = ',y[1]:12:7);
60748082Sbosticwriteln(output,'  V2 = ',y[2]:12:7,'   I2 = ',x[2]:12:7);
60848082Sbosticwriteln(output,'  V3 = ',y[3]:12:7,'   I3 = ',x[3]:12:7);
60948082Sbosticwriteln(output,'  V4 = ',y[4]:12:7,'   I4 = ',x[4]:12:7);
61048082Sbosticwriteln(output,'  V5 = ',y[5]:12:7,'   I5 = ',x[5]:12:7);
61148082Sbosticwriteln(output,'  V6 = ',x[7]:12:7,'   I6 = ',y[6]:12:7);
61248082Sbosticwriteln(output,'  V7 = ',y[7]:12:7,'   I7 = ',x[6]:12:7);
61348082Sbosticwriteln(output,'  V8 = ',x[8]:12:7,'   I8 = ',y[8]:12:7);
61448082Sbosticend;
61548082Sbostic
61648082Sbostic
61748082Sbostic
61848082Sbostic
61948082Sbostic{Finally, the main routine controls the whole simulation process.}
62048082Sbostic
62148082Sbosticbegin
62248082SbosticInitializeEverything;
62348082SbosticPrintReport;
62448082Sbosticfor timestep := 1 to maxsteps do
62548082Sbostic   begin
62648082Sbostic   itcount := 0;
62748082Sbostic   optimcount := 0;
62848082Sbostic   newtoncount := 0;
62948082Sbostic   closenough := FALSE;
63048082Sbostic   time := h * timestep;
63148082Sbostic   repeat
63248082Sbostic      begin
63348082Sbostic      itcount := itcount + 1;
63448082Sbostic      YStep;
63548082Sbostic      XStep;
63648082Sbostic      for update := 1 to N do
63748082Sbostic	 begin
63848082Sbostic	 x[update] := xnext[update];
63948082Sbostic	 y[update] := ynext[update];
64048082Sbostic	 end;
64148082Sbostic      oldxnorm := newxnorm;
64248082Sbostic      newxnorm := OneNorm(x);
64348082Sbostic      if abs(newxnorm - oldxnorm) <= ROUGHLYZERO
64448082Sbostic         then closenough := TRUE;
64548082Sbostic      end;
64648082Sbostic      if itcount < 4 then closenough := FALSE;
64748082Sbostic   until (itcount = 25) or closenough;
64848082Sbostic   PrintReport;
64948082Sbostic   end;
65048082Sbosticend.
65148082Sbostic
652