      PROGRAM ECO
      IMPLICIT NONE

CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
C 
C THIS FILE CONTAINS FORTRAN CODE FOR MODELLING A SIMPLE PREDATOR-PREY
C MODEL.  THE TWO ANIMAL POPULATIONS MODELLED ARE RABBITS AND FOXES THAT
C LIVE ON SOME PIECE OF LAND.  THE TWO ANIMAL POPULATIONS MODELLED ARE
C RABBITS AND FOXES THAT LIVE ON SOME PIECE OF LAND. THE ANIMAL
C POPULATIONS ARE REPRESENTED BY TWO TWO-DIMENSIONAL ARRAYS OF SIZE
C NS_Size BY WE_Size. PRECISELY, THE NUMBER OF FOXES THAT LIVE IN THE
C I,J-TH STRETCH OF LAND (WITH 1<=I<=NS_Size AND 1<=J<=WE_Size) IS STORED
C AS FOX (I, J). THE CORRESPONDING FIGURE FOR RABBITS IS STORED IN RABBIT
C (I, J). BOUNDARY CONDITIONS ARE ENFORCED SO THAT THE LAND IS ACTUALLY
C A TORUS AND CAN BE THOUGHT TO EXTEND PERIODICALLY BEYOND THE GIVEN
C BOUNDS NS_Size AND WE_Size.  THE POPULATIONS OF EACH STRETCH IS UPDATED
C AT EACH GENERATION ACCORDING TO SOME SIMPLE RULES AND THE TOTAL
C POPULATIONS ARE SUMMED AT REGULAR INTERVALS OF TIME. THE CORRESPONDENCE
C BETWEEN ARRAY INDICES AND CARDINAL DIRECTIONS IS SHOWN BY THE DIAGRAMS
C BELOW WITH ARROWS POINTING IN THE DIRECTION OF INCREASING VALUE.
C 
C                   +-----J----->        
C                   |                                  
C                   |                   +--> EAST
C                   I   A(I,J)          |        
C                   |                   V 
C                   |                 SOUTH
C                   V                 
C
C PROCEDURES AND THEIR ROLES:
CCCCCCCCCCCCCCCCCCCCCCCCCCCCC
C
C SetLand: INITIALISES THE LOCAL RABBIT AND FOX POPULATIONS.
C Evolve:  IS CALLED REPEATEDLY TO COMPUTE THE NEXT GENERATION
C          OF BOTH FOXES AND RABBITS. Evolve CALLS THE SUBROUTINE
C          FillBorder HANDLE BOUNDARY CONDITIONS.
C GetPopulation: COMPUTES THE TOTAL POPULATION OF THE SPECIE
C          IT IS GIVEN AS ARGUMENT.
C FillBorder: HANDLES THE BOUNDARY CONDITIONS FOR THE SPECIE
C          IT IS GIVEN AS ARGUMENT.
C
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
C
C ARRAY DIMENSIONS AND RELATED PARAMETERS
C
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
      INCLUDE  'param.inc'
      INTEGER NITER, PERIOD
      PARAMETER (NITER=50, PERIOD=1)
C
C ARRAYS
C
C THE ARRAYS STORING THE NUMBER OF ANIMALS IN EACH STRETCH OF LAND HAVE
C BORDERS THAT ARE USED TO STORE HALO DATA THUS SIMPLIFYING THE CODING
C OF PERIODIC CONDITIONS. THE ACTUAL DATA FOR EACH ANIMAL POPULATION IS
C STORED IN COLUMNS 1 THROUGH WE_Size AND IN ROWS 1 THROUGH NS_Size OF THE
C ARRAYS BELOW.  FROM NEAREST NEIGHBOUR THE HALO DATA IS STORED IN ROWS
C 0 AND NS_Size+1 AND IN COLUMNS 0 AND WE_Size+1 OF THOSE ARRAYS.
C
      REAL Rabbit(0:NS_Size+1,0:WE_Size+1),
     &     Fox(0:NS_Size+1,0:WE_Size+1)
C
C THE ARRAY NAMED model RECORDS THE PARAMETERS OF THE PREDATOR-PREY MODEL.
C
      REAL model(2,3)
C
C FUNCTION & INTRINSIC
C
      INTEGER NINT, MOD
      INTRINSIC NINT, MOD, MAX
C
C LOOP INDICES AND COUNTERS
C
      INTEGER K
      INTEGER nbrab, nbfox
C
C THE ERROR CODE
C
      INTEGER ierror
C
C INITIALISE THE PROBLEM
C
      CALL SetLand(Rabbit,Fox,model,ierror)
C
C ITERATE
C
      DO K = 1, NITER

         CALL Evolve(Rabbit,Fox,model,ierror)
         IF( MOD(K,PERIOD).EQ.0 ) THEN
            CALL GetPopulation(Rabbit,nbrab,ierror)
            CALL GetPopulation(Fox,nbfox,ierror)
            WRITE (*, 100), 'Year ', K, ' : ', 
     &            nbrab, ' rabbits and ', nbfox, ' foxes.'
         END IF
      END DO
 100  FORMAT(A5,I3,A3,I10,A13,I10,A7)
      STOP
      END

CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
C
C INITIALISE THE POPULATION OF RABBITS AND FOXES.
C
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
      SUBROUTINE SetLand(Rabbit,Fox,model,ierror)
      IMPLICIT NONE
      INCLUDE 'param.inc'
      REAL Rabbit(0:NS_Size+1,0:WE_Size+1),
     &   Fox(0:NS_Size+1,0:WE_Size+1), model(2,3)
      INTEGER ierror

      INTEGER gi, gj
C
C SET THE PARAMETERS OF THE PREDATOR-PREY MODEL
C
       model(RAB,SAME) = -0.2
       model(RAB,OTHER) = 0.6
       model(RAB,MIGRANT) = 0.01
       model(FXX,OTHER) = 0.6
       model(FXX,SAME) = -1.8
       model(FXX,MIGRANT) = 0.02
C
C INITIALISE THE ANIMAL POPULATIONS
C 
      DO gj = 1, WE_Size
         DO gi = 1, NS_Size
             Rabbit(gi,gj) =
     &          128.0*(gi-1)*(NS_Size-gi)*(gj-1)*(WE_Size-gj) /
     &          REAL(NS_Size*NS_Size*WE_Size*WE_Size)
             Fox(gi,gj) =
     &          8.0*(gi/REAL(NS_Size)-0.5)*(gi/REAL(NS_Size)-0.5)+ 
     &          8.0*(gj/REAL(WE_Size)-0.5)*(gj/REAL(WE_Size)-0.5)
         END DO
      END DO

      RETURN
      END
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
C
C COMPUTE THE NEXT GENERATION OF FOXES AND RABBITS
C
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
      SUBROUTINE Evolve(Rabbit,Fox,model,ierror)
      IMPLICIT NONE
      INCLUDE 'param.inc'
      REAL Rabbit(0:NS_Size+1,0:WE_Size+1),
     &   Fox(0:NS_Size+1,0:WE_Size+1), model(2,3)
      INTEGER ierror

      INTEGER gi, gj

      REAL TRabbit(0:NS_Size+1,0:WE_Size+1),
     &   TFox(0:NS_Size+1,0:WE_Size+1)
      REAL AlR, BtR, MuR, AlF, BtF, MuF

      AlR = model(RAB,SAME)
      BtR = model(RAB,OTHER)
      MuR  = model(RAB,MIGRANT)
      BtF = model(FXX,SAME)
      AlF = model(FXX,OTHER)
      MuF  = model(FXX,MIGRANT)
C
C FILL-IN THE BORDERS OF THE LOCAL Rabbit and Fox ARRAYS.
C
      CALL FillBorder(Rabbit,ierror)
      CALL FillBorder(Fox,ierror)
C
C UPDATE THE RABBIT AND FOX POPULATIONS.
C
      DO gj = 1, WE_Size
         DO gi = 1, NS_Size
            TRabbit(gi,gj) = (1.0+AlR-4.0*MuR)*Rabbit(gi,gj) +
     &         BtR*Fox(gi,gj) +
     &         MuR*(Rabbit(gi,gj-1)+Rabbit(gi,gj+1)+
     &             Rabbit(gi-1,gj)+Rabbit(gi+1,gj))

            TFox(gi,gj) = AlF*Rabbit(gi,gj) +
     &         (1.0+BtF-4.0*MuF)*Fox(gi,gj) +
     &         MuF*(Fox(gi,gj-1)+Fox(gi,gj+1)+
     &             Fox(gi-1,gj)+Fox(gi+1,gj))
         END DO
      END DO
C
C ENSURE THE NUMBERS IN Rabbit and Fox ARE NON-NEGATIVE.
C
      DO gj = 1, WE_Size
         DO gi = 1, NS_Size
            Rabbit(gi,gj) = MAX(0.0, TRabbit(gi,gj))
            Fox(gi,gj) = MAX(0.0, TFox(gi,gj))
         END DO
      END DO

      RETURN
      END
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
C
C SET THE BOUNDARY CONDITIONS FOR A SINGLE ANIMAL POPULATION. 
C
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
      SUBROUTINE FillBorder(Animal,ierror)
      IMPLICIT NONE
      INCLUDE 'param.inc'
      REAL Animal(0:NS_Size+1,0:WE_Size+1)
      INTEGER ierror
      INTEGER i, j
C
C MOVE BORDERS TO THE EAST AND TO THE WEST.
C
      DO i = 1, NS_Size
         Animal(i,0) = Animal(i,WE_Size)
         Animal(i,WE_Size+1) = Animal(i,1)
      END DO
C
C MOVE BORDERS TO THE NORTH AND TO THE SOUTH.
C
      DO j = 1, WE_Size
         Animal(0,j) = Animal(NS_Size,j)
         Animal(NS_Size+1,j) = Animal(1,j)
      END DO

      RETURN
      END
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
C
C COUNT THE TOTAL POPULATION FOR A SINGLE SPECIE.
C
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
      SUBROUTINE GetPopulation(Animal,count,ierror)
      IMPLICIT NONE
      INCLUDE 'param.inc'
      REAL Animal(0:NS_Size+1,0:WE_Size+1)
      INTEGER count
      INTEGER ierror
      INTEGER i, j
      REAL p

      INTRINSIC NINT

      p = 0.0
      DO j = 1, WE_Size
         DO i = 1, NS_Size
            p = p + Animal(i,j)
         END DO
      END DO

      count = NINT(p)

      RETURN
      END



