c
c  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
c  .                                                             .
c  .                  copyright (c) 1998 by UCAR                 .
c  .                                                             .
c  .       University Corporation for Atmospheric Research       .
c  .                                                             .
c  .                      all rights reserved                    .
c  .                                                             .
c  .                                                             .
c  .                         SPHEREPACK3.0                       .
c  .                                                             .
c  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
c
c
c ... file trssph.f
c
c     contains documentation and code for subroutine trssph
c
c ... required files
c
c     sphcom.f, hrfft.f, gaqd.f, shaec.f, shsec.f, shagc.f, shsgc.f
c
c
c     subroutine trssph(intl,igrida,nlona,nlata,da,igridb,nlonb,nlatb,
c    +db,wsave,lsave,lsvmin,work,lwork,lwkmin,dwork,ldwork,ier)
c
c *** purpose
c
c     subroutine trssph transfers data given in array da on a grid on the
c     full sphere to data in array db on a grid on the full sphere.  the
c     grids on which da is given and db is generated can be specified
c     independently of each other (see description below and the arguments
c     igrida,igridb).  for transferring vector data on the sphere, use
c     subroutine trvsph.

c     notice that scalar and vector quantities are fundamentally different
c     on the sphere.  for example, vectors are discontinuous and multiple
c     valued at the poles.  scalars are continuous and single valued at the
c     poles. erroneous results would be produced if one attempted to transfer
c     vector fields between grids with subroutine trssph applied to each
c     component of the vector.
c
c
c *** underlying grid assumptions and a description
c
c     discussions with the ncar scd data support group and others indicate
c     there is no standard grid for storing observational or model generated
c     data on the sphere.  subroutine trssph was designed to handle most
c     cases likely to be encountered when moving data from one grid format
c     to another.
c
c     the grid on which da is given must be equally spaced in longitude
c     and either equally spaced or gaussian in latitude (or colatitude).
c     longitude, which can be either the first or second dimension of da,
c     subdivides [0,2pi) excluding the periodic point 2pi.  (co)latitude,
c     which can be the second or first dimension of da, has south
c     to north or north to south orientation with increasing subscript
c     value in da (see the argument igrida).
c
c     the grid on which db is generated must be equally spaced in longitude
c     and either equally spaced or gaussian in latitude (or colatitude).
c     longitude, which can be either the first or second dimension of db,
c     subdivides [0,2pi) excluding the periodic point 2pi.  (co)latitude,
c     which can be the second or first dimension of db, has south
c     to north or north to south orientation with increasing subscript
c     value in db (see the argument igridb).
c
c     let nlon be either nlona or nlonb (the number of grid points in
c     longitude.  the longitude grid subdivides [0,2pi) into nlon spaced
c     points
c
c          (j-1)*2.*pi/nlon  (j=1,...,nlon).
c
c     it is not necessary to communicate to subroutine trssph whether the
c     underlying grids are in latitude or colatitude.  it is only necessary
c     to communicate whether they run south to north or north to south with
c     increasing subscripts.  a brief discussion of latitude and colatitude
c     follows.  equally spaced latitude grids are assumed to subdivide
c     [-pi/2,pi/2] with the south pole at -pi/2 and north pole at pi/2.
c     equally spaced colatitude grids subdivide [0,pi] with the north pole
c     at 0 and south pole at pi.  equally spaced partitions on the sphere
c     include both poles.  gaussian latitude grids subdivide (-pi/2,pi/2)
c     and gaussian colatitude grids subdivide (0,pi).  gaussian grids do not
c     include the poles.  the gaussian grid points are uniquely determined by
c     the size of the partition.  they can be computed in colatitude in
c     (0,pi) (north to south) in double precision by the spherepack subroutine
c     gaqd.  let nlat be nlata or nlatb if either the da or db grid is
c     gaussian.  let
c
c        north pole                             south pole
c        ----------                             ----------
c           0.0    <  cth(1) < ... < cth(nlat)  <   pi
c
c
c     be nlat gaussian colatitude points in the interval (0,pi) and let
c
c        south pole                        north pole
c        ----------                        ----------
c           -pi/2  < th(1) < ... < th(nlat) < pi/2
c
c     be nlat gaussian latitude points in the open interval (-pi/2,pi/2).
c     these are related by
c
c          th(i) = -pi/2 + cth(i)  (i=1,...,nlat)
c
c     if the da or db grid is equally spaced in (co)latitude then
c
c          ctht(i) = (i-1)*pi/(nlat-1)
c                                               (i=1,...,nlat)
c          tht(i) = -pi/2 + (i-1)*pi/(nlat-1)
c
c     define the equally spaced (north to south) colatitude and (south to
c     north) latitude grids.
c
c
c *** method (simplified description)
c
c     for simplicity, assume da is a nlat by nlon data tabulation and da(i,j)
c     is the value at latitude theta(i) and longitude phi(j).  then
c     coefficients a(m,n) and b(m,n) can be determined so that da(i,j) is
c     approximated by the sum
c
c         l-1  n
c     (a) sum sum pbar(m,n,theta(i))*(a(m,n)*cos(m*phi(j)+b(m,n)*sin(m*phi(j))
c         n=0 m=0
c
c     here pbar(n,m,theta) are the normalized associated legendre functions
c     and l = min0(nlat,(nlon+2)/2).  the determination of a(m,n) and b(m,n)
c     is called spherical harmonic analysis. a sum of this form can then be
c     used to regenerate the data in db on the new grid with the known
c     a(m,n) and b(m,n).  this is referred to spherical harmonic synthesis.
c     analysis and synthesis subroutines from the software package spherepack,
c     are used for these purposes.
c
c     if da or db is not in mathematical spherical coordinates then array
c     transposition and/or subscript reordering is used prior to harmonic
c     analysis and after harmonic synthesis.
c
c *** advantages
c
c     the use of surface spherical harmonics to transfer spherical grid data
c     has advantages over pointwise grid interpolation schemes on the sphere.
c     it is highly accurate.  if p(x,y,z) is any polynomial of degree n or
c     less in x,y,z cartesian coordinates which is restricted to the surface
c     of the sphere, then p is exactly represented by sums of the form (a)
c     whenever n = mino(nlat,nlon/2) (i.e., transfers with spherical harmonics
c     have n(th) order accuracy.  by way of contrast, bilinear interpolation
c     schemes are exact for polynomials of degree one.  bicubic interpolation
c     is exact only for polynomials of degree three or less.  the method
c     also produces a weighted least squares fit to the data in which waves
c     are resolved uniformly on the full sphere.  high frequencies, induced
c     by closeness of grid points near the poles (due to computational
c     or observational errors) are smoothed.  finally, the method is
c     consistent with methods used to generate data in numerical spectral
c     models based on spherical harmonics.  for more discussion of these and
c     related issues,  see the article: "on the spectral approximation of
c     discrete scalar and vector functions on the sphere," siam j. numer.
c     anal., vol 16. dec 1979, pp. 934-949, by paul swarztrauber.
c
c
c *** comment
c
c     on a nlon by nlat or nlat by nlon grid (gaussian or equally spaced)
c     spherical harmonic analysis generates and synthesis utilizes
c     min0(nlat,(nlon+2)/2)) by nlat coefficients.  consequently, for
c     da and db,  if either
c
c             min0(nlatb,(nlonb+2)/2) < min0(nlata,(nlona+2)/2)
c
c     or if
c
c             nlatb < nlata
c
c     then all the coefficients generated by an analysis of da cannot be used
c     in the synthesis which generates db.  in this case "information" can be
c     lost in generating db.  more precisely, information will be lost if the
c     analysis of da yields nonzero coefficients which are outside the bounds
c     determined by the db grid.  nevertheless, transference of values with
c     spherical harmonics will yield results consistent with grid resolution
c     and is highly accurate.
c
c
c *** input arguments
c
c ... intl
c
c     an initialization argument which should be zero on an initial call to
c     trssph.  intl should be one if trssph is being recalled and
c
c          igrida,nlona,nlata,igridb,nlonb,nlatb
c
c     have not changed from the previous call.  if any of these arguments
c     have changed, intl=0 must be used to avoid undetectable errors.  calls
c     with intl=1 bypass redundant computation and save time.  it can be used
c     when transferring multiple data sets with the same underlying grids.
c
c
c ... igrida
c
c     an integer vector dimensioned two which identifies the underlying grid
c     on the full sphere for the given data array da as follows:
c
c     igrida(1)
c
c     = -1
c     if the latitude (or colatitude) grid for da is an equally spaced
c     partition of [-pi/2,pi/2] ( or [0,pi] ) including the poles which
c     runs north to south
c
c     = +1
c     if the latitude (or colatitude) grid for da is an equally spaced
c     partition of [-pi/2,pi/2] ( or [0,pi] ) including the poles which
c     runs south to north
c
c     = -2
c     if the latitude (or colatitude) grid for da is a gaussian partition
c     of (-pi/2,pi/2) ( or (0,pi) ) excluding the poles which runs north
c     to south
c
c     = +2
c     if the latitude (or colatitude) grid for da is a gaussian partition
c     of (-pi/2,pi/2) ( or (0,pi) ) excluding the poles which runs south
c     north
c
c     igrida(2)
c
c     = 0 if the underlying grid for da is a nlona by nlata
c
c     = 1 if the underlying grid for da is a nlata by nlona
c
c
c ... nlona
c
c     the number of longitude points on the uniform grid which partitions
c     [0,2pi) for the given data array da.  nlona is also the first or second
c     dimension of da (see igrida(2)) in the program which calls trssph.
c     nlona determines the grid increment in longitude as 2*pi/nlona. for
c     example nlona = 72 for a five degree grid.  nlona must be greater than
c     or equal to 4.  the efficiency of the computation is improved when
c     nlona is a product of small prime numbers
c
c ... nlata
c
c     the number of points in the latitude (or colatitude) grid
c     for the given data array da.  nlata is also the first or second
c     dimension of da (see igrida(2)) in the program which calls trssph.
c     if nlata is odd then the equator will be located at the (nlata+1)/2
c     gaussian grid point.  if nlata is even then the equator will be
c     located half way between the nlata/2 and nlata/2+1 grid points.
c
c *** note:
c     igrida(1)=-1 or igrida(1)=-2 and igrida(2)=1 corresponds to
c     the "usual" mathematical spherical coordinate system required
c     by most of the drivers in spherepack2.  igrida(1)=1 or igrida(1)=2
c     and igrida(2)=0 corresponds to the "usual" geophysical spherical
c     coordinate system.
c
c ... da
c
c     a two dimensional array that contains the data to be transferred.
c     da must be dimensioned nlona by nlata in the program calling trssph if
c     igrida(2) = 0.  da must be dimensioned nlata by nlona in the program
c     calling trssph if igrida(2) = 1.  if da is not properly dimensioned
c     and if the latitude (colatitude) values do not run south to north or
c     north to south as flagged by igrida(1) (this cannot be checked!) then
c     incorrect results will be produced.
c
c ... igridb
c
c     an integer vector dimensioned two which identifies the underlying grid
c     on the full sphere for the transformed data array db as follows:
c
c     igridb(1)
c
c     = -1
c     if the latitude (or colatitude) grid for db is an equally spaced
c     partition of [-pi/2,pi/2] ( or [0,pi] ) including the poles which
c     north to south
c
c     = +1
c     if the latitude (or colatitude) grid for db is an equally spaced
c     partition of [-pi/2,pi/2] ( or [0,pi] ) including the poles which
c     south to north
c
c     = -2
c     if the latitude (or colatitude) grid for db is a gaussian partition
c     of (-pi/2,pi/2) ( or (0,pi) ) excluding the poles which runs north to
c     south
c
c     = +2
c     if the latitude (or colatitude) grid for db is a gaussian partition
c     of (-pi/2,pi/2) ( or (0,pi) ) excluding the poles which runs south to
c     north
c
c
c     igridb(2)
c
c     = 0 if the underlying grid for db is a nlonb by nlatb
c
c     = 1 if the underlying grid for db is a nlatb by nlonb
c
c
c ... nlonb
c
c     the number of longitude points on the uniform grid which partitions
c     [0,2pi) for the transformed data array db.  nlonb is also the first or
c     second dimension of db (see igridb(2)) in the program which calls
c     trssph.  nlonb determines the grid increment in longitude as 2*pi/nlonb.
c     for example nlonb = 72 for a five degree grid.  nlonb must be greater
c     than or equal to 4.  the efficiency of the computation is improved when
c     nlonb is a product of small prime numbers
c
c ... nlatb
c
c     the number of points in the latitude (or colatitude) grid
c     for the transformed data array db.  nlatb is also the first or second
c     dimension of db (see igridb(2)) in the program which calls trssph.
c     if nlatb is odd then the equator will be located at the (nlatb+1)/2
c     gaussian grid point.  if nlatb is even then the equator will be
c     located half way between the nlatb/2 and nlatb/2+1 grid points.
c
c ... wsave
c
c     a saved work space array that can be utilized repeatedly by trssph
c     as long as the arguments nlata,nlona,nlatb,nlonb remain unchanged.
c     wsave is set by a intl=0 call to trssph.  wsave must not be altered
c     when trssph is being recalled with intl=1.
c
c ... lsave
c
c     the dimension of the work space wsave as it appears in the program
c     that calls trssph.  the minimum required value of lsave for the
c     current set of input arguments is set in the output argument lsvmin.
c     it can be determined by calling trssph with lsave=0 and printing lsvmin.
c     let
c
c          lwa =  2*nlata*la2+3*((la1-2)*(nlata+nlata-la1-1))/2+nlona+15
c
c     if the grid for da is equally spaced in (co)latitude.  let
c
c          lwa = nlata*(2*la2+3*la1-2)+3*la1*(1-la1)/2+nlona+15
c
c     if the grid for da is gaussian in (co)latitude.
c     let
c
c          lwb = nlatb*(2*lb2+3*lb1-2)+3*lb1*(1-lb1)/2+nlonb+15
c
c     if the grid for db is gaussian in (co)latitude.  let
c
c          lwb = 2*nlatb*lb2+3*((lb1-2)*(nlatb+nlatb-lb1-1))/2+nlonb+15
c
c     if the grid for db is equally spaced in (co)latitude.  then
c     the quantity
c
c          lwa + lwb
c
c     is the minimum required length of wsave.  this value is returned
c     in the output argument lsvmin even if lsave is to small (ierror=10)
c
c ... work
c
c     a real work array that does not have to be preserved
c
c ... lwork
c
c     the dimension of the array work as it appears in the program
c     calling trssph. the minimum required value of lwork for the current
c     set of input arguments is set in the output argument lwkmin.
c     it can be determined by calling trssph with lwork=0 and printing
c     lwkmin.  an estimate for lwork follows.  let nlat,nlon,l1,l2 be
c     defined by
c
c       nlat = max0(nlata,nlatb), nlon = nax0(nlona,nlonb),
c       l1 = min0(nlat,(nlon+2)/2), l2 = (nlat+1)/2
c
c     then the quantity
c
c          nlat*(4*l1+nlon+2*nlat+4)+3*((l1-2)*2*(2*nlat-l1-1))/2
c
c     will suffice as a length for the unsaved work space.
c
c  *  both of the formulas above for lsave and lwork may overestimate the
c     required minimum values.  they can be predetermined by calling trssph
c     with lsave=lwork=0 and printout of lsvmin and lwkmin.
c
c ... dwork
c
c     a double precision work array that does not have to be preserved.
c
c ... ldwork
c
c     The length of dwork in the routine calling trssph.
c     Let
c
c       nlat = max0(nlata,nlatb)
c
c     ldwork must be at least nlat*(nlat+4)
c
c *** output arguments
c
c
c ... db
c
c     a two dimensional array that contains the transformed data.  db
c     must be dimensioned nlonb by nlatb in the program calling trssph if
c     igridb(2) = 0 or 1.  db must be dimensioned nlatb by nlonb in the
c     program calling trssph if igridb(2) = 1.  if db is not properly
c     dimensioned and if the latitude (colatitude) values do not run south
c     north or north to south as flagged by igrdb(1) (this cannot be checked!)
c     then incorrect results will be produced.
c
c ... lsvmin
c
c     the minimum length of the saved work space in wsave.
c     lsvmin is computed even if lsave < lsvmin (ier = 10).
c
c ... lwkmin
c
c     the minimum length of the unsaved work space in work.
c     lwkmin is computed even if lwork < lwkmin (ier = 11).
c
c *** error argument
c
c ... ier = 0  if no errors are detected
c
c         = 1  if intl is not 0 or 1
c
c         = 2  if igrida(1) is not -1 or +1 or -2 or +2
c
c         = 3  if igrida(2) is not 0 or 1
c
c         = 4  if nlona is less than 4
c
c         = 5  if nlata is less than 3
c
c         = 6  if igridb(1) is not -1 or +1 or -2 or +2
c
c         = 7  if igridb(2) is not 0 or 1
c
c         = 8  if nlonb is less than 4
c
c         = 9  if nlatb is less than 3

c         =10  if there is insufficient saved work space (lsave < lsvmin)
c
c         =11  if there is insufficient unsaved work space (lwork < lwkmin)
c
c         =12  indicates failure in an eigenvalue routine which computes
c              gaussian weights and points
c
c         =13  if ldwork is too small (insufficient unsaved double precision
c              work space)
c
c *****************************************************
c *****************************************************
c
c     end of argument description ... code follows
c
c *****************************************************
c *****************************************************
c
      SUBROUTINE TRSSPH (INTL,IGRIDA,NLONA,NLATA,DA,IGRIDB,NLONB,NLATB,
     +DB,WSAVE,LSAVE,LSVMIN,WORK,LWORK,LWKMIN,DWORK,LDWORK,IER)
      implicit none
      integer intl,igrida(2),nlona,nlata,igridb(2),nlonb,nlatb
      integer lsave,lsvmin,lwork,lwkmin,ldwork,ier
      real da(*),db(*),wsave(*),work(*)
      double precision dwork(*)
      integer ig,igrda,igrdb,la1,la2,lb1,lb2,lwa,lwb,iaa,iab,iba,ibb
      integer lwk3,lwk4,lw,iw,jb,nt,isym,nlat
c
c     include a save statement to ensure local variables in trssph, set during
c     an intl=0 call, are preserved if trssph is recalled with intl=1
c
      save
c
c     check input arguments
c
      ier = 1
      if (intl*(intl-1).ne.0) return
      ier = 2
      ig = igrida(1)
      if ((ig-1)*(ig+1)*(ig-2)*(ig+2).ne.0) return
      ier = 3
      ig = igrida(2)
      if (ig*(ig-1).ne.0) return
      ier = 4
      if (nlona .lt. 4) return
      ier = 5
      if (nlata .lt.3) return
      ier = 6
      ig = igridb(1)
      if ((ig-1)*(ig+1)*(ig-2)*(ig+2).ne.0) return
      ier = 7
      ig = igridb(2)
      if (ig*(ig-1).ne.0) return
      ier = 8
      if (nlonb .lt.4) return
      ier = 9
      if (nlatb .lt.3) return
      ier = 0

      igrda = iabs(igrida(1))
      igrdb = iabs(igridb(1))
      if (intl.eq.0) then
      la1 = min0(nlata,(nlona+2)/2)
      la2 = (nlata+1)/2
      lb1 = min0(nlatb,(nlonb+2)/2)
      lb2 = (nlatb+1)/2
c
c     set saved work space length for analysis
c
      if (igrda .eq. 1) then
c
c     saved space for analysis on  equally spaced grid
c
      lwa =  2*nlata*la2+3*((la1-2)*(nlata+nlata-la1-1))/2+nlona+15
      else
c
c     saved space for analysis on gaussian grid
c
      lwa = nlata*(2*la2+3*la1-2)+3*la1*(1-la1)/2+nlona+15
      end if
c
c     set wsave pointer
c
      jb = 1+lwa
c
c     set pointers for spherical harmonic coefs
c
      iaa = 1
      iba = iaa+la1*nlata
      iab = iba+la1*nlata
      if (igrdb .eq. 2) then
c
c     set saved work space length for gaussian synthesis
c
      lwb = nlatb*(2*lb2+3*lb1-2)+3*lb1*(1-lb1)/2+nlonb+15
      else
c
c     set saved work space length for equally spaced synthesis
c
      lwb = 2*nlatb*lb2+3*((lb1-2)*(nlatb+nlatb-lb1-1))/2+nlonb+15
      end if
c
c     set minimum saved work space length
c
      lsvmin = lwa + lwb
c
c     set remaining harmonic pointer
c
      ibb = iab+lb1*nlatb
c
c     set pointers for remaining work
c
      iw = ibb+lb1*nlatb
c
c     set remaining work space length in lw
c
      lw = lwork - iw
      lwk3 = nlata*nlona*2
      lwk4 = nlatb*nlonb*2
c
c     set minimum unsaved work space required by trssph
c
      lwkmin = iw + max0(lwk3,lwk4)
c
c     set error flags if saved or unsaved work spaces are insufficient
c
      ier = 10
      if (lsave .lt. lsvmin) return
      ier = 11
      if (lwork .lt. lwkmin) return
      ier = 13
      nlat = max0(nlata,nlatb)
      if (ldwork .lt. nlat*(nlat+4)) return
      ier = 0
      if (igrda .eq. 1) then
c
c     initialize wsave for equally spaced analysis
c
      call shaeci(nlata,nlona,wsave,lwa,dwork,ldwork,ier)
      else
c
c     initialize wsave for gaussian analysis
c
      call shagci(nlata,nlona,wsave,lwa,dwork,ldwork,ier)
      if (ier.ne.0) then
c
c     flag failure in spherepack gaussian software
c
      ier = 12
      return
      end if
      end if

      if (igrdb .eq. 2) then
c
c     initialize wsave for gaussian synthesis
c
      call shsgci(nlatb,nlonb,wsave(jb),lwb,dwork,ldwork,ier)
      if (ier.ne.0) then
c
c     flag failure in spherepack gaussian software
c
      ier = 12
      return
      end if
      else
c
c     initialize wsave for equally spaced synthesis
c
      call shseci(nlatb,nlonb,wsave(jb),lwb,dwork,ldwork,ier)
      end if
c
c     end of initialization (intl=0) call
c
      end if
c
c     transpose and/or reorder (co)latitude if necessary for da
c     (arrays must have latitude (colatitude) as the first dimension
c     and run north to south for spherepack software)
c
      if (igrida(2) .eq. 0) call trsplat(nlona,nlata,da,work)
      if (igrida(1) .gt. 0) call convlat(nlata,nlona,da)

      nt = 1
      isym = 0
      if (igrda .eq. 2) then
c
c     do spherical harmonic analysis of "adjusted" da on gaussian grid
c
      call shagc(nlata,nlona,isym,nt,da,nlata,nlona,work(iaa),
     +work(iba),la1,nlata,wsave,lwa,work(iw),lw,ier)
      else
c
c     do spherical harmonic analysis of "adjusted" da on equally spaced grid
c
      call shaec(nlata,nlona,isym,nt,da,nlata,nlona,work(iaa),
     +work(iba),la1,nlata,wsave,lwa,work(iw),lw,ier)
      end if
c
c     transfer da grid coefficients to db grid coefficients
c     truncating to zero as necessary
c
      call trab(la1,nlata,work(iaa),work(iba),lb1,nlatb,work(iab),
     +          work(ibb))

      if (igrdb .eq. 1) then
c
c     do spherical harmonic synthesis on nlatb by nlonb equally spaced grid
c
      call shsec(nlatb,nlonb,isym,nt,db,nlatb,nlonb,work(iab),
     +work(ibb),lb1,nlatb,wsave(jb),lwb,work(iw),lw,ier)
      else
c
c     do spherical harmonic synthesis on nlatb by nlonb gaussian grid
c
      call shsgc(nlatb,nlonb,isym,nt,db,nlatb,nlonb,work(iab),
     +work(ibb),lb1,nlatb,wsave(jb),lwb,work(iw),lw,ier)
      end if
c
c     both da,db are currently latitude by longitude north to south arrays
c     restore da and set db to agree with flags in igrida and igridb
c
      if (igrida(1) .gt. 0) call convlat(nlata,nlona,da)
      if (igridb(1) .gt. 0) call convlat(nlatb,nlonb,db)
      if (igrida(2) .eq. 0) call trsplat(nlata,nlona,da,work)
      if (igridb(2) .eq. 0) call trsplat(nlatb,nlonb,db,work)
      return
      end

      subroutine trab(ma,na,aa,ba,mb,nb,ab,bb)
      implicit none
      integer ma,na,mb,nb,i,j,m,n
      real aa(ma,na),ba(ma,na),ab(mb,nb),bb(mb,nb)
c
c     set coefficients for b grid from coefficients for a grid
c
      m = min0(ma,mb)
      n = min0(na,nb)
      do j=1,n
	do i=1,m
	  ab(i,j) = aa(i,j)
	  bb(i,j) = ba(i,j)
	end do
      end do
c
c     set coefs outside triangle to zero
c
      do i=m+1,mb
	do j=1,nb
	  ab(i,j) = 0.0
	  bb(i,j) = 0.0
	end do
      end do
      do j=n+1,nb
	do i=1,mb
	  ab(i,j) = 0.0
	  bb(i,j) = 0.0
	end do
      end do
      return
      end

      subroutine trsplat(n,m,data,work)
c
c     transpose the n by m array data to a m by n array data
c     work must be at least n*m words long
c
      implicit none
      integer n,m,i,j,ij,ji
      real data(*),work(*)
      do j=1,m
	do i=1,n
	  ij = (j-1)*n+i
	  work(ij) = data(ij)
	end do
      end do
      do i=1,n
	do j=1,m
	  ji = (i-1)*m+j
	  ij = (j-1)*n+i
	  data(ji) = work(ij)
	end do
      end do
      return
      end

      subroutine convlat(nlat,nlon,data)
c
c     reverse order of latitude (colatitude) grids
c
      implicit none
      integer nlat,nlon,nlat2,i,ib,j
      real data(nlat,nlon),temp
      nlat2 = nlat/2
      do i=1,nlat2
	ib = nlat-i+1
	do j=1,nlon
	  temp = data(i,j)
	  data(i,j) = data(ib,j)
	  data(ib,j) = temp
	end do
      end do
      return
      end
