      PROGRAM invasion
*     generate invasion percolation cluster
      IMPLICIT NONE
      REAL*8 site(0:200,0:100)
      INTEGER IR_, Lx, Ly, perx(5000), pery(5000), nper
      CALL GWopen(IR_, 0)
      CALL initial(Lx,Ly)
      CALL assign(site,perx,pery,nper,Lx,Ly)
      CALL invade(site,perx,pery,nper,Lx,Ly)
      CALL average(site,Lx,Ly)
      CALL GWquit(IR_)
      END
C
      SUBROUTINE initial(Lx,Ly)
      IMPLICIT NONE
      REAL xwin, ywin, GWaspect
      REAL dmy, rnd
      INTEGER IR_, x, y, Lx, Ly
      dmy = rnd(-1)
      WRITE(*,'(A,$)') 'length in y direction = '
      READ(*,*) Ly
      Lx = 2*Ly
      CALL GWvport(IR_, 0.01*GWaspect(1), 0.2, 0.65*GWaspect(1), 0.99)
      CALL compute_aspect_ratio(REAL(Lx),xwin,ywin)
      CALL GWindow(IR_, -0.5, -0.5, xwin-0.5, ywin-0.5)
      CALL GWsetpen(IR_, 0, -1, -1, -1)
      CALL GWrect(IR_, 1.0, 1.0, Lx+1.0, Ly+1.0)
      DO y = 1, Ly
         DO x = 1, Lx
            CALL GWsetpxl(IR_, REAL(x)+0.5, REAL(y)+0.5, 0)
         END DO
      END DO
      END
C
      SUBROUTINE assign(site,perx,pery,nper,Lx,Ly)
      IMPLICIT NONE
      REAL*8 site(0:200,0:100)
      REAL rnd
      INTEGER IR_, x, y, nper, perx(5000), pery(5000), Lx, Ly
      DO y = 1, Ly
         site(1,y) = 1                      ! occupy first column
         CALL GWsrect(IR_, 1.0, REAL(y), 
     +                     2.0, REAL(y)+1.0, 16)
      END DO
*     assign random numbers to remaining sites
      DO y = 1, Ly
         DO x = 2, Lx
            site(x,y) = rnd(0)
         END DO
      END DO
*     sites in second column are initial perimeter sites
*     site(x,y) greater than 2 if perimeter site
      x = 2
      nper = 0
      DO y = 1, Ly
         site(x,y) = 2 + site(x,y)
         nper = nper + 1                    ! number of perimeter sites
*        sort perimeter sites
*        order perimeter list
         CALL insert(site,perx,pery,nper,x,y)
      END DO
      END
C
      SUBROUTINE insert(site,perx,pery,nper,x,y)
*     call linear or binary sort
      IMPLICIT NONE
      REAL*8 site(0:200,0:100)
      INTEGER ilist, ninsert, nper, x, y, perx(5000), pery(5000)
      CALL binary_search(site,perx,pery,nper,x,y,ninsert)
*     move sites with smaller random numbers to next higher array index
      DO ilist = nper, ninsert + 1, - 1
         perx(ilist) = perx(ilist-1)
         pery(ilist) = pery(ilist-1)
      END DO
      perx(ninsert) = x                     ! new site inserted in list
      pery(ninsert) = y
      END
C
      SUBROUTINE binary_search(site,perx,pery,nper,x,y,ninsert)
*     divide list in half and determine half in which random # belongs
*     continue this division until position of number is determined
      IMPLICIT NONE
      REAL*8 site(0:200,0:100)
      INTEGER nmid, xmid, ymid, nper, x, y, ninsert, nfirst, nlast, 
     +        perx(5000), pery(5000)
      LOGICAL Ltmp1_
      nfirst = 1                            ! beginning of list
      nlast = nper - 1                      ! end of list
      IF(nlast .LT. 1) nlast = 1
      nmid = (nfirst + nlast)/2             ! middle of list
*     determine which half of list new number is located
      Ltmp1_ = .TRUE.
      DO WHILE(Ltmp1_)
         IF(nlast - nfirst .LE. 1) THEN
            ninsert = nlast
            RETURN
         END IF
         xmid = perx(nmid)
         ymid = pery(nmid)
         IF(site(x,y) .GT. site(xmid,ymid)) THEN
            nlast = nmid                    ! search upper half
         ELSE
            nfirst = nmid                   ! search lower half
         END IF
         nmid = (nfirst + nlast)/2
      END DO
      END
C
      SUBROUTINE linear_search(site,perx,pery,nper,x,y,ninsert)
      IMPLICIT NONE
      REAL*8 site(0:200,0:100)
      INTEGER iper, xperim, yperim, nper, x, y, ninsert,
     +        perx(5000), pery(5000)
      IF(nper .EQ. 1) THEN
         ninsert = 1
      ELSE
         DO iper = 1, nper - 1
            xperim = perx(iper)
            yperim = pery(iper)
            IF(site(x,y) .GT. site(xperim,yperim)) THEN
               ninsert = iper               ! insert new site
               RETURN
            END IF
         END DO
      END IF
      ninsert = nper
      END
C
      SUBROUTINE invade(site,perx,pery,nper,Lx,Ly)
*     nx and ny are components of vectors pointing to nearest neighbors
      IMPLICIT NONE
      REAL*8 site(0:200,0:100)
      INTEGER IR_, nx(4), ny(4), perx(5000), pery(5000),
     +       Lx, Ly, i, x, xnew, y, ynew, nper, DP_, DATA_(8)
      LOGICAL Ltmp1_
      DATA DP_/1/, DATA_/1,0,-1,0,0,1,0,-1/
      DO i = 1, 4
         nx(i) = DATA_(DP_)
         DP_ = DP_ + 1
         ny(i) = DATA_(DP_)
         DP_ = DP_ + 1
      END DO
      Ltmp1_ = .TRUE.
      DO WHILE(Ltmp1_)
         x = perx(nper)
         y = pery(nper)
         nper = nper - 1
*        mark site occupied and no longer perimeter site
         site(x,y) = site(x,y) - 1
         CALL GWsrect(IR_, REAL(x), REAL(y), 
     +                     REAL(x)+1.0, REAL(y)+1.0, 16)
         DO i = 1, 4
            xnew = x + nx(i)
            ynew = y + ny(i)
            IF(ynew .GT. Ly) THEN
               ynew = 1
            ELSE IF(ynew .LT. 1) THEN
               ynew = Ly
            END IF
            IF(site(xnew,ynew) .LT. 1) THEN
               site(xnew,ynew) = site(xnew,ynew) + 2
               nper = nper + 1
               CALL insert(site,perx,pery,nper,xnew,ynew)
            END IF
         END DO
         Ltmp1_ = .NOT.(x .GE. Lx)
      END DO
      END
C
      SUBROUTINE average(site,Lx,Ly)
*     compute probability density P(r)
      IMPLICIT NONE
      REAL*8 site(0:200,0:100), dr, r, P(0:20)
      INTEGER Lmax, Lmin, n, nbin, nr(0:20), occupied,
     +       ibin, x, y, Lx, Ly
      DATA occupied/0/, P/21*0.0D0/, nr/21*0/
      Lmin = Lx/3
      Lmax = 2*Lmin
      n = (Lmax - Lmin + 1)*Ly              ! # sites in middle half of lattice
      dr = 0.05D0
      nbin = 1/dr
      DO x = Lmin, Lmax
         DO y = 1, Ly
            ibin = nbin*(mod(site(x,y),1))
            nr(ibin) = nr(ibin) + 1
            IF(site(x,y) .GE. 1 .AND. site(x,y) .LT. 2) THEN
               occupied = occupied + 1      ! total # of occupied sites
               P(ibin) = P(ibin) + 1
            END IF
         END DO
      END DO
      WRITE(*,*) '# occupied sites =', occupied
      WRITE(*,'(2A13)') ' r', '  P(r)'
      WRITE(*,*)
      DO ibin = 0, nbin
         r = dr*ibin
         IF(nr(ibin) .GT. 0) WRITE(*,'(2F13.6)') r, P(ibin)/nr(ibin)
      END DO
      WRITE(*,*)
      END
