More Problems; ECOLI6a

[From Bruce Abbott (941110.1015 EST)]

Message flow to me from CSG-L has slowed to near zero since last Friday. The
problem has been traced to an overloaded campus SMTP-link computer that routes
our internet mail into/out of our local cc:mail system. Outgoing messages are
waiting in the queue for hours or days to be processed; meanwhile, when
incoming mail exceeds the capacity of the input queue, the SMTP sends a
message back to systems such as listservers telling them to stop trying. The
result is that messages are simply not getting through. I was able to
download CSG-L log9411a yesterday and found all sorts of messages I had not
seen.

Apparently the problem has arisen because too many of our faculty have started
subscribing to lists and the resulting traffic has jammed up our limited-
capacity system. If the problem persists (as I expect it will) I will try to
solve it by unsubscribing to CSG-L and then resubscribing under my VAX
account, which uses a different link to the internet. Then I'll have to learn
how to use VAX mail (eech) and do a lot of FTPing of messages between my PC
and the VAX.

I HAVE received the frameplt unit and, just this morning, opcond3.pas, which
compiled and ran fine. Meanwhile, I have been playing around with frameplt
and added it to ECOLI6 with some interesting results. The modified program,
ECOLI6a, appears below.

Tom Bourbon: It sounds like ECOLI6 has infected your compiler. I suspect that
the TP 7.0 immune system is more effective than the one in TP 6.0, but even
so, I don't see how the real values being computed could get out of range
here. Another possibility is that you have been inadvertently reinforcing
this behavior in your compiler. Assuming that compiling is reinforcing to a
compiler (as seems reasonable), any behavior that increases the number of
compiles would be selected for. (;->]

{***********************************************************************
* ECOLI6a: NUTRIENT REGULATION IN E. COLI *
* *
* Programmer: Dr. Bruce B. Abbott *
* Psychological Sciences *
* Indiana U. - Purdue U. *
* Fort Wayne, IN 46805-1499 *
* (219) 481-6399 *
* *
* Created: 11/09/94 *
* *
* This program simulates the "swim and tumble" behavior of e. coli *
* using a two-level perceptual control system. The bottom level *
* regulates change in nutrient levels by altering the rate of *
* tumbling inversely with the rate of change of sensed nutrient. *
* The direction of e. coli's travel after tumbling is random. *
* *
* The second level regulates the gain of the first-level system *
* according to the e. coli's level of stored nutrients relative to *
* a reference level of 100 units. E. coli is assumed to absorb the *
* nutrients around it at a rate proportional to nutrient *
* concentration, and to use up nutrients at a rate proportional to *
* its speed. *
* *
* The environment of e. coli contains two food sources indicated by *
* small rectangles. Nutrient level is 100 at each source, but *
* decreases with the square of the radial distance from each source. *
* Thus, as e. coli wanders away from these sources, the level of *
* nutrient in its vicinity drops off rapidly. *
* *
***********************************************************************}

program Ecoli6;

uses
  CRT, Graph, GrUtils, frameplt;

const
  TWOPI = PI * 2;
  ENDSESSION = 50000;
var
  MaxX, MaxY, Line: integer;
  NutrX, NutrY, NutrX2, NutrY2,
  X, Y, T, T0, DeltaT, Tmax, TimeSinceTumble, MinTime: integer;
  NutMag, NutCon, dNutRef, dNutError, dNut, Gain, MaxGain,
  AbsorbRate, LossRate: real;
  Fuel, FuelRef: real;
  EcoliX, EcoliY,
  Speed, Angle: real;
  Ch: char;
  Clock: longint;
  Frame1: frametype;
  Z: real;

procedure InitScreen;
begin
  ClrScr;
  InitGraphics;
  SetFillStyle(0,0);
  MaxX := GetMaxX; MaxY := GetMaxY;
  Rectangle(0, 0, MaxX, MaxY);
  OutTextXY(MaxX div 2 - 200, Y+5,
    'E. COLI SIMULATION: REGULATING STORED NUTRIENTS');
  OutTextXY(40, MaxY-30, 'Press ESC to Quit...');
  OutTextXY(MaxX-75, Line+20, 'Gain');
  OutTextXY(MaxX-75, Line+40, 'Stores');
  OutTextXY(MaxX-75, Line+60, 'Nutrient');
  with Frame1 do
  begin
    mx := getMaxX;
    my := getMaxY;
    numyvars := 3;
    xbase := 45; ybase := 50;
    xsize := 580; ysize := 100;
    numxgrid := 20; numygrid := 5;
    xzero := 0; yzero := 50;
    xmax := 600;
    ymax[1] := 250;
    ymax[2] := 250;
    ymax[3] := 5;
    xvar := @Z;
    yvar[1] := @Fuel;
    yvar[2] := @FuelRef;
    yvar[3] := @dNut;
    color[1] := yellow;
    color[2] := lightred;
    color[3] := lightgreen;
    ylegend[1] := 'Fuel';
    ylegend[2] := 'F.Ref';
    ylegend[3] := 'dNut';
    xlegend := 'Time';
  end;
end;

procedure ShowReal(x,y: integer; v: real);
var s: string;
begin
str(v:12:2, s);
bar (x,y,x+textwidth(s),y+textheight(s));
outtextxy(x,y,s);
end;

procedure Tumble(var Angle: real);
begin
  Angle := TwoPi * Random;
end;

procedure InitSim;
begin
  Randomize;
  NutrX := MaxX div 3;
  NutrY := MaxY div 2 - 50;
  NutrX2 := MaxX - NutrX;
  NutrY2:= NutrY;
  EcoliX := 50.0;
  EcoliY := 50.0;
  X := Round(EcoliX);
  Y := Round(EcoliY);
  Rectangle(NutrX-2, NutrY-2, NutrX+2, NutrY+2);
  Rectangle(NutrX2-2, NutrY2-2, NutrX2+2, NutrY2+2);
  Speed := 1.0;
  NutMag := 100.0; { max concentration }
  dNutRef := 0.00; { Reference rate of change in concentration }
  dNut := 0;
  Tmax := 200;
  T0 := 5;
  T := 0;
  MinTime := 1;
  TimeSinceTumble := 0;
  Gain :=50.0;
  MaxGain := 50000.0;
  FuelRef := 100;
  Fuel := 90;
  AbsorbRate := 0.005;
  LossRate := 0.2;
  repeat Tumble(Angle) until (Angle < PI/2);
  Clock := 0;
end;

function NutConcen(X, Y, NutrX, NutrY: real): real;
{ Nutient concentration at point X, Y: environment function }
var
  Dist: real;
begin
  Dist := Sqrt(Sqr(X - NutrX) + Sqr(Y - NutrY));
  NutConcen := NutMag / (1 + 0.001*(Sqr(Dist)));
end;

procedure StepEColi;
var
  NewNut: real;
begin
  EcoliX := EcoliX + Speed * cos(Angle);
  EcoliY := EcoliY + Speed * sin(Angle);
  X := Round(EcoliX);
  Y := Round(EcoliY);
  PutPixel(X, Y, yellow);
  NewNut := NutConcen(EcoliX, EcoliY, NutrX, NutrY)
    + NutConcen(EcoliX, EcoliY, NutrX2, NutrY2);
  dNut := {dNut * 0.25 + 0.5 * }(NewNut - NutCon);
  DeltaT := Round(Gain * (dNutRef - dNut));
  T := T + T0 + DeltaT;
  inc(TimeSinceTumble);
  if T < 0 then T := 0;
  if (T > Tmax) and (TimeSinceTumble >= MinTime) then
    begin
      Tumble(Angle);
      T := 0;
      TimeSinceTumble := 0;
    end;
  NutCon := NewNut;
  Fuel := Fuel + AbsorbRate*NutCon - LossRate*Speed;
  if Fuel < 0 then Fuel := 0 else
    if Fuel > 200 then Fuel := 200;
  Gain := 50 * (FuelRef - Fuel);
  if (Gain > MaxGain) then Gain := MaxGain
  else if (Gain < -MaxGain) then Gain := -MaxGain;
  If (Clock mod 10 = 0) then
    begin
      ShowReal(MaxX-175, Line+20, Gain);
      ShowReal(MaxX-175, Line+40, Fuel);
      ShowReal(MaxX-175, Line+60, NewNut);
    end;
end;

begin
  InitScreen;
  InitSim;
  InitFrame(Frame1);
  Z := 0;
  repeat
    inc(Clock);
    StepEcoli;
    Z := Z + 0.10;
    If Z > 600.0 then
      begin
        ClrPlot(Frame1);
        Z := 0.0;
      end;
  setviewport(0,0, MaxX, MaxY, true);
    PlotVar(Frame1);
   setViewPort(0, 0, MaxX, MaxY-150, true);
    Delay(5);
    if Keypressed then Ch := ReadKey;
  until (Ch = #27) or (Clock >= ENDSESSION);
  if (Ch <> #27) then Ch := ReadKey;
  RestoreCRTMode;
  CloseGraph;
end.