c
c  FUNCTION EPDF(EF,EW,N,Q,ICTL)
c  Prgmmr: Yuejian Zhu           Org: np23          Date: 2007-0801
c
c   function epdf to build up Probability Density Function by using picewise
c     linear approximation.
c
c   parameters:
c     input:
c     ef   -- forecasts for n ensemble members
c     ew   -- forecast weights for n ensemble members
c     n    -- ensemble members
c     qq   -- forecast value (specified) when ictl = 1
c          -- probability value (0-1.0, specified) when ictl = -1
c          -- 1.0  for weighted mean when ictl = 0
c          -- -1.0 for unweighted mean when ictl = 0
c          -- 2.0  for weighted spread when ictl = 0
c          -- -2.0 for unweighted spread when ictl = 0
c     ictl -- 1 to calculate probability from forecast value 
c            -1 to calculate forecast value from giving probability
c             0 to calculate special requests                       
c
c   Fortran 77 on IBMSP
c
      function epdf(ef,ew,n,qq,ictl)
      dimension ef(n),ew(n)
      dimension q(n),u(n),w(n),qa(n+1),d(n,3)
C--------+---------+---------+---------+---------+---------+---------+---------+
c
c     normalized the weights in case of input weights are not normalized
c
c     print *, "ew=",(ew(i),i=1,n)
c     print *, "ef=",(ef(i),i=1,n)
      ew1 = 0.0
      do i = 1, n
       ew1 = ew1 + ew(i)
      enddo
      do i = 1, n
       ew(i) = ew(i)/ew1
      enddo
c
      if (ictl.eq.0) then
c
c     for special requests:
c     if qq=1.0,  to calculate weighted mean
c     if qq=-1.0, to calculate unweighted mean
c     if qq=2.0,  to calculate weighted spread
c     if qq=-2.0, to calculate unweighted spread
c
       wm = 0.0
       uwm = 0.0
       do i = 1, n
        wm = wm + ef(i)*ew(i)
        uwm = uwm + ef(i)/float(n)
       enddo
       epdf = 0.0
       if (qq.eq.1.0) then
        epdf = wm                     
       else if (qq.eq.-1.0) then
        epdf = uwm                        
       else if (qq.eq.2.0) then
        ssprd = 0.0
        do i = 1, n
         ssprd = ssprd + (ef(i)-wm)*ew(i)*(ef(i)-wm)*ew(i)
        enddo
        epdf = sqrt(ssprd*float(n*n)/float(n-1))
       else if (qq.eq.-2.0) then
        ssprd = 0.0
        do i = 1, n
         ssprd = ssprd + (ef(i)-uwm)*(ef(i)-uwm)
        enddo
        epdf = sqrt(ssprd/float(n-1))
c       return
       else
        epdf=-9999.99
c       return
       endif
       return
      endif
c
c     This sorting program will:
c      keep original data order
c      get new order (low to high)
c      new order data with original index
c
      do i = 1, n
       d(i,1) = ef(i)
      enddo
      call sortmm(d,n,3,1)
c     write (*,'("ORG DATA SET",13f5.1)') (d(i,1),i=1,n)
c     write (*,'("NEW DATA SET",13f5.1)') (d(i,2),i=1,n)
c     write (*,'("N DATA INDEX",13f5.1)') (d(i,3),i=1,n)

      do i = 1, n
       ef(i) = d(i,2)
      enddo
c
c     consider statistical the same values if their difference is less wqual to
c
      cr = (ef(n) - ef(1))*0.001
c
c     to eliminate the duplication, give extra weight
c     m will be new dimension after this process (m<=n)
c
      m = 1
      q(1) = ef(1)
      u(1) = ew(int(d(1,3)))
      do i = 2, n  
       if ((ef(i)-ef(i-1)).gt.cr) then
        m = m + 1
        q(m) = ef(i)
        u(m) = ew(int(d(i,3)))                 
       else
        u(m) = u(m) + ew(int(d(i,3)))
       endif
      enddo
c
c     for extreme case, all ensemble values are the same
c
      if (m.eq.1) then
       if (ictl.eq.1) then
        if (qq.lt.q(1)) then
         epdf=0.0
         return
        else if (qq.gt.q(m)) then
         epdf=100.0
         return
        else
         epdf=50.0
         return
        endif
       else if (ictl.eq.-1) then
        epdf=q(1)
        return
       else if (ictl.eq.0) then
        if (abs(qq).eq.1) then
         epdf=q(1)
         return
        else if (abs(qq).eq.2) then
         epdf=0.0
         return
        else
         epdf=-9999.99
         return
        endif
       else
        epdf=-9999.99
        return
       endif
      endif

      do i = 1, n
       ef(i) = d(i,1)
      enddo

c     write (*,'("ENS WEIGHTS:",13f5.3)') (u(i),i=1,m)
c
c     to calculate ensemble segment weights
c
      w(1) = u(1) / (q(2) - q(1))
      w(m) = u(m) / (q(m) - q(m-1)) 
      do i = 2, m-1
ccc    find a bug to to calculate segment weight (08/07/2007)
c      w(i) = (u(i+1) + u(i)) / (q(i+1) - q(i-1))
ccc    Yuejian suggested weight
c      w(i) = (u(i+1) + 2.0*u(i) + u(i-1)) / (q(i+1) - q(i-1)) / 2.0
ccc    Keith suggested weight
       w(i) = 2.0*u(i) / (q(i+1) - q(i-1))
      enddo
      wsum=0.0
      do i = 1, m
       wsum = wsum + w(i)
      enddo
c
c     normalized PDF weights for each value
c
c     do i = 1, m
c      w(i) = w(i)/wsum
c     enddo
c     write (*,'("PDF WEIGHTS:",13f5.3)') (w(i),i=1,m)
c
c     calculate left and right bounds by approximation (considering tails)
c
c     modfied qlt and qrt approximation for extreme cases (small spread)
c      08/17/2007 -Yuejian Zhu
      if (3*m.le.2*n) then
       qdelta=(q(m)-q(1))/float(n-1)
       qltd=2.0/(w(1)*float(n+1))
       qrtd=2.0/(w(m)*float(n+1))
       if (qltd.gt.2.0*qdelta) then
        qltd=2.0*qdelta
       endif
       if (qrtd.gt.2.0*qdelta) then
        qrtd=2.0*qdelta
       endif
       qlt=q(1) - qltd
       qrt=q(m) + qrtd
      else
c
c     find bug to calculate qlt and qrt
c      08/22/2007 -Yuejian Zhu
       qlt=q(1) - 1.0/(w(1)*float(n+1))
       qrt=q(m) + 1.0/(w(m)*float(n+1))
c      qlt=q(1) - 2.0/(w(1)*float(n+1))
c      qrt=q(m) + 2.0/(w(m)*float(n+1))
      endif
c
c     normalized area of each trapezoidal
c
      qa(1) = (q(1) - qlt)*w(1)/2.0
      qun = qa(1)
      do i = 2, m
       qa(i) = (w(i-1)+w(i))*(q(i)-q(i-1))/2.0
       qun = qun + qa(i)                               
      enddo
      qa(m+1) = (qrt - q(m))*w(m)/2.0
      qun = qun + qa(m+1)                     
      qa(1) = qa(1)/qun
      do i = 2, m+1
       qa(i) = qa(i-1) + qa(i)/qun
      enddo

c     write (*,'("CDF  AREAS :",14f5.3)') (qa(i),i=1,m+1)
c     print *, "left bound is ",qlt,": right bound is ",qrt

      if (ictl.eq.1) then
c
c     to find out the position of give value qq
c
      if (qq.le.qlt) then
       epdf=0.0
       return
      endif
      if (qq.ge.qrt) then
       epdf=1.0
       return
      endif

      k=m
      do i = 1, m
       if (qq.lt.q(i)) then
        k=i-1
        exit
       endif
      enddo
c 101  continue

      if (k.eq.0) then
       ww = w(1)*(qq - qlt)/(q(1)-qlt)
       fta = ww*(qq - qlt)/(2.0*qun)
       epdf = fta
       return
      else if (k.eq.m) then
c
c     cumulative trapezoid area (CTA)
c
       cta = qa(m)
c
c     fractional trapezoid area
c
       ww = w(m)*(qrt - qq)/(qrt-q(m))
       fta = ww*(qrt - qq)/(2.0*qun)
c
c     the area is the probability (0.0-1.0) of given value qq 
c
       epdf = cta + fta
       return
      else
c
c     cumulative trapezoid area (CTA)
c
       cta = qa(k)
c
c     fractional trapezoid area
c
       ww = w(k) + (w(k+1)-w(k))*(qq - q(k))/(q(k+1) - q(k))
       fta = (ww + w(k))*(qq - q(k))/(2.0*qun)
c
c     the area is the probability (0.0-1.0) of given value qq 
c
       epdf = cta + fta
       return

      endif

      elseif (ictl.eq.-1) then

       if (qq.le.0.0) then
        epdf=qlt
        return
       endif
       if (qq.ge.1.0) then
        epdf=qrt
        return
       endif

       k = m
       do i = 1, m
        if (qq.lt.qa(i)) then
         k=i-1
         exit
        endif
       enddo
c  102  continue

c
c      to solve the quadratic equation ( ax2 + bx + c = 0 )
c
       if (k.eq.0) then
        fta = qq*qun
        a = w(1)/(q(1)-qlt)
        b = 0.0
        c = -2.0*fta
        if (a.eq.0.0) then
         epdf=-9999.99
         return
        else
         epdf = qlt + sqrt(-c/a) 
         return
        endif
       else if (k.eq.m) then
        fta = (qq - qa(m))*qun
        a = -w(m)/(qrt-q(m))
        b = 2.0*w(m)
        c = -2.0*fta
        b2m4ac = b*b - 4.0*a*c
        if ( b2m4ac.lt.0.0) then
         print *, "There is no real solution for this problem"
         epdf=-9999.99
         return
        endif
        if (a.eq.0.0) then
         epdf = q(m) - c/b
         return
        else
         epdf = q(m) + (sqrt(b2m4ac) - b)/(2.0*a)
         return
        endif
       else
        fta = (qq - qa(k))*qun
        a = (w(k+1)-w(k))/(q(k+1)-q(k))
        b = 2.0*w(k)
        c = -2.0*fta
        b2m4ac = b*b - 4.0*a*c
        if ( b2m4ac.lt.0.0) then
         print *, "There is no real solution for this problem"
         epdf=-9999.99
         return
        endif
        if (a.eq.0.0) then
         epdf = q(k) - c/b
         return
        else
         epdf = q(k) + (sqrt(b2m4ac) - b)/(2.0*a)
         return
        endif
       endif
      else
       epdf=-9999.99
       return
      endif

      return
      end