[comp.sys.amiga] graphs, runge kutta

conn@stratus.UUCP (Avery Shealey) (10/16/87)

Thanks for the responces that have been given to me in the past few
weeks. Makes me glad I bought an amiga. This is the graphs and runge kutta
solver that people asked for. Sorry to have to post it, but I am having a
lot of trouble with the mailer. Only about one person I have mailed to
has gotten it. Soory about this.

 
Delete everything above the cut line and run through /bin/sh to
extract makefile, swing.c, rk.c, graphs.c. It will definitely
compile under Manx 3.4a with all patches. If you have any
questions, comments, or suggestions about the program or code, please
let me know.

Avery Shealey
School of Information & Computer Science, Georgia Tech, Atlanta GA 30332
Internet:  conn@stratus.gatech.edu	 CSNet:  conn%stratus@gatech	
UUCP:  ...!{akgua,allegra,amd,hplabs,seismo,ihnp4}!gatech!stratus!conn
#cut line======================================================
cat <<SHAR_EOF >makefile
CFLAGS = +l

swing: swing.o rk.o graphs.o
    ln swing.o rk.o graphs.o -lm32 -lc32

SHAR_EOF
cat <<SHAR_EOF >swing.c
/* Copyright 1987, by Avery Shealey -- this code may be freely
   distributed as long as this notice remains intact --
   the code may not be sold without express written of
   the author */

/* this is the main driver for the differential equation solver -
   it is included as an example of how to use the solver and the 
   graphics - the user must declare the variable numeq and supply
   the function derivative to get the runge kutta solver to work -
   to use the graphics, simply call the initialization first
   and cleanup when you leave - 
   if you have any suggestions, problems or comments, feel free
   to contact me */

/* the program computes the solution to the simple pendulum
   problem and plots the phase portrait of the solution -
   the pendulum is of length 2 with the force of gravity defined to
   be 32 - play with the world values - if you want to see how accurate
   the precision is, start the conditions out at about
   y[0] = 3.14 -- about pi -- and y[1] = 0 -- no velocity -- 
   - WARNING - WARNING - WARNING - WARNING - WARNING -
   unless you have a pendulum fetish, this display will not be very
   exciting - it was written only to demonstrate the runge kutta
   solver and the graphs interface */

#include <intuition/intuition.h>
#include <exec/types.h>
#include <math.h>

#define NUMEQ 2
int numeq = 2;

double g = 32, len = 2, t, h, y[NUMEQ], dy[NUMEQ];
double xmin, xmax, ymin, ymax;

main()
{
  void init(), initgraphics(), cleanupgraphics(), rk();
  int GetWinStat();

  init();
  initgraphics(320, 200, xmin, xmax, ymin, ymax);
  moveto(y[0], y[1]);
  while (GetWinStat() == TRUE) {
    rk(t, h, y, dy);
    drawto(y[0], y[1]);
    t += h;
  }
  cleanupgraphics();
}

void derivative(t, y, dy)
double t, y[], dy[];
{
  double sin();

  dy[0] = y[1];
  dy[1] = (-g / len) * sin(y[0]);
}

void init()
{
  char *str, *malloc(), *gets();
  double atof();

  str = malloc(20);
  printf("Enter initial t ");
  gets(str);
  t = atof(str);
  printf("Enter initial h ");
  gets(str);
  h = atof(str);
  printf("Enter y[0] ");
  gets(str);
  y[0] = atof(str);
  printf("Enter y[1] ");
  gets(str);
  y[1] = atof(str);
  printf("Enter xmin ");
  gets(str);
  xmin = atof(str);
  printf("Enter xmax ");
  gets(str);
  xmax = atof(str);
  printf("Enter ymin ");
  gets(str);
  ymin = atof(str);
  printf("Enter ymax ");
  gets(str);
  ymax = atof(str);
}
SHAR_EOF
cat <<SHAR_EOF >rk.c
/* Copyright 1987, by Avery Shealey -- this code may be freely
   distributed as long as this notice remains intact --
   the code may not be sold without express written of
   the author */

/* this module is the runge kutta differential equation solver --
   it will solve a system of first order differential equations --
   the external variable numeq should contain the number of equations
   -- the parameters are :
      t - the independent variable
      h - the stepsize (generally 0.01 is a good value)
      y - the array containing the solution at the last step --
          should initially contain the starting values for eqch equation
      dy - used to hold temporary values in the computation - this is
           not declared locally to avoid the cost of allocating stack
           space at each invocation - this could be placed at the start
           of this module, but it was declared in the main module - do
           what you like with it
*/

extern int numeq;

rk(t, h, y, dy)
double t, h, y[], dy[];
{
  void derivative();
  double k1[10], k2[10], k3[10], k4[10], temp[10];
  register int i;

  derivative(t, y, dy);
  for (i = 0; i < numeq; i++)
    k1[i] = h * dy[i];
  for (i = 0; i < numeq; i++)
    temp[i] = y[i] + 0.5*k1[i];
  derivative(t + 0.5*h, temp, dy);
  for (i = 0; i < numeq; i++)
    k2[i] = h * dy[i];
  for (i = 0; i < numeq; i++)
    temp[i] = y[i] + 0.5*k2[i];
  derivative(t + 0.5*h, temp, dy);
  for (i = 0; i < numeq; i++)
    k3[i] = h * dy[i];
  for (i = 0; i < numeq; i++)
    temp[i] = y[i] + k3[i];
  derivative(t + h, temp, dy);
  for (i = 0; i < numeq; i++)
    k4[i] = h * dy[i];
  for (i = 0; i < numeq; i++)
    y[i] = y[i] + (1.0 / 6.0) * (k1[i] + 2*k2[i] + 2*k3[i] + k4[i]);
}
SHAR_EOF
cat <<SHAR_EOF >graphs.c
/* Copyright 1987, by Avery Shealey -- this code may be freely
   distributed as long as this notice remains intact --
   the code may not be sold without express written consent of
   the author */

/* this is the graphics module -- it may not be the most efficient,
   but is was designed to be easy to use and easily extendable --
   the user does not have to worry with any of the normal details --
   simply call initgraphics with the necessary startup conditions --
   then call getwinstat to see if the window has been closed -- the
   module is easily extendible without a lot if trouble -- if you
   have any trouble or suggestions, please mail */

#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <exec/types.h>

/* window for the graphics */

struct NewWindow newwindow = {
  0,0,320,200,
  -1,-1,
  CLOSEWINDOW,
  WINDOWDRAG | WINDOWCLOSE | WINDOWDEPTH | SMART_REFRESH,
  NULL, NULL,
  (UBYTE *)"Graph",
  NULL, NULL,
  10, 10, 640, 400,
  WBENCHSCREEN };

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Window *window;
struct RastPort *rp;

int XMAX, YMAX;
double xmin, ymin, xmax, ymax;
double xscale, yscale;

/* cleanup and release resources */

void cleanupgraphics()
{
  if (IntuitionBase)
    CloseLibrary(IntuitionBase);
  if (GfxBase)
    CloseLibrary(GfxBase);
  if (window)
    CloseWindow(window);
}

/* open the libraries and graphics window */

void opengraphics()
{
  void *OpenLibrary();
  struct Window *OpenWindow();

  if ((IntuitionBase = (struct IntuitionBase *)
      OpenLibrary("intuition.library", 0)) == NULL) {
    printf("unable to open intuition.\n");
    cleanupgraphics();
    exit(1);
  }

  if ((GfxBase = (struct GfxBase *)
      OpenLibrary("graphics.library",0)) == NULL) {
    printf("unable to open graphics.\n");
    cleanupgraphics();
    exit(2);
  }

  newwindow.Width = XMAX;
  newwindow.Height = YMAX;
  if ((window = OpenWindow(&newwindow)) == NULL) {
    printf("unable to open window.\n");
    cleanupgraphics();
    exit(3);
  }

  rp = window->RPort;
}

/* initialize the graphics -- set up the scale factors
   and draw the grid */
/* the parameters are :
     width - width of the window
     height - height of the window
     wxmin, wxmax - min and max x world coordinates
     wymin, wymax - min and max y world coordinates
*/

void initgraphics(width, height, wxmin, wxmax, wymin, wymax)
int width, height;
double wxmin, wxmax, wymin, wymax;
{
  double i, j;
  void moveto(), drawto();

  XMAX = width - 1;
  YMAX = height - 1;
  xmin = wxmin;
  xmax = wxmax;
  ymin = wymin;
  ymax = wymax;
  xscale = XMAX / (xmax - xmin);
  yscale = YMAX / (ymax - ymin);
  opengraphics();

  SetAPen(rp, 2);
  for (i = xmin; i <= xmax; i += (xmax - xmin)/4) {
    moveto(i, ymin);
    drawto(i, ymax);
  }
  for (j = ymin; j <= ymax; j += (ymax - ymin)/4) {
    moveto(xmin, j);
    drawto(xmax, j);
  }
  SetAPen(rp, 1);
}

/* plot a point */

void plot(x, y)
double x, y;
{
  int xcoord, ycoord;
  double floor();

  xcoord = (int) floor((xscale * (x - xmin)) + 0.5);
  ycoord = YMAX - (int) floor((yscale * (y - ymin)) + 0.5);
  Move(rp, xcoord, ycoord);
  Draw(rp, xcoord, ycoord);
}

/* draw from the last pen position to the new coordinate */

void drawto(x, y)
double x, y;
{
  int xcoord, ycoord;
  double floor();

  xcoord = (int) floor((xscale * (x - xmin)) + 0.5);
  ycoord = YMAX - (int) floor((yscale * (y - ymin)) + 0.5);
  Draw(rp, xcoord, ycoord);
}

/* move to a new pen position */

void moveto(x, y)
double x, y;
{
  int xcoord, ycoord;
  double floor();

  xcoord = (int) floor((xscale * (x - xmin)) + 0.5);
  ycoord = YMAX - (int) floor((yscale * (y - ymin)) + 0.5);
  Move(rp, xcoord, ycoord);
}

/* see if the window close gadget has been selected -- returns
   FALSE if window gadget has been selected, TRUE otherwise */

int GetWinStat()
{
  struct Message *GetMsg();
  struct IntuiMessage *msg;
  ULONG class;
  int value = TRUE;

  while (msg = (struct IntuiMessage *)GetMsg(window->UserPort)) {
    class = msg->Class;
    ReplyMsg(msg);
    if (class == CLOSEWINDOW)
      value = FALSE;
  }
  return(valuembehing.

*.