From alanh@daphne.llnl.gov Tue Aug 24 16:06:44 1993
Date: Tue, 24 Aug 93 14:10:07 PDT
From: alanh@daphne.llnl.gov ( Alan Hindmarsh)
To: tony@aurora.cs.msstate.edu
Subject: demo for d.p. LSODI
Content-Length: 16398
X-Lines: 498
Status: RO

c-----------------------------------------------------------------------
c demonstration program for the lsodi package.
c this is the version of 18 august, 1981.
c
c this version is in double precision.
c
c this program solves a semi-discretized form of the burgers equation,
c
c     u  = -(u*u/2)  + eta * u
c      t           x          xx
c
c for a = -1 .le. x .le. 1 = b, t .ge. 0.
c here eta = 0.05.
c boundary conditions.. u(-1,t) = u(1,t) = 0.
c initial profile.. square wave
c     u(0,x) = 0    for 1/2 .lt. abs(x) .le. 1
c     u(0,x) = 1/2  for abs(x) = 1/2
c     u(0,x) = 1    for 0 .le. abs(x) .lt. 1/2
c
c an ode system is generated by a simplified galerkin treatment
c of the spatial variable x.
c
c reference..
c r. c. y. chin, g. w. hedstrom, and k. e. karlsson,
c a simplified galerkin method for hyperbolic equations,
c math. comp., vol. 33, no. 146 (april 1979), pp. 647-658.
c
c the problem is run with the lsodi package with a 10-point mesh
c and a 100-point mesh.  in each case, it is run with two tolerances
c and for various appropriate values of the method flag mf.
c output is on unit lout, set to 6 in a data statement below.
c-----------------------------------------------------------------------
      external res, addabd, addafl, jacbd, jacfl
      integer i, io, istate, itol, iwork, j, k,
     1   l, lout, liw, lrw, meth, miter, mf, ml, mu,
     2   n, nout, npts, nerr,
     3   nptsm1, n14, n34, n14m1, n14p1, n34m1, n34p1
      integer nm1
      double precision a, b, eta, delta,
     1   zero, fourth, half, one, hun,
     2   t, tout, tlast, tinit, errfac,
     3   atol, rtol, rwork, y, ydoti, elkup
      double precision eodsq, r4d
      dimension y(99), ydoti(99), tout(4), atol(2), rtol(2)
      dimension rwork(2002), iwork(125)
c pass problem parameters in the common block test1.
      common /test1/ r4d, eodsq, nm1
c
c set problem parameters and run parameters
      data eta/0.05d0/, a/-1.0d0/, b/1.0d0/
      data zero/0.0d0/, fourth/0.25d0/, half/.5d0/, one/1.0d0/,
     1   hun/100.0d0/
      data tinit/0.0d0/, tlast/0.4d0/
      data tout/.10d0,.20d0,.30d0,.40d0/
      data ml/1/, mu/1/, lout/6/
      data nout/4/, lrw/2002/, liw/125/
      data itol/1/, rtol/1.0d-3, 1.0d-6/, atol/1.0d-3, 1.0d-6/
c
      iwork(1) = ml
      iwork(2) = mu
      nerr = 0
c
c loop over two values of npts.
      do 300  npts = 10, 100, 90
c
c compute the mesh width delta and other parameters.
      delta = (b - a)/dfloat(npts)
      r4d = fourth/delta
      eodsq = eta/delta**2
      nptsm1 = npts - 1
      n14 = npts/4
      n34 = 3 * n14
      n14m1 = n14 - 1
      n14p1 = n14m1 + 2
      n34m1 = n34 - 1
      n34p1 = n34m1 + 2
      n = nptsm1
      nm1 = n - 1
c
c set the initial profile (for output purposes only).
c
      do 10 i = 1,n14m1
   10   y(i) = zero
      y(n14) = half
      do 20 i = n14p1,n34m1
   20   y(i) = one
      y(n34) = half
      do 30 i = n34p1,nptsm1
   30   y(i) = zero
c
      write (lout,1000)
      write (lout,1100) eta,a,b,tinit,tlast,ml,mu,n
      write (lout,1200) zero, (y(i), i=1,n), zero
c
c the j loop is over error tolerances.
c
      do 200 j = 1,2
c
c   this method flag loop is for demonstration only.
c
      do 100 meth = 1,2
       do 100 miter = 1,5
        if ( miter .eq. 3 )  go to 100
        if ( miter .le. 2 .and. npts .gt. 10 )  go to 100
        if ( miter .eq. 5 .and. npts .lt. 100 )  go to 100
        mf = 10*meth + miter
c
c set the initial profile.
c
        do 40 i = 1,n14m1
   40     y(i) = zero
        y(n14) = half
        do 50 i = n14p1,n34m1
   50     y(i) = one
        y(n34) = half
        do 60 i = n34p1,nptsm1
   60     y(i) = zero
c
        t = tinit
        istate = 0
c
        write (lout,1500) itol, rtol(j), atol(j), mf, npts
c
c  output loop for each case
c
        do 80 io = 1,nout
c
c         call lsodi
          if ( miter .le. 2 )  call lsodi ( res, addafl, jacfl,
     1      n, y, ydoti, t, tout(io), itol, rtol(j), atol(j), 1,
     2      istate, 0, rwork, lrw, iwork, liw, mf )
          if ( miter .ge. 4 )  call lsodi ( res, addabd, jacbd,
     1      n, y, ydoti, t, tout(io), itol, rtol(j), atol(j), 1,
     2      istate, 0, rwork, lrw, iwork, liw, mf )
          write (lout,2000) t, rwork(11), iwork(14),zero,
     1                      (y(i), i=1,n), zero
c
c if istate is not 2 on return, go to error section.
          if (istate .ne. 2)  go to 90
c
   80     continue
c
c
        write (lout,3000) mf, iwork(11), iwork(12), iwork(13),
     1                iwork(17), iwork(18)
c
c estimate final error and print result.
        errfac = elkup( n, y, rwork(21), itol, rtol(j), atol(j) )
        if ( errfac .gt. hun )  go to 85
          write (lout,5000)  errfac
          go to 100
   85     write (lout,5001)  errfac
          nerr = nerr + 1
          go to 100
   90   write (lout,4000) mf, t, istate
        nerr = nerr + 1
  100   continue
  200 continue
  300 continue
c
      write (lout,6000) nerr
      stop
c
 1000 format(1h1///20x,32h demonstration problem for lsodi )
 1100 format(//10x,35h-- simplified galerkin solution of ,
     1       19hburgers equation --///
     1       13x,30hdiffusion coefficient is eta =,e10.2/
     1       13x,24huniform mesh on interval,e12.3,4h to ,e12.3/
     2       13x,24hzero boundary conditions/
     2       13x,30hinitial data were as follows..//20x,5ht0 = ,e12.5/
     2       20x,8htlast = ,e12.5/20x,5hml = ,i2/
     4       20x,5hmu = ,i2/20x,5hn  = ,i3//)
c
 1200 format(//1x,18h initial profile..,89x,e12.4/10(10e12.4/))
c
 1500 format(1h1/1x,15hrun with itol =,i2,8h  rtol =,e12.2,
     1       8h  atol =,e12.2,7h   mf =,i3,9h   npts =,i4///)
c
 2000 format(/1x,20houtput for time t = ,e12.5,16h     current h =,
     1       e12.5,18h   current order =,i2,37x,e12.5/10(10e12.4/))
c
 3000 format(1x,80(1h*)/1x,26hfinal statistics for mf = ,i2,3h.. ,
     1       i5,7h steps,,i6,5h res,,i6,11h jacobians,,
     2       16h    rwork size =,i6,17h,    iwork size =,i6)
c
 4000 format(/1x,80(1h*)//20x,28hfinal time reached for mf = ,i2,
     1       9h was t = ,e12.5/25x,18hat which istate = ,i2//1x,80(1h*))
 5000 format(1x,34hfinal output is correct to within ,e8.1,
     1       30h  times local error tolerance. )
 5001 format(1x,25hfinal output is wrong by ,e8.1,
     1       30h  times local error tolerance. )
 6000 format(////1x,47h run completed.. number of errors encountered =,
     1       i3)
c
c end of main program for the lsodi demonstration problem.
      end
      subroutine gfun (n, t, y, g)
c this subroutine computes the function g(y,t) for the
c lsodi demonstration problem.
c it uses r4d = 1/(4*delta), eodsq = eta/delta**2, and nm1 = n - 1
c from the common block test1.
c
      integer i, n, nm1
      double precision t, y, g, r4d, eodsq, two
      dimension g(n), y(n)
      common /test1/ r4d, eodsq, nm1
      data two/2.0d0/
c
      g(1) = -r4d*y(2)**2 + eodsq*(y(2) - two*y(1))
c
      do 20 i = 2,nm1
        g(i) = r4d*(y(i-1)**2 - y(i+1)**2)
     1        + eodsq*(y(i+1) - two*y(i) + y(i-1))
   20   continue
c
      g(n) = r4d*y(nm1)**2 + eodsq*(y(nm1) - two*y(n))
c
      return
c end of subroutine gfun for the lsodi demonstration problem.
      end
      subroutine addabd (n, t, y, ml, mu, pa, m0)
c this subroutine computes the matrix a in band form, adds it to pa,
c and returns the sum in pa.
c this coding is for the lsodi demonstration problem.
c the matrix a is tridiagonal, of order n, with nonzero elements
c (reading across) of  1/6, 4/6, 1/6.
c
      integer i, n, m0, ml, mu, mup1, mup2
      double precision t, y, pa, fact1, fact4, one, four, six
      dimension y(n), pa(m0,n)
      data one/1.0d0/, four/4.0d0/, six/6.0d0/
c
c set the pointers.
      mup1 = mu + 1
      mup2 = mu + 2
c compute the elements of a.
      fact1 = one/six
      fact4 = four/six
c add the matrix a to the matrix pa (banded).
      do 10 i = 1,n
        pa(mu,i) = pa(mu,i) + fact1
        pa(mup1,i) = pa(mup1,i) + fact4
        pa(mup2,i) = pa(mup2,i) + fact1
   10   continue
      return
c end of subroutine addabd for the lsodi demonstration problem.
      end
      subroutine addafl (n, t, y, ml, mu, pa, m0)
c this subroutine computes the matrix a in full form, adds it to
c pa, and returns the sum in pa.
c it uses nm1 = n - 1 from common.
c this coding is for the lsodi demonstration problem.
c the matrix a is tridiagonal, of order n, with nonzero elements
c (reading across) of  1/6, 4/6, 1/6.
c
      integer i, n, m0, ml, mu, nm1
      double precision t, y, pa, r4d, eodsq, one, four, six,
     1   fact1, fact4
      dimension y(n), pa(m0,n)
      common /test1/ r4d, eodsq, nm1
      data one/1.0d0/, four/4.0d0/, six/6.0d0/
c
c compute the elements of a.
      fact1 = one/six
      fact4 = four/six
c
c add the matrix a to the matrix pa (full).
c
      do 110  i = 2, nm1
         pa(i,i+1) = pa(i,i+1) + fact1
         pa(i,i) = pa(i,i) + fact4
         pa(i,i-1) = pa(i,i-1) + fact1
  110    continue
      pa(1,2) = pa(1,2) + fact1
      pa(1,1) = pa(1,1) + fact4
      pa(n,n) = pa(n,n) + fact4
      pa(n,nm1) = pa(n,nm1) + fact1
      return
c end of subroutine addafl for the lsodi demonstration problem.
      end
      subroutine jacbd (n, t, y, s, ml, mu, pa, m0)
c this subroutine computes the jacobian dg/dy = d(g-a*s)/dy
c and stores
c
c   i   j
c dg /dy   in  pa(i-j+mu+1,j)
c
c for the lsodi demonstration problem (band matrix case).
c it uses r4d = 1/(4*delta), eodsq = eta/delta**2, and nm1 = n - 1
c from the common block test1.
c
      integer i, j, n, m0, ml, mu, mup1, mup2, nm1
      double precision t, y, s, pa, diag, r4d, eodsq, two, r2d
      dimension y(n), s(n), pa(m0,n)
      common /test1/ r4d, eodsq, nm1
      data two/2.0d0/
c
      mup1 = mu + 1
      mup2 = mu + 2
      diag = -two*eodsq
      r2d = two*r4d
c                     1   1
c compute and store dg /dy
      pa(mup1,1) = diag
c
c                     1   2
c compute and store dg /dy
      pa(mu,2) = -r2d*y(2) + eodsq
c
      do 20 i = 2,nm1
c
c                     i   i-1
c compute and store dg /dy
        pa(mup2,i-1) = r2d*y(i-1) + eodsq
c
c                     i   i
c compute and store dg /dy
      pa(mup1,i) = diag
c
c                     i   i+1
c compute and store dg /dy
        pa(mu,i+1) = -r2d*y(i+1) + eodsq
   20   continue
c
c                     n   n-1
c compute and store dg /dy
      pa(mup2,nm1) = r2d*y(nm1) + eodsq
c
c                     n   n
c compute and store dg /dy
      pa(mup1,n) = diag
c
      return
c end of subroutine jacbd for the lsodi demonstration problem.
      end
      subroutine jacfl (n, t, y, s, ml, mu, pa, m0)
c this subroutine computes the jacobian dg/dy = d(g-a*s)/dy
c and stores
c
c   i   j
c dg /dy   in  pa(i,j)
c
c for the lsodi demonstration problem (full matrix case).
c it uses r4d = 1/(4*delta), eodsq = eta/delta**2, and nm1 = n - 1
c from the common block test1.
c
      integer i, j, n, m0, ml, mu, nm1
      double precision t, y, s, pa, diag, r4d, eodsq, two, r2d
      dimension y(n), s(n), pa(m0,n)
      common /test1/ r4d, eodsq, nm1
      data two/2.0d0/
c
      diag = -two*eodsq
      r2d = two*r4d
c
c                     1   1
c compute and store dg /dy
      pa(1,1) = diag
c
c                     1   2
c compute and store dg /dy
      pa(1,2) = -r2d*y(2) + eodsq
c
      do 120  i = 2,nm1
c
c                     i   i-1
c compute and store dg /dy
        pa(i,i-1) = r2d*y(i-1) + eodsq
c
c                     i   i
c compute and store dg /dy
      pa(i,i) = diag
c
c                     i   i+1
c compute and store dg /dy
        pa(i,i+1) = -r2d*y(i+1) + eodsq
  120   continue
c
c                     n   n-1
c compute and store dg /dy
      pa(n,nm1) = r2d*y(nm1) + eodsq
c
c                     n   n
c compute and store dg /dy
      pa(n,n) = diag
c
      return
c end of subroutine jacfl for the lsodi demonstration problem.
      end
      subroutine res (n, t, y, v, r, ires)
c this subroutine computes the residual vector
c   r = g(t,y) - a(t,y)*v
c for the lsodi demonstration problem.
c it uses nm1 = n - 1 from common.
c if ires = -1, only g(t,y) is returned in r, since a(t,y) does
c not depend on y.
c no changes need to be made to this routine if n is changed.
c
      integer i, ires, n, nm1
      double precision t, y, v, r, r4d, eodsq, one, four, six,
     1   fact1, fact4
      dimension y(n), v(n), r(n)
      common /test1/ r4d, eodsq, nm1
      data one /1.0d0/, four /4.0d0/, six /6.0d0/
c
      call gfun (n, t, y, r)
      if (ires .eq. -1) return
c
      fact1 = one/six
      fact4 = four/six
      r(1) = r(1) - (fact4*v(1) + fact1*v(2))
      do 10 i = 2, nm1
  10   r(i) = r(i) - (fact1*v(i-1) + fact4*v(i) + fact1*v(i+1))
      r(n) = r(n) - (fact1*v(nm1) + fact4*v(n))
      return
c end of subroutine res for the lsodi demonstration problem.
      end
      double precision function elkup (n, y, ewt, itol, rtol, atol)
c elkup looks up approximately correct values of y at t = 0.4,
c ytrue = y9 or y99 depending on whether n = 9 or 99.  these were
c obtained by running lsodi with very tight tolerances.
c the returned value is
c elkup  =  norm of  ( y - ytrue ) / ( rtol*abs(ytrue) + atol ).
c
      integer n, itol, i
      double precision y, ewt, rtol, atol, y9, y99, y99a, y99b, y99c,
     1   y99d, y99e, y99f, y99g, vnorm
      dimension y(n), ewt(n), y9(9), y99(99)
      dimension y99a(16), y99b(16), y99c(16), y99d(16), y99e(16),
     1          y99f(16), y99g(3)
      equivalence (y99a(1),y99(1)), (y99b(1),y99(17)),
     1      (y99c(1),y99(33)), (y99d(1),y99(49)), (y99e(1),y99(65)),
     1      (y99f(1),y99(81)), (y99g(1),y99(97))
      data y9 /
     1 1.07001457d-01, 2.77432492d-01, 5.02444616d-01, 7.21037157d-01,
     1 9.01670441d-01, 8.88832048d-01, 4.96572850d-01, 9.46924362d-02,
     1-6.90855199d-03 /
      data y99a /
     1 2.05114384d-03, 4.19527452d-03, 6.52533872d-03, 9.13412751d-03,
     1 1.21140191d-02, 1.55565301d-02, 1.95516488d-02, 2.41869487d-02,
     1 2.95465081d-02, 3.57096839d-02, 4.27498067d-02, 5.07328729d-02,
     1 5.97163151d-02, 6.97479236d-02, 8.08649804d-02, 9.30936515d-02 /
      data y99b /
     1 1.06448659d-01, 1.20933239d-01, 1.36539367d-01, 1.53248227d-01,
     1 1.71030869d-01, 1.89849031d-01, 2.09656044d-01, 2.30397804d-01,
     1 2.52013749d-01, 2.74437805d-01, 2.97599285d-01, 3.21423708d-01,
     1 3.45833531d-01, 3.70748792d-01, 3.96087655d-01, 4.21766871d-01 /
      data y99c /
     1 4.47702161d-01, 4.73808532d-01, 5.00000546d-01, 5.26192549d-01,
     1 5.52298887d-01, 5.78234121d-01, 6.03913258d-01, 6.29252015d-01,
     1 6.54167141d-01, 6.78576790d-01, 7.02400987d-01, 7.25562165d-01,
     1 7.47985803d-01, 7.69601151d-01, 7.90342031d-01, 8.10147715d-01 /
      data y99d /
     1 8.28963844d-01, 8.46743353d-01, 8.63447369d-01, 8.79046021d-01,
     1 8.93519106d-01, 9.06856541d-01, 9.19058529d-01, 9.30135374d-01,
     1 9.40106872d-01, 9.49001208d-01, 9.56853318d-01, 9.63702661d-01,
     1 9.69590361d-01, 9.74555682d-01, 9.78631814d-01, 9.81840924d-01 /
      data y99e /
     1 9.84188430d-01, 9.85656465d-01, 9.86196496d-01, 9.85721098d-01,
     1 9.84094964d-01, 9.81125395d-01, 9.76552747d-01, 9.70041743d-01,
     1 9.61175143d-01, 9.49452051d-01, 9.34294085d-01, 9.15063568d-01,
     1 8.91098383d-01, 8.61767660d-01, 8.26550038d-01, 7.85131249d-01 /
      data y99f /
     1 7.37510044d-01, 6.84092540d-01, 6.25748369d-01, 5.63802368d-01,
     1 4.99946558d-01, 4.36077986d-01, 3.74091566d-01, 3.15672765d-01,
     1 2.62134958d-01, 2.14330497d-01, 1.72640946d-01, 1.37031155d-01,
     1 1.07140815d-01, 8.23867920d-02, 6.20562432d-02, 4.53794321d-02 /
      data y99g / 3.15789227d-02, 1.98968820d-02, 9.60472135d-03 /
c
      if ( n - 9 )  9,9, 99
c
c compute local error tolerance using correct y (n=9).
c
    9 call ewset( n, itol, rtol, atol, y9, ewt )
c
c invert ewt and replace y by the error, y - ytrue.
c
      do 19  i = 1, 9
        ewt(i) = 1.0d0/ewt(i)
   19   y(i) = y(i) - y9(i)
      go to 200
c
c compute local error tolerance using correct y (n=99).
c
   99 call ewset( n, itol, rtol, atol, y99, ewt )
c
c invert ewt and replace y by the error, y - ytrue.
c
      do 199  i = 1, 99
        ewt(i) = 1.0d0/ewt(i)
  199   y(i) = y(i) - y99(i)
c
c find weighted norm of the error.
c
  200 elkup = vnorm (n, y, ewt)
      return
c end of function elkup for the lsodi demonstration program.
      end

