      subroutine spois(m,n,idf,f,del,tm,tn,w)
c
      integer m,n,idf
      real    del
      real    f(idf,1),tm(1),tn(1),w(1)
c
c      this routine solves the second order five point discrete
c      poissons equation using fourier transforms.
c       the boundary condition is assumed to be dirichlet.
c
c       petter bjorstad mai 1980.
c
c      input.
c      m,n	number of interior gridpoints in
c      	x and y directions. m and n must both be odd.
c      del	meshratio (dy/dx).
c      idf 	declared rowdimension of array f.
c      tm	array containing sin(.5*i*pi/(m+1)) , i=1,2,..m.
c      tn	array containing sin(.5*j*pi/(n+1)) , j=1,2,..n.
c       f       array containing the appropriate right hand
c               side. (the discrete forcing function and
c               the contribution from the boundary condition.)
c               this can be defined by calling the routine spoirh.
c
c      output.
c      f	containing the solution.
c      	all other input variables are unchanged.
c
c      workspace.
c      w	having at least int(3.5*max(m,n)+16) elements.
c
c      note that the current version wastes space and time
c      by recomputing and double storing trigonometric
c      information. (in the fourier transform part)
c       this routine is not designed to be very fast , but it
c       does have an operationcount of order n*m*max(log(n),log(m)).
c
c       routines called:      sftrnx,sftrny
c       fortran:              float
c
c      local variables.
c
      integer i,j
      real    scal1,scal2
c
      call sftrnx(m,n,f,idf,w)
      call sftrny(m,n,f,idf,w)
      i     = 16*(m+1)*(n+1)
      scal1 = float(i)
      scal2 = del*del*scal1
      do 10 i=1,m
      	w(i) = scal2*tm(i)*tm(i)
   10      	continue
      do 20 j=1,n
      	w(m+j) = scal1*tn(j)*tn(j)
   20      	continue
      do 30 j=1,n
      do 30 i=1,m
      	f(i,j) = f(i,j)/(w(i)+w(m+j))
   30      	continue
      call sftrny(m,n,f,idf,w)
      call sftrnx(m,n,f,idf,w)
      return
      end
      subroutine spoirh(m,n,idf,f,dx,dy,xmin,ymin)
c
      integer m,n,idf,nr
      real    dx,dy,xmin,ymin
      real    f(idf,1)
c
c      sets up the right hand side (from data f and g)
c      for the discrete poissons equation. this routine
c      is often called before the routine spois.
c       the user must supply functions func(x,y) and g(x,y).
c       func(x,y) computes the forcingfunction at an interor
c                 gridpoint. (corresponding to (x,y)).
c       g(x,y)    computes the value of the boundary function
c                 at a given boundary gridpoint (x,y).
c
c      input.
c      m,n       	number of gridpoints in x and y direction.
c       idf             declared rowdimension of f.
c      dx,dy		gridspacing in x and y direction.
c       xmin,ymin       x at west edge,y at south edge.
c
c       output.
c
c       f               array containing the appropriate right
c                       hand side.
c
c       user supplied functions:    func,g
c
c
c       local variables.
c
      integer i,j
      real    x,y,dy2,del2,x1,y1
c
      dy2 = dy*dy
        del2= (dy/dx)**2
      x1  = xmin+(m+1)*dx
      y1  = ymin+(n+1)*dy
      do 10 j=1,n
      	y = ymin+dy*j
      	do 10 i=1,m
      		x = xmin+dx*i
      		f(i,j) = -dy2*func(x,y)
   10                   continue
      do 20 j=1,n
      	y = ymin+dy*j
      	f(1,j) = f(1,j)+g(xmin,y)*del2
      	f(m,j) = f(m,j)+g(x1,y)*del2
   20           continue
        do 30 i=1,m
      	x = xmin+dx*i
      	f(i,1) = f(i,1)+g(x,ymin)
      	f(i,n) = f(i,n)+g(x,y1)
   30           continue
      return
      end
      subroutine strig(n,tn)
c
      integer n
      real    tn(1)
c
c      this routine fills in the array tn(n) with
c      trigonometric information needed in spois.
c      (this is a very slow version.)
c
c      tn(i)=sin(.5*i*pi/(n+1))  i=1,2,.. n.
c
c       fortran:         atan,sin,cos,float
c
c       local variables.
c
      integer i
      real    pi,arg
c
      pi  = 4.e0*atan(1.e0)
      arg = .5e0*pi/float(n+1)
      do 10 i = 1,n
      	tn(i) = sin(arg*i)
   10           continue
      return
      end
      subroutine sftrnx(m,n,f,idf,ws)
c
      integer m,n,idf
      real    f(idf,1)
      real    ws(1)
c
c     performs n sine transforms. the transform is unscaled.
c     m must be odd.(when ssint is called.)
c     the workspace ws must have at least int(3.5*m+16) elements.
c     the call to scopy is performed since ssint uses a vector
c     of lenght m+1. (if f(m+1,n) is a legal address then one
c     can save and restore this value instead.)
c
c     fourier:            ssinti,ssint   (swarztrauber version 3.)
c     blas:               scopy
c
      integer j
      real    x1
c
      call ssinti(m,ws(m+2))
      do 500 j=1,n
         call scopy(m,f(1,j),1,ws,1)
         call ssint(m,ws,ws(m+2))
         call scopy(m,ws,1,f(1,j),1)
  500    continue
      return
      end
      subroutine sftrny(m,n,f,idf,ws)
c
      integer m,n,idf
      real    f(idf,1)
      real    ws(1)
c
c     performs m sine transforms. the transform is unscaled.
c     n should be odd. (when ssint is called.)
c     workspace ws must have at least int(3.5*n+16) elements.
c
c     fourier:            ssinti,ssint   (swarztrauber version 3.)
c     blas:               scopy
c
      integer i,j
c
      call ssinti(n,ws(n+2))
      do 500 i   =1,m
         call scopy(n,f(i,1),idf,ws,1)
         call ssint(n,ws,ws(n+2))
         call scopy(n,ws,1,f(i,1),idf)
  500    continue
      return
      end
