# include
# include
# include
# include
int main ( int argc, char *argv[] );
void r8vla2_write ( char *output_filename, int m, int n, double a[m][n] );
int s_len_trim ( char *s );
int s_to_i4 ( char *s, int *last, int *error );
void timestamp ( );
/******************************************************************************/
int main ( int argc, char *argv[] )
/******************************************************************************/
/*
Purpose:
FD_PREDATOR_PREY solves a pair of predator-prey ODE's.
Discussion:
The physical system under consideration is a pair of animal populations.
The PREY reproduce rapidly; for each animal alive at the beginning of the
year, two more will be born by the end of the year. The prey do not have
a natural death rate; instead, they only die by being eaten by the predator.
Every prey animal has 1 chance in 1000 of being eaten in a given year by
a given predator.
The PREDATORS only die of starvation, but this happens very quickly.
If unfed, a predator will tend to starve in about 1/10 of a year.
On the other hand, the predator reproduction rate is dependent on
eating prey, and the chances of this depend on the number of available prey.
The resulting differential equations can be written:
PREY(0) = 5000
PRED(0) = 100
d PREY / dT = 2 * PREY(T) - 0.001 * PREY(T) * PRED(T)
d PRED / dT = - 10 * PRED(T) + 0.002 * PREY(T) * PRED(T)
Here, the initial values (5000,100) are a somewhat arbitrary starting point.
The pair of ordinary differential equations that result have an interesting
behavior. For certain choices of the interaction coefficients (such as
those given here), the populations of predator and prey will tend to
a periodic oscillation. The two populations will be out of phase; the number
of prey will rise, then after a delay, the predators will rise as the prey
begins to fall, causing the predator population to crash again.
In this program, the pair of ODE's is solved with a simple finite difference
approximation using a fixed step size. In general, this is NOT an efficient
or reliable way of solving differential equations. However, this program is
intended to illustrate the ideas of finite difference approximation.
In particular, if we choose a fixed time step size DT, then a derivative
such as dPREY/dT is approximated by:
d PREY / dT = approximately ( PREY(T+DT) - PREY(T) ) / DT
which means that the first differential equation can be written as
PREY(T+DT) = PREY(T) + DT * ( 2 * PREY(T) - 0.001 * PREY(T) * PRED(T) ).
We can rewrite the equation for PRED as well. Then, since we know the
values of PRED and PREY at time 0, we can use these finite difference
equations to estimate the values of PRED and PREY at time DT. These values
can be used to get estimates at time 2*DT, and so on. To get from time
T_START = 0 to time T_STOP = 5, we simply take STEP_NUM steps each of size
DT = ( T_STOP - T_START ) / STEP_NUM.
Because finite differences are only an approximation to derivatives, this
process only produces estimates of the solution. And these estimates tend
to become more inaccurate for large values of time. Usually, we can reduce
this error by decreasing DT and taking more, smaller time steps.
In this example, for instance, taking just 100 steps gives nonsensical
answers. Using STEP_NUM = 1000 gives an approximate solution that seems
to have the right kind of oscillatory behavior, except that the amplitude
of the waves increases with each repetition. Using 10000 steps, the
approximation begins to become accurate enough that we can see that the
waves seem to have a fixed period and amplitude.
Licensing:
This code is distributed under the MIT license.
Modified:
16 February 2011
Author:
John Burkardt
Reference:
George Lindfield, John Penny,
Numerical Methods Using MATLAB,
Second Edition,
Prentice Hall, 1999,
ISBN: 0-13-012641-1,
LC: QA297.P45.
Parameters:
Input, int STEP_NUM, the number of steps.
*/
{
# define LINE_MAX_LEN 255
double dt;
char filename[255];
int i;
double pred_init = 100.0;
double prey_init = 5000.0;
int step_num;
double t_start;
double t_stop;
timestamp ( );
printf ( "\n" );
printf ( "FD_PREDATOR_PREY\n" );
printf ( " C version\n" );
printf ( "\n" );
printf ( " A finite difference approximate solution of a pair\n" );
printf ( " of ordinary differential equations for a population\n" );
printf ( " of predators and prey.\n" );
printf ( "\n" );
printf ( " The exact solution shows wave behavior, with a fixed\n" );
printf ( " period and amplitude. The finite difference approximation\n" );
printf ( " can provide a good estimate for this behavior if the stepsize\n" );
printf ( " DT is small enough.\n" );
/*
STEP_NUM is an input argument or else read from the user interactively.
*/
if ( 1 < argc )
{
step_num = atoi ( argv[1] );
/*
s_to_i4 ( argv[1], &length, &ierror );
*/
}
else
{
printf ( "\n" );
printf ( "FD_PREDATOR_PREY:\n" );
printf ( " Please enter the number of time steps:\n" );
scanf ( "%d", &step_num );
}
t_start = 0.0;
t_stop = 5.0;
dt = ( t_stop - t_start ) / ( double ) ( step_num );
printf ( "\n" );
printf ( " Initial time = %f\n", t_start );
printf ( " Final time = %f\n", t_stop );
printf ( " Initial prey = %f\n", prey_init );
printf ( " Initial pred = %f\n", pred_init );
printf ( " Number of steps = %d\n", step_num );
/*
Declare TRF as a VLA (Variable Length Array).
*/
double trf[3][step_num+1];
trf[0][0] = t_start;
trf[1][0] = prey_init;
trf[2][0] = pred_init;
for ( i = 0; i < step_num; i++ )
{
trf[0][i+1] = trf[0][i] + dt;
trf[1][i+1] = trf[1][i] + dt
* ( 2.0 * trf[1][i] - 0.001 * trf[1][i] * trf[2][i] );
trf[2][i+1] = trf[2][i] + dt
* ( - 10.0 * trf[2][i] + 0.002 * trf[1][i] * trf[2][i] );
}
/*
Write data to files.
*/
sprintf ( filename, "trf_%d.txt", step_num );
r8vla2_write ( filename, 3, step_num + 1, trf );
printf ( " T, R, F values written to \"%s\".\n", filename );
/*
Terminate.
*/
printf ( "\n" );
printf ( "FD_PREDATOR_PREY\n" );
printf ( " Normal end of execution.\n" );
printf ( "\n" );
timestamp ( );
return 0;
}
/******************************************************************************/
void r8vla2_write ( char *output_filename, int m, int n, double a[m][n] )
/******************************************************************************/
/*
Purpose:
R8VLA2_WRITE writes an R8VLA2 file.
Licensing:
This code is distributed under the MIT license.
Modified:
28 June 2012
Author:
John Burkardt
Parameters:
Input, char *OUTPUT_FILENAME, the output filename.
Input, int M, the spatial dimension.
Input, int N, the number of points.
Input, double TABLE[M][N], the table data.
*/
{
int i;
int j;
FILE *output;
/*
Open the file.
*/
output = fopen ( output_filename, "wt" );
if ( !output )
{
printf ( "\n" );
printf ( "R8MAT_WRITE - Fatal error!\n" );
printf ( " Could not open the output file.\n" );
return;
}
/*
Write the data.
*/
for ( j = 0; j < n; j++ )
{
for ( i = 0; i < m; i++ )
{
fprintf ( output, " %24.16e", a[i][j] );
}
fprintf ( output, "\n" );
}
/*
Close the file.
*/
fclose ( output );
return;
}
/******************************************************************************/
int s_len_trim ( char *s )
/******************************************************************************/
/*
Purpose:
S_LEN_TRIM returns the length of a string to the last nonblank.
Licensing:
This code is distributed under the MIT license.
Modified:
26 April 2003
Author:
John Burkardt
Parameters:
Input, char *S, a pointer to a string.
Output, int S_LEN_TRIM, the length of the string to the last nonblank.
If S_LEN_TRIM is 0, then the string is entirely blank.
*/
{
int n;
char *t;
n = strlen ( s );
t = s + strlen ( s ) - 1;
while ( 0 < n )
{
if ( *t != ' ' )
{
return n;
}
t--;
n--;
}
return n;
}
/******************************************************************************/
int s_to_i4 ( char *s, int *last, int *error )
/******************************************************************************/
/*
Purpose:
S_TO_I4 reads an I4 from a string.
Licensing:
This code is distributed under the MIT license.
Modified:
13 June 2003
Author:
John Burkardt
Parameters:
Input, char *S, a string to be examined.
Output, int *LAST, the last character of S used to make IVAL.
Output, int *ERROR is TRUE (1) if an error occurred and FALSE (0) otherwise.
Output, int *S_TO_I4, the integer value read from the string.
If the string is blank, then IVAL will be returned 0.
*/
{
char c;
int i;
int isgn;
int istate;
int ival;
*error = 0;
istate = 0;
isgn = 1;
i = 0;
ival = 0;
while ( *s )
{
c = s[i];
i = i + 1;
/*
Haven't read anything.
*/
if ( istate == 0 )
{
if ( c == ' ' )
{
}
else if ( c == '-' )
{
istate = 1;
isgn = -1;
}
else if ( c == '+' )
{
istate = 1;
isgn = + 1;
}
else if ( '0' <= c && c <= '9' )
{
istate = 2;
ival = c - '0';
}
else
{
*error = 1;
return ival;
}
}
/*
Have read the sign, expecting digits.
*/
else if ( istate == 1 )
{
if ( c == ' ' )
{
}
else if ( '0' <= c && c <= '9' )
{
istate = 2;
ival = c - '0';
}
else
{
*error = 1;
return ival;
}
}
/*
Have read at least one digit, expecting more.
*/
else if ( istate == 2 )
{
if ( '0' <= c && c <= '9' )
{
ival = 10 * (ival) + c - '0';
}
else
{
ival = isgn * ival;
*last = i - 1;
return ival;
}
}
}
/*
If we read all the characters in the string, see if we're OK.
*/
if ( istate == 2 )
{
ival = isgn * ival;
*last = s_len_trim ( s );
}
else
{
*error = 1;
*last = 0;
}
return ival;
}
/******************************************************************************/
void timestamp ( void )
/******************************************************************************/
/*
Purpose:
TIMESTAMP prints the current YMDHMS date as a time stamp.
Example:
31 May 2001 09:45:54 AM
Licensing:
This code is distributed under the MIT license.
Modified:
24 September 2003
Author:
John Burkardt
Parameters:
None
*/
{
# define TIME_SIZE 40
static char time_buffer[TIME_SIZE];
const struct tm *tm;
time_t now;
now = time ( NULL );
tm = localtime ( &now );
strftime ( time_buffer, TIME_SIZE, "%d %B %Y %I:%M:%S %p", tm );
printf ( "%s\n", time_buffer );
return;
# undef TIME_SIZE
}