c
c     closurestats - calculate statistics (area, volume, etc) for
c                    fundamental closures identified by sortclosures
c                    program.
c
c     Saltus - 14 Sep 2001 - for NPRA oil & gas assessment project
c
      program closurestats
c
      parameter (MAXPTS=300,MAXROWS=500,MAXCOLS=600)
      parameter (MAXCLOSE=5000)
      parameter (dval1=1e30,dval2=-1e31)
      dimension xpts(MAXCLOSE,MAXPTS),ypts(MAXCLOSE,MAXPTS)
      dimension grid(MAXROWS,MAXCOLS)
      dimension hgrid(MAXROWS,MAXCOLS)
      dimension areaka(MAXCLOSE),volkm3(MAXCLOSE)
      dimension topdepth(MAXCLOSE),ttopdepth(MAXCLOSE)
      dimension ntopdepth(MAXCLOSE)
      dimension heightft(MAXCLOSE),narea(MAXCLOSE),nheight(MAXCLOSE)
      dimension nareahist(MAXCLOSE/10),nheighthist(MAXCLOSE/10)
      dimension ntophist(MAXCLOSE/10)
      dimension tareaka(MAXCLOSE),theightft(MAXCLOSE)
      dimension thmin(MAXCLOSE),thmax(MAXCLOSE),tzval(MAXCLOSE)
      dimension txcenter(MAXCLOSE),tycenter(MAXCLOSE),tnpts(MAXCLOSE)
      dimension itcont(MAXCLOSE)
      character id*56,pgm*8
      character buffer*80
      integer tnpts
c
      print *,'open chosen.xyz, grid.sg, and stats.xyz'
c
      open(10,file="chosen.xyz",form='formatted',status='old')
      open(11,file="grid.sg",form='unformatted',status='old')
      open(12,file="stats.xyz",form='formatted',status='unknown')
      open(13,file="centers.xyz",form='formatted',status='unknown')
      open(14,file="ccontours.xyz",form='formatted',status='unknown')
c
c     read grid into memory
c
      print *,'reading grid into memory...'
      read(11)id,pgm,ncol,nrow,nz,xo,dx,yo,dy
      print *, id,pgm,ncol,nrow,nz,xo,dx,yo,dy
      cellarea=dx*dy
      ndatacells=0
      do 3 i=1,nrow
        read(11)dummy,(grid(i,j),j=1,ncol)
        do 2 k=1,ncol
          if ((grid(i,k).gt.-1e30).and.(grid(i,k).lt.1e30)) then
            ndatacells=ndatacells+1
          end if
    2   continue
    3 continue
c
      print *, 'grid input to memory'
      percentdata=real(ndatacells)/real(ncol*nrow)
      dataareakm=ndatacells*cellarea/(1000*1000)
c
c     1 km^2 = 0.391 sq mile
c     1 sq mile = 640 acres
c     1 km^2 = 250 acres
c     (km^2)/4 = k acres = ka
c
      dataareaka=dataareakm/4
      print *, 'data area (% of grid) =',percentdata*100.
      print *, 'data area (kacres) =',dataareaka
c
      buffer='"Automated statistics on closed highs"'
      write(12,*)buffer
      buffer='"from program closurestats v1.0 (Saltus, USGS, 10/2001)"'
      write(12,*)buffer
      buffer='"CONTOUR INTERVAL:"'
      write(12,*)buffer
      buffer='"GRID INTERVAL:"'
      write(12,*)buffer
      buffer='"PLAY NAME:"'
      write(12,*)buffer
      buffer='"SURFACE NAME:"'
      write(12,*)buffer
      write(12,*)
      buffer='"Total data area of grid (kacres)"'
      write(12,*)buffer
      write(12,*)dataareaka
      write(12,*)
c
c     initial hgrid (output of closure heights)
c
      do 4 i=1,nrow
      do 44 j=1,ncol
        hgrid(i,j)=dval2
   44 continue
    4 continue
c
c     input contours and compute stats
c
      ncount=1
      ncontour=1
    5 continue
      read(10,*,end=999)xpts(ncontour,1),ypts(ncontour,1),
     & zval,ndir,num,tnpts(ncontour)
      itcont(ncount)=0
      xmin=xpts(ncontour,1)
      xmax=xpts(ncontour,1)
      ymin=ypts(ncontour,1)
      ymax=ypts(ncontour,1)
      do 10 i=2,tnpts(ncontour)
      read(10,*)xpts(ncontour,i),ypts(ncontour,i)
      if (xpts(ncontour,i).lt.xmin) xmin=xpts(ncontour,i)
      if (xpts(ncontour,i).gt.xmax) xmax=xpts(ncontour,i)
      if (ypts(ncontour,i).lt.ymin) ymin=ypts(ncontour,i)
      if (ypts(ncontour,i).gt.ymax) ymax=ypts(ncontour,i)
   10 continue
c     print *,'read',num,' contour with',tnpts(ncontour),' points.'
c     print *,xmin,xmax,ymin,ymax,' = xmin,xmax,ymin,ymax'
c
c     calculate statistics
c
      istart=1+(ymin-yo)/dy
      istart=max(1,istart)
      istart=min(nrow,istart)
      iend=1+(ymax-yo)/dy
      iend=max(1,iend)
      iend=min(nrow,iend)
      jstart=1+(xmin-xo)/dx
      jstart=max(1,jstart)
      jstart=min(ncol,jstart)
      jend=1+(xmax-xo)/dx
      jend=max(1,jend)
      jend=min(ncol,jend)
c     if ((istart.eq.ncol).or.(jstart.eq.nrow)) then
c       print *,'Outside grid area',istart,iend,jstart,jend
c       goto 5
c     end if

c
c     check that grid coords are within spec
c
c
c     print *,istart,iend,jstart,jend,
c    &    ' = istart,iend,jstart,jend'
c
      xcenter=xmin+(xmax-xmin)/2
      ycenter=ymin+(ymax-ymin)/2
c
      area=0.
      volpos=0.
      volneg=0.
      heightmax=0.
      heightmin=0.
      ncellp=0.
      ncelln=0.
c
      do 20 i=istart,iend
        do 15 j=jstart,jend
          xtest=xo+(j-1)*dx
          ytest=yo+(i-1)*dy
c     print *,'calling inside'
          intest=inside(xtest,ytest,xpts,ypts,tnpts(ncontour),
     &                  ncontour,MAXCLOSE,MAXPTS)
c     print *,'back from inside'
          if ((intest.eq.0).and.(grid(i,j).lt.1e20)
     &         .and.(grid(i,j).gt.-1e20)) then 
            cellheight=grid(i,j)-zval
            if (cellheight.gt.10.) then
              print *,ncontour,i,j,grid(i,j),zval
            end if
            if (cellheight.gt.0) then
              hgrid(i,j)=cellheight
              ncellp=ncellp+1
              volpos=volpos+cellheight*cellarea
              if (cellheight.gt.heightmax) heightmax=cellheight
            else
              ncelln=ncelln+1
              volneg=volneg+cellheight*cellarea
              if (cellheight.lt.heightmin) heightmin=cellheight
            end if
          end if
   15   continue
   20 continue
      volposkm3=volpos/(1000*1000*3.28)
      volnegkm3=volneg/(1000*1000*3.28)
      volume=volposkm3+volnegkm3
      areakm2=ncellp*cellarea/(1000*1000)
c
c     units - currently a mix of kft (zval) & meters (x,y)
c      
      if (volume.gt.0.0) then
        areaka(ncount)=areakm2/4.
        tareaka(ncount)=areakm2/4.
        volkm3(ncount)=volposkm3
        heightft(ncount)=3280.*(volposkm3/areakm2)
        theightft(ncount)=3280.*(volposkm3/areakm2)
        topdepth(ncount)=zval+heightmax
        ttopdepth(ncount)=topdepth(ncount)
c       print *,ncount,xcenter/1000,ycenter/1000,zval,areaka(ncount)
c       print *,ncontour
c       write(12,100)ncount,xcenter/1000,ycenter/1000,zval,areakm2/4,
c    &      volposkm3,heightft(ncount),heightmin*1000,heightmax*1000
        txcenter(ncount)=xcenter
        tycenter(ncount)=ycenter
        tzval(ncount)=zval
        thmin(ncount)=heightmin
        thmax(ncount)=heightmax
        itcont(ncount)=ncontour
        ncount=ncount+1
      end if
      ncontour=ncontour+1
      goto 5
c
  999 continue
      ncount=ncount-1
      print *,ncount,' closed contours with positive volume'
      print *,'creating hgrid.sg output grid...'
c
      open(15,file="hgrid.sg",form='unformatted',status='unknown')
      id="Closure height grid"
      pgm="clsrstat"
      write(15)id,pgm,ncol,nrow,nz,xo,dx,yo,dy
      do 50 i=1,nrow
        write(15)dummy,(hgrid(i,j),j=1,ncol)
   50 continue
c
c     find 5%, 50%, and 95% values for area & height
c
      i5=nint(real(ncount)*.05)
      i50=nint(real(ncount)*.5)
      i95=nint(real(ncount)*.95)
      if (i5.le.0) i5=1
      if (i95.gt.ncount) i95=ncount
      print *,'i5, i50, i95 =',i5,i50,i95
c
      call rshsort(areaka,narea,ncount)
      call rshsort(heightft,nheight,ncount)
      call rshsort(topdepth,ntopdepth,ncount)
      write(12,*)
      buffer='"AREA distribution (kacre)"'
      write(12,*)buffer
      write(12,150)'M5%','M50%','M95%'
      write(12,155)areaka(i5),areaka(i50),areaka(i95)
      print *,'Area (kacres) distribution:'
      print *,'M5%=',areaka(i5),' M50%=',areaka(i50),
     & ' M95%=',areaka(i95)
      write(12,*)
      buffer='"HEIGHT distribution (ft)"'
      write(12,*)buffer
      write(12,150)'M5%','M50%','M95%'
      write(12,155)heightft(i5),heightft(i50),heightft(i95)
      print *,'Height (ft) distribution:'
      print *,'M5%=',heightft(i5),' M50%=',heightft(i50),
     & ' M95%=',heightft(i95)
      write(12,*)
      buffer='"TOPDEPTH distribution (kft)"'
      write(12,*)buffer
      write(12,150)'M5%','M50%','M95%'
      write(12,155)topdepth(i5),topdepth(i50),topdepth(i95)
      print *,'Topdepth (kft) distribution:'
      print *,'M5%=',topdepth(i5),' M50%=',topdepth(i50),
     & ' M95%=',topdepth(i95)
  150 format(3a12)
  155 format(3f12.5) 
c
c     construct area and height histograms
c
      print *,'Histograms...'
c
      nbins=ncount/10.
      areaint=areaka(ncount)/nbins
      heightint=heightft(ncount)/nbins
      topint=(topdepth(ncount)-topdepth(1))/nbins
c
      print *,'area interval =',areaint
      print *,'height interval =',heightint
      print *,'top interval =',topint
c
      do 60 i=1,nbins
        nareahist(i)=0
        nheighthist(i)=0 
        ntophist(i)=0 
   60 continue
c
      do 65 i=1,ncount
        iabin=ifix(areaka(i)/areaint)+1
        if (iabin.gt.nbins) iabin=nbins
        ihbin=ifix(heightft(i)/heightint)+1
        if (ihbin.gt.nbins) ihbin=nbins
        itbin=ifix((topdepth(i)-topdepth(1))/topint)+1
        if (itbin.gt.nbins) itbin=nbins
        nareahist(iabin)=nareahist(iabin)+1
        nheighthist(ihbin)=nheighthist(ihbin)+1
        ntophist(itbin)=ntophist(itbin)+1
c       print *,areaka(i),iabin,heightft(i),ihbin
   65 continue
c
      write(12,*)
      buffer='"Histograms"'
      write(12,*)buffer
      write(12,160)'Bin','Area_ka','#pts','Height_ft','#pts',
     & 'Top_kft','#pts'
      do 70 i=1,nbins
        write(12,165)i,areaint*i,nareahist(i),
     &                 heightint*i,nheighthist(i),
     &                 topdepth(1)+topint*(i-1),ntophist(i)
  160   format(a5,a12,a5,a12,a5,a12,a5)
  165   format(i5,f12.2,i5,f12.0,i5,f12.3,i5)
   70 continue  
c
c     write stats file header
c
      write(12,*)
      buffer='"Summary table for closed highs"'
      write(12,*)buffer
      write(12,105)'num',' xcenter_km',' ycenter_km',
     & ' bot_kft','top_kft',' area_ka',' vol_km3',' vol_kaft',
     & ' have_ft',' hmin_ft',' hmax_ft'
  100   format(i5,2f12.3,2f8.1,f12.2,2f12.2,f8.1,2f10.1)
  105   format(a5,2a12,2a8,3a12,a8,2a10)
c
c     write stats file table
c
      do 80 i=1,ncount
        j=narea(ncount+1-i)
        write(12,100)i,txcenter(j)/1000,tycenter(j)/1000,
     &              tzval(j),ttopdepth(j),tareaka(j),
     &      volkm3(j),volkm3(j)*820,
     &      theightft(j),thmin(j)*1000,thmax(j)*1000
        write(13,*)txcenter(j),tycenter(j),i,tzval(j)
        write(14,'("LINE ",i5)')i
        do 30 ix=1,tnpts(itcont(j))
          write(14,*)xpts(itcont(j),ix),ypts(itcont(j),ix)
   30   continue
   80 continue
c
      close(11)
      close(12)
      close(13)
      close(14)
      close(15)
      end
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
      subroutine rshsort (array,neword,num)
c     Modified from Kernighan and Pflauger, Elements of Programming Style,
c       page 134.

c      array = list of reals; List is returned sorted...
c      neword = integer array
c         (If i is index in sorted list,
c          then neword(i) is position in original list.)
c      num  = number of items in list

      real array(num)
      integer neword(num)

      do 2 i=1,num
  2   neword(i)=i

      igap=num
  5   if(igap.le.1) return
      igap=igap/2
      imax=num-igap

 10   iex=0

      do 20 i=1,imax
      iplusg=i+igap
      if(array(i).le.array(iplusg)) go to 20
        save=array(i)
        array(i)=array(iplusg)
        array(iplusg)=save
        indtmp=neword(i)
        neword(i)=neword(iplusg)
        neword(iplusg)=indtmp
      iex=1
 20   continue

      if(iex.ne.0) goto 10
      goto 5

      end
C+
C      INSIDE - tests whether point is inside polygon
C
C    Call INSIDE (x,y,xbod,ybod,npt,nbd,mbod,mcorn)
C
C    x,y= point to test
C    xbod,ybod= two-dimensional arrays with corners of body
C    npt= number of points in body
C    nbd= body number (first subscript of xbod, ybod)
C    mbod= 1st dimension of xbod,ybod arrays
C    mcorn= 2nd dimension of xbod,ybod arrays
C
C    RETURNS:  0= x,y inside
C              1= x,y outside
C-
C  *********************************************
      Integer Function inside(x,y,xbod,ybod,npt,nbd,mbod,mcorn)
      Dimension xbod(mbod,mcorn),ybod(mbod,mcorn)
c     Double Precision 
C
C     bail for trivial cases npt=1 or 2
C
      if (npt.le.2) then
        inside=1
        return
      end if
C
C     find xmin,xmax,ymin,ymax for polygon
C
      xmin=xbod(nbd,1)
      xmax=xbod(nbd,1)
      ymin=ybod(nbd,1)
      ymax=ybod(nbd,1)
      do 10 i=1,npt
        if (xbod(nbd,i).lt.xmin) xmin=xbod(nbd,i)
        if (xbod(nbd,i).gt.xmax) xmax=xbod(nbd,i)
        if (ybod(nbd,i).lt.ymin) ymin=ybod(nbd,i)
        if (ybod(nbd,i).gt.ymax) ymax=ybod(nbd,i)
   10 continue
c     print *,'xmin,xmax,ymin,ymax=',xmin,xmax,ymin,ymax
C
C     check if test point completely outside polygon box
C
      if ((x.gt.xmax).or.(x.lt.xmin).or.(y.gt.ymax)
     &               .or.(y.lt.ymin)) then
        inside=1
c       print *,'test point outside polygon bounding box'
        return
      end if
C
C     construct radial line from test point to a point
C      outside the polygon min, max box
C
      x2=xmax+2.*abs(xmax)
      y2=ymax+3.*abs(ymax)
c
c
c     print *,'x2,y2=',x2,y2
C
C     check for intersections of radial line with all polygon sides
C     int is number of intersections
C     if int=odd, then pt is inside
C     if int=even, then pt is outside
C
      int=0
      ipar=0
      Do 50 i=1,npt-1
      xp1=xbod(nbd,i)
      yp1=ybod(nbd,i)
      xp2=xbod(nbd,i+1)
      yp2=ybod(nbd,i+1)
      intest=insect2(x,y,x2,y2,xp1,yp1,xp2,yp2,int,ipar)
c     print *,'i,int=',i,int
      if (intest.ne.0) then
        x2t=xmin-3.*abs(xmin)
        y2t=ymin-2.*abs(ymin)
        intest=insect2(x,y,x2t,y2t,xp1,yp1,xp2,yp2,int,ipar)
        if (intest.ne.0) then
          print *,'Possible missed intersection'
        end if
      end if
   50 Continue
      xp1=xbod(nbd,npt)
      yp1=ybod(nbd,npt)
      xp2=xbod(nbd,1)
      yp2=ybod(nbd,1)
      intest=insect2(x,y,x2,y2,xp1,yp1,xp2,yp2,int,ipar)
c     print *,'i,int=',i+1,int
      if (intest.ne.0) then
        x2t=xmin-3.*abs(xmin)
        y2t=ymin-2.*abs(ymin)
        intest=insect2(x,y,x2t,y2t,xp1,yp1,xp2,yp2,int,ipar)
        if (intest.ne.0) then
          print *,'Possible missed intersection'
        end if
      end if
C
C     examine int and report results
C
c     print *,'int=',int
      If (mod(int,2).EQ.0) then
        inside=1
c       int1=int
c
c     if first answer is outside, try again (just in case)
c
c       x2=xmin-2.*abs(xmin)
c       y2=ymin-3.*abs(ymin)
c       int=0
c       ipar=0
c       Do 150 i=1,npt-1
c       xp1=xbod(nbd,i)
c       yp1=ybod(nbd,i)
c       xp2=xbod(nbd,i+1)
c       yp2=ybod(nbd,i+1)
c       intest=insect2(x,y,x2,y2,xp1,yp1,xp2,yp2,int,ipar)
c       print *,'i,int=',i,int
c       if (intest.ne.0) then
c         x2t=xmin-3.*abs(xmin)
c         y2t=ymin-2.*abs(ymin)
c         intest=insect2(x,y,x2t,y2t,xp1,yp1,xp2,yp2,int,ipar)
c         if (intest.ne.0) then
c           print *,'Possible missed intersection'
c         end if
c       end if
c 150   Continue
c       xp1=xbod(nbd,npt)
c       yp1=ybod(nbd,npt)
c       xp2=xbod(nbd,1)
c       yp2=ybod(nbd,1)
c       intest=insect2(x,y,x2,y2,xp1,yp1,xp2,yp2,int,ipar)
c       print *,'i,int=',i+1,int
c       if (intest.ne.0) then
c         x2t=xmin-3.*abs(xmin)
c         y2t=ymin-2.*abs(ymin)
c         intest=insect2(x,y,x2t,y2t,xp1,yp1,xp2,yp2,int,ipar)
c         if (intest.ne.0) then
c           print *,'Possible missed intersection'
c         end if
c       end if
c       if (mod(int,2).ne.mod(int1,2)) then
c         print *,'Changed result with 2nd insect2 test...'
c       end if
c       if (mod(int,2).EQ.0) then
c         inside=1
c       else
c         inside=0
c       end if
      else
        inside=0
      end if
      Return
      End
C
C     INSECT2  finds intersection of two lines 
C
C  *********************************************
      Integer function insect2(x1,y1,x2,y2,a1,b1,a2,b2,int,ipar)
C
C     if an intersection is found, then increment int
C     if lines are parallel, increment ipar
C
C     insect2=0 normal return
C            =1 intersection falls on a1,b1
C            =2 intersection falls on a2,b2
C
C     conditions 1 & 2 could mean that line is tangent to
C       polygon (no intersection) or that it crosses at 
C       vertex (intersection).  Further testing is required
C       to solve this condition.
C
C     xsect(x1,y1,x2,y2,yloc)=(yloc-y1)*((x2-x1)/(y2-y1))+x1
C 
C     calculate line parameters
C
C     slopes (s) & intercepts (yint)
C
C     ltype = 0 for finite slope
C           = 1 for vertical line
C
      insect2=0
c     print *,'x1,y1,x2,y2=',x1,y1,x2,y2
c     print *,'a1,b1,a2,b2=',a1,b1,a2,b2
      if (x2.eq.x1) then
        ltype1=1
      else
        ltype1=0
        s1=(y2-y1)/(x2-x1)
        yint1=y1-s1*x1
c       print *,'s1,yint1=',s1,yint1
      end if
      if (a2.eq.a1) then
        ltype2=1
      else
        ltype2=0
        s2=(b2-b1)/(a2-a1)
        yint2=b1-s2*a1
c       print *,'s2,yint2=',s2,yint2
      end if
C
C     Set min, max for line segments
C
      if (x1.lt.x2) then
        xmin=x1
        xmax=x2
      else
        xmin=x2
        xmax=x1
      end if
      if (y1.lt.y2) then
        ymin=y1
        ymax=y2
      else
        ymin=y2
        ymax=y1
      end if
      if (a1.lt.a2) then
        amin=a1
        amax=a2
      else
        amin=a2
        amax=a1
      end if
      if (b1.lt.b2) then
        bmin=b1
        bmax=b2
      else
        bmin=b2
        bmax=b1
      end if
C
C     find intersection and test if it is on both segments
C
      if ((ltype1.eq.0).and.(ltype2.eq.0)) then
C
C     both lines not vertical
C
        if (s1.eq.s2) then
C
C     equal slopes = parallel
C
          ipar=ipar+1
        else
C
C     not parallel
C
          xi=(yint2-yint1)/(s1-s2)
          yi=s1*xi+yint1
          if (s1.eq.0) then
C
C     line 1 horizontal
C
            if ((xi.gt.xmin).and.(xi.lt.xmax).and.
     &          (xi.gt.amin).and.(xi.lt.amax).and.
     &          (yi.gt.bmin).and.(yi.lt.bmax)) then
              int=int+1
            end if
          else if (s2.eq.0) then
C
C     line 2 horizontal
C
            if ((xi.gt.xmin).and.(xi.lt.xmax).and.
     &          (xi.gt.amin).and.(xi.lt.amax).and.
     &          (yi.gt.ymin).and.(yi.lt.ymax)) then
              int=int+1
            end if
          else
C
C     neither line horizontal
C
            if ((xi.gt.xmin).and.(xi.lt.xmax).and.
     &          (xi.gt.amin).and.(xi.lt.amax).and.
     &          (yi.gt.ymin).and.(yi.lt.ymax).and.
     &          (yi.gt.bmin).and.(yi.lt.bmax)) then
              int=int+1
            end if
          end if
        end if       
      else if ((ltype1.eq.1).and.(ltype2.eq.0)) then
C
C     line 1 vertical, line 2 not
C
        xi=x1
        yi=s2*xi+yint2
        if (s2.eq.0) then
C
C     line 2 horizontal
C
          if ((xi.gt.amin).and.(xi.lt.amax).and.
     &        (yi.gt.ymin).and.(yi.lt.ymax)) then
            int=int+1
          end if
        else
C
C     line 2 not horizontal
C
          if ((xi.gt.amin).and.(xi.lt.amax).and.
     &        (yi.gt.ymin).and.(yi.lt.ymax).and.
     &        (yi.gt.bmin).and.(yi.lt.bmax)) then
            int=int+1
          end if
        end if
      else if ((ltype1.eq.0).and.(ltype2.eq.1)) then
C
C     line 2 vertical, line 1 not
C
        xi=x2
        yi=s1*xi+yint1
        if (s1.eq.0) then
C
C     line 1 horizontal
C
          if ((xi.gt.xmin).and.(xi.lt.xmax).and.
     &        (yi.gt.bmin).and.(yi.lt.bmax)) then
            int=int+1
          end if
        else
C
C     line 1 not horizontal
C
          if ((xi.gt.xmin).and.(xi.lt.xmax).and.
     &        (yi.gt.ymin).and.(yi.lt.ymax).and.
     &        (yi.gt.bmin).and.(yi.lt.bmax)) then
            int=int+1
          end if
        end if
      else
C
C     both lines vertical = parallel
C
        ipar=ipar+1
      end if
C
      Return
      End
