<> <> <> <> <> <> <> <> DIRECTORY BasicTime USING [GMT, Now], Convert USING [RopeFromReal, RopeFromTime], FS USING [StreamOpen], Graph USING [Entity, EntityGroup, EntityHash, EntityHashSize, EntityList, EntityRec, GRAPH, GraphHandle, NestedEntities, NestedEntitiesList, NestedEntitiesRec, SegmentDataList, SegmentDataRec, ValueList], GraphOps USING [AddCurve, AddText, AppendValues, Lock, NewGraph, Unlock], GraphPrivate USING [PaintLegend, PaintTails, PaintAll], GraphUtil USING [Almost, AppendX, AppendY], IO USING [int, PutF, PutFR, real, Reset, rope, STREAM, time], Labels USING [Set], Process USING [Yield], Rope USING [Concat, Cat, FromRefText, ROPE], ThymeGlobals USING [argument, argumentPtr, branchPtr, conLinkPtr, Error, FindNodeOrBranch, FlushCloseNil, GetSignedNumber, Handle, instTreePtr, MakeStringNB, maxPlots, maxPrints, namePtr, Next, nodePtr, OutputFileRoot, plotBlkPtr, plotBlk, printBlk, printBlkPtr, RefC, RefCircuitRec, RefCktInstRec, RefI, RefL, RefR, RefV, version], ViewerTools USING [GetContents]; ThymeOutput: CEDAR PROGRAM IMPORTS BasicTime, Convert, FS, GraphOps, GraphPrivate, GraphUtil, IO, Labels, Process, Rope, ThymeGlobals, ViewerTools EXPORTS ThymeGlobals = BEGIN OPEN ThymeGlobals; nodeComment: Rope.ROPE = ": node"; InitPP: PUBLIC PROC[handle: Handle, tMin, tMax: REAL] = { OPEN handle.vars; file: Rope.ROPE _ Rope.Concat[OutputFileRoot[handle], ".graph"]; tid: INT _ -1; [graphHandle, ] _ GraphOps.NewGraph[ fileName: file, comment: title, xName: Rope.Cat["Time[", Unit[tUnit, "S"], "]"], bounds: [tMin/tUnit, yMin, tMax/tUnit, yMax] ]; GraphOps.Lock[graphHandle]; graphHandle.chart.viewer.inhibitDestroy _ TRUE; <> [] _ GraphOps.AddText[handle: graphHandle, rope: title, place: [0.5, 1.1], fontIndex: 2, justifX: center, justifY: bottom]; [] _ GraphOps.AddText[handle: graphHandle, rope: file, place: [0, -0.35], fontIndex: 1, justifX: left, justifY: bottom]; [] _ GraphOps.AddText[handle: graphHandle, rope: Convert.RopeFromTime[from: simTime, includeDayOfWeek: TRUE], place: [1.0, -0.35], fontIndex: 1, justifX: right, justifY: bottom]; [] _ GraphOps.AddText[handle: graphHandle, rope: Rope.Cat["[", Unit[tUnit, "S"], "]"], place: [1.01, 0.0], justifX: left, justifY: bottom]; [] _ GraphOps.AddText[handle: graphHandle, rope: Rope.Cat["[", Unit[vUnit, "V"], ", ", Unit[iUnit, "A"], "]"], place: [0.0, 1.01], justifX: left, justifY: bottom]; GraphOps.Unlock[graphHandle]; GraphPrivate.PaintAll[graphHandle, TRUE, FALSE, TRUE]; }; -- InitPP Unit: PROC [unit: REAL, base: Rope.ROPE] RETURNS [Rope.ROPE] = { dUnit: REAL _ SELECT unit FROM > 30.0 => 1.0e3, > 30.0e-3 => 1.0, > 30.0e-6 => 1.0e-3, > 30.0e-9 => 1.0e-6, ENDCASE => 1.0e-9; mul: Rope.ROPE _ SELECT dUnit FROM 1.0e3 => "k", 1.0 => "", 1.0e-3 => "m", 1.0e-6 => "u", ENDCASE => "n"; RETURN[Rope.Cat[ IF GraphUtil.Almost[unit, dUnit] THEN "" ELSE Convert.RopeFromReal[unit/dUnit], mul, base]]; }; -- Unit InitNE: PROC [handle: Handle, t: REAL] = { EnlistTree: PROC[tree: instTreePtr, group: Graph.EntityGroup, parent: Graph.NestedEntities, hash: Graph.EntityHash, lastId: INT, graph: Graph.GRAPH] RETURNS [newLastId: INT, ne: Graph.NestedEntities _ NIL] = { lastChild, nel: Graph.NestedEntitiesList _ NIL; newLastId _ lastId; ne _ NEW[Graph.NestedEntitiesRec _ [parent: parent]]; IF parent # NIL THEN { cktInst: RefCktInstRec _ NARROW[tree.instance.details]; cktInstOfDetails: RefCircuitRec _ NARROW[cktInst.of.details]; ne.name _ tree.instance.name; ne.comment _ IO.PutFR[": %g[%g]", IO.rope[cktInst.of.name], IO.rope[Arguments[cktInst.connections, cktInstOfDetails.fakeNodes]] ]; }; newLastId _ EnlistNB[tree, group, ne, hash, newLastId, graph]; FOR i: instTreePtr _ tree.sons, i.brothers UNTIL i=NIL DO child: Graph.NestedEntities; [newLastId, child] _ EnlistTree[i, group, ne, hash, newLastId, graph]; nel _ CONS[child, NIL]; IF lastChild = NIL THEN ne.children _ nel ELSE lastChild.rest _ nel; lastChild _ nel; ENDLOOP; }; -- EnlistTree EnlistNB: PROC[tree: instTreePtr, group: Graph.EntityGroup, parent: Graph.NestedEntities, hash: Graph.EntityHash, lastId: INT, graph: Graph.GRAPH] RETURNS [newLastId: INT] = { PlotIt: PROC [entity: Graph.Entity] = { <> lel: Graph.EntityList _ CONS[entity, NIL]; sdl: Graph.SegmentDataList _ CONS[ NEW[Graph.SegmentDataRec _ [end: entity.oldValues.first]], NIL]; entity.segments _ entity.lastSegment _ sdl; IF graph.entityList = NIL THEN graph.entityList _ lel ELSE FOR el: Graph.EntityList _ graph.entityList, el.rest UNTIL el = NIL DO IF el.rest = NIL THEN {el.rest _ lel; EXIT}; ENDLOOP; }; -- PlotIt lastEL, el: Graph.EntityList _ NIL; hashIndex: INT[0..Graph.EntityHashSize); newLastId _ lastId; FOR n: nodePtr _ tree.nodes, n.brotherNodes UNTIL n=NIL DO entity: Graph.Entity _ NEW[Graph.EntityRec _ [ name: n.nodeName.name, comment: nodeComment, group: group, parent: parent, id: (newLastId _ newLastId+1) ]]; entity.oldValues _ entity.lastValue _ CONS[n.nHist.y/handle.vars.vUnit, NIL]; <<[] _ GraphUtil.AppendY[entity, n.nHist.y/handle.vars.vUnit, 0, 0];>> n.entity _ entity; hashIndex _ entity.id MOD Graph.EntityHashSize; hash[hashIndex] _ CONS[entity, hash[hashIndex]]; el _ CONS[entity, NIL]; IF lastEL = NIL THEN parent.entityList _ lastEL _ el ELSE {lastEL.rest _ el; lastEL _ el}; IF newLastId <= 6 THEN PlotIt[entity]; ENDLOOP; FOR b: branchPtr _ tree.branches, b.brotherBranches UNTIL b=NIL DO entity: Graph.Entity _ NEW[Graph.EntityRec _ [ name: b.branchName.name, comment: IO.PutFR[": %g[%g, %g]", IO.rope[BranchType[b]], IO.rope[b.posNode.nodeName.name], IO.rope[b.negNode.nodeName.name] ], group: group, parent: parent, id: (newLastId _ newLastId+1) ]]; entity.oldValues _ entity.lastValue _ CONS[BranchCurrent[b]/handle.vars.iUnit, NIL]; <<[] _ GraphUtil.AppendY[entity, BranchCurrent[b]/handle.vars.iUnit, 0, 0];>> b.entity _ entity; hashIndex _ entity.id MOD Graph.EntityHashSize; hash[hashIndex] _ CONS[entity, hash[hashIndex]]; el _ CONS[entity, NIL]; IF lastEL = NIL THEN parent.entityList _ lastEL _ el ELSE {lastEL.rest _ el; lastEL _ el}; IF newLastId <= 6 THEN PlotIt[entity]; ENDLOOP; }; -- EnlistNB Arguments: PROC[conn: conLinkPtr, fakes: namePtr] RETURNS [r: Rope.ROPE _ NIL] = { FOR c: conLinkPtr _ conn, c.nextLink UNTIL c = NIL DO r _ IF r = NIL THEN Rope.Cat[fakes.name, ": ", c.namedNode.name] ELSE Rope.Cat[fakes.name, ": ", c.namedNode.name, ", ", r]; fakes _ fakes.nextName; ENDLOOP; }; -- Arguments BranchType: PROC[branch: branchPtr] RETURNS [Rope.ROPE] = { RETURN[WITH branch.body SELECT FROM r: RefR => "R", c: RefC => "C", v: RefV => "V", i: RefI => "I", l: RefL => "L", ENDCASE => NIL -- (error. Will it happen?) ]; }; -- BranchType gh: Graph.GraphHandle _ handle.vars.graphHandle; group: Graph.EntityGroup _ gh.entityGroupList.first; ne: Graph.NestedEntities; [] _ GraphUtil.AppendX[group.x, t/handle.vars.tUnit]; group.length _ 1; [handle.vars.lastEntityId, ne] _ EnlistTree[handle.vars.treeRoot, group, NIL, gh.entityHash, handle.vars.lastEntityId, gh.graph]; ne.name _ group.ys.name; ne.comment _ group.ys.comment; group.ys _ ne; IF gh.graph.entityList # NIL THEN GraphPrivate.PaintLegend[gh, gh.graph.entityList.first, paint, FALSE]; -- just for legends. }; -- InitNE BranchCurrent: PROC [branch: branchPtr] RETURNS [REAL] = { RETURN[WITH branch.body SELECT FROM r: RefR => (branch.posNode.nHist.y - branch.negNode.nHist.y)/branch.comVal, c: RefC => (branch.posNode.nHist.f0 - branch.negNode.nHist.f0)*branch.comVal, v: RefV => v.vsCurrent, i: RefI => branch.comVal, l: RefL => l.iHist.y/branch.comVal, ENDCASE => 0.0 -- (error. Will it happen?) ]; }; -- BranchCurrent UpdatePP: PUBLIC PROC[handle: Handle, t: REAL] = { firstTime: BOOL; group: Graph.EntityGroup; GraphOps.Lock[handle.vars.graphHandle]; group _ handle.vars.graphHandle.entityGroupList.first; firstTime _ group.ys.entityList = NIL; IF firstTime THEN InitNE[handle, t] ELSE { UpdateTree: PROC [tree: instTreePtr] = { AppendIt: PROC [new: REAL, entity: Graph.Entity] = { old: REAL _ GraphUtil.AppendY[entity, new, t1, t2]; IF entity.segments # NIL THEN { v1 _ CONS[old, v1]; v2 _ CONS[new, v2]; pel _ CONS[entity, pel]; }; }; -- AppendIt FOR n: nodePtr _ tree.nodes, n.brotherNodes UNTIL n=NIL DO AppendIt[n.nHist.y/handle.vars.vUnit, n.entity]; ENDLOOP; FOR b: branchPtr _ tree.branches, b.brotherBranches UNTIL b=NIL DO AppendIt[BranchCurrent[b]/handle.vars.iUnit, b.entity]; ENDLOOP; FOR i: instTreePtr _ tree.sons, i.brothers UNTIL i=NIL DO UpdateTree[i]; ENDLOOP; }; -- UpdateTree t2: REAL _ t/handle.vars.tUnit; t1: REAL _ GraphUtil.AppendX[group.x, t2]; pel: Graph.EntityList _ NIL; v1, v2: Graph.ValueList _ NIL; UpdateTree[handle.vars.treeRoot]; group.length _ group.length + 1; GraphPrivate.PaintTails[handle.vars.graphHandle, t1, t2, v1, v2, pel, paint]; }; GraphOps.Unlock[handle.vars.graphHandle]; }; -- UpdatePP InitPlot: PUBLIC PROC[handle: Handle, tMin, tMax: REAL]= { OPEN handle.vars; rope: Rope.ROPE; pl: plotBlkPtr; FOR i: NAT IN [0..numPlots) DO OPEN plots[i]; file: Rope.ROPE _ Rope.Concat[OutputFileRoot[handle], IO.PutFR[".graph%g", IO.int[i]]]; time: Rope.ROPE _ Convert.RopeFromTime[from: simTime, includeDayOfWeek: TRUE]; xmin: REAL _ tMin/plots[i].plotTimeRelTo; xmax: REAL _ tMax/plots[i].plotTimeRelTo; [plotHandle, ] _ GraphOps.NewGraph[ fileName: file, comment: title, xName: Rope.Cat["Time[", Unit[plots[i].plotTimeRelTo, "S"], "]"], bounds: [xmin, ymin, xmax, ymax] ]; GraphOps.Lock[plotHandle]; plotHandle.chart.viewer.inhibitDestroy _ TRUE; plotHandle.userEditAllowed _ FALSE; [] _ GraphOps.AddText[handle: plotHandle, rope: title, place: [0.5, 1.1], fontIndex: 2, justifX: center, justifY: bottom]; [] _ GraphOps.AddText[handle: plotHandle, rope: file, place: [0, -0.35], fontIndex: 1, justifX: left, justifY: bottom]; [] _ GraphOps.AddText[handle: plotHandle, rope: time, place: [1.0, -0.35], fontIndex: 1, justifX: right, justifY: bottom]; [] _ GraphOps.AddText[handle: plotHandle, rope: Rope.Cat["[", Unit[plots[i].plotTimeRelTo, "S"], "]"], place: [1.01, 0.0], justifX: left, justifY: bottom]; pl _ plotList; UNTIL pl = NIL DO heading: Rope.ROPE _ SELECT TRUE FROM pl.arg.getComVal => "Value of ", pl.arg.current => "Current through ", pl.arg.dvdt => "Derivative of ", ENDCASE => "Voltage at "; rope_ heading.Concat[MakeStringNB[handle, pl.arg.node, pl.arg.branch]]; IF pl.relativeTo # 1.0 THEN rope _ IO.PutFR["%g/%g", IO.rope[rope], IO.real[pl.relativeTo]]; [] _ GraphOps.AddCurve[handle: plotHandle, groupId: 0, name: rope]; pl _ pl.nextBlk; ENDLOOP; GraphOps.Unlock[plotHandle]; GraphPrivate.PaintAll[plotHandle, TRUE, FALSE, TRUE]; ENDLOOP; }; -- InitPlot PlotFromList: PUBLIC PROC[handle: Handle, t: REAL] = { OPEN handle.vars; FOR iPlot: NAT IN [0..numPlots) DO values: Graph.ValueList _ NIL; p: plotBlkPtr_ plots[iPlot].plotList; time: REAL _ t/plots[iPlot].plotTimeRelTo; UNTIL p = NIL DO values _ CONS[EvaluateArgument[p.arg]/p.relativeTo, values]; p _ p.nextBlk; ENDLOOP; GraphOps.Lock[plots[iPlot].plotHandle]; GraphOps.AppendValues[plots[iPlot].plotHandle, 0, time, values]; GraphOps.Unlock[plots[iPlot].plotHandle]; ENDLOOP; }; -- PlotFromList GetPlotNum: PROC [handle: Handle] RETURNS[r: REAL_ 1.0] = { r_ GetSignedNumber[handle]; IF handle.vars.item = comma THEN Next[handle] ELSE Error[handle, 603,, FALSE] }; -- GetPlotNum <> <> <> <> <> <> <= maxPlots THEN {>> <> <> <<};>> <> <> <<};>> <> <> <<}>> <> <> <> <= plots[numPlots].ymax THEN Error[handle, 630, FALSE];>> <> <> <<[n, b] _ FindNodeOrBranch[handle];>> <> <> <> <> <> <> <> <<[nextBlk: plots[numPlots].plotList, relativeTo: Scale[handle], arg: NEW[argument_ [FALSE, n, b, cv, D, I]]]>> <<];>> <> <<};>> <> <<}; -- MakePlotList>> <<>> MakePlotList: PUBLIC PROC[handle: Handle]= { OPEN handle.vars; I, D, cv: BOOL; pb: plotBlkPtr; n: nodePtr; b: branchPtr; IF numPlots >= maxPlots THEN { Error[handle, 632, FALSE]; numPlots _ numPlots - 1 }; IF item = leftB THEN Next[handle] ELSE Error[handle, 600]; IF item = string THEN { plots[numPlots].title _ Rope.FromRefText[newString]; Next[handle]; IF item = comma THEN Next[handle] ELSE Error[handle, 603,, FALSE] }; IF item = colon THEN { plots[numPlots].plotTimeRelTo_ Scale[handle]; IF item = comma THEN Next[handle] ELSE Error[handle, 603,, FALSE] } ELSE plots[numPlots].plotTimeRelTo _ 1.0; plots[numPlots].ymin _ GetPlotNum[handle]; plots[numPlots].ymax _ GetPlotNum[handle]; IF plots[numPlots].ymin >= plots[numPlots].ymax THEN Error[handle, 630, FALSE]; plots[numPlots].plotList _ NIL; UNTIL item # name DO [n, b] _ FindNodeOrBranch[handle]; IF n = NIL AND b = NIL THEN Error[handle, 620] ELSE { I_ b # NIL AND item = upArrow; D_ n # NIL AND item = quote; cv_ b # NIL AND item = atSign; IF I OR D OR cv THEN Next[handle]; pb_ NEW[plotBlk_ [nextBlk: plots[numPlots].plotList, relativeTo: Scale[handle], arg: NEW[argument_ [FALSE, n, b, cv, D, I]]] ]; plots[numPlots].plotList_ pb; }; IF item = comma THEN Next[handle] ELSE EXIT; ENDLOOP; IF item = rightB THEN Next[handle] ELSE Error[handle, 601, TRUE]; numPlots _ numPlots + 1; }; -- MakePlotList PutMsgLine: PUBLIC PROC[handle: Handle, s: Rope.ROPE]= { handle.msgStream.PutF["%g\n", IO.rope[s]]; Process.Yield[]; }; -- PutMsgLine EvaluateArgument: PROC[a: argumentPtr] RETURNS[iv: REAL]= { b: branchPtr; IF a.getComVal THEN RETURN[a.branch.comVal]; IF a.node # NIL THEN iv_ IF a.dvdt THEN a.node.nHist.f0 ELSE a.node.nHist.y ELSE { b_ a.branch; IF a.current THEN WITH b.body SELECT FROM r: RefR => iv_ (b.posNode.nHist.y - b.negNode.nHist.y)/b.comVal; c: RefC => iv_ (b.posNode.nHist.f0 - b.negNode.nHist.f0)*b.comVal; l: RefL => iv_ l.iHist.y/b.comVal; v: RefV => iv_ v.vsCurrent; i: RefI => iv_ b.comVal; ENDCASE ELSE iv_ b.posNode.nHist.y - b.negNode.nHist.y; }; }; -- EvaluateArgument InitPrint: PUBLIC PROC[handle: Handle, time: BasicTime.GMT]= { FOR i: NAT IN [0..handle.vars.numPrints) DO output: IO.STREAM_ handle.vars.prints[i].printStream; output.PutF["* Simulation started at %g.\n", IO.time[time]]; ENDLOOP; }; -- InitPrint PrintFromList: PUBLIC PROC[handle: Handle, ni: INT, t: REAL, printStep: BOOL]= { i: NAT; p: printBlkPtr; r, trel: REAL; FOR i IN [0..handle.vars.numPrints) DO output: IO.STREAM_ handle.vars.prints[i].printStream; p_ handle.vars.prints[i].printList; trel_ t/handle.vars.prints[i].printTimeRelTo; output.PutF["%10.3e", IO.real[trel]]; IF printStep THEN output.PutF["(%2d)", IO.int[ni]]; UNTIL p=NIL DO r_ EvaluateArgument[p.arg]/p.relativeTo; output.PutF[" %10.3f", IO.real[r]]; p_ p.nextBlk; ENDLOOP; output.PutF["\n"]; ENDLOOP; }; -- PrintFromList Scale: PROC[handle: Handle] RETURNS[s: REAL_ 1.0]= { IF handle.vars.item=colon THEN {Next[handle]; s_ GetSignedNumber[handle]}; }; -- Scale MakePrintList: PUBLIC PROC[handle: Handle]= { OPEN handle.vars; I, D, cv: BOOL; pb, pb2, pb3: printBlkPtr; n: nodePtr; b: branchPtr; outFileNameRoot, outFileName, outFiles: Rope.ROPE; IF numPrints >= maxPrints THEN { Error[handle, 631]; numPrints_ numPrints - 1; }; IF item=leftB THEN Next[handle] ELSE Error[handle, 600]; IF item=colon THEN { prints[numPrints].printTimeRelTo_ Scale[handle]; IF item=comma THEN Next[handle] ELSE Error[handle, 603,, FALSE]; } ELSE prints[numPrints].printTimeRelTo_ 1.0; prints[numPrints].printList_ NIL; UNTIL item # name DO [n, b]_ FindNodeOrBranch[handle]; IF n=NIL AND b=NIL THEN Error[handle, 620] ELSE { I_ (b # NIL) AND item=upArrow; -- branch current D_ (n # NIL) AND item=quote; -- derivative of node voltage cv_ (b # NIL) AND item=atSign; -- branch value IF I OR D OR cv THEN Next[handle]; pb_ NEW[printBlk_ [nextBlk: prints[numPrints].printList, relativeTo: Scale[handle], arg: NEW[argument_ [FALSE, n, b, cv, D, I]] ] ]; prints[numPrints].printList_ pb; }; IF item=comma THEN Next[handle] ELSE EXIT; ENDLOOP; pb_ NIL; pb3_ prints[numPrints].printList; UNTIL pb3=NIL DO pb2_ pb3; pb3_ pb3.nextBlk; pb2.nextBlk_ pb; pb_ pb2; ENDLOOP; prints[numPrints].printList_ pb; outFileNameRoot_ OutputFileRoot[handle]; outFileName_ IO.PutFR["%g.out%g", IO.rope[outFileNameRoot], IO.int[numPrints]]; prints[numPrints].printStream_ FS.StreamOpen[fileName: outFileName, accessOptions: $create]; prints[numPrints].printStream.Reset[ ]; outFiles_ IF numPrints=0 THEN outFileName ELSE IO.PutFR["%g.out0...out%g", IO.rope[outFileNameRoot], IO.int[numPrints]]; Labels.Set[handle.output, outFiles]; prints[numPrints].printStream.PutF[ "** %g\n*\n* File: %g\n* Input: %g\n* Time: %g\n*\n", IO.rope[version], IO.rope[outFileName], IO.rope[ViewerTools.GetContents[handle.input]], IO.time[simTime] ]; numPrints_ numPrints + 1; IF item=rightB THEN Next[handle] ELSE Error[handle, 601, TRUE]; }; -- MakePrintList DumpAll: PUBLIC PROC[handle: Handle, t: REAL]= { OPEN handle.vars; dname: Rope.ROPE; dump: IO.STREAM; nodes: nodePtr_ nodeList; inds: branchPtr_ inductorList; dname_ IO.PutFR["%g.dump", IO.rope[OutputFileRoot[handle]]]; dump_ FS.StreamOpen[fileName: dname, accessOptions: $create]; dump.Reset[]; dump.PutF["ic[%f,\n", IO.real[t]]; UNTIL nodes=NIL DO dump.PutF["%g_ %f", IO.rope[MakeStringNB[handle, nodes, NIL, FALSE]], IO.real[nodes.nHist.y]]; nodes_ nodes.nextNode; IF nodes # NIL THEN dump.PutF[",\n"] ELSE dump.PutF["\n"]; ENDLOOP; UNTIL inds=NIL DO indsBody: RefL_ NARROW[inds.body]; dump.PutF["%g_ %f", IO.rope[MakeStringNB[handle, NIL, inds, FALSE]], IO.real[indsBody.iHist.y]]; inds_ indsBody.nextInductor; IF inds # NIL THEN IO.PutF[dump, ",\n"] ELSE IO.PutF[dump, "\n"]; ENDLOOP; dump.PutF["];\n"]; handle.msgStream.PutF["Dumped into file %g at %g.\n", IO.rope[dname], IO.time[]]; dump _ FlushCloseNil[dump]; }; -- DumpAll END. CHANGE LOG Wilhelm, April 6, 1982 11: 36 AM Barth, 7-May-82 10: 45: 07 PDT Chen, June 12, 1984 6:59:26 pm PDT, cedarized. Chen, July 22, 1985 8:09:51 pm PDT, => Cedar6.0. Chen, November 24, 1985 2:42:28 pm PST, added InitPP and UpdatePP and related procs for postprocessor. Also modified other plotting related codes to use the Graph package. Christian Jacobi, June 10, 1986 7:00:30 pm PDT, Yield on messages, to avoid monopolizing cpu.