      subroutine nongradopt(ndim,funkmin,f1dim,beta,
     &      bmin,bmax,ftol,fatbeta)
      implicit none
! This subroutine minimizes function funkmin to estimate ndim parameters
! using non-gradient based methods
!
      integer ndim
      double precision beta(1:ndim),bmin(1:ndim),
     &bmax(1:ndim),ftol,fatbeta,f1dim
!
! ------------------ Inputs -----------------------------
! ndim:  the total number of parameters to be estimated
! bmax:  the maximum possible value of beta, used to determine the distance scaling factor
! bmin:  the minimum possible value of beta, used to determine the distance scaling factor
! beta: initial guess, overwritten upon return
! ftol: tolerance for convergence
! fatbeta: the cost function valuate at beta, overwritten upon return 
! funkmin is the name of the subroutine that computes the cost function
! f1dim: the one dimensional cost function

! ------------------ Outputs ----------------------------
! beta:  The best parameters obtained
! fatbeta: the cost function value at beta

      integer n,nn,mpamoeba,npamoeba,iredo,maxredo,ITMAX,
     &   icycle
      parameter(maxredo=5,ITMAX=50000)
      double precision fbest,xbest(1:ndim),term,
     &    xinidir(1:ndim,1:ndim),xbest0(1:ndim),
     &    pamoeba(1:ndim+1,1:ndim),famoeba(1:ndim+1)
      external funkmin,f1dim
! End of declaration of variables
!---------------------------------------------------------------
      icycle=0
1     iredo=0
3     do n=1,ndim
        xbest(n)=beta(n)
        do nn=1,ndim
          xinidir(n,nn)=0.0d0
        enddo
        xinidir(n,n)=1.0d0
      enddo
      fbest=fatbeta
      call powell(beta,xinidir(1:ndim,1:ndim),ndim,ndim,
     &     ftol,fatbeta,bmin,bmax,funkmin,f1dim,ITMAX)
      if(fatbeta.gt.fbest)then
        do n=1,ndim
          beta(n)=xbest(n)
        enddo
        fatbeta=fbest
        goto 10
      endif
      if((fbest-fatbeta).gt.100.0d0*ftol)then
        if(iredo.gt.maxredo)goto 10
        iredo=iredo+1
        goto 3
      endif
10    iredo=0
20    do n=1,ndim
        xbest(n)=beta(n)
      enddo
      fbest=fatbeta
      do nn=1,ndim
        pamoeba(1,nn)=beta(nn)
      enddo
      famoeba(1)=fatbeta
      do n=2,ndim+1
        do nn=1,ndim
          pamoeba(n,nn)=beta(nn)
        enddo
        if((bmax(n-1)-pamoeba(n,n-1))
     &     .gt.(pamoeba(n,n-1)-bmin(n-1)))then
          pamoeba(n,n-1)=pamoeba(n,n-1)+
     &           (bmax(n-1)-pamoeba(n,n-1))*0.1d0
        else
          pamoeba(n,n-1)=pamoeba(n,n-1)-
     &           (pamoeba(n,n-1)-bmin(n-1))*0.1d0
        endif
        do nn=1,ndim
          xbest0(nn)=pamoeba(n,nn)
        enddo
        call funkmin(ndim,xbest0,famoeba(n))
      enddo
      mpamoeba=ndim+1
      npamoeba=ndim
      fatbeta=1.0d+100
      term=1.0d0
30    nn=ITMAX/20
      call amebsa(pamoeba(1:ndim+1,1:ndim),famoeba(1:ndim+1),
     &mpamoeba,npamoeba,ndim,beta,fatbeta,ftol,funkmin,nn,term)
      if(fatbeta.lt.fbest)then
        if((fbest-fatbeta).gt.ftol*100.0d0.and.term.gt.1.0d-2)then
          term=term/3.0d0
          fbest=fatbeta
          do n=1,ndim
            xbest(n)=beta(n)
          enddo
          goto 30
        endif
        do n=1,ndim
          xbest(n)=beta(n)
        enddo
        fbest=fatbeta
      else
        do n=1,ndim
          beta(n)=xbest(n)
        enddo
        fatbeta=fbest
      endif
      do nn=1,ndim
        pamoeba(1,nn)=beta(nn)
      enddo
      famoeba(1)=fatbeta
      do n=2,ndim+1
        do nn=1,ndim
          pamoeba(n,nn)=beta(nn)
        enddo
        if((bmax(n-1)-pamoeba(n,n-1))
     &     .gt.(pamoeba(n,n-1)-bmin(n-1)))then
          pamoeba(n,n-1)=pamoeba(n,n-1)+
     &           (bmax(n-1)-pamoeba(n,n-1))*0.1d0
        else
          pamoeba(n,n-1)=pamoeba(n,n-1)-
     &           (pamoeba(n,n-1)-bmin(n-1))*0.1d0
        endif
        do nn=1,ndim
          xbest0(nn)=pamoeba(n,nn)
        enddo
        call funkmin(ndim,xbest0,famoeba(n))
      enddo
      mpamoeba=ndim+1
      npamoeba=ndim
      call guamoeba(pamoeba(1:ndim+1,1:ndim),famoeba(1:ndim+1),
     &mpamoeba,npamoeba,ndim,ftol,funkmin,ITMAX/20)  
      nn=1
      do n=2,ndim+1
        if(famoeba(n).lt.famoeba(nn))nn=n
      enddo
      fatbeta=famoeba(nn)         
      do n=1,ndim
        beta(n)=pamoeba(nn,n)
        if(beta(n).lt.bmin(n).or.beta(n).gt.bmax(n))then
          do nn=1,ndim
            beta(nn)=xbest(nn)
          enddo
          fatbeta=fbest
          return
        endif
      enddo
      if((fbest-fatbeta).gt.ftol*100.0d0)then
        if(iredo.gt.maxredo)then
          if(icycle.lt.maxredo)then
            icycle=icycle+1
            goto 1
          else
            return
          endif
        endif
        iredo=iredo+1
        goto 20
      endif
      return
      end subroutine nongradopt
!&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
      SUBROUTINE guamoeba(p,y,mp,np,ndim,ftol,funkmin,ITMAX)
      implicit none
      INTEGER iter,mp,ndim,np,NMAX,ITMAX
      double precision ftol,p(mp,np),y(mp),TINY
      PARAMETER (TINY=1.0d-10)
      external funkmin
CU    USES guamotry,funkmin
      INTEGER i,ihi,ilo,inhi,j,m,n
      double precision rtol,cumx,swap,ysave,ytry,pcumx(ndim),
     &  guamotry,degen
      iter=0
1     do 12 n=1,ndim
        cumx=0.0d0
        do 11 m=1,ndim+1
          cumx=cumx+p(m,n)
11      continue
        pcumx(n)=cumx
12    continue
2     ilo=1
      if (y(1).gt.y(2)) then
        ihi=1
        inhi=2
      else
        ihi=2
        inhi=1
      endif
      do 13 i=1,ndim+1
        if(y(i).le.y(ilo)) ilo=i
        if(y(i).gt.y(ihi)) then
          inhi=ihi
          ihi=i
        else if(y(i).gt.y(inhi)) then
          if(i.ne.ihi) inhi=i
        endif
13    continue
      rtol=2.0d0*dabs(y(ihi)-y(ilo))/
     &     (dabs(y(ihi))+dabs(y(ilo))+TINY)
      if (rtol.lt.ftol) then
        swap=y(1)
        y(1)=y(ilo)
        y(ilo)=swap
        do 14 n=1,ndim
          swap=p(1,n)
          p(1,n)=p(ilo,n)
          p(ilo,n)=swap
14      continue
        return
      endif

! check to see if the simplex is degenerate; if so, stop
      degen=0.0d0
      do i=1,mp
        do m=i+1,mp
          do n=1,np
            if(dabs(p(m,n)-p(i,n)).gt.degen)then
              degen=dabs(p(m,n)-p(i,n))         
            endif
          enddo
        enddo
      enddo      
      if(degen.lt.ftol*ftol)then
        swap=y(1)
        y(1)=y(ilo)
        y(ilo)=swap
        do n=1,ndim
          swap=p(1,n)
          p(1,n)=p(ilo,n)
          p(ilo,n)=swap
        enddo
        return   
      endif
      if(iter.ge.ITMAX)return
      iter=iter+2
      ytry=guamotry(p,y,pcumx,mp,np,ndim,funkmin,ihi,-1.0d0)
      if (ytry.le.y(ilo))then
        ytry=guamotry(p,y,pcumx,mp,np,ndim,funkmin,ihi,2.0d0)
      else if (ytry.ge.y(inhi)) then
        ysave=y(ihi)
        ytry=guamotry(p,y,pcumx,mp,np,ndim,funkmin,ihi,0.5d0)
        if (ytry.ge.ysave) then
          do 16 i=1,ndim+1
            if(i.ne.ilo)then
              do 15 j=1,ndim
                pcumx(j)=0.5d0*(p(i,j)+p(ilo,j))
                p(i,j)=pcumx(j)
15            continue
              call funkmin(ndim,pcumx,y(i))
            endif
16        continue
          iter=iter+ndim
          goto 1
        endif
      else
        iter=iter-1
      endif
      goto 2
      END
C  (C) Copr. 1986-92 Numerical Recipes Software v%1jw#<0(9p#3.

      DOUBLE PRECISION FUNCTION guamotry(p,y,psum,
     &   mp,np,ndim,funkmin,ihi,fac)
      implicit none
      INTEGER ihi,mp,ndim,np
      double precision fac,p(mp,np),psum(np),y(mp)
      EXTERNAL funkmin
CU    USES funkmin
      INTEGER j
      double precision fac1,fac2,ytry,ptry(ndim)
      fac1=(1.0d0-fac)/dble(ndim)
      fac2=fac1-fac
      do 11 j=1,ndim
        ptry(j)=psum(j)*fac1-p(ihi,j)*fac2
11    continue
      call funkmin(ndim,ptry,ytry)
      if (ytry.lt.y(ihi)) then
        y(ihi)=ytry
        do 12 j=1,ndim
          psum(j)=psum(j)-p(ihi,j)+ptry(j)
          p(ihi,j)=ptry(j)
12      continue
      endif
      guamotry=ytry
      return
      END
C  (C) Copr. 1986-92 Numerical Recipes Software v%1jw#<0(9p#3.

c#######################################################################

      SUBROUTINE amebsa(p,y,mp,np,ndim,pb,yb,ftol,funkmin,iter,temptr)
      implicit none
      INTEGER iter,mp,ndim,np
      double precision ftol,temptr,yb,p(mp,np),pb(np),y(mp)
      EXTERNAL funkmin
CU    USES amotsa,funkmin,ran1
      INTEGER i,idum,ihi,ilo,inhi,j,m,n
      double precision rtol,sum,swap,tt,yhi,ylo,ynhi,ysave,yt,ytry,
     &psum(ndim),amotsa,ran1
      COMMON /ambsa/ tt,idum
      tt=-temptr
1     do 12 n=1,ndim
        sum=0.0d0
        do 11 m=1,ndim+1
          sum=sum+p(m,n)
11      continue
        psum(n)=sum
12    continue
2     ilo=1
      inhi=1
      ihi=2
      ylo=y(1)+tt*dlog(ran1(idum))
      ynhi=ylo
      yhi=y(2)+tt*dlog(ran1(idum))
      if (ylo.gt.yhi) then
        ihi=1
        inhi=2
        ilo=2
        ynhi=yhi
        yhi=ylo
        ylo=ynhi
      endif
      do 13 i=3,ndim+1
        yt=y(i)+tt*dlog(ran1(idum))
        if(yt.le.ylo) then
          ilo=i
          ylo=yt
        endif
        if(yt.gt.yhi) then
          inhi=ihi
          ynhi=yhi
          ihi=i
          yhi=yt
        else if(yt.gt.ynhi) then
          inhi=i
          ynhi=yt
        endif
13    continue
      rtol=2.0d0*dabs(yhi-ylo)/(dabs(yhi)+dabs(ylo))
      if(rtol.lt.ftol.or.iter.lt.0) then
        swap=y(1)
        y(1)=y(ilo)
        y(ilo)=swap
        do 14 n=1,ndim
          swap=p(1,n)
          p(1,n)=p(ilo,n)
          p(ilo,n)=swap
14      continue
        return
      endif
      iter=iter-2
      ytry=amotsa(p(1:mp,1:np),
     &y,psum,mp,np,ndim,pb,yb,funkmin,ihi,yhi,-1.0d0)
      if (ytry.le.ylo) then
        ytry=amotsa(p(1:mp,1:np),
     &y,psum,mp,np,ndim,pb,yb,funkmin,ihi,yhi,2.0d0)
      else if (ytry.ge.ynhi) then
        ysave=yhi
        ytry=amotsa(p(1:mp,1:np),
     &y,psum,mp,np,ndim,pb,yb,funkmin,ihi,yhi,0.5d0)
        if (ytry.ge.ysave) then
          do 16 i=1,ndim+1
            if(i.ne.ilo)then
              do 15 j=1,ndim
                psum(j)=0.5d0*(p(i,j)+p(ilo,j))
                p(i,j)=psum(j)
15            continue
              call funkmin(ndim,psum,y(i))
            endif
16        continue
          iter=iter-ndim
          goto 1
        endif
      else
        iter=iter+1
      endif
      goto 2
      END

      double precision FUNCTION amotsa
     &(p,y,psum,mp,np,ndim,pb,yb,funkmin,ihi,yhi,fac)
      implicit none
      INTEGER ihi,mp,ndim,np
      double precision fac,yb,yhi,p(mp,np),pb(np),psum(ndim),y(mp)
      EXTERNAL funkmin
CU    USES funkmin,ran1
      INTEGER idum,j
      double precision fac1,fac2,tt,yflu,ytry,ptry(ndim),ran1
      COMMON /ambsa/ tt,idum
      fac1=(1.0d0-fac)/dble(ndim)
      fac2=fac1-fac
      do 11 j=1,ndim
        ptry(j)=psum(j)*fac1-p(ihi,j)*fac2
11    continue
      call funkmin(ndim,ptry,ytry)
      if (ytry.le.yb) then
        do 12 j=1,ndim
          pb(j)=ptry(j)
12      continue
        yb=ytry
      endif
      yflu=ytry-tt*log(ran1(idum))
      if (yflu.lt.yhi) then
        y(ihi)=ytry
        yhi=yflu
        do 13 j=1,ndim
          psum(j)=psum(j)-p(ihi,j)+ptry(j)
          p(ihi,j)=ptry(j)
13      continue
      endif
      amotsa=yflu
      return
      END
