rename
[unres4.git] / source / unres / minim.F90
diff --git a/source/unres/minim.F90 b/source/unres/minim.F90
new file mode 100644 (file)
index 0000000..4305640
--- /dev/null
@@ -0,0 +1,6508 @@
+      module minimm
+!-----------------------------------------------------------------------------
+      use io_units
+      use names
+      use math
+!      use MPI_data
+      use geometry_data
+      use energy_data
+      use control_data
+      use minim_data
+      use geometry
+!      use csa_data
+!      use energy
+      implicit none
+!-----------------------------------------------------------------------------
+!
+!
+!-----------------------------------------------------------------------------
+      contains
+!-----------------------------------------------------------------------------
+! cored.f
+!-----------------------------------------------------------------------------
+      subroutine assst(iv, liv, lv, v)
+!
+!  ***  assess candidate step (***sol version 2.3)  ***
+!
+      integer :: liv, l,lv
+      integer :: iv(liv)
+      real(kind=8) :: v(lv)
+!
+!  ***  purpose  ***
+!
+!        this subroutine is called by an unconstrained minimization
+!     routine to assess the next candidate step.  it may recommend one
+!     of several courses of action, such as accepting the step, recom-
+!     puting it using the same or a new quadratic model, or halting due
+!     to convergence or false convergence.  see the return code listing
+!     below.
+!
+!--------------------------  parameter usage  --------------------------
+!
+!  iv (i/o) integer parameter and scratch vector -- see description
+!             below of iv values referenced.
+! liv (in)  length of iv array.
+!  lv (in)  length of v array.
+!   v (i/o) real parameter and scratch vector -- see description
+!             below of v values referenced.
+!
+!  ***  iv values referenced  ***
+!
+!    iv(irc) (i/o) on input for the first step tried in a new iteration,
+!             iv(irc) should be set to 3 or 4 (the value to which it is
+!             set when step is definitely to be accepted).  on input
+!             after step has been recomputed, iv(irc) should be
+!             unchanged since the previous return of assst.
+!                on output, iv(irc) is a return code having one of the
+!             following values...
+!                  1 = switch models or try smaller step.
+!                  2 = switch models or accept step.
+!                  3 = accept step and determine v(radfac) by gradient
+!                       tests.
+!                  4 = accept step, v(radfac) has been determined.
+!                  5 = recompute step (using the same model).
+!                  6 = recompute step with radius = v(lmaxs) but do not
+!                       evaulate the objective function.
+!                  7 = x-convergence (see v(xctol)).
+!                  8 = relative function convergence (see v(rfctol)).
+!                  9 = both x- and relative function convergence.
+!                 10 = absolute function convergence (see v(afctol)).
+!                 11 = singular convergence (see v(lmaxs)).
+!                 12 = false convergence (see v(xftol)).
+!                 13 = iv(irc) was out of range on input.
+!             return code i has precdence over i+1 for i = 9, 10, 11.
+! iv(mlstgd) (i/o) saved value of iv(model).
+!  iv(model) (i/o) on input, iv(model) should be an integer identifying
+!             the current quadratic model of the objective function.
+!             if a previous step yielded a better function reduction,
+!             then iv(model) will be set to iv(mlstgd) on output.
+! iv(nfcall) (in)  invocation count for the objective function.
+! iv(nfgcal) (i/o) value of iv(nfcall) at step that gave the biggest
+!             function reduction this iteration.  iv(nfgcal) remains
+!             unchanged until a function reduction is obtained.
+! iv(radinc) (i/o) the number of radius increases (or minus the number
+!             of decreases) so far this iteration.
+! iv(restor) (out) set to 1 if v(f) has been restored and x should be
+!             restored to its initial value, to 2 if x should be saved,
+!             to 3 if x should be restored from the saved value, and to
+!             0 otherwise.
+!  iv(stage) (i/o) count of the number of models tried so far in the
+!             current iteration.
+! iv(stglim) (in)  maximum number of models to consider.
+! iv(switch) (out) set to 0 unless a new model is being tried and it
+!             gives a smaller function value than the previous model,
+!             in which case assst sets iv(switch) = 1.
+! iv(toobig) (in)  is nonzero if step was too big (e.g. if it caused
+!             overflow).
+!   iv(xirc) (i/o) value that iv(irc) would have in the absence of
+!             convergence, false convergence, and oversized steps.
+!
+!  ***  v values referenced  ***
+!
+! v(afctol) (in)  absolute function convergence tolerance.  if the
+!             absolute value of the current function value v(f) is less
+!             than v(afctol), then assst returns with iv(irc) = 10.
+! v(decfac) (in)  factor by which to decrease radius when iv(toobig) is
+!             nonzero.
+! v(dstnrm) (in)  the 2-norm of d*step.
+! v(dstsav) (i/o) value of v(dstnrm) on saved step.
+!   v(dst0) (in)  the 2-norm of d times the newton step (when defined,
+!             i.e., for v(nreduc) .ge. 0).
+!      v(f) (i/o) on both input and output, v(f) is the objective func-
+!             tion value at x.  if x is restored to a previous value,
+!             then v(f) is restored to the corresponding value.
+!   v(fdif) (out) the function reduction v(f0) - v(f) (for the output
+!             value of v(f) if an earlier step gave a bigger function
+!             decrease, and for the input value of v(f) otherwise).
+! v(flstgd) (i/o) saved value of v(f).
+!     v(f0) (in)  objective function value at start of iteration.
+! v(gtslst) (i/o) value of v(gtstep) on saved step.
+! v(gtstep) (in)  inner product between step and gradient.
+! v(incfac) (in)  minimum factor by which to increase radius.
+!  v(lmaxs) (in)  maximum reasonable step size (and initial step bound).
+!             if the actual function decrease is no more than twice
+!             what was predicted, if a return with iv(irc) = 7, 8, 9,
+!             or 10 does not occur, if v(dstnrm) .gt. v(lmaxs), and if
+!             v(preduc) .le. v(sctol) * abs(v(f0)), then assst re-
+!             turns with iv(irc) = 11.  if so doing appears worthwhile,
+!             then assst repeats this test with v(preduc) computed for
+!             a step of length v(lmaxs) (by a return with iv(irc) = 6).
+! v(nreduc) (i/o)  function reduction predicted by quadratic model for
+!             newton step.  if assst is called with iv(irc) = 6, i.e.,
+!             if v(preduc) has been computed with radius = v(lmaxs) for
+!             use in the singular convervence test, then v(nreduc) is
+!             set to -v(preduc) before the latter is restored.
+! v(plstgd) (i/o) value of v(preduc) on saved step.
+! v(preduc) (i/o) function reduction predicted by quadratic model for
+!             current step.
+! v(radfac) (out) factor to be used in determining the new radius,
+!             which should be v(radfac)*dst, where  dst  is either the
+!             output value of v(dstnrm) or the 2-norm of
+!             diag(newd)*step  for the output value of step and the
+!             updated version, newd, of the scale vector d.  for
+!             iv(irc) = 3, v(radfac) = 1.0 is returned.
+! v(rdfcmn) (in)  minimum value for v(radfac) in terms of the input
+!             value of v(dstnrm) -- suggested value = 0.1.
+! v(rdfcmx) (in)  maximum value for v(radfac) -- suggested value = 4.0.
+!  v(reldx) (in) scaled relative change in x caused by step, computed
+!             (e.g.) by function  reldst  as
+!                 max (d(i)*abs(x(i)-x0(i)), 1 .le. i .le. p) /
+!                    max (d(i)*(abs(x(i))+abs(x0(i))), 1 .le. i .le. p).
+! v(rfctol) (in)  relative function convergence tolerance.  if the
+!             actual function reduction is at most twice what was pre-
+!             dicted and  v(nreduc) .le. v(rfctol)*abs(v(f0)),  then
+!             assst returns with iv(irc) = 8 or 9.
+! v(stppar) (in)  marquardt parameter -- 0 means full newton step.
+! v(tuner1) (in)  tuning constant used to decide if the function
+!             reduction was much less than expected.  suggested
+!             value = 0.1.
+! v(tuner2) (in)  tuning constant used to decide if the function
+!             reduction was large enough to accept step.  suggested
+!             value = 10**-4.
+! v(tuner3) (in)  tuning constant used to decide if the radius
+!             should be increased.  suggested value = 0.75.
+!  v(xctol) (in)  x-convergence criterion.  if step is a newton step
+!             (v(stppar) = 0) having v(reldx) .le. v(xctol) and giving
+!             at most twice the predicted function decrease, then
+!             assst returns iv(irc) = 7 or 9.
+!  v(xftol) (in)  false convergence tolerance.  if step gave no or only
+!             a small function decrease and v(reldx) .le. v(xftol),
+!             then assst returns with iv(irc) = 12.
+!
+!-------------------------------  notes  -------------------------------
+!
+!  ***  application and usage restrictions  ***
+!
+!        this routine is called as part of the nl2sol (nonlinear
+!     least-squares) package.  it may be used in any unconstrained
+!     minimization solver that uses dogleg, goldfeld-quandt-trotter,
+!     or levenberg-marquardt steps.
+!
+!  ***  algorithm notes  ***
+!
+!        see (1) for further discussion of the assessing and model
+!     switching strategies.  while nl2sol considers only two models,
+!     assst is designed to handle any number of models.
+!
+!  ***  usage notes  ***
+!
+!        on the first call of an iteration, only the i/o variables
+!     step, x, iv(irc), iv(model), v(f), v(dstnrm), v(gtstep), and
+!     v(preduc) need have been initialized.  between calls, no i/o
+!     values execpt step, x, iv(model), v(f) and the stopping toler-
+!     ances should be changed.
+!        after a return for convergence or false convergence, one can
+!     change the stopping tolerances and call assst again, in which
+!     case the stopping tests will be repeated.
+!
+!  ***  references  ***
+!
+!     (1) dennis, j.e., jr., gay, d.m., and welsch, r.e. (1981),
+!        an adaptive nonlinear least-squares algorithm,
+!        acm trans. math. software, vol. 7, no. 3.
+!
+!     (2) powell, m.j.d. (1970)  a fortran subroutine for solving
+!        systems of nonlinear algebraic equations, in numerical
+!        methods for nonlinear algebraic equations, edited by
+!        p. rabinowitz, gordon and breach, london.
+!
+!  ***  history  ***
+!
+!        john dennis designed much of this routine, starting with
+!     ideas in (2). roy welsch suggested the model switching strategy.
+!        david gay and stephen peters cast this subroutine into a more
+!     portable form (winter 1977), and david gay cast it into its
+!     present form (fall 1978).
+!
+!  ***  general  ***
+!
+!     this subroutine was written in connection with research
+!     supported by the national science foundation under grants
+!     mcs-7600324, dcr75-10143, 76-14311dss, mcs76-11989, and
+!     mcs-7906671.
+!
+!------------------------  external quantities  ------------------------
+!
+!  ***  no external functions and subroutines  ***
+!
+!  ***  intrinsic functions  ***
+!/+
+!el      real(kind=8) :: dabs, dmax1
+!/
+!  ***  no common blocks  ***
+!
+!--------------------------  local variables  --------------------------
+!
+      logical :: goodx
+      integer :: i, nfc
+      real(kind=8) :: emax, emaxs, gts, rfac1, xmax
+!el      real(kind=8) :: half, one, onep2, two, zero
+!
+!  ***  subscripts for iv and v  ***
+!
+!el      integer :: afctol, decfac, dstnrm, dstsav, dst0, f, fdif, flstgd, f0,&
+!el              gtslst, gtstep, incfac, irc, lmaxs, mlstgd, model, nfcall,&
+!el              nfgcal, nreduc, plstgd, preduc, radfac, radinc, rdfcmn,&
+!el              rdfcmx, reldx, restor, rfctol, sctol, stage, stglim,&
+!el              stppar, switch, toobig, tuner1, tuner2, tuner3, xctol,&
+!el              xftol, xirc
+!
+!
+!  ***  data initializations  ***
+!
+!/6
+!     data half/0.5d+0/, one/1.d+0/, onep2/1.2d+0/, two/2.d+0/,
+!    1     zero/0.d+0/
+!/7
+      real(kind=8),parameter :: half=0.5d+0, one=1.d+0, onep2=1.2d+0, two=2.d+0,&
+                 zero=0.d+0
+!/
+!
+!/6
+!     data irc/29/, mlstgd/32/, model/5/, nfcall/6/, nfgcal/7/,
+!    1     radinc/8/, restor/9/, stage/10/, stglim/11/, switch/12/,
+!    2     toobig/2/, xirc/13/
+!/7
+      integer,parameter :: irc=29, mlstgd=32, model=5, nfcall=6, nfgcal=7,&
+                 radinc=8, restor=9, stage=10, stglim=11, switch=12,&
+                 toobig=2, xirc=13
+!/
+!/6
+!     data afctol/31/, decfac/22/, dstnrm/2/, dst0/3/, dstsav/18/,
+!    1     f/10/, fdif/11/, flstgd/12/, f0/13/, gtslst/14/, gtstep/4/,
+!    2     incfac/23/, lmaxs/36/, nreduc/6/, plstgd/15/, preduc/7/,
+!    3     radfac/16/, rdfcmn/24/, rdfcmx/25/, reldx/17/, rfctol/32/,
+!    4     sctol/37/, stppar/5/, tuner1/26/, tuner2/27/, tuner3/28/,
+!    5     xctol/33/, xftol/34/
+!/7
+      integer,parameter :: afctol=31, decfac=22, dstnrm=2, dst0=3, dstsav=18,&
+                 f=10, fdif=11, flstgd=12, f0=13, gtslst=14, gtstep=4,&
+                 incfac=23, lmaxs=36, nreduc=6, plstgd=15, preduc=7,&
+                 radfac=16, rdfcmn=24, rdfcmx=25, reldx=17, rfctol=32,&
+                 sctol=37, stppar=5, tuner1=26, tuner2=27, tuner3=28,&
+                 xctol=33, xftol=34
+!/
+!
+!+++++++++++++++++++++++++++++++  body  ++++++++++++++++++++++++++++++++
+!
+      nfc = iv(nfcall)
+      iv(switch) = 0
+      iv(restor) = 0
+      rfac1 = one
+      goodx = .true.
+      i = iv(irc)
+      if (i .ge. 1 .and. i .le. 12) &
+                   go to (20,30,10,10,40,280,220,220,220,220,220,170), i
+         iv(irc) = 13
+         go to 999
+!
+!  ***  initialize for new iteration  ***
+!
+ 10   iv(stage) = 1
+      iv(radinc) = 0
+      v(flstgd) = v(f0)
+      if (iv(toobig) .eq. 0) go to 110
+         iv(stage) = -1
+         iv(xirc) = i
+         go to 60
+!
+!  ***  step was recomputed with new model or smaller radius  ***
+!  ***  first decide which  ***
+!
+ 20   if (iv(model) .ne. iv(mlstgd)) go to 30
+!        ***  old model retained, smaller radius tried  ***
+!        ***  do not consider any more new models this iteration  ***
+         iv(stage) = iv(stglim)
+         iv(radinc) = -1
+         go to 110
+!
+!  ***  a new model is being tried.  decide whether to keep it.  ***
+!
+ 30   iv(stage) = iv(stage) + 1
+!
+!     ***  now we add the possibiltiy that step was recomputed with  ***
+!     ***  the same model, perhaps because of an oversized step.     ***
+!
+ 40   if (iv(stage) .gt. 0) go to 50
+!
+!        ***  step was recomputed because it was too big.  ***
+!
+         if (iv(toobig) .ne. 0) go to 60
+!
+!        ***  restore iv(stage) and pick up where we left off.  ***
+!
+         iv(stage) = -iv(stage)
+         i = iv(xirc)
+         go to (20, 30, 110, 110, 70), i
+!
+ 50   if (iv(toobig) .eq. 0) go to 70
+!
+!  ***  handle oversize step  ***
+!
+      if (iv(radinc) .gt. 0) go to 80
+         iv(stage) = -iv(stage)
+         iv(xirc) = iv(irc)
+!
+ 60      v(radfac) = v(decfac)
+         iv(radinc) = iv(radinc) - 1
+         iv(irc) = 5
+         iv(restor) = 1
+         go to 999
+!
+ 70   if (v(f) .lt. v(flstgd)) go to 110
+!
+!     *** the new step is a loser.  restore old model.  ***
+!
+      if (iv(model) .eq. iv(mlstgd)) go to 80
+         iv(model) = iv(mlstgd)
+         iv(switch) = 1
+!
+!     ***  restore step, etc. only if a previous step decreased v(f).
+!
+ 80   if (v(flstgd) .ge. v(f0)) go to 110
+         iv(restor) = 1
+         v(f) = v(flstgd)
+         v(preduc) = v(plstgd)
+         v(gtstep) = v(gtslst)
+         if (iv(switch) .eq. 0) rfac1 = v(dstnrm) / v(dstsav)
+         v(dstnrm) = v(dstsav)
+         nfc = iv(nfgcal)
+         goodx = .false.
+!
+ 110  v(fdif) = v(f0) - v(f)
+      if (v(fdif) .gt. v(tuner2) * v(preduc)) go to 140
+      if(iv(radinc).gt.0) go to 140
+!
+!        ***  no (or only a trivial) function decrease
+!        ***  -- so try new model or smaller radius
+!
+         if (v(f) .lt. v(f0)) go to 120
+              iv(mlstgd) = iv(model)
+              v(flstgd) = v(f)
+              v(f) = v(f0)
+              iv(restor) = 1
+              go to 130
+ 120     iv(nfgcal) = nfc
+ 130     iv(irc) = 1
+         if (iv(stage) .lt. iv(stglim)) go to 160
+              iv(irc) = 5
+              iv(radinc) = iv(radinc) - 1
+              go to 160
+!
+!  ***  nontrivial function decrease achieved  ***
+!
+ 140  iv(nfgcal) = nfc
+      rfac1 = one
+      v(dstsav) = v(dstnrm)
+      if (v(fdif) .gt. v(preduc)*v(tuner1)) go to 190
+!
+!  ***  decrease was much less than predicted -- either change models
+!  ***  or accept step with decreased radius.
+!
+      if (iv(stage) .ge. iv(stglim)) go to 150
+!        ***  consider switching models  ***
+         iv(irc) = 2
+         go to 160
+!
+!     ***  accept step with decreased radius  ***
+!
+ 150  iv(irc) = 4
+!
+!  ***  set v(radfac) to fletcher*s decrease factor  ***
+!
+ 160  iv(xirc) = iv(irc)
+      emax = v(gtstep) + v(fdif)
+      v(radfac) = half * rfac1
+      if (emax .lt. v(gtstep)) v(radfac) = rfac1 * dmax1(v(rdfcmn),&
+                                                 half * v(gtstep)/emax)
+!
+!  ***  do false convergence test  ***
+!
+ 170  if (v(reldx) .le. v(xftol)) go to 180
+         iv(irc) = iv(xirc)
+         if (v(f) .lt. v(f0)) go to 200
+              go to 230
+!
+ 180  iv(irc) = 12
+      go to 240
+!
+!  ***  handle good function decrease  ***
+!
+ 190  if (v(fdif) .lt. (-v(tuner3) * v(gtstep))) go to 210
+!
+!     ***  increasing radius looks worthwhile.  see if we just
+!     ***  recomputed step with a decreased radius or restored step
+!     ***  after recomputing it with a larger radius.
+!
+      if (iv(radinc) .lt. 0) go to 210
+      if (iv(restor) .eq. 1) go to 210
+!
+!        ***  we did not.  try a longer step unless this was a newton
+!        ***  step.
+
+         v(radfac) = v(rdfcmx)
+         gts = v(gtstep)
+         if (v(fdif) .lt. (half/v(radfac) - one) * gts) &
+                  v(radfac) = dmax1(v(incfac), half*gts/(gts + v(fdif)))
+         iv(irc) = 4
+         if (v(stppar) .eq. zero) go to 230
+         if (v(dst0) .ge. zero .and. (v(dst0) .lt. two*v(dstnrm) &
+                   .or. v(nreduc) .lt. onep2*v(fdif)))  go to 230
+!             ***  step was not a newton step.  recompute it with
+!             ***  a larger radius.
+              iv(irc) = 5
+              iv(radinc) = iv(radinc) + 1
+!
+!  ***  save values corresponding to good step  ***
+!
+ 200  v(flstgd) = v(f)
+      iv(mlstgd) = iv(model)
+      if (iv(restor) .ne. 1) iv(restor) = 2
+      v(dstsav) = v(dstnrm)
+      iv(nfgcal) = nfc
+      v(plstgd) = v(preduc)
+      v(gtslst) = v(gtstep)
+      go to 230
+!
+!  ***  accept step with radius unchanged  ***
+!
+ 210  v(radfac) = one
+      iv(irc) = 3
+      go to 230
+!
+!  ***  come here for a restart after convergence  ***
+!
+ 220  iv(irc) = iv(xirc)
+      if (v(dstsav) .ge. zero) go to 240
+         iv(irc) = 12
+         go to 240
+!
+!  ***  perform convergence tests  ***
+!
+ 230  iv(xirc) = iv(irc)
+ 240  if (iv(restor) .eq. 1 .and. v(flstgd) .lt. v(f0)) iv(restor) = 3
+      if (half * v(fdif) .gt. v(preduc)) go to 999
+      emax = v(rfctol) * dabs(v(f0))
+      emaxs = v(sctol) * dabs(v(f0))
+      if (v(dstnrm) .gt. v(lmaxs) .and. v(preduc) .le. emaxs) &
+                             iv(irc) = 11
+      if (v(dst0) .lt. zero) go to 250
+      i = 0
+      if ((v(nreduc) .gt. zero .and. v(nreduc) .le. emax) .or. &
+          (v(nreduc) .eq. zero .and. v(preduc) .eq. zero))  i = 2
+      if (v(stppar) .eq. zero .and. v(reldx) .le. v(xctol) &
+                              .and. goodx)                  i = i + 1
+      if (i .gt. 0) iv(irc) = i + 6
+!
+!  ***  consider recomputing step of length v(lmaxs) for singular
+!  ***  convergence test.
+!
+ 250  if (iv(irc) .gt. 5 .and. iv(irc) .ne. 12) go to 999
+      if (v(dstnrm) .gt. v(lmaxs)) go to 260
+         if (v(preduc) .ge. emaxs) go to 999
+              if (v(dst0) .le. zero) go to 270
+                   if (half * v(dst0) .le. v(lmaxs)) go to 999
+                        go to 270
+ 260  if (half * v(dstnrm) .le. v(lmaxs)) go to 999
+      xmax = v(lmaxs) / v(dstnrm)
+      if (xmax * (two - xmax) * v(preduc) .ge. emaxs) go to 999
+ 270  if (v(nreduc) .lt. zero) go to 290
+!
+!  ***  recompute v(preduc) for use in singular convergence test  ***
+!
+      v(gtslst) = v(gtstep)
+      v(dstsav) = v(dstnrm)
+      if (iv(irc) .eq. 12) v(dstsav) = -v(dstsav)
+      v(plstgd) = v(preduc)
+      i = iv(restor)
+      iv(restor) = 2
+      if (i .eq. 3) iv(restor) = 0
+      iv(irc) = 6
+      go to 999
+!
+!  ***  perform singular convergence test with recomputed v(preduc)  ***
+!
+ 280  v(gtstep) = v(gtslst)
+      v(dstnrm) = dabs(v(dstsav))
+      iv(irc) = iv(xirc)
+      if (v(dstsav) .le. zero) iv(irc) = 12
+      v(nreduc) = -v(preduc)
+      v(preduc) = v(plstgd)
+      iv(restor) = 3
+ 290  if (-v(nreduc) .le. v(sctol) * dabs(v(f0))) iv(irc) = 11
+!
+ 999  return
+!
+!  ***  last card of assst follows  ***
+      end subroutine assst
+!-----------------------------------------------------------------------------
+      subroutine deflt(alg, iv, liv, lv, v)
+!
+!  ***  supply ***sol (version 2.3) default values to iv and v  ***
+!
+!  ***  alg = 1 means regression constants.
+!  ***  alg = 2 means general unconstrained optimization constants.
+!
+      integer :: liv, l,lv
+      integer :: alg, iv(liv)
+      real(kind=8) :: v(lv)
+!
+!el      external imdcon, vdflt
+!el      integer imdcon
+! imdcon... returns machine-dependent integer constants.
+! vdflt.... provides default values to v.
+!
+      integer :: miv, m
+      integer :: miniv(2), minv(2)
+!
+!  ***  subscripts for iv  ***
+!
+!el      integer algsav, covprt, covreq, dtype, hc, ierr, inith, inits,
+!el     1        ipivot, ivneed, lastiv, lastv, lmat, mxfcal, mxiter,
+!el     2        nfcov, ngcov, nvdflt, outlev, parprt, parsav, perm,
+!el     3        prunit, qrtyp, rdreq, rmat, solprt, statpr, vneed,
+!el     4        vsave, x0prt
+!
+!  ***  iv subscript values  ***
+!
+!/6
+!     data algsav/51/, covprt/14/, covreq/15/, dtype/16/, hc/71/,
+!    1     ierr/75/, inith/25/, inits/25/, ipivot/76/, ivneed/3/,
+!    2     lastiv/44/, lastv/45/, lmat/42/, mxfcal/17/, mxiter/18/,
+!    3     nfcov/52/, ngcov/53/, nvdflt/50/, outlev/19/, parprt/20/,
+!    4     parsav/49/, perm/58/, prunit/21/, qrtyp/80/, rdreq/57/,
+!    5     rmat/78/, solprt/22/, statpr/23/, vneed/4/, vsave/60/,
+!    6     x0prt/24/
+!/7
+      integer,parameter :: algsav=51, covprt=14, covreq=15, dtype=16, hc=71,&
+                 ierr=75, inith=25, inits=25, ipivot=76, ivneed=3,&
+                 lastiv=44, lastv=45, lmat=42, mxfcal=17, mxiter=18,&
+                 nfcov=52, ngcov=53, nvdflt=50, outlev=19, parprt=20,&
+                 parsav=49, perm=58, prunit=21, qrtyp=80, rdreq=57,&
+                 rmat=78, solprt=22, statpr=23, vneed=4, vsave=60,&
+                 x0prt=24
+!/
+      data miniv(1)/80/, miniv(2)/59/, minv(1)/98/, minv(2)/71/
+!el local variables
+      integer :: mv
+!
+!-------------------------------  body  --------------------------------
+!
+      if (alg .lt. 1 .or. alg .gt. 2) go to 40
+      miv = miniv(alg)
+      if (liv .lt. miv) go to 20
+      mv = minv(alg)
+      if (lv .lt. mv) go to 30
+      call vdflt(alg, lv, v)
+      iv(1) = 12
+      iv(algsav) = alg
+      iv(ivneed) = 0
+      iv(lastiv) = miv
+      iv(lastv) = mv
+      iv(lmat) = mv + 1
+      iv(mxfcal) = 200
+      iv(mxiter) = 150
+      iv(outlev) = 1
+      iv(parprt) = 1
+      iv(perm) = miv + 1
+      iv(prunit) = imdcon(1)
+      iv(solprt) = 1
+      iv(statpr) = 1
+      iv(vneed) = 0
+      iv(x0prt) = 1
+!
+      if (alg .ge. 2) go to 10
+!
+!  ***  regression  values
+!
+      iv(covprt) = 3
+      iv(covreq) = 1
+      iv(dtype) = 1
+      iv(hc) = 0
+      iv(ierr) = 0
+      iv(inits) = 0
+      iv(ipivot) = 0
+      iv(nvdflt) = 32
+      iv(parsav) = 67
+      iv(qrtyp) = 1
+      iv(rdreq) = 3
+      iv(rmat) = 0
+      iv(vsave) = 58
+      go to 999
+!
+!  ***  general optimization values
+!
+ 10   iv(dtype) = 0
+      iv(inith) = 1
+      iv(nfcov) = 0
+      iv(ngcov) = 0
+      iv(nvdflt) = 25
+      iv(parsav) = 47
+      go to 999
+!
+ 20   iv(1) = 15
+      go to 999
+!
+ 30   iv(1) = 16
+      go to 999
+!
+ 40   iv(1) = 67
+!
+ 999  return
+!  ***  last card of deflt follows  ***
+      end subroutine deflt
+!-----------------------------------------------------------------------------
+      real(kind=8) function dotprd(p,x,y)
+!
+!  ***  return the inner product of the p-vectors x and y.  ***
+!
+      integer :: p
+      real(kind=8) :: x(p), y(p)
+!
+      integer :: i
+!el      real(kind=8) :: one, zero
+      real(kind=8) :: sqteta, t
+!/+
+!el      real(kind=8) :: dmax1, dabs
+!/
+!el      external rmdcon
+!el      real(kind=8) :: rmdcon
+!
+!  ***  rmdcon(2) returns a machine-dependent constant, sqteta, which
+!  ***  is slightly larger than the smallest positive number that
+!  ***  can be squared without underflowing.
+!
+!/6
+!     data one/1.d+0/, sqteta/0.d+0/, zero/0.d+0/
+!/7
+      real(kind=8),parameter :: one=1.d+0, zero=0.d+0
+      data sqteta/0.d+0/
+!/
+!
+      dotprd = zero
+      if (p .le. 0) go to 999
+!rc      if (sqteta .eq. zero) sqteta = rmdcon(2)
+      do 20 i = 1, p
+!rc         t = dmax1(dabs(x(i)), dabs(y(i)))
+!rc         if (t .gt. one) go to 10
+!rc         if (t .lt. sqteta) go to 20
+!rc         t = (x(i)/sqteta)*y(i)
+!rc         if (dabs(t) .lt. sqteta) go to 20
+ 10      dotprd = dotprd + x(i)*y(i)
+ 20   continue
+!
+ 999  return
+!  ***  last card of dotprd follows  ***
+      end function dotprd
+!-----------------------------------------------------------------------------
+      subroutine itsum(d, g, iv, liv, lv, p, v, x)
+!
+!  ***  print iteration summary for ***sol (version 2.3)  ***
+!
+!  ***  parameter declarations  ***
+!
+      integer :: liv, lv, p
+      integer :: iv(liv)
+      real(kind=8) :: d(p), g(p), v(lv), x(p)
+!
+!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+!
+!  ***  local variables  ***
+!
+      integer :: alg, i, iv1, m, nf, ng, ol, pu
+!/6
+!     real model1(6), model2(6)
+!/7
+      character(len=4) :: model1(6), model2(6)
+!/
+      real(kind=8) :: nreldf, oldf, preldf, reldf      !el, zero
+!
+!  ***  intrinsic functions  ***
+!/+
+!el      integer :: iabs
+!el      real(kind=8) :: dabs, dmax1
+!/
+!  ***  no external functions or subroutines  ***
+!
+!  ***  subscripts for iv and v  ***
+!
+!el      integer algsav, dstnrm, f, fdif, f0, needhd, nfcall, nfcov, ngcov,
+!el     1        ngcall, niter, nreduc, outlev, preduc, prntit, prunit,
+!el     2        reldx, solprt, statpr, stppar, sused, x0prt
+!
+!  ***  iv subscript values  ***
+!
+!/6
+!     data algsav/51/, needhd/36/, nfcall/6/, nfcov/52/, ngcall/30/,
+!    1     ngcov/53/, niter/31/, outlev/19/, prntit/39/, prunit/21/,
+!    2     solprt/22/, statpr/23/, sused/64/, x0prt/24/
+!/7
+      integer,parameter :: algsav=51, needhd=36, nfcall=6, nfcov=52, ngcall=30,&
+                 ngcov=53, niter=31, outlev=19, prntit=39, prunit=21,&
+                 solprt=22, statpr=23, sused=64, x0prt=24
+!/
+!
+!  ***  v subscript values  ***
+!
+!/6
+!     data dstnrm/2/, f/10/, f0/13/, fdif/11/, nreduc/6/, preduc/7/,
+!    1     reldx/17/, stppar/5/
+!/7
+      integer,parameter :: dstnrm=2, f=10, f0=13, fdif=11, nreduc=6, preduc=7,&
+                 reldx=17, stppar=5
+!/
+!
+!/6
+!     data zero/0.d+0/
+!/7
+      real(kind=8),parameter :: zero=0.d+0
+!/
+!/6
+!     data model1(1)/4h    /, model1(2)/4h    /, model1(3)/4h    /,
+!    1     model1(4)/4h    /, model1(5)/4h  g /, model1(6)/4h  s /,
+!    2     model2(1)/4h g  /, model2(2)/4h s  /, model2(3)/4hg-s /,
+!    3     model2(4)/4hs-g /, model2(5)/4h-s-g/, model2(6)/4h-g-s/
+!/7
+      data model1/'    ','    ','    ','    ','  g ','  s '/,&
+           model2/' g  ',' s  ','g-s ','s-g ','-s-g','-g-s'/
+!/
+!
+!-------------------------------  body  --------------------------------
+!
+      pu = iv(prunit)
+      if (pu .eq. 0) go to 999
+      iv1 = iv(1)
+      if (iv1 .gt. 62) iv1 = iv1 - 51
+      ol = iv(outlev)
+      alg = iv(algsav)
+      if (iv1 .lt. 2 .or. iv1 .gt. 15) go to 370
+      if (iv1 .ge. 12) go to 120
+      if (iv1 .eq. 2 .and. iv(niter) .eq. 0) go to 390
+      if (ol .eq. 0) go to 120
+      if (iv1 .ge. 10 .and. iv(prntit) .eq. 0) go to 120
+      if (iv1 .gt. 2) go to 10
+         iv(prntit) = iv(prntit) + 1
+         if (iv(prntit) .lt. iabs(ol)) go to 999
+ 10   nf = iv(nfcall) - iabs(iv(nfcov))
+      iv(prntit) = 0
+      reldf = zero
+      preldf = zero
+      oldf = dmax1(dabs(v(f0)), dabs(v(f)))
+      if (oldf .le. zero) go to 20
+         reldf = v(fdif) / oldf
+         preldf = v(preduc) / oldf
+ 20   if (ol .gt. 0) go to 60
+!
+!        ***  print short summary line  ***
+!
+         if (iv(needhd) .eq. 1 .and. alg .eq. 1) write(pu,30)
+ 30   format(/10h   it   nf,6x,1hf,7x,5hreldf,3x,6hpreldf,3x,5hreldx,&
+             2x,13hmodel  stppar)
+         if (iv(needhd) .eq. 1 .and. alg .eq. 2) write(pu,40)
+ 40   format(/11h    it   nf,7x,1hf,8x,5hreldf,4x,6hpreldf,4x,5hreldx,&
+             3x,6hstppar)
+         iv(needhd) = 0
+         if (alg .eq. 2) go to 50
+         m = iv(sused)
+         write(pu,100) iv(niter), nf, v(f), reldf, preldf, v(reldx),&
+                       model1(m), model2(m), v(stppar)
+         go to 120
+!
+ 50      write(pu,110) iv(niter), nf, v(f), reldf, preldf, v(reldx),&
+                       v(stppar)
+         go to 120
+!
+!     ***  print long summary line  ***
+!
+ 60   if (iv(needhd) .eq. 1 .and. alg .eq. 1) write(pu,70)
+ 70   format(/11h    it   nf,6x,1hf,7x,5hreldf,3x,6hpreldf,3x,5hreldx,&
+             2x,13hmodel  stppar,2x,6hd*step,2x,7hnpreldf)
+      if (iv(needhd) .eq. 1 .and. alg .eq. 2) write(pu,80)
+ 80   format(/11h    it   nf,7x,1hf,8x,5hreldf,4x,6hpreldf,4x,5hreldx,&
+             3x,6hstppar,3x,6hd*step,3x,7hnpreldf)
+      iv(needhd) = 0
+      nreldf = zero
+      if (oldf .gt. zero) nreldf = v(nreduc) / oldf
+      if (alg .eq. 2) go to 90
+      m = iv(sused)
+      write(pu,100) iv(niter), nf, v(f), reldf, preldf, v(reldx),&
+                   model1(m), model2(m), v(stppar), v(dstnrm), nreldf
+      go to 120
+!
+ 90   write(pu,110) iv(niter), nf, v(f), reldf, preldf,&
+                   v(reldx), v(stppar), v(dstnrm), nreldf
+ 100  format(i6,i5,d10.3,2d9.2,d8.1,a3,a4,2d8.1,d9.2)
+ 110  format(i6,i5,d11.3,2d10.2,3d9.1,d10.2)
+!
+ 120  if (iv(statpr) .lt. 0) go to 430
+      go to (999, 999, 130, 150, 170, 190, 210, 230, 250, 270, 290, 310,&
+             330, 350, 520), iv1
+!
+ 130  write(pu,140)
+ 140  format(/26h ***** x-convergence *****)
+      go to 430
+!
+ 150  write(pu,160)
+ 160  format(/42h ***** relative function convergence *****)
+      go to 430
+!
+ 170  write(pu,180)
+ 180  format(/49h ***** x- and relative function convergence *****)
+      go to 430
+!
+ 190  write(pu,200)
+ 200  format(/42h ***** absolute function convergence *****)
+      go to 430
+!
+ 210  write(pu,220)
+ 220  format(/33h ***** singular convergence *****)
+      go to 430
+!
+ 230  write(pu,240)
+ 240  format(/30h ***** false convergence *****)
+      go to 430
+!
+ 250  write(pu,260)
+ 260  format(/38h ***** function evaluation limit *****)
+      go to 430
+!
+ 270  write(pu,280)
+ 280  format(/28h ***** iteration limit *****)
+      go to 430
+!
+ 290  write(pu,300)
+ 300  format(/18h ***** stopx *****)
+      go to 430
+!
+ 310  write(pu,320)
+ 320  format(/44h ***** initial f(x) cannot be computed *****)
+!
+      go to 390
+!
+ 330  write(pu,340)
+ 340  format(/37h ***** bad parameters to assess *****)
+      go to 999
+!
+ 350  write(pu,360)
+ 360  format(/43h ***** gradient could not be computed *****)
+      if (iv(niter) .gt. 0) go to 480
+      go to 390
+!
+ 370  write(pu,380) iv(1)
+ 380  format(/14h ***** iv(1) =,i5,6h *****)
+      go to 999
+!
+!  ***  initial call on itsum  ***
+!
+ 390  if (iv(x0prt) .ne. 0) write(pu,400) (i, x(i), d(i), i = 1, p)
+ 400  format(/23h     i     initial x(i),8x,4hd(i)//(1x,i5,d17.6,d14.3))
+!     *** the following are to avoid undefined variables when the
+!     *** function evaluation limit is 1...
+      v(dstnrm) = zero
+      v(fdif) = zero
+      v(nreduc) = zero
+      v(preduc) = zero
+      v(reldx)  = zero
+      if (iv1 .ge. 12) go to 999
+      iv(needhd) = 0
+      iv(prntit) = 0
+      if (ol .eq. 0) go to 999
+      if (ol .lt. 0 .and. alg .eq. 1) write(pu,30)
+      if (ol .lt. 0 .and. alg .eq. 2) write(pu,40)
+      if (ol .gt. 0 .and. alg .eq. 1) write(pu,70)
+      if (ol .gt. 0 .and. alg .eq. 2) write(pu,80)
+      if (alg .eq. 1) write(pu,410) v(f)
+      if (alg .eq. 2) write(pu,420) v(f)
+ 410  format(/11h     0    1,d10.3)
+!365  format(/11h     0    1,e11.3)
+ 420  format(/11h     0    1,d11.3)
+      go to 999
+!
+!  ***  print various information requested on solution  ***
+!
+ 430  iv(needhd) = 1
+      if (iv(statpr) .eq. 0) go to 480
+         oldf = dmax1(dabs(v(f0)), dabs(v(f)))
+         preldf = zero
+         nreldf = zero
+         if (oldf .le. zero) go to 440
+              preldf = v(preduc) / oldf
+              nreldf = v(nreduc) / oldf
+ 440     nf = iv(nfcall) - iv(nfcov)
+         ng = iv(ngcall) - iv(ngcov)
+         write(pu,450) v(f), v(reldx), nf, ng, preldf, nreldf
+ 450  format(/9h function,d17.6,8h   reldx,d17.3/12h func. evals,&
+         i8,9x,11hgrad. evals,i8/7h preldf,d16.3,6x,7hnpreldf,d15.3)
+!
+         if (iv(nfcov) .gt. 0) write(pu,460) iv(nfcov)
+ 460     format(/1x,i4,50h extra func. evals for covariance and diagnostics.)
+         if (iv(ngcov) .gt. 0) write(pu,470) iv(ngcov)
+ 470     format(1x,i4,50h extra grad. evals for covariance and diagnostics.)
+!
+ 480  if (iv(solprt) .eq. 0) go to 999
+         iv(needhd) = 1
+         write(pu,490)
+ 490  format(/22h     i      final x(i),8x,4hd(i),10x,4hg(i)/)
+         do 500 i = 1, p
+              write(pu,510) i, x(i), d(i), g(i)
+ 500          continue
+ 510     format(1x,i5,d16.6,2d14.3)
+      go to 999
+!
+ 520  write(pu,530)
+ 530  format(/24h inconsistent dimensions)
+ 999  return
+!  ***  last card of itsum follows  ***
+      end subroutine itsum
+!-----------------------------------------------------------------------------
+      subroutine litvmu(n, x, l, y)
+!
+!  ***  solve  (l**t)*x = y,  where  l  is an  n x n  lower triangular
+!  ***  matrix stored compactly by rows.  x and y may occupy the same
+!  ***  storage.  ***
+!
+      integer :: n
+!al   real(kind=8) :: x(n), l(1), y(n)
+      real(kind=8) :: x(n), l(n*(n+1)/2), y(n)
+      integer :: i, ii, ij, im1, i0, j, np1
+      real(kind=8) :: xi       !el, zero
+!/6
+!     data zero/0.d+0/
+!/7
+      real(kind=8),parameter :: zero=0.d+0
+!/
+!
+      do 10 i = 1, n
+ 10      x(i) = y(i)
+      np1 = n + 1
+      i0 = n*(n+1)/2
+      do 30 ii = 1, n
+         i = np1 - ii
+         xi = x(i)/l(i0)
+         x(i) = xi
+         if (i .le. 1) go to 999
+         i0 = i0 - i
+         if (xi .eq. zero) go to 30
+         im1 = i - 1
+         do 20 j = 1, im1
+              ij = i0 + j
+              x(j) = x(j) - xi*l(ij)
+ 20           continue
+ 30      continue
+ 999  return
+!  ***  last card of litvmu follows  ***
+      end subroutine litvmu
+!-----------------------------------------------------------------------------
+      subroutine livmul(n, x, l, y)
+!
+!  ***  solve  l*x = y, where  l  is an  n x n  lower triangular
+!  ***  matrix stored compactly by rows.  x and y may occupy the same
+!  ***  storage.  ***
+!
+      integer :: n
+!al   real(kind=8) :: x(n), l(1), y(n)
+      real(kind=8) :: x(n), l(n*(n+1)/2), y(n)
+!el      external dotprd
+!el      real(kind=8) :: dotprd
+      integer :: i, j, k
+      real(kind=8) :: t        !el, zero
+!/6
+!     data zero/0.d+0/
+!/7
+      real(kind=8),parameter :: zero=0.d+0
+!/
+!
+      do 10 k = 1, n
+         if (y(k) .ne. zero) go to 20
+         x(k) = zero
+ 10      continue
+      go to 999
+ 20   j = k*(k+1)/2
+      x(k) = y(k) / l(j)
+      if (k .ge. n) go to 999
+      k = k + 1
+      do 30 i = k, n
+         t = dotprd(i-1, l(j+1), x)
+         j = j + i
+         x(i) = (y(i) - t)/l(j)
+ 30      continue
+ 999  return
+!  ***  last card of livmul follows  ***
+      end subroutine livmul
+!-----------------------------------------------------------------------------
+      subroutine parck(alg, d, iv, liv, lv, n, v)
+!
+!  ***  check ***sol (version 2.3) parameters, print changed values  ***
+!
+!  ***  alg = 1 for regression, alg = 2 for general unconstrained opt.
+!
+      integer :: alg, liv, lv, n
+      integer :: iv(liv)
+      real(kind=8) :: d(n), v(lv)
+!
+!el      external rmdcon, vcopy, vdflt
+!el      real(kind=8) :: rmdcon
+! rmdcon -- returns machine-dependent constants.
+! vcopy  -- copies one vector to another.
+! vdflt  -- supplies default parameter values to v alone.
+!/+
+!el      integer :: max0
+!/
+!
+!  ***  local variables  ***
+!
+      integer :: i, ii, iv1, j, k, l, m, miv1, miv2, ndfalt, parsv1, pu
+      integer :: ijmp, jlim(2), miniv(2), ndflt(2)
+!/6
+!     integer varnm(2), sh(2)
+!     real cngd(3), dflt(3), vn(2,34), which(3)
+!/7
+      character(len=1) :: varnm(2), sh(2)
+      character(len=4) :: cngd(3), dflt(3), vn(2,34), which(3)
+!/
+      real(kind=8) :: big, machep, tiny, vk, vm(34), vx(34), zero
+!
+!  ***  iv and v subscripts  ***
+!
+!el      integer algsav, dinit, dtype, dtype0, epslon, inits, ivneed,
+!el     1        lastiv, lastv, lmat, nextiv, nextv, nvdflt, oldn,
+!el     2        parprt, parsav, perm, prunit, vneed
+!
+!
+!/6
+!     data algsav/51/, dinit/38/, dtype/16/, dtype0/54/, epslon/19/,
+!    1     inits/25/, ivneed/3/, lastiv/44/, lastv/45/, lmat/42/,
+!    2     nextiv/46/, nextv/47/, nvdflt/50/, oldn/38/, parprt/20/,
+!    3     parsav/49/, perm/58/, prunit/21/, vneed/4/
+!/7
+      integer,parameter :: algsav=51, dinit=38, dtype=16, dtype0=54, epslon=19,&
+                 inits=25, ivneed=3, lastiv=44, lastv=45, lmat=42,&
+                 nextiv=46, nextv=47, nvdflt=50, oldn=38, parprt=20,&
+                 parsav=49, perm=58, prunit=21, vneed=4
+      save big, machep, tiny
+!/
+!
+      data big/0.d+0/, machep/-1.d+0/, tiny/1.d+0/, zero/0.d+0/
+!/6
+!     data vn(1,1),vn(2,1)/4hepsl,4hon../
+!     data vn(1,2),vn(2,2)/4hphmn,4hfc../
+!     data vn(1,3),vn(2,3)/4hphmx,4hfc../
+!     data vn(1,4),vn(2,4)/4hdecf,4hac../
+!     data vn(1,5),vn(2,5)/4hincf,4hac../
+!     data vn(1,6),vn(2,6)/4hrdfc,4hmn../
+!     data vn(1,7),vn(2,7)/4hrdfc,4hmx../
+!     data vn(1,8),vn(2,8)/4htune,4hr1../
+!     data vn(1,9),vn(2,9)/4htune,4hr2../
+!     data vn(1,10),vn(2,10)/4htune,4hr3../
+!     data vn(1,11),vn(2,11)/4htune,4hr4../
+!     data vn(1,12),vn(2,12)/4htune,4hr5../
+!     data vn(1,13),vn(2,13)/4hafct,4hol../
+!     data vn(1,14),vn(2,14)/4hrfct,4hol../
+!     data vn(1,15),vn(2,15)/4hxcto,4hl.../
+!     data vn(1,16),vn(2,16)/4hxfto,4hl.../
+!     data vn(1,17),vn(2,17)/4hlmax,4h0.../
+!     data vn(1,18),vn(2,18)/4hlmax,4hs.../
+!     data vn(1,19),vn(2,19)/4hscto,4hl.../
+!     data vn(1,20),vn(2,20)/4hdini,4ht.../
+!     data vn(1,21),vn(2,21)/4hdtin,4hit../
+!     data vn(1,22),vn(2,22)/4hd0in,4hit../
+!     data vn(1,23),vn(2,23)/4hdfac,4h..../
+!     data vn(1,24),vn(2,24)/4hdltf,4hdc../
+!     data vn(1,25),vn(2,25)/4hdltf,4hdj../
+!     data vn(1,26),vn(2,26)/4hdelt,4ha0../
+!     data vn(1,27),vn(2,27)/4hfuzz,4h..../
+!     data vn(1,28),vn(2,28)/4hrlim,4hit../
+!     data vn(1,29),vn(2,29)/4hcosm,4hin../
+!     data vn(1,30),vn(2,30)/4hhube,4hrc../
+!     data vn(1,31),vn(2,31)/4hrspt,4hol../
+!     data vn(1,32),vn(2,32)/4hsigm,4hin../
+!     data vn(1,33),vn(2,33)/4heta0,4h..../
+!     data vn(1,34),vn(2,34)/4hbias,4h..../
+!/7
+      data vn(1,1),vn(2,1)/'epsl','on..'/
+      data vn(1,2),vn(2,2)/'phmn','fc..'/
+      data vn(1,3),vn(2,3)/'phmx','fc..'/
+      data vn(1,4),vn(2,4)/'decf','ac..'/
+      data vn(1,5),vn(2,5)/'incf','ac..'/
+      data vn(1,6),vn(2,6)/'rdfc','mn..'/
+      data vn(1,7),vn(2,7)/'rdfc','mx..'/
+      data vn(1,8),vn(2,8)/'tune','r1..'/
+      data vn(1,9),vn(2,9)/'tune','r2..'/
+      data vn(1,10),vn(2,10)/'tune','r3..'/
+      data vn(1,11),vn(2,11)/'tune','r4..'/
+      data vn(1,12),vn(2,12)/'tune','r5..'/
+      data vn(1,13),vn(2,13)/'afct','ol..'/
+      data vn(1,14),vn(2,14)/'rfct','ol..'/
+      data vn(1,15),vn(2,15)/'xcto','l...'/
+      data vn(1,16),vn(2,16)/'xfto','l...'/
+      data vn(1,17),vn(2,17)/'lmax','0...'/
+      data vn(1,18),vn(2,18)/'lmax','s...'/
+      data vn(1,19),vn(2,19)/'scto','l...'/
+      data vn(1,20),vn(2,20)/'dini','t...'/
+      data vn(1,21),vn(2,21)/'dtin','it..'/
+      data vn(1,22),vn(2,22)/'d0in','it..'/
+      data vn(1,23),vn(2,23)/'dfac','....'/
+      data vn(1,24),vn(2,24)/'dltf','dc..'/
+      data vn(1,25),vn(2,25)/'dltf','dj..'/
+      data vn(1,26),vn(2,26)/'delt','a0..'/
+      data vn(1,27),vn(2,27)/'fuzz','....'/
+      data vn(1,28),vn(2,28)/'rlim','it..'/
+      data vn(1,29),vn(2,29)/'cosm','in..'/
+      data vn(1,30),vn(2,30)/'hube','rc..'/
+      data vn(1,31),vn(2,31)/'rspt','ol..'/
+      data vn(1,32),vn(2,32)/'sigm','in..'/
+      data vn(1,33),vn(2,33)/'eta0','....'/
+      data vn(1,34),vn(2,34)/'bias','....'/
+!/
+!
+      data vm(1)/1.0d-3/, vm(2)/-0.99d+0/, vm(3)/1.0d-3/, vm(4)/1.0d-2/,&
+           vm(5)/1.2d+0/, vm(6)/1.d-2/, vm(7)/1.2d+0/, vm(8)/0.d+0/,&
+           vm(9)/0.d+0/, vm(10)/1.d-3/, vm(11)/-1.d+0/, vm(13)/0.d+0/,&
+           vm(15)/0.d+0/, vm(16)/0.d+0/, vm(19)/0.d+0/, vm(20)/-10.d+0/,&
+           vm(21)/0.d+0/, vm(22)/0.d+0/, vm(23)/0.d+0/, vm(27)/1.01d+0/,&
+           vm(28)/1.d+10/, vm(30)/0.d+0/, vm(31)/0.d+0/, vm(32)/0.d+0/,&
+           vm(34)/0.d+0/
+      data vx(1)/0.9d+0/, vx(2)/-1.d-3/, vx(3)/1.d+1/, vx(4)/0.8d+0/,&
+           vx(5)/1.d+2/, vx(6)/0.8d+0/, vx(7)/1.d+2/, vx(8)/0.5d+0/,&
+           vx(9)/0.5d+0/, vx(10)/1.d+0/, vx(11)/1.d+0/, vx(14)/0.1d+0/,&
+           vx(15)/1.d+0/, vx(16)/1.d+0/, vx(19)/1.d+0/, vx(23)/1.d+0/,&
+           vx(24)/1.d+0/, vx(25)/1.d+0/, vx(26)/1.d+0/, vx(27)/1.d+10/,&
+           vx(29)/1.d+0/, vx(31)/1.d+0/, vx(32)/1.d+0/, vx(33)/1.d+0/,&
+           vx(34)/1.d+0/
+!
+!/6
+!     data varnm(1)/1hp/, varnm(2)/1hn/, sh(1)/1hs/, sh(2)/1hh/
+!     data cngd(1),cngd(2),cngd(3)/4h---c,4hhang,4hed v/,
+!    1     dflt(1),dflt(2),dflt(3)/4hnond,4hefau,4hlt v/
+!/7
+      data varnm(1)/'p'/, varnm(2)/'n'/, sh(1)/'s'/, sh(2)/'h'/
+      data cngd(1),cngd(2),cngd(3)/'---c','hang','ed v'/,&
+           dflt(1),dflt(2),dflt(3)/'nond','efau','lt v'/
+!/
+      data ijmp/33/, jlim(1)/0/, jlim(2)/24/, ndflt(1)/32/, ndflt(2)/25/
+      data miniv(1)/80/, miniv(2)/59/
+!
+!...............................  body  ................................
+!
+      pu = 0
+      if (prunit .le. liv) pu = iv(prunit)
+      if (alg .lt. 1 .or. alg .gt. 2) go to 340
+      if (iv(1) .eq. 0) call deflt(alg, iv, liv, lv, v)
+      iv1 = iv(1)
+      if (iv1 .ne. 13 .and. iv1 .ne. 12) go to 10
+      miv1 = miniv(alg)
+      if (perm .le. liv) miv1 = max0(miv1, iv(perm) - 1)
+      if (ivneed .le. liv) miv2 = miv1 + max0(iv(ivneed), 0)
+      if (lastiv .le. liv) iv(lastiv) = miv2
+      if (liv .lt. miv1) go to 300
+      iv(ivneed) = 0
+      iv(lastv) = max0(iv(vneed), 0) + iv(lmat) - 1
+      iv(vneed) = 0
+      if (liv .lt. miv2) go to 300
+      if (lv .lt. iv(lastv)) go to 320
+ 10   if (alg .eq. iv(algsav)) go to 30
+         if (pu .ne. 0) write(pu,20) alg, iv(algsav)
+ 20      format(/39h the first parameter to deflt should be,i3,&
+                12h rather than,i3)
+         iv(1) = 82
+         go to 999
+ 30   if (iv1 .lt. 12 .or. iv1 .gt. 14) go to 60
+         if (n .ge. 1) go to 50
+              iv(1) = 81
+              if (pu .eq. 0) go to 999
+              write(pu,40) varnm(alg), n
+ 40           format(/8h /// bad,a1,2h =,i5)
+              go to 999
+ 50      if (iv1 .ne. 14) iv(nextiv) = iv(perm)
+         if (iv1 .ne. 14) iv(nextv) = iv(lmat)
+         if (iv1 .eq. 13) go to 999
+         k = iv(parsav) - epslon
+         call vdflt(alg, lv-k, v(k+1))
+         iv(dtype0) = 2 - alg
+         iv(oldn) = n
+         which(1) = dflt(1)
+         which(2) = dflt(2)
+         which(3) = dflt(3)
+         go to 110
+ 60   if (n .eq. iv(oldn)) go to 80
+         iv(1) = 17
+         if (pu .eq. 0) go to 999
+         write(pu,70) varnm(alg), iv(oldn), n
+ 70      format(/5h /// ,1a1,14h changed from ,i5,4h to ,i5)
+         go to 999
+!
+ 80   if (iv1 .le. 11 .and. iv1 .ge. 1) go to 100
+         iv(1) = 80
+         if (pu .ne. 0) write(pu,90) iv1
+ 90      format(/13h ///  iv(1) =,i5,28h should be between 0 and 14.)
+         go to 999
+!
+ 100  which(1) = cngd(1)
+      which(2) = cngd(2)
+      which(3) = cngd(3)
+!
+ 110  if (iv1 .eq. 14) iv1 = 12
+      if (big .gt. tiny) go to 120
+         tiny = rmdcon(1)
+         machep = rmdcon(3)
+         big = rmdcon(6)
+         vm(12) = machep
+         vx(12) = big
+         vx(13) = big
+         vm(14) = machep
+         vm(17) = tiny
+         vx(17) = big
+         vm(18) = tiny
+         vx(18) = big
+         vx(20) = big
+         vx(21) = big
+         vx(22) = big
+         vm(24) = machep
+         vm(25) = machep
+         vm(26) = machep
+         vx(28) = rmdcon(5)
+         vm(29) = machep
+         vx(30) = big
+         vm(33) = machep
+ 120  m = 0
+      i = 1
+      j = jlim(alg)
+      k = epslon
+      ndfalt = ndflt(alg)
+      do 150 l = 1, ndfalt
+         vk = v(k)
+         if (vk .ge. vm(i) .and. vk .le. vx(i)) go to 140
+              m = k
+              if (pu .ne. 0) write(pu,130) vn(1,i), vn(2,i), k, vk,&
+                                          vm(i), vx(i)
+ 130          format(/6h ///  ,2a4,5h.. v(,i2,3h) =,d11.3,7h should,&
+                     11h be between,d11.3,4h and,d11.3)
+ 140     k = k + 1
+         i = i + 1
+         if (i .eq. j) i = ijmp
+ 150     continue
+!
+      if (iv(nvdflt) .eq. ndfalt) go to 170
+         iv(1) = 51
+         if (pu .eq. 0) go to 999
+         write(pu,160) iv(nvdflt), ndfalt
+ 160     format(/13h iv(nvdflt) =,i5,13h rather than ,i5)
+         go to 999
+ 170  if ((iv(dtype) .gt. 0 .or. v(dinit) .gt. zero) .and. iv1 .eq. 12) &
+                        go to 200
+      do 190 i = 1, n
+         if (d(i) .gt. zero) go to 190
+              m = 18
+              if (pu .ne. 0) write(pu,180) i, d(i)
+ 180     format(/8h ///  d(,i3,3h) =,d11.3,19h should be positive)
+ 190     continue
+ 200  if (m .eq. 0) go to 210
+         iv(1) = m
+         go to 999
+!
+ 210  if (pu .eq. 0 .or. iv(parprt) .eq. 0) go to 999
+      if (iv1 .ne. 12 .or. iv(inits) .eq. alg-1) go to 230
+         m = 1
+         write(pu,220) sh(alg), iv(inits)
+ 220     format(/22h nondefault values..../5h init,a1,14h..... iv(25) =,&
+                i3)
+ 230  if (iv(dtype) .eq. iv(dtype0)) go to 250
+         if (m .eq. 0) write(pu,260) which
+         m = 1
+         write(pu,240) iv(dtype)
+ 240     format(20h dtype..... iv(16) =,i3)
+ 250  i = 1
+      j = jlim(alg)
+      k = epslon
+      l = iv(parsav)
+      ndfalt = ndflt(alg)
+      do 290 ii = 1, ndfalt
+         if (v(k) .eq. v(l)) go to 280
+              if (m .eq. 0) write(pu,260) which
+ 260          format(/1h ,3a4,9halues..../)
+              m = 1
+              write(pu,270) vn(1,i), vn(2,i), k, v(k)
+ 270          format(1x,2a4,5h.. v(,i2,3h) =,d15.7)
+ 280     k = k + 1
+         l = l + 1
+         i = i + 1
+         if (i .eq. j) i = ijmp
+ 290     continue
+!
+      iv(dtype0) = iv(dtype)
+      parsv1 = iv(parsav)
+      call vcopy(iv(nvdflt), v(parsv1), v(epslon))
+      go to 999
+!
+ 300  iv(1) = 15
+      if (pu .eq. 0) go to 999
+      write(pu,310) liv, miv2
+ 310  format(/10h /// liv =,i5,17h must be at least,i5)
+      if (liv .lt. miv1) go to 999
+      if (lv .lt. iv(lastv)) go to 320
+      go to 999
+!
+ 320  iv(1) = 16
+      if (pu .eq. 0) go to 999
+      write(pu,330) lv, iv(lastv)
+ 330  format(/9h /// lv =,i5,17h must be at least,i5)
+      go to 999
+!
+ 340  iv(1) = 67
+      if (pu .eq. 0) go to 999
+      write(pu,350) alg
+ 350  format(/10h /// alg =,i5,15h must be 1 or 2)
+!
+ 999  return
+!  ***  last card of parck follows  ***
+      end subroutine parck
+!-----------------------------------------------------------------------------
+      real(kind=8) function reldst(p, d, x, x0)
+!
+!  ***  compute and return relative difference between x and x0  ***
+!  ***  nl2sol version 2.2  ***
+!
+      integer :: p
+      real(kind=8) :: d(p), x(p), x0(p)
+!/+
+!el      real(kind=8) :: dabs
+!/
+      integer :: i
+      real(kind=8) :: emax, t, xmax    !el, zero
+!/6
+!     data zero/0.d+0/
+!/7
+      real(kind=8),parameter :: zero=0.d+0
+!/
+!
+      emax = zero
+      xmax = zero
+      do 10 i = 1, p
+         t = dabs(d(i) * (x(i) - x0(i)))
+         if (emax .lt. t) emax = t
+         t = d(i) * (dabs(x(i)) + dabs(x0(i)))
+         if (xmax .lt. t) xmax = t
+ 10      continue
+      reldst = zero
+      if (xmax .gt. zero) reldst = emax / xmax
+ 999  return
+!  ***  last card of reldst follows  ***
+      end function reldst
+!-----------------------------------------------------------------------------
+      subroutine vaxpy(p, w, a, x, y)
+!
+!  ***  set w = a*x + y  --  w, x, y = p-vectors, a = scalar  ***
+!
+      integer :: p
+      real(kind=8) :: a, w(p), x(p), y(p)
+!
+      integer :: i
+!
+      do 10 i = 1, p
+ 10      w(i) = a*x(i) + y(i)
+      return
+      end subroutine vaxpy
+!-----------------------------------------------------------------------------
+      subroutine vcopy(p, y, x)
+!
+!  ***  set y = x, where x and y are p-vectors  ***
+!
+      integer :: p
+      real(kind=8) :: x(p), y(p)
+!
+      integer :: i
+!
+      do 10 i = 1, p
+ 10      y(i) = x(i)
+      return
+      end subroutine vcopy
+!-----------------------------------------------------------------------------
+      subroutine vdflt(alg, lv, v)
+!
+!  ***  supply ***sol (version 2.3) default values to v  ***
+!
+!  ***  alg = 1 means regression constants.
+!  ***  alg = 2 means general unconstrained optimization constants.
+!
+      integer :: alg, l,lv
+      real(kind=8) :: v(lv)
+!/+
+!el      real(kind=8) :: dmax1
+!/
+!el      external rmdcon
+!el      real(kind=8) :: rmdcon
+! rmdcon... returns machine-dependent constants
+!
+      real(kind=8) :: machep, mepcrt, sqteps   !el one, three
+!
+!  ***  subscripts for v  ***
+!
+!el      integer afctol, bias, cosmin, decfac, delta0, dfac, dinit, dltfdc,
+!el     1        dltfdj, dtinit, d0init, epslon, eta0, fuzz, huberc,
+!el     2        incfac, lmax0, lmaxs, phmnfc, phmxfc, rdfcmn, rdfcmx,
+!el     3        rfctol, rlimit, rsptol, sctol, sigmin, tuner1, tuner2,
+!el     4        tuner3, tuner4, tuner5, xctol, xftol
+!
+!/6
+!     data one/1.d+0/, three/3.d+0/
+!/7
+      real(kind=8),parameter :: one=1.d+0, three=3.d+0
+!/
+!
+!  ***  v subscript values  ***
+!
+!/6
+!     data afctol/31/, bias/43/, cosmin/47/, decfac/22/, delta0/44/,
+!    1     dfac/41/, dinit/38/, dltfdc/42/, dltfdj/43/, dtinit/39/,
+!    2     d0init/40/, epslon/19/, eta0/42/, fuzz/45/, huberc/48/,
+!    3     incfac/23/, lmax0/35/, lmaxs/36/, phmnfc/20/, phmxfc/21/,
+!    4     rdfcmn/24/, rdfcmx/25/, rfctol/32/, rlimit/46/, rsptol/49/,
+!    5     sctol/37/, sigmin/50/, tuner1/26/, tuner2/27/, tuner3/28/,
+!    6     tuner4/29/, tuner5/30/, xctol/33/, xftol/34/
+!/7
+      integer,parameter :: afctol=31, bias=43, cosmin=47, decfac=22, delta0=44,&
+                 dfac=41, dinit=38, dltfdc=42, dltfdj=43, dtinit=39,&
+                 d0init=40, epslon=19, eta0=42, fuzz=45, huberc=48,&
+                 incfac=23, lmax0=35, lmaxs=36, phmnfc=20, phmxfc=21,&
+                 rdfcmn=24, rdfcmx=25, rfctol=32, rlimit=46, rsptol=49,&
+                 sctol=37, sigmin=50, tuner1=26, tuner2=27, tuner3=28,&
+                 tuner4=29, tuner5=30, xctol=33, xftol=34
+!/
+!
+!-------------------------------  body  --------------------------------
+!
+      machep = rmdcon(3)
+      v(afctol) = 1.d-20
+      if (machep .gt. 1.d-10) v(afctol) = machep**2
+      v(decfac) = 0.5d+0
+      sqteps = rmdcon(4)
+      v(dfac) = 0.6d+0
+      v(delta0) = sqteps
+      v(dtinit) = 1.d-6
+      mepcrt = machep ** (one/three)
+      v(d0init) = 1.d+0
+      v(epslon) = 0.1d+0
+      v(incfac) = 2.d+0
+      v(lmax0) = 1.d+0
+      v(lmaxs) = 1.d+0
+      v(phmnfc) = -0.1d+0
+      v(phmxfc) = 0.1d+0
+      v(rdfcmn) = 0.1d+0
+      v(rdfcmx) = 4.d+0
+      v(rfctol) = dmax1(1.d-10, mepcrt**2)
+      v(sctol) = v(rfctol)
+      v(tuner1) = 0.1d+0
+      v(tuner2) = 1.d-4
+      v(tuner3) = 0.75d+0
+      v(tuner4) = 0.5d+0
+      v(tuner5) = 0.75d+0
+      v(xctol) = sqteps
+      v(xftol) = 1.d+2 * machep
+!
+      if (alg .ge. 2) go to 10
+!
+!  ***  regression  values
+!
+      v(cosmin) = dmax1(1.d-6, 1.d+2 * machep)
+      v(dinit) = 0.d+0
+      v(dltfdc) = mepcrt
+      v(dltfdj) = sqteps
+      v(fuzz) = 1.5d+0
+      v(huberc) = 0.7d+0
+      v(rlimit) = rmdcon(5)
+      v(rsptol) = 1.d-3
+      v(sigmin) = 1.d-4
+      go to 999
+!
+!  ***  general optimization values
+!
+ 10   v(bias) = 0.8d+0
+      v(dinit) = -1.0d+0
+      v(eta0) = 1.0d+3 * machep
+!
+ 999  return
+!  ***  last card of vdflt follows  ***
+      end subroutine vdflt
+!-----------------------------------------------------------------------------
+      subroutine vscopy(p, y, s)
+!
+!  ***  set p-vector y to scalar s  ***
+!
+      integer :: p
+      real(kind=8) :: s, y(p)
+!
+      integer :: i
+!
+      do 10 i = 1, p
+ 10      y(i) = s
+      return
+      end subroutine vscopy
+!-----------------------------------------------------------------------------
+      real(kind=8) function v2norm(p, x)
+!
+!  ***  return the 2-norm of the p-vector x, taking  ***
+!  ***  care to avoid the most likely underflows.    ***
+!
+      integer :: p
+      real(kind=8) :: x(p)
+!
+      integer :: i, j
+      real(kind=8) :: r, scale, sqteta, t, xi  !el, one, zero
+!/+
+!el      real(kind=8) :: dabs, dsqrt
+!/
+!el      external rmdcon
+!el      real(kind=8) :: rmdcon
+!
+!/6
+!     data one/1.d+0/, zero/0.d+0/
+!/7
+      real(kind=8),parameter :: one=1.d+0, zero=0.d+0
+      save sqteta
+!/
+      data sqteta/0.d+0/
+!
+      if (p .gt. 0) go to 10
+         v2norm = zero
+         go to 999
+ 10   do 20 i = 1, p
+         if (x(i) .ne. zero) go to 30
+ 20      continue
+      v2norm = zero
+      go to 999
+!
+ 30   scale = dabs(x(i))
+      if (i .lt. p) go to 40
+         v2norm = scale
+         go to 999
+ 40   t = one
+      if (sqteta .eq. zero) sqteta = rmdcon(2)
+!
+!     ***  sqteta is (slightly larger than) the square root of the
+!     ***  smallest positive floating point number on the machine.
+!     ***  the tests involving sqteta are done to prevent underflows.
+!
+      j = i + 1
+      do 60 i = j, p
+         xi = dabs(x(i))
+         if (xi .gt. scale) go to 50
+              r = xi / scale
+              if (r .gt. sqteta) t = t + r*r
+              go to 60
+ 50           r = scale / xi
+              if (r .le. sqteta) r = zero
+              t = one  +  t * r*r
+              scale = xi
+ 60      continue
+!
+      v2norm = scale * dsqrt(t)
+ 999  return
+!  ***  last card of v2norm follows  ***
+      end function v2norm
+!-----------------------------------------------------------------------------
+      subroutine humsl(n,d,x,calcf,calcgh,iv,liv,lv,v,uiparm,urparm,ufparm)
+!
+!  ***  minimize general unconstrained objective function using   ***
+!  ***  (analytic) gradient and hessian provided by the caller.   ***
+!
+      integer :: liv, lv, n
+      integer :: iv(liv), uiparm(1)
+      real(kind=8) :: d(n), x(n), v(lv), urparm(1)
+      real(kind=8),external :: ufparm
+!     dimension v(78 + n*(n+12)), uiparm(*), urparm(*)
+      external :: calcf, calcgh
+!
+!------------------------------  discussion  ---------------------------
+!
+!        this routine is like sumsl, except that the subroutine para-
+!     meter calcg of sumsl (which computes the gradient of the objec-
+!     tive function) is replaced by the subroutine parameter calcgh,
+!     which computes both the gradient and (lower triangle of the)
+!     hessian of the objective function.  the calling sequence is...
+!             call calcgh(n, x, nf, g, h, uiparm, urparm, ufparm)
+!     parameters n, x, nf, g, uiparm, urparm, and ufparm are the same
+!     as for sumsl, while h is an array of length n*(n+1)/2 in which
+!     calcgh must store the lower triangle of the hessian at x.  start-
+!     ing at h(1), calcgh must store the hessian entries in the order
+!     (1,1), (2,1), (2,2), (3,1), (3,2), (3,3), ...
+!        the value printed (by itsum) in the column labelled stppar
+!     is the levenberg-marquardt used in computing the current step.
+!     zero means a full newton step.  if the special case described in
+!     ref. 1 is detected, then stppar is negated.  the value printed
+!     in the column labelled npreldf is zero if the current hessian
+!     is not positive definite.
+!        it sometimes proves worthwhile to let d be determined from the
+!     diagonal of the hessian matrix by setting iv(dtype) = 1 and
+!     v(dinit) = 0.  the following iv and v components are relevant...
+!
+! iv(dtol)..... iv(59) gives the starting subscript in v of the dtol
+!             array used when d is updated.  (iv(dtol) can be
+!             initialized by calling humsl with iv(1) = 13.)
+! iv(dtype).... iv(16) tells how the scale vector d should be chosen.
+!             iv(dtype) .le. 0 means that d should not be updated, and
+!             iv(dtype) .ge. 1 means that d should be updated as
+!             described below with v(dfac).  default = 0.
+! v(dfac)..... v(41) and the dtol and d0 arrays (see v(dtinit) and
+!             v(d0init)) are used in updating the scale vector d when
+!             iv(dtype) .gt. 0.  (d is initialized according to
+!             v(dinit), described in sumsl.)  let
+!                  d1(i) = max(sqrt(abs(h(i,i))), v(dfac)*d(i)),
+!             where h(i,i) is the i-th diagonal element of the current
+!             hessian.  if iv(dtype) = 1, then d(i) is set to d1(i)
+!             unless d1(i) .lt. dtol(i), in which case d(i) is set to
+!                  max(d0(i), dtol(i)).
+!             if iv(dtype) .ge. 2, then d is updated during the first
+!             iteration as for iv(dtype) = 1 (after any initialization
+!             due to v(dinit)) and is left unchanged thereafter.
+!             default = 0.6.
+! v(dtinit)... v(39), if positive, is the value to which all components
+!             of the dtol array (see v(dfac)) are initialized.  if
+!             v(dtinit) = 0, then it is assumed that the caller has
+!             stored dtol in v starting at v(iv(dtol)).
+!             default = 10**-6.
+! v(d0init)... v(40), if positive, is the value to which all components
+!             of the d0 vector (see v(dfac)) are initialized.  if
+!             v(dfac) = 0, then it is assumed that the caller has
+!             stored d0 in v starting at v(iv(dtol)+n).  default = 1.0.
+!
+!  ***  reference  ***
+!
+! 1. gay, d.m. (1981), computing optimal locally constrained steps,
+!         siam j. sci. statist. comput. 2, pp. 186-197.
+!.
+!  ***  general  ***
+!
+!     coded by david m. gay (winter 1980).  revised sept. 1982.
+!     this subroutine was written in connection with research supported
+!     in part by the national science foundation under grants
+!     mcs-7600324 and mcs-7906671.
+!
+!----------------------------  declarations  ---------------------------
+!
+!el      external deflt, humit
+!
+! deflt... provides default input values for iv and v.
+! humit... reverse-communication routine that does humsl algorithm.
+!
+      integer :: g1, h1, iv1, lh, nf
+      real(kind=8) :: f
+!
+!  ***  subscripts for iv   ***
+!
+!el      integer g, h, nextv, nfcall, nfgcal, toobig, vneed
+!
+!/6
+!     data nextv/47/, nfcall/6/, nfgcal/7/, g/28/, h/56/, toobig/2/,
+!    1     vneed/4/
+!/7
+      integer,parameter :: nextv=47, nfcall=6, nfgcal=7, g=28, h=56,&
+                           toobig=2,vneed=4
+!/
+!
+!+++++++++++++++++++++++++++++++  body  ++++++++++++++++++++++++++++++++
+!
+      lh = n * (n + 1) / 2
+      if (iv(1) .eq. 0) call deflt(2, iv, liv, lv, v)
+      if (iv(1) .eq. 12 .or. iv(1) .eq. 13) &
+           iv(vneed) = iv(vneed) + n*(n+3)/2
+      iv1 = iv(1)
+      if (iv1 .eq. 14) go to 10
+      if (iv1 .gt. 2 .and. iv1 .lt. 12) go to 10
+      g1 = 1
+      h1 = 1
+      if (iv1 .eq. 12) iv(1) = 13
+      go to 20
+!
+ 10   g1 = iv(g)
+      h1 = iv(h)
+!
+ 20   call humit(d, f, v(g1), v(h1), iv, lh, liv, lv, n, v, x)
+      if (iv(1) - 2) 30, 40, 50
+!
+ 30   nf = iv(nfcall)
+      call calcf(n, x, nf, f, uiparm, urparm, ufparm)
+      if (nf .le. 0) iv(toobig) = 1
+      go to 20
+!
+ 40   call calcgh(n, x, iv(nfgcal), v(g1), v(h1), uiparm, urparm,&
+                  ufparm)
+      go to 20
+!
+ 50   if (iv(1) .ne. 14) go to 999
+!
+!  ***  storage allocation
+!
+      iv(g) = iv(nextv)
+      iv(h) = iv(g) + n
+      iv(nextv) = iv(h) + n*(n+1)/2
+      if (iv1 .ne. 13) go to 10
+!
+ 999  return
+!  ***  last card of humsl follows  ***
+      end subroutine humsl
+!-----------------------------------------------------------------------------
+      subroutine humit(d, fx, g, h, iv, lh, liv, lv, n, v, x)
+!
+!  ***  carry out humsl (unconstrained minimization) iterations, using
+!  ***  hessian matrix provided by the caller.
+!
+!el      use control
+      use control, only:stopx
+
+!  ***  parameter declarations  ***
+!
+      integer :: lh, liv, lv, n
+      integer :: iv(liv)
+      real(kind=8) :: d(n), fx, g(n), h(lh), v(lv), x(n)
+!
+!--------------------------  parameter usage  --------------------------
+!
+! d.... scale vector.
+! fx... function value.
+! g.... gradient vector.
+! h.... lower triangle of the hessian, stored rowwise.
+! iv... integer value array.
+! lh... length of h = p*(p+1)/2.
+! liv.. length of iv (at least 60).
+! lv... length of v (at least 78 + n*(n+21)/2).
+! n.... number of variables (components in x and g).
+! v.... floating-point value array.
+! x.... parameter vector.
+!
+!  ***  discussion  ***
+!
+!        parameters iv, n, v, and x are the same as the corresponding
+!     ones to humsl (which see), except that v can be shorter (since
+!     the part of v that humsl uses for storing g and h is not needed).
+!     moreover, compared with humsl, iv(1) may have the two additional
+!     output values 1 and 2, which are explained below, as is the use
+!     of iv(toobig) and iv(nfgcal).  the value iv(g), which is an
+!     output value from humsl, is not referenced by humit or the
+!     subroutines it calls.
+!
+! iv(1) = 1 means the caller should set fx to f(x), the function value
+!             at x, and call humit again, having changed none of the
+!             other parameters.  an exception occurs if f(x) cannot be
+!             computed (e.g. if overflow would occur), which may happen
+!             because of an oversized step.  in this case the caller
+!             should set iv(toobig) = iv(2) to 1, which will cause
+!             humit to ignore fx and try a smaller step.  the para-
+!             meter nf that humsl passes to calcf (for possible use by
+!             calcgh) is a copy of iv(nfcall) = iv(6).
+! iv(1) = 2 means the caller should set g to g(x), the gradient of f at
+!             x, and h to the lower triangle of h(x), the hessian of f
+!             at x, and call humit again, having changed none of the
+!             other parameters except perhaps the scale vector d.
+!                  the parameter nf that humsl passes to calcg is
+!             iv(nfgcal) = iv(7).  if g(x) and h(x) cannot be evaluated,
+!             then the caller may set iv(nfgcal) to 0, in which case
+!             humit will return with iv(1) = 65.
+!                  note -- humit overwrites h with the lower triangle
+!             of  diag(d)**-1 * h(x) * diag(d)**-1.
+!.
+!  ***  general  ***
+!
+!     coded by david m. gay (winter 1980).  revised sept. 1982.
+!     this subroutine was written in connection with research supported
+!     in part by the national science foundation under grants
+!     mcs-7600324 and mcs-7906671.
+!
+!        (see sumsl and humsl for references.)
+!
+!+++++++++++++++++++++++++++  declarations  ++++++++++++++++++++++++++++
+!
+!  ***  local variables  ***
+!
+      integer :: dg1, dummy, i, j, k, l, lstgst, nn1o2, step1,&
+              temp1, w1, x01
+      real(kind=8) :: t
+!
+!     ***  constants  ***
+!
+!el      real(kind=8) :: one, onep2, zero
+!
+!  ***  no intrinsic functions  ***
+!
+!  ***  external functions and subroutines  ***
+!
+!el      external assst, deflt, dotprd, dupdu, gqtst, itsum, parck,
+!el     1         reldst, slvmul, stopx, vaxpy, vcopy, vscopy, v2norm
+!el      logical stopx
+!el      real(kind=8) :: dotprd, reldst, v2norm
+!
+! assst.... assesses candidate step.
+! deflt.... provides default iv and v input values.
+! dotprd... returns inner product of two vectors.
+! dupdu.... updates scale vector d.
+! gqtst.... computes optimally locally constrained step.
+! itsum.... prints iteration summary and info on initial and final x.
+! parck.... checks validity of input iv and v values.
+! reldst... computes v(reldx) = relative step size.
+! slvmul... multiplies symmetric matrix times vector, given the lower
+!             triangle of the matrix.
+! stopx.... returns .true. if the break key has been pressed.
+! vaxpy.... computes scalar times one vector plus another.
+! vcopy.... copies one vector to another.
+! vscopy... sets all elements of a vector to a scalar.
+! v2norm... returns the 2-norm of a vector.
+!
+!  ***  subscripts for iv and v  ***
+!
+!el      integer cnvcod, dg, dgnorm, dinit, dstnrm, dtinit, dtol,
+!el     1        dtype, d0init, f, f0, fdif, gtstep, incfac, irc, kagqt,
+!el     2        lmat, lmax0, lmaxs, mode, model, mxfcal, mxiter, nextv,
+!el     3        nfcall, nfgcal, ngcall, niter, preduc, radfac, radinc,
+!el     4        radius, rad0, reldx, restor, step, stglim, stlstg, stppar,
+!el     5        toobig, tuner4, tuner5, vneed, w, xirc, x0
+!
+!  ***  iv subscript values  ***
+!
+!/6
+!     data cnvcod/55/, dg/37/, dtol/59/, dtype/16/, irc/29/, kagqt/33/,
+!    1     lmat/42/, mode/35/, model/5/, mxfcal/17/, mxiter/18/,
+!    2     nextv/47/, nfcall/6/, nfgcal/7/, ngcall/30/, niter/31/,
+!    3     radinc/8/, restor/9/, step/40/, stglim/11/, stlstg/41/,
+!    4     toobig/2/, vneed/4/, w/34/, xirc/13/, x0/43/
+!/7
+      integer,parameter :: cnvcod=55, dg=37, dtol=59, dtype=16, irc=29, kagqt=33,&
+                 lmat=42, mode=35, model=5, mxfcal=17, mxiter=18,&
+                 nextv=47, nfcall=6, nfgcal=7, ngcall=30, niter=31,&
+                 radinc=8, restor=9, step=40, stglim=11, stlstg=41,&
+                 toobig=2, vneed=4, w=34, xirc=13, x0=43
+!/
+!
+!  ***  v subscript values  ***
+!
+!/6
+!     data dgnorm/1/, dinit/38/, dstnrm/2/, dtinit/39/, d0init/40/,
+!    1     f/10/, f0/13/, fdif/11/, gtstep/4/, incfac/23/, lmax0/35/,
+!    2     lmaxs/36/, preduc/7/, radfac/16/, radius/8/, rad0/9/,
+!    3     reldx/17/, stppar/5/, tuner4/29/, tuner5/30/
+!/7
+      integer,parameter :: dgnorm=1, dinit=38, dstnrm=2, dtinit=39, d0init=40,&
+                 f=10, f0=13, fdif=11, gtstep=4, incfac=23, lmax0=35,&
+                 lmaxs=36, preduc=7, radfac=16, radius=8, rad0=9,&
+                 reldx=17, stppar=5, tuner4=29, tuner5=30
+!/
+!
+!/6
+!     data one/1.d+0/, onep2/1.2d+0/, zero/0.d+0/
+!/7
+      real(kind=8),parameter :: one=1.d+0, onep2=1.2d+0, zero=0.d+0
+!/
+!
+!+++++++++++++++++++++++++++++++  body  ++++++++++++++++++++++++++++++++
+!
+      i = iv(1)
+      if (i .eq. 1) go to 30
+      if (i .eq. 2) go to 40
+!
+!  ***  check validity of iv and v input values  ***
+!
+      if (iv(1) .eq. 0) call deflt(2, iv, liv, lv, v)
+      if (iv(1) .eq. 12 .or. iv(1) .eq. 13) &
+           iv(vneed) = iv(vneed) + n*(n+21)/2 + 7
+      call parck(2, d, iv, liv, lv, n, v)
+      i = iv(1) - 2
+      if (i .gt. 12) go to 999
+      nn1o2 = n * (n + 1) / 2
+      if (lh .ge. nn1o2) go to (210,210,210,210,210,210,160,120,160,&
+                                10,10,20), i
+         iv(1) = 66
+         go to 350
+!
+!  ***  storage allocation  ***
+!
+ 10   iv(dtol) = iv(lmat) + nn1o2
+      iv(x0) = iv(dtol) + 2*n
+      iv(step) = iv(x0) + n
+      iv(stlstg) = iv(step) + n
+      iv(dg) = iv(stlstg) + n
+      iv(w) = iv(dg) + n
+      iv(nextv) = iv(w) + 4*n + 7
+      if (iv(1) .ne. 13) go to 20
+         iv(1) = 14
+         go to 999
+!
+!  ***  initialization  ***
+!
+ 20   iv(niter) = 0
+      iv(nfcall) = 1
+      iv(ngcall) = 1
+      iv(nfgcal) = 1
+      iv(mode) = -1
+      iv(model) = 1
+      iv(stglim) = 1
+      iv(toobig) = 0
+      iv(cnvcod) = 0
+      iv(radinc) = 0
+      v(rad0) = zero
+      v(stppar) = zero
+      if (v(dinit) .ge. zero) call vscopy(n, d, v(dinit))
+      k = iv(dtol)
+      if (v(dtinit) .gt. zero) call vscopy(n, v(k), v(dtinit))
+      k = k + n
+      if (v(d0init) .gt. zero) call vscopy(n, v(k), v(d0init))
+      iv(1) = 1
+      go to 999
+!
+ 30   v(f) = fx
+      if (iv(mode) .ge. 0) go to 210
+      iv(1) = 2
+      if (iv(toobig) .eq. 0) go to 999
+         iv(1) = 63
+         go to 350
+!
+!  ***  make sure gradient could be computed  ***
+!
+ 40   if (iv(nfgcal) .ne. 0) go to 50
+         iv(1) = 65
+         go to 350
+!
+!  ***  update the scale vector d  ***
+!
+ 50   dg1 = iv(dg)
+      if (iv(dtype) .le. 0) go to 70
+      k = dg1
+      j = 0
+      do 60 i = 1, n
+         j = j + i
+         v(k) = h(j)
+         k = k + 1
+ 60      continue
+      call dupdu(d, v(dg1), iv, liv, lv, n, v)
+!
+!  ***  compute scaled gradient and its norm  ***
+!
+ 70   dg1 = iv(dg)
+      k = dg1
+      do 80 i = 1, n
+         v(k) = g(i) / d(i)
+         k = k + 1
+ 80      continue
+      v(dgnorm) = v2norm(n, v(dg1))
+!
+!  ***  compute scaled hessian  ***
+!
+      k = 1
+      do 100 i = 1, n
+         t = one / d(i)
+         do 90 j = 1, i
+              h(k) = t * h(k) / d(j)
+              k = k + 1
+ 90           continue
+ 100     continue
+!
+      if (iv(cnvcod) .ne. 0) go to 340
+      if (iv(mode) .eq. 0) go to 300
+!
+!  ***  allow first step to have scaled 2-norm at most v(lmax0)  ***
+!
+      v(radius) = v(lmax0)
+!
+      iv(mode) = 0
+!
+!
+!-----------------------------  main loop  -----------------------------
+!
+!
+!  ***  print iteration summary, check iteration limit  ***
+!
+ 110  call itsum(d, g, iv, liv, lv, n, v, x)
+ 120  k = iv(niter)
+      if (k .lt. iv(mxiter)) go to 130
+         iv(1) = 10
+         go to 350
+!
+ 130  iv(niter) = k + 1
+!
+!  ***  initialize for start of next iteration  ***
+!
+      dg1 = iv(dg)
+      x01 = iv(x0)
+      v(f0) = v(f)
+      iv(irc) = 4
+      iv(kagqt) = -1
+!
+!     ***  copy x to x0  ***
+!
+      call vcopy(n, v(x01), x)
+!
+!  ***  update radius  ***
+!
+      if (k .eq. 0) go to 150
+      step1 = iv(step)
+      k = step1
+      do 140 i = 1, n
+         v(k) = d(i) * v(k)
+         k = k + 1
+ 140     continue
+      v(radius) = v(radfac) * v2norm(n, v(step1))
+!
+!  ***  check stopx and function evaluation limit  ***
+!
+! AL 4/30/95
+      dummy=iv(nfcall)
+ 150  if (.not. stopx(dummy)) go to 170
+         iv(1) = 11
+         go to 180
+!
+!     ***  come here when restarting after func. eval. limit or stopx.
+!
+ 160  if (v(f) .ge. v(f0)) go to 170
+         v(radfac) = one
+         k = iv(niter)
+         go to 130
+!
+ 170  if (iv(nfcall) .lt. iv(mxfcal)) go to 190
+         iv(1) = 9
+ 180     if (v(f) .ge. v(f0)) go to 350
+!
+!        ***  in case of stopx or function evaluation limit with
+!        ***  improved v(f), evaluate the gradient at x.
+!
+              iv(cnvcod) = iv(1)
+              go to 290
+!
+!. . . . . . . . . . . . .  compute candidate step  . . . . . . . . . .
+!
+ 190  step1 = iv(step)
+      dg1 = iv(dg)
+      l = iv(lmat)
+      w1 = iv(w)
+      call gqtst(d, v(dg1), h, iv(kagqt), v(l), n, v(step1), v, v(w1))
+      if (iv(irc) .eq. 6) go to 210
+!
+!  ***  check whether evaluating f(x0 + step) looks worthwhile  ***
+!
+      if (v(dstnrm) .le. zero) go to 210
+      if (iv(irc) .ne. 5) go to 200
+      if (v(radfac) .le. one) go to 200
+      if (v(preduc) .le. onep2 * v(fdif)) go to 210
+!
+!  ***  compute f(x0 + step)  ***
+!
+ 200  x01 = iv(x0)
+      step1 = iv(step)
+      call vaxpy(n, x, one, v(step1), v(x01))
+      iv(nfcall) = iv(nfcall) + 1
+      iv(1) = 1
+      iv(toobig) = 0
+      go to 999
+!
+!. . . . . . . . . . . . .  assess candidate step  . . . . . . . . . . .
+!
+ 210  x01 = iv(x0)
+      v(reldx) = reldst(n, d, x, v(x01))
+      call assst(iv, liv, lv, v)
+      step1 = iv(step)
+      lstgst = iv(stlstg)
+      if (iv(restor) .eq. 1) call vcopy(n, x, v(x01))
+      if (iv(restor) .eq. 2) call vcopy(n, v(lstgst), v(step1))
+      if (iv(restor) .ne. 3) go to 220
+         call vcopy(n, v(step1), v(lstgst))
+         call vaxpy(n, x, one, v(step1), v(x01))
+         v(reldx) = reldst(n, d, x, v(x01))
+!
+ 220  k = iv(irc)
+      go to (230,260,260,260,230,240,250,250,250,250,250,250,330,300), k
+!
+!     ***  recompute step with new radius  ***
+!
+ 230     v(radius) = v(radfac) * v(dstnrm)
+         go to 150
+!
+!  ***  compute step of length v(lmaxs) for singular convergence test.
+!
+ 240  v(radius) = v(lmaxs)
+      go to 190
+!
+!  ***  convergence or false convergence  ***
+!
+ 250  iv(cnvcod) = k - 4
+      if (v(f) .ge. v(f0)) go to 340
+         if (iv(xirc) .eq. 14) go to 340
+              iv(xirc) = 14
+!
+!. . . . . . . . . . . .  process acceptable step  . . . . . . . . . . .
+!
+ 260  if (iv(irc) .ne. 3) go to 290
+         temp1 = lstgst
+!
+!     ***  prepare for gradient tests  ***
+!     ***  set  temp1 = hessian * step + g(x0)
+!     ***             = diag(d) * (h * step + g(x0))
+!
+!        use x0 vector as temporary.
+         k = x01
+         do 270 i = 1, n
+              v(k) = d(i) * v(step1)
+              k = k + 1
+              step1 = step1 + 1
+ 270          continue
+         call slvmul(n, v(temp1), h, v(x01))
+         do 280 i = 1, n
+              v(temp1) = d(i) * v(temp1) + g(i)
+              temp1 = temp1 + 1
+ 280          continue
+!
+!  ***  compute gradient and hessian  ***
+!
+ 290  iv(ngcall) = iv(ngcall) + 1
+      iv(1) = 2
+      go to 999
+!
+ 300  iv(1) = 2
+      if (iv(irc) .ne. 3) go to 110
+!
+!  ***  set v(radfac) by gradient tests  ***
+!
+      temp1 = iv(stlstg)
+      step1 = iv(step)
+!
+!     ***  set  temp1 = diag(d)**-1 * (hessian*step + (g(x0)-g(x)))  ***
+!
+      k = temp1
+      do 310 i = 1, n
+         v(k) = (v(k) - g(i)) / d(i)
+         k = k + 1
+ 310     continue
+!
+!     ***  do gradient tests  ***
+!
+      if (v2norm(n, v(temp1)) .le. v(dgnorm) * v(tuner4)) go to 320
+           if (dotprd(n, g, v(step1)) &
+                     .ge. v(gtstep) * v(tuner5))  go to 110
+ 320            v(radfac) = v(incfac)
+                go to 110
+!
+!. . . . . . . . . . . . . .  misc. details  . . . . . . . . . . . . . .
+!
+!  ***  bad parameters to assess  ***
+!
+ 330  iv(1) = 64
+      go to 350
+!
+!  ***  print summary of final iteration and other requested items  ***
+!
+ 340  iv(1) = iv(cnvcod)
+      iv(cnvcod) = 0
+ 350  call itsum(d, g, iv, liv, lv, n, v, x)
+!
+ 999  return
+!
+!  ***  last card of humit follows  ***
+      end subroutine humit
+!-----------------------------------------------------------------------------
+      subroutine dupdu(d, hdiag, iv, liv, lv, n, v)
+!
+!  ***  update scale vector d for humsl  ***
+!
+!  ***  parameter declarations  ***
+!
+      integer :: liv, lv, n
+      integer :: iv(liv)
+      real(kind=8) :: d(n), hdiag(n), v(lv)
+!
+!  ***  local variables  ***
+!
+      integer :: dtoli, d0i, i
+      real(kind=8) :: t, vdfac
+!
+!  ***  intrinsic functions  ***
+!/+
+!el      real(kind=8) :: dabs, dmax1, dsqrt
+!/
+!  ***  subscripts for iv and v  ***
+!
+!el      integer :: dfac, dtol, dtype, niter
+!/6
+!     data dfac/41/, dtol/59/, dtype/16/, niter/31/
+!/7
+      integer,parameter :: dfac=41, dtol=59, dtype=16, niter=31
+!/
+!
+!-------------------------------  body  --------------------------------
+!
+      i = iv(dtype)
+      if (i .eq. 1) go to 10
+         if (iv(niter) .gt. 0) go to 999
+!
+ 10   dtoli = iv(dtol)
+      d0i = dtoli + n
+      vdfac = v(dfac)
+      do 20 i = 1, n
+         t = dmax1(dsqrt(dabs(hdiag(i))), vdfac*d(i))
+         if (t .lt. v(dtoli)) t = dmax1(v(dtoli), v(d0i))
+         d(i) = t
+         dtoli = dtoli + 1
+         d0i = d0i + 1
+ 20      continue
+!
+ 999  return
+!  ***  last card of dupdu follows  ***
+      end subroutine dupdu
+!-----------------------------------------------------------------------------
+      subroutine gqtst(d, dig, dihdi, ka, l, p, step, v, w)
+!
+!  *** compute goldfeld-quandt-trotter step by more-hebden technique ***
+!  ***  (nl2sol version 2.2), modified a la more and sorensen  ***
+!
+!  ***  parameter declarations  ***
+!
+      integer :: ka, p
+!al   real(kind=8) :: d(p), dig(p), dihdi(1), l(1), v(21), step(p),
+!al  1                 w(1)
+      real(kind=8) :: d(p), dig(p), dihdi(p*(p+1)/2), l(p*(p+1)/2),&
+          v(21), step(p),w(4*p+7)
+!     dimension dihdi(p*(p+1)/2), l(p*(p+1)/2), w(4*p+7)
+!
+!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+!
+!  ***  purpose  ***
+!
+!        given the (compactly stored) lower triangle of a scaled
+!     hessian (approximation) and a nonzero scaled gradient vector,
+!     this subroutine computes a goldfeld-quandt-trotter step of
+!     approximate length v(radius) by the more-hebden technique.  in
+!     other words, step is computed to (approximately) minimize
+!     psi(step) = (g**t)*step + 0.5*(step**t)*h*step  such that the
+!     2-norm of d*step is at most (approximately) v(radius), where
+!     g  is the gradient,  h  is the hessian, and  d  is a diagonal
+!     scale matrix whose diagonal is stored in the parameter d.
+!     (gqtst assumes  dig = d**-1 * g  and  dihdi = d**-1 * h * d**-1.)
+!
+!  ***  parameter description  ***
+!
+!     d (in)  = the scale vector, i.e. the diagonal of the scale
+!              matrix  d  mentioned above under purpose.
+!   dig (in)  = the scaled gradient vector, d**-1 * g.  if g = 0, then
+!              step = 0  and  v(stppar) = 0  are returned.
+! dihdi (in)  = lower triangle of the scaled hessian (approximation),
+!              i.e., d**-1 * h * d**-1, stored compactly by rows., i.e.,
+!              in the order (1,1), (2,1), (2,2), (3,1), (3,2), etc.
+!    ka (i/o) = the number of hebden iterations (so far) taken to deter-
+!              mine step.  ka .lt. 0 on input means this is the first
+!              attempt to determine step (for the present dig and dihdi)
+!              -- ka is initialized to 0 in this case.  output with
+!              ka = 0  (or v(stppar) = 0)  means  step = -(h**-1)*g.
+!     l (i/o) = workspace of length p*(p+1)/2 for cholesky factors.
+!     p (in)  = number of parameters -- the hessian is a  p x p  matrix.
+!  step (i/o) = the step computed.
+!     v (i/o) contains various constants and variables described below.
+!     w (i/o) = workspace of length 4*p + 6.
+!
+!  ***  entries in v  ***
+!
+! v(dgnorm) (i/o) = 2-norm of (d**-1)*g.
+! v(dstnrm) (output) = 2-norm of d*step.
+! v(dst0)   (i/o) = 2-norm of d*(h**-1)*g (for pos. def. h only), or
+!             overestimate of smallest eigenvalue of (d**-1)*h*(d**-1).
+! v(epslon) (in)  = max. rel. error allowed for psi(step).  for the
+!             step returned, psi(step) will exceed its optimal value
+!             by less than -v(epslon)*psi(step).  suggested value = 0.1.
+! v(gtstep) (out) = inner product between g and step.
+! v(nreduc) (out) = psi(-(h**-1)*g) = psi(newton step)  (for pos. def.
+!             h only -- v(nreduc) is set to zero otherwise).
+! v(phmnfc) (in)  = tol. (together with v(phmxfc)) for accepting step
+!             (more*s sigma).  the error v(dstnrm) - v(radius) must lie
+!             between v(phmnfc)*v(radius) and v(phmxfc)*v(radius).
+! v(phmxfc) (in)  (see v(phmnfc).)
+!             suggested values -- v(phmnfc) = -0.25, v(phmxfc) = 0.5.
+! v(preduc) (out) = psi(step) = predicted obj. func. reduction for step.
+! v(radius) (in)  = radius of current (scaled) trust region.
+! v(rad0)   (i/o) = value of v(radius) from previous call.
+! v(stppar) (i/o) is normally the marquardt parameter, i.e. the alpha
+!             described below under algorithm notes.  if h + alpha*d**2
+!             (see algorithm notes) is (nearly) singular, however,
+!             then v(stppar) = -alpha.
+!
+!  ***  usage notes  ***
+!
+!     if it is desired to recompute step using a different value of
+!     v(radius), then this routine may be restarted by calling it
+!     with all parameters unchanged except v(radius).  (this explains
+!     why step and w are listed as i/o).  on an initial call (one with
+!     ka .lt. 0), step and w need not be initialized and only compo-
+!     nents v(epslon), v(stppar), v(phmnfc), v(phmxfc), v(radius), and
+!     v(rad0) of v must be initialized.
+!
+!  ***  algorithm notes  ***
+!
+!        the desired g-q-t step (ref. 2, 3, 4, 6) satisfies
+!     (h + alpha*d**2)*step = -g  for some nonnegative alpha such that
+!     h + alpha*d**2 is positive semidefinite.  alpha and step are
+!     computed by a scheme analogous to the one described in ref. 5.
+!     estimates of the smallest and largest eigenvalues of the hessian
+!     are obtained from the gerschgorin circle theorem enhanced by a
+!     simple form of the scaling described in ref. 7.  cases in which
+!     h + alpha*d**2 is nearly (or exactly) singular are handled by
+!     the technique discussed in ref. 2.  in these cases, a step of
+!     (exact) length v(radius) is returned for which psi(step) exceeds
+!     its optimal value by less than -v(epslon)*psi(step).  the test
+!     suggested in ref. 6 for detecting the special case is performed
+!     once two matrix factorizations have been done -- doing so sooner
+!     seems to degrade the performance of optimization routines that
+!     call this routine.
+!
+!  ***  functions and subroutines called  ***
+!
+! dotprd - returns inner product of two vectors.
+! litvmu - applies inverse-transpose of compact lower triang. matrix.
+! livmul - applies inverse of compact lower triang. matrix.
+! lsqrt  - finds cholesky factor (of compactly stored lower triang.).
+! lsvmin - returns approx. to min. sing. value of lower triang. matrix.
+! rmdcon - returns machine-dependent constants.
+! v2norm - returns 2-norm of a vector.
+!
+!  ***  references  ***
+!
+! 1.  dennis, j.e., gay, d.m., and welsch, r.e. (1981), an adaptive
+!             nonlinear least-squares algorithm, acm trans. math.
+!             software, vol. 7, no. 3.
+! 2.  gay, d.m. (1981), computing optimal locally constrained steps,
+!             siam j. sci. statist. computing, vol. 2, no. 2, pp.
+!             186-197.
+! 3.  goldfeld, s.m., quandt, r.e., and trotter, h.f. (1966),
+!             maximization by quadratic hill-climbing, econometrica 34,
+!             pp. 541-551.
+! 4.  hebden, m.d. (1973), an algorithm for minimization using exact
+!             second derivatives, report t.p. 515, theoretical physics
+!             div., a.e.r.e. harwell, oxon., england.
+! 5.  more, j.j. (1978), the levenberg-marquardt algorithm, implemen-
+!             tation and theory, pp.105-116 of springer lecture notes
+!             in mathematics no. 630, edited by g.a. watson, springer-
+!             verlag, berlin and new york.
+! 6.  more, j.j., and sorensen, d.c. (1981), computing a trust region
+!             step, technical report anl-81-83, argonne national lab.
+! 7.  varga, r.s. (1965), minimal gerschgorin sets, pacific j. math. 15,
+!             pp. 719-729.
+!
+!  ***  general  ***
+!
+!     coded by david m. gay.
+!     this subroutine was written in connection with research
+!     supported by the national science foundation under grants
+!     mcs-7600324, dcr75-10143, 76-14311dss, mcs76-11989, and
+!     mcs-7906671.
+!
+!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+!
+!  ***  local variables  ***
+!
+      logical :: restrt
+      integer :: dggdmx, diag, diag0, dstsav, emax, emin, i, im1, inc, irc,&
+              j, k, kalim, kamin, k1, lk0, phipin, q, q0, uk0, x
+      real(kind=8) :: alphak, aki, akk, delta, dst, eps, gtsta, lk,&
+                       oldphi, phi, phimax, phimin, psifac, rad, radsq,&
+                       root, si, sk, sw, t, twopsi, t1, t2, uk, wi
+!
+!     ***  constants  ***
+      real(kind=8) :: big, dgxfac      !el, epsfac, four, half, kappa, negone,
+!el     1                 one, p001, six, three, two, zero
+!
+!  ***  intrinsic functions  ***
+!/+
+!el      real(kind=8) :: dabs, dmax1, dmin1, dsqrt
+!/
+!  ***  external functions and subroutines  ***
+!
+!el      external dotprd, litvmu, livmul, lsqrt, lsvmin, rmdcon, v2norm
+!el      real(kind=8) :: dotprd, lsvmin, rmdcon, v2norm
+!
+!  ***  subscripts for v  ***
+!
+!el      integer dgnorm, dstnrm, dst0, epslon, gtstep, stppar, nreduc,
+!el     1        phmnfc, phmxfc, preduc, radius, rad0
+!/6
+!     data dgnorm/1/, dstnrm/2/, dst0/3/, epslon/19/, gtstep/4/,
+!    1     nreduc/6/, phmnfc/20/, phmxfc/21/, preduc/7/, radius/8/,
+!    2     rad0/9/, stppar/5/
+!/7
+      integer,parameter :: dgnorm=1, dstnrm=2, dst0=3, epslon=19, gtstep=4,&
+                 nreduc=6, phmnfc=20, phmxfc=21, preduc=7, radius=8,&
+                 rad0=9, stppar=5
+!/
+!
+!/6
+!     data epsfac/50.0d+0/, four/4.0d+0/, half/0.5d+0/,
+!    1     kappa/2.0d+0/, negone/-1.0d+0/, one/1.0d+0/, p001/1.0d-3/,
+!    2     six/6.0d+0/, three/3.0d+0/, two/2.0d+0/, zero/0.0d+0/
+!/7
+     real(kind=8), parameter :: epsfac=50.0d+0, four=4.0d+0, half=0.5d+0,&
+           kappa=2.0d+0, negone=-1.0d+0, one=1.0d+0, p001=1.0d-3,&
+           six=6.0d+0, three=3.0d+0, two=2.0d+0, zero=0.0d+0
+      save dgxfac
+!/
+      data big/0.d+0/, dgxfac/0.d+0/
+!
+!  ***  body  ***
+!
+!     ***  store largest abs. entry in (d**-1)*h*(d**-1) at w(dggdmx).
+      dggdmx = p + 1
+!     ***  store gerschgorin over- and underestimates of the largest
+!     ***  and smallest eigenvalues of (d**-1)*h*(d**-1) at w(emax)
+!     ***  and w(emin) respectively.
+      emax = dggdmx + 1
+      emin = emax + 1
+!     ***  for use in recomputing step, the final values of lk, uk, dst,
+!     ***  and the inverse derivative of more*s phi at 0 (for pos. def.
+!     ***  h) are stored in w(lk0), w(uk0), w(dstsav), and w(phipin)
+!     ***  respectively.
+      lk0 = emin + 1
+      phipin = lk0 + 1
+      uk0 = phipin + 1
+      dstsav = uk0 + 1
+!     ***  store diag of (d**-1)*h*(d**-1) in w(diag),...,w(diag0+p).
+      diag0 = dstsav
+      diag = diag0 + 1
+!     ***  store -d*step in w(q),...,w(q0+p).
+      q0 = diag0 + p
+      q = q0 + 1
+!     ***  allocate storage for scratch vector x  ***
+      x = q + p
+      rad = v(radius)
+      radsq = rad**2
+!     ***  phitol = max. error allowed in dst = v(dstnrm) = 2-norm of
+!     ***  d*step.
+      phimax = v(phmxfc) * rad
+      phimin = v(phmnfc) * rad
+      psifac = two * v(epslon) / (three * (four * (v(phmnfc) + one) * &
+                             (kappa + one)  +  kappa  +  two) * rad**2)
+!     ***  oldphi is used to detect limits of numerical accuracy.  if
+!     ***  we recompute step and it does not change, then we accept it.
+      oldphi = zero
+      eps = v(epslon)
+      irc = 0
+      restrt = .false.
+      kalim = ka + 50
+!
+!  ***  start or restart, depending on ka  ***
+!
+      if (ka .ge. 0) go to 290
+!
+!  ***  fresh start  ***
+!
+      k = 0
+      uk = negone
+      ka = 0
+      kalim = 50
+      v(dgnorm) = v2norm(p, dig)
+      v(nreduc) = zero
+      v(dst0) = zero
+      kamin = 3
+      if (v(dgnorm) .eq. zero) kamin = 0
+!
+!     ***  store diag(dihdi) in w(diag0+1),...,w(diag0+p)  ***
+!
+      j = 0
+      do 10 i = 1, p
+         j = j + i
+         k1 = diag0 + i
+         w(k1) = dihdi(j)
+ 10      continue
+!
+!     ***  determine w(dggdmx), the largest element of dihdi  ***
+!
+      t1 = zero
+      j = p * (p + 1) / 2
+      do 20 i = 1, j
+         t = dabs(dihdi(i))
+         if (t1 .lt. t) t1 = t
+ 20      continue
+      w(dggdmx) = t1
+!
+!  ***  try alpha = 0  ***
+!
+ 30   call lsqrt(1, p, l, dihdi, irc)
+      if (irc .eq. 0) go to 50
+!        ***  indef. h -- underestimate smallest eigenvalue, use this
+!        ***  estimate to initialize lower bound lk on alpha.
+         j = irc*(irc+1)/2
+         t = l(j)
+         l(j) = one
+         do 40 i = 1, irc
+ 40           w(i) = zero
+         w(irc) = one
+         call litvmu(irc, w, l, w)
+         t1 = v2norm(irc, w)
+         lk = -t / t1 / t1
+         v(dst0) = -lk
+         if (restrt) go to 210
+         go to 70
+!
+!     ***  positive definite h -- compute unmodified newton step.  ***
+ 50   lk = zero
+      t = lsvmin(p, l, w(q), w(q))
+      if (t .ge. one) go to 60
+         if (big .le. zero) big = rmdcon(6)
+         if (v(dgnorm) .ge. t*t*big) go to 70
+ 60   call livmul(p, w(q), l, dig)
+      gtsta = dotprd(p, w(q), w(q))
+      v(nreduc) = half * gtsta
+      call litvmu(p, w(q), l, w(q))
+      dst = v2norm(p, w(q))
+      v(dst0) = dst
+      phi = dst - rad
+      if (phi .le. phimax) go to 260
+      if (restrt) go to 210
+!
+!  ***  prepare to compute gerschgorin estimates of largest (and
+!  ***  smallest) eigenvalues.  ***
+!
+ 70   k = 0
+      do 100 i = 1, p
+         wi = zero
+         if (i .eq. 1) go to 90
+         im1 = i - 1
+         do 80 j = 1, im1
+              k = k + 1
+              t = dabs(dihdi(k))
+              wi = wi + t
+              w(j) = w(j) + t
+ 80           continue
+ 90      w(i) = wi
+         k = k + 1
+ 100     continue
+!
+!  ***  (under-)estimate smallest eigenvalue of (d**-1)*h*(d**-1)  ***
+!
+      k = 1
+      t1 = w(diag) - w(1)
+      if (p .le. 1) go to 120
+      do 110 i = 2, p
+         j = diag0 + i
+         t = w(j) - w(i)
+         if (t .ge. t1) go to 110
+              t1 = t
+              k = i
+ 110     continue
+!
+ 120  sk = w(k)
+      j = diag0 + k
+      akk = w(j)
+      k1 = k*(k-1)/2 + 1
+      inc = 1
+      t = zero
+      do 150 i = 1, p
+         if (i .eq. k) go to 130
+         aki = dabs(dihdi(k1))
+         si = w(i)
+         j = diag0 + i
+         t1 = half * (akk - w(j) + si - aki)
+         t1 = t1 + dsqrt(t1*t1 + sk*aki)
+         if (t .lt. t1) t = t1
+         if (i .lt. k) go to 140
+ 130     inc = i
+ 140     k1 = k1 + inc
+ 150     continue
+!
+      w(emin) = akk - t
+      uk = v(dgnorm)/rad - w(emin)
+      if (v(dgnorm) .eq. zero) uk = uk + p001 + p001*uk
+      if (uk .le. zero) uk = p001
+!
+!  ***  compute gerschgorin (over-)estimate of largest eigenvalue  ***
+!
+      k = 1
+      t1 = w(diag) + w(1)
+      if (p .le. 1) go to 170
+      do 160 i = 2, p
+         j = diag0 + i
+         t = w(j) + w(i)
+         if (t .le. t1) go to 160
+              t1 = t
+              k = i
+ 160     continue
+!
+ 170  sk = w(k)
+      j = diag0 + k
+      akk = w(j)
+      k1 = k*(k-1)/2 + 1
+      inc = 1
+      t = zero
+      do 200 i = 1, p
+         if (i .eq. k) go to 180
+         aki = dabs(dihdi(k1))
+         si = w(i)
+         j = diag0 + i
+         t1 = half * (w(j) + si - aki - akk)
+         t1 = t1 + dsqrt(t1*t1 + sk*aki)
+         if (t .lt. t1) t = t1
+         if (i .lt. k) go to 190
+ 180     inc = i
+ 190     k1 = k1 + inc
+ 200     continue
+!
+      w(emax) = akk + t
+      lk = dmax1(lk, v(dgnorm)/rad - w(emax))
+!
+!     ***  alphak = current value of alpha (see alg. notes above).  we
+!     ***  use more*s scheme for initializing it.
+      alphak = dabs(v(stppar)) * v(rad0)/rad
+!
+      if (irc .ne. 0) go to 210
+!
+!  ***  compute l0 for positive definite h  ***
+!
+      call livmul(p, w, l, w(q))
+      t = v2norm(p, w)
+      w(phipin) = dst / t / t
+      lk = dmax1(lk, phi*w(phipin))
+!
+!  ***  safeguard alphak and add alphak*i to (d**-1)*h*(d**-1)  ***
+!
+ 210  ka = ka + 1
+      if (-v(dst0) .ge. alphak .or. alphak .lt. lk .or. alphak .ge. uk) &
+                            alphak = uk * dmax1(p001, dsqrt(lk/uk))
+      if (alphak .le. zero) alphak = half * uk
+      if (alphak .le. zero) alphak = uk
+      k = 0
+      do 220 i = 1, p
+         k = k + i
+         j = diag0 + i
+         dihdi(k) = w(j) + alphak
+ 220     continue
+!
+!  ***  try computing cholesky decomposition  ***
+!
+      call lsqrt(1, p, l, dihdi, irc)
+      if (irc .eq. 0) go to 240
+!
+!  ***  (d**-1)*h*(d**-1) + alphak*i  is indefinite -- overestimate
+!  ***  smallest eigenvalue for use in updating lk  ***
+!
+      j = (irc*(irc+1))/2
+      t = l(j)
+      l(j) = one
+      do 230 i = 1, irc
+ 230     w(i) = zero
+      w(irc) = one
+      call litvmu(irc, w, l, w)
+      t1 = v2norm(irc, w)
+      lk = alphak - t/t1/t1
+      v(dst0) = -lk
+      go to 210
+!
+!  ***  alphak makes (d**-1)*h*(d**-1) positive definite.
+!  ***  compute q = -d*step, check for convergence.  ***
+!
+ 240  call livmul(p, w(q), l, dig)
+      gtsta = dotprd(p, w(q), w(q))
+      call litvmu(p, w(q), l, w(q))
+      dst = v2norm(p, w(q))
+      phi = dst - rad
+      if (phi .le. phimax .and. phi .ge. phimin) go to 270
+      if (phi .eq. oldphi) go to 270
+      oldphi = phi
+      if (phi .lt. zero) go to 330
+!
+!  ***  unacceptable alphak -- update lk, uk, alphak  ***
+!
+ 250  if (ka .ge. kalim) go to 270
+!     ***  the following dmin1 is necessary because of restarts  ***
+      if (phi .lt. zero) uk = dmin1(uk, alphak)
+!     *** kamin = 0 only iff the gradient vanishes  ***
+      if (kamin .eq. 0) go to 210
+      call livmul(p, w, l, w(q))
+      t1 = v2norm(p, w)
+      alphak = alphak  +  (phi/t1) * (dst/t1) * (dst/rad)
+      lk = dmax1(lk, alphak)
+      go to 210
+!
+!  ***  acceptable step on first try  ***
+!
+ 260  alphak = zero
+!
+!  ***  successful step in general.  compute step = -(d**-1)*q  ***
+!
+ 270  do 280 i = 1, p
+         j = q0 + i
+         step(i) = -w(j)/d(i)
+ 280     continue
+      v(gtstep) = -gtsta
+      v(preduc) = half * (dabs(alphak)*dst*dst + gtsta)
+      go to 410
+!
+!
+!  ***  restart with new radius  ***
+!
+ 290  if (v(dst0) .le. zero .or. v(dst0) - rad .gt. phimax) go to 310
+!
+!     ***  prepare to return newton step  ***
+!
+         restrt = .true.
+         ka = ka + 1
+         k = 0
+         do 300 i = 1, p
+              k = k + i
+              j = diag0 + i
+              dihdi(k) = w(j)
+ 300          continue
+         uk = negone
+         go to 30
+!
+ 310  kamin = ka + 3
+      if (v(dgnorm) .eq. zero) kamin = 0
+      if (ka .eq. 0) go to 50
+!
+      dst = w(dstsav)
+      alphak = dabs(v(stppar))
+      phi = dst - rad
+      t = v(dgnorm)/rad
+      uk = t - w(emin)
+      if (v(dgnorm) .eq. zero) uk = uk + p001 + p001*uk
+      if (uk .le. zero) uk = p001
+      if (rad .gt. v(rad0)) go to 320
+!
+!        ***  smaller radius  ***
+         lk = zero
+         if (alphak .gt. zero) lk = w(lk0)
+         lk = dmax1(lk, t - w(emax))
+         if (v(dst0) .gt. zero) lk = dmax1(lk, (v(dst0)-rad)*w(phipin))
+         go to 250
+!
+!     ***  bigger radius  ***
+ 320  if (alphak .gt. zero) uk = dmin1(uk, w(uk0))
+      lk = dmax1(zero, -v(dst0), t - w(emax))
+      if (v(dst0) .gt. zero) lk = dmax1(lk, (v(dst0)-rad)*w(phipin))
+      go to 250
+!
+!  ***  decide whether to check for special case... in practice (from
+!  ***  the standpoint of the calling optimization code) it seems best
+!  ***  not to check until a few iterations have failed -- hence the
+!  ***  test on kamin below.
+!
+ 330  delta = alphak + dmin1(zero, v(dst0))
+      twopsi = alphak*dst*dst + gtsta
+      if (ka .ge. kamin) go to 340
+!     *** if the test in ref. 2 is satisfied, fall through to handle
+!     *** the special case (as soon as the more-sorensen test detects
+!     *** it).
+      if (delta .ge. psifac*twopsi) go to 370
+!
+!  ***  check for the special case of  h + alpha*d**2  (nearly)
+!  ***  singular.  use one step of inverse power method with start
+!  ***  from lsvmin to obtain approximate eigenvector corresponding
+!  ***  to smallest eigenvalue of (d**-1)*h*(d**-1).  lsvmin returns
+!  ***  x and w with  l*w = x.
+!
+ 340  t = lsvmin(p, l, w(x), w)
+!
+!     ***  normalize w  ***
+      do 350 i = 1, p
+ 350     w(i) = t*w(i)
+!     ***  complete current inv. power iter. -- replace w by (l**-t)*w.
+      call litvmu(p, w, l, w)
+      t2 = one/v2norm(p, w)
+      do 360 i = 1, p
+ 360     w(i) = t2*w(i)
+      t = t2 * t
+!
+!  ***  now w is the desired approximate (unit) eigenvector and
+!  ***  t*x = ((d**-1)*h*(d**-1) + alphak*i)*w.
+!
+      sw = dotprd(p, w(q), w)
+      t1 = (rad + dst) * (rad - dst)
+      root = dsqrt(sw*sw + t1)
+      if (sw .lt. zero) root = -root
+      si = t1 / (sw + root)
+!
+!  ***  the actual test for the special case...
+!
+      if ((t2*si)**2 .le. eps*(dst**2 + alphak*radsq)) go to 380
+!
+!  ***  update upper bound on smallest eigenvalue (when not positive)
+!  ***  (as recommended by more and sorensen) and continue...
+!
+      if (v(dst0) .le. zero) v(dst0) = dmin1(v(dst0), t2**2 - alphak)
+      lk = dmax1(lk, -v(dst0))
+!
+!  ***  check whether we can hope to detect the special case in
+!  ***  the available arithmetic.  accept step as it is if not.
+!
+!     ***  if not yet available, obtain machine dependent value dgxfac.
+ 370  if (dgxfac .eq. zero) dgxfac = epsfac * rmdcon(3)
+!
+      if (delta .gt. dgxfac*w(dggdmx)) go to 250
+         go to 270
+!
+!  ***  special case detected... negate alphak to indicate special case
+!
+ 380  alphak = -alphak
+      v(preduc) = half * twopsi
+!
+!  ***  accept current step if adding si*w would lead to a
+!  ***  further relative reduction in psi of less than v(epslon)/3.
+!
+      t1 = zero
+      t = si*(alphak*sw - half*si*(alphak + t*dotprd(p,w(x),w)))
+      if (t .lt. eps*twopsi/six) go to 390
+         v(preduc) = v(preduc) + t
+         dst = rad
+         t1 = -si
+ 390  do 400 i = 1, p
+         j = q0 + i
+         w(j) = t1*w(i) - w(j)
+         step(i) = w(j) / d(i)
+ 400     continue
+      v(gtstep) = dotprd(p, dig, w(q))
+!
+!  ***  save values for use in a possible restart  ***
+!
+ 410  v(dstnrm) = dst
+      v(stppar) = alphak
+      w(lk0) = lk
+      w(uk0) = uk
+      v(rad0) = rad
+      w(dstsav) = dst
+!
+!     ***  restore diagonal of dihdi  ***
+!
+      j = 0
+      do 420 i = 1, p
+         j = j + i
+         k = diag0 + i
+         dihdi(j) = w(k)
+ 420     continue
+!
+ 999  return
+!
+!  ***  last card of gqtst follows  ***
+      end subroutine gqtst
+!-----------------------------------------------------------------------------
+      subroutine lsqrt(n1, n, l, a, irc)
+!
+!  ***  compute rows n1 through n of the cholesky factor  l  of
+!  ***  a = l*(l**t),  where  l  and the lower triangle of  a  are both
+!  ***  stored compactly by rows (and may occupy the same storage).
+!  ***  irc = 0 means all went well.  irc = j means the leading
+!  ***  principal  j x j  submatrix of  a  is not positive definite --
+!  ***  and  l(j*(j+1)/2)  contains the (nonpos.) reduced j-th diagonal.
+!
+!  ***  parameters  ***
+!
+      integer :: n1, n, irc
+!al   real(kind=8) :: l(1), a(1)
+      real(kind=8) :: l(n*(n+1)/2), a(n*(n+1)/2)
+!     dimension l(n*(n+1)/2), a(n*(n+1)/2)
+!
+!  ***  local variables  ***
+!
+      integer :: i, ij, ik, im1, i0, j, jk, jm1, j0, k
+      real(kind=8) :: t, td    !el, zero
+!
+!  ***  intrinsic functions  ***
+!/+
+!el      real(kind=8) :: dsqrt
+!/
+!/6
+!     data zero/0.d+0/
+!/7
+      real(kind=8),parameter :: zero=0.d+0
+!/
+!
+!  ***  body  ***
+!
+      i0 = n1 * (n1 - 1) / 2
+      do 50 i = n1, n
+         td = zero
+         if (i .eq. 1) go to 40
+         j0 = 0
+         im1 = i - 1
+         do 30 j = 1, im1
+              t = zero
+              if (j .eq. 1) go to 20
+              jm1 = j - 1
+              do 10 k = 1, jm1
+                   ik = i0 + k
+                   jk = j0 + k
+                   t = t + l(ik)*l(jk)
+ 10                continue
+ 20           ij = i0 + j
+              j0 = j0 + j
+              t = (a(ij) - t) / l(j0)
+              l(ij) = t
+              td = td + t*t
+ 30           continue
+ 40      i0 = i0 + i
+         t = a(i0) - td
+         if (t .le. zero) go to 60
+         l(i0) = dsqrt(t)
+ 50      continue
+!
+      irc = 0
+      go to 999
+!
+ 60   l(i0) = t
+      irc = i
+!
+ 999  return
+!
+!  ***  last card of lsqrt  ***
+      end subroutine lsqrt
+!-----------------------------------------------------------------------------
+      real(kind=8) function lsvmin(p, l, x, y)
+!
+!  ***  estimate smallest sing. value of packed lower triang. matrix l
+!
+!  ***  parameter declarations  ***
+!
+      integer :: p
+!al   real(kind=8) :: l(1), x(p), y(p)
+      real(kind=8) :: l(p*(p+1)/2), x(p), y(p)
+!     dimension l(p*(p+1)/2)
+!
+!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+!
+!  ***  purpose  ***
+!
+!     this function returns a good over-estimate of the smallest
+!     singular value of the packed lower triangular matrix l.
+!
+!  ***  parameter description  ***
+!
+!  p (in)  = the order of l.  l is a  p x p  lower triangular matrix.
+!  l (in)  = array holding the elements of  l  in row order, i.e.
+!             l(1,1), l(2,1), l(2,2), l(3,1), l(3,2), l(3,3), etc.
+!  x (out) if lsvmin returns a positive value, then x is a normalized
+!             approximate left singular vector corresponding to the
+!             smallest singular value.  this approximation may be very
+!             crude.  if lsvmin returns zero, then some components of x
+!             are zero and the rest retain their input values.
+!  y (out) if lsvmin returns a positive value, then y = (l**-1)*x is an
+!             unnormalized approximate right singular vector correspond-
+!             ing to the smallest singular value.  this approximation
+!             may be crude.  if lsvmin returns zero, then y retains its
+!             input value.  the caller may pass the same vector for x
+!             and y (nonstandard fortran usage), in which case y over-
+!             writes x (for nonzero lsvmin returns).
+!
+!  ***  algorithm notes  ***
+!
+!     the algorithm is based on (1), with the additional provision that
+!     lsvmin = 0 is returned if the smallest diagonal element of l
+!     (in magnitude) is not more than the unit roundoff times the
+!     largest.  the algorithm uses a random number generator proposed
+!     in (4), which passes the spectral test with flying colors -- see
+!     (2) and (3).
+!
+!  ***  subroutines and functions called  ***
+!
+!        v2norm - function, returns the 2-norm of a vector.
+!
+!  ***  references  ***
+!
+!     (1) cline, a., moler, c., stewart, g., and wilkinson, j.h.(1977),
+!         an estimate for the condition number of a matrix, report
+!         tm-310, applied math. div., argonne national laboratory.
+!
+!     (2) hoaglin, d.c. (1976), theoretical properties of congruential
+!         random-number generators --  an empirical view,
+!         memorandum ns-340, dept. of statistics, harvard univ.
+!
+!     (3) knuth, d.e. (1969), the art of computer programming, vol. 2
+!         (seminumerical algorithms), addison-wesley, reading, mass.
+!
+!     (4) smith, c.s. (1971), multiplicative pseudo-random number
+!         generators with prime modulus, j. assoc. comput. mach. 18,
+!         pp. 586-593.
+!
+!  ***  history  ***
+!
+!     designed and coded by david m. gay (winter 1977/summer 1978).
+!
+!  ***  general  ***
+!
+!     this subroutine was written in connection with research
+!     supported by the national science foundation under grants
+!     mcs-7600324, dcr75-10143, 76-14311dss, and mcs76-11989.
+!
+!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+!
+!  ***  local variables  ***
+!
+      integer :: i, ii, ix, j, ji, jj, jjj, jm1, j0, pm1
+      real(kind=8) :: b, sminus, splus, t, xminus, xplus
+!
+!  ***  constants  ***
+!
+!el      real(kind=8) :: half, one, r9973, zero
+!
+!  ***  intrinsic functions  ***
+!/+
+!el      integer mod
+!el      real float
+!el      real(kind=8) :: dabs
+!/
+!  ***  external functions and subroutines  ***
+!
+!el      external dotprd, v2norm, vaxpy
+!el      real(kind=8) :: dotprd, v2norm
+!
+!/6
+!     data half/0.5d+0/, one/1.d+0/, r9973/9973.d+0/, zero/0.d+0/
+!/7
+      real(kind=8),parameter :: half=0.5d+0, one=1.d+0, r9973=9973.d+0, zero=0.d+0
+!/
+!
+!  ***  body  ***
+!
+      ix = 2
+      pm1 = p - 1
+!
+!  ***  first check whether to return lsvmin = 0 and initialize x  ***
+!
+      ii = 0
+      j0 = p*pm1/2
+      jj = j0 + p
+      if (l(jj) .eq. zero) go to 110
+      ix = mod(3432*ix, 9973)
+      b = half*(one + float(ix)/r9973)
+      xplus = b / l(jj)
+      x(p) = xplus
+      if (p .le. 1) go to 60
+      do 10 i = 1, pm1
+         ii = ii + i
+         if (l(ii) .eq. zero) go to 110
+         ji = j0 + i
+         x(i) = xplus * l(ji)
+ 10      continue
+!
+!  ***  solve (l**t)*x = b, where the components of b have randomly
+!  ***  chosen magnitudes in (.5,1) with signs chosen to make x large.
+!
+!     do j = p-1 to 1 by -1...
+      do 50 jjj = 1, pm1
+         j = p - jjj
+!       ***  determine x(j) in this iteration. note for i = 1,2,...,j
+!       ***  that x(i) holds the current partial sum for row i.
+         ix = mod(3432*ix, 9973)
+         b = half*(one + float(ix)/r9973)
+         xplus = (b - x(j))
+         xminus = (-b - x(j))
+         splus = dabs(xplus)
+         sminus = dabs(xminus)
+         jm1 = j - 1
+         j0 = j*jm1/2
+         jj = j0 + j
+         xplus = xplus/l(jj)
+         xminus = xminus/l(jj)
+         if (jm1 .eq. 0) go to 30
+         do 20 i = 1, jm1
+              ji = j0 + i
+              splus = splus + dabs(x(i) + l(ji)*xplus)
+              sminus = sminus + dabs(x(i) + l(ji)*xminus)
+ 20           continue
+ 30      if (sminus .gt. splus) xplus = xminus
+         x(j) = xplus
+!       ***  update partial sums  ***
+         if (jm1 .gt. 0) call vaxpy(jm1, x, xplus, l(j0+1), x)
+ 50      continue
+!
+!  ***  normalize x  ***
+!
+ 60   t = one/v2norm(p, x)
+      do 70 i = 1, p
+ 70      x(i) = t*x(i)
+!
+!  ***  solve l*y = x and return lsvmin = 1/twonorm(y)  ***
+!
+      do 100 j = 1, p
+         jm1 = j - 1
+         j0 = j*jm1/2
+         jj = j0 + j
+         t = zero
+         if (jm1 .gt. 0) t = dotprd(jm1, l(j0+1), y)
+         y(j) = (x(j) - t) / l(jj)
+ 100     continue
+!
+      lsvmin = one/v2norm(p, y)
+      go to 999
+!
+ 110  lsvmin = zero
+ 999  return
+!  ***  last card of lsvmin follows  ***
+      end function lsvmin
+!-----------------------------------------------------------------------------
+      subroutine slvmul(p, y, s, x)
+!
+!  ***  set  y = s * x,  s = p x p symmetric matrix.  ***
+!  ***  lower triangle of  s  stored rowwise.         ***
+!
+!  ***  parameter declarations  ***
+!
+      integer :: p
+!al   real(kind=8) :: s(1), x(p), y(p)
+      real(kind=8) :: s(p*(p+1)/2), x(p), y(p)
+!     dimension s(p*(p+1)/2)
+!
+!  ***  local variables  ***
+!
+      integer :: i, im1, j, k
+      real(kind=8) :: xi
+!
+!  ***  no intrinsic functions  ***
+!
+!  ***  external function  ***
+!
+!el      external dotprd
+!el      real(kind=8) :: dotprd
+!
+!-----------------------------------------------------------------------
+!
+      j = 1
+      do 10 i = 1, p
+         y(i) = dotprd(i, s(j), x)
+         j = j + i
+ 10      continue
+!
+      if (p .le. 1) go to 999
+      j = 1
+      do 40 i = 2, p
+         xi = x(i)
+         im1 = i - 1
+         j = j + 1
+         do 30 k = 1, im1
+              y(k) = y(k) + s(j)*xi
+              j = j + 1
+ 30           continue
+ 40      continue
+!
+ 999  return
+!  ***  last card of slvmul follows  ***
+      end subroutine slvmul
+!-----------------------------------------------------------------------------
+! minimize_p.F
+!-----------------------------------------------------------------------------
+      subroutine minimize(etot,x,iretcode,nfun)
+
+      use energy, only: func,gradient,fdum!,etotal,enerprint
+      use comm_srutu
+!      implicit real*8 (a-h,o-z)
+!      include 'DIMENSIONS'
+      integer,parameter :: liv=60
+!      integer :: lv=(77+(6*nres)*(6*nres+17)/2)       !(77+maxvar*(maxvar+17)/2)) (maxvar=6*maxres)
+!********************************************************************
+! OPTIMIZE sets up SUMSL or DFP and provides a simple interface for *
+! the calling subprogram.                                           *     
+! when d(i)=1.0, then v(35) is the length of the initial step,      *     
+! calculated in the usual pythagorean way.                          *     
+! absolute convergence occurs when the function is within v(31) of  *     
+! zero. unless you know the minimum value in advance, abs convg     *     
+! is probably not useful.                                           *     
+! relative convergence is when the model predicts that the function *   
+! will decrease by less than v(32)*abs(fun).                        *   
+!********************************************************************
+!      include 'COMMON.IOUNITS'
+!      include 'COMMON.VAR'
+!      include 'COMMON.GEO'
+!      include 'COMMON.MINIM'
+      integer :: i
+!el      common /srutu/ icall
+      integer,dimension(liv) :: iv                                               
+      real(kind=8) :: minval   !,v(1:77+(6*nres)*(6*nres+17)/2)        !(1:lv)
+!el      real(kind=8),dimension(6*nres) :: x,d,xx      !(maxvar) (maxvar=6*maxres)
+      real(kind=8),dimension(6*nres) :: x,d,xx !(maxvar) (maxvar=6*maxres)
+      real(kind=8) :: energia(0:n_ene)
+!      external func,gradient,fdum
+!      external func_restr,grad_restr
+      logical :: not_done,change,reduce 
+!el      common /przechowalnia/ v
+!el local variables
+      integer :: iretcode,nfun,lv,nvar_restr,idum(1),j
+      real(kind=8) :: etot,rdum(1)     !,fdum
+
+      lv=(77+(6*nres)*(6*nres+17)/2)   !(77+maxvar*(maxvar+17)/2)) (maxvar=6*maxres)
+
+      if (.not.allocated(v)) allocate(v(1:lv))
+
+      icall = 1
+
+      NOT_DONE=.TRUE.
+
+!     DO WHILE (NOT_DONE)
+
+      call deflt(2,iv,liv,lv,v)                                         
+! 12 means fresh start, dont call deflt                                 
+      iv(1)=12                                                          
+! max num of fun calls                                                  
+      if (maxfun.eq.0) maxfun=500
+      iv(17)=maxfun
+! max num of iterations                                                 
+      if (maxmin.eq.0) maxmin=1000
+      iv(18)=maxmin
+! controls output                                                       
+      iv(19)=2                                                          
+! selects output unit                                                   
+      iv(21)=0
+      if (print_min_ini+print_min_stat+print_min_res.gt.0) iv(21)=iout
+! 1 means to print out result                                           
+      iv(22)=print_min_res
+! 1 means to print out summary stats                                    
+      iv(23)=print_min_stat
+! 1 means to print initial x and d                                      
+      iv(24)=print_min_ini
+! min val for v(radfac) default is 0.1                                  
+      v(24)=0.1D0                                                       
+! max val for v(radfac) default is 4.0                                  
+      v(25)=2.0D0                                                       
+!     v(25)=4.0D0                                                       
+! check false conv if (act fnctn decrease) .lt. v(26)*(exp decrease)    
+! the sumsl default is 0.1                                              
+      v(26)=0.1D0
+! false conv if (act fnctn decrease) .lt. v(34)                         
+! the sumsl default is 100*machep                                       
+      v(34)=v(34)/100.0D0                                               
+! absolute convergence                                                  
+      if (tolf.eq.0.0D0) tolf=1.0D-4
+      v(31)=tolf
+! relative convergence                                                  
+      if (rtolf.eq.0.0D0) rtolf=1.0D-4
+      v(32)=rtolf
+! controls initial step size                                            
+       v(35)=1.0D-1                                                    
+! large vals of d correspond to small components of step                
+      do i=1,nphi
+        d(i)=1.0D-1
+      enddo
+      do i=nphi+1,nvar
+        d(i)=1.0D-1
+      enddo
+!d    print *,'Calling SUMSL'
+!     call var_to_geom(nvar,x)
+!     call chainbuild
+!     call etotal(energia(0))
+!     etot = energia(0)
+!elmask_r=.true.
+      IF (mask_r) THEN
+       call x2xx(x,xx,nvar_restr)
+       call sumsl(nvar_restr,d,xx,func_restr,grad_restr,&
+                          iv,liv,lv,v,idum,rdum,fdum)      
+       call xx2x(x,xx)
+      ELSE
+       call sumsl(nvar,d,x,func,gradient,iv,liv,lv,v,idum,rdum,fdum)      
+      ENDIF
+      etot=v(10)                                                      
+      iretcode=iv(1)
+!d    print *,'Exit SUMSL; return code:',iretcode,' energy:',etot
+!d    write (iout,'(/a,i4/)') 'SUMSL return code:',iv(1)
+!     call intout
+!     change=reduce(x)
+      call var_to_geom(nvar,x)
+!     if (change) then
+!       write (iout,'(a)') 'Reduction worked, minimizing again...'
+!     else
+!       not_done=.false.
+!     endif
+      call chainbuild
+
+!el---------------------
+!      write (iout,'(/a)') &
+!        "Cartesian coordinates of the reference structure after SUMSL"
+!      write (iout,'(a,3(3x,a5),5x,3(3x,a5))') &
+!       "Residue","X(CA)","Y(CA)","Z(CA)","X(SC)","Y(SC)","Z(SC)"
+!      do i=1,nres
+!        write (iout,'(a3,1x,i3,3f8.3,5x,3f8.3)') &
+!          restyp(itype(i)),i,(c(j,i),j=1,3),&
+!          (c(j,i+nres),j=1,3)
+!      enddo
+!el----------------------------
+!     call etotal(energia) !sp
+!     etot=energia(0)
+!     call enerprint(energia) !sp
+      nfun=iv(6)
+
+!     write (*,*) 'Processor',MyID,' leaves MINIMIZE.'
+
+!     ENDDO ! NOT_DONE
+
+      return
+      end subroutine minimize
+!-----------------------------------------------------------------------------
+! gradient_p.F
+!-----------------------------------------------------------------------------
+      subroutine grad_restr(n,x,nf,g,uiparm,urparm,ufparm)
+
+      use energy, only: cartder,zerograd,etotal,sum_gradient
+!      implicit real*8 (a-h,o-z)
+!      include 'DIMENSIONS'
+!      include 'COMMON.CHAIN'
+!      include 'COMMON.DERIV'
+!      include 'COMMON.VAR'
+!      include 'COMMON.INTERACT'
+!      include 'COMMON.FFIELD'
+!      include 'COMMON.IOUNITS'
+!EL      external ufparm
+      integer :: uiparm(1)
+      real(kind=8) :: urparm(1)
+      real(kind=8),dimension(6*nres) :: x,g !(maxvar) (maxvar=6*maxres)
+      integer :: n,nf,ig,ind,i,j,ij,k,igall
+      real(kind=8) :: f,gphii,gthetai,galphai,gomegai
+      real(kind=8),external :: ufparm
+
+      icg=mod(nf,2)+1
+      if (nf-nfl+1) 20,30,40
+   20 call func_restr(n,x,nf,f,uiparm,urparm,ufparm)
+!     write (iout,*) 'grad 20'
+      if (nf.eq.0) return
+      goto 40
+   30 continue
+#ifdef OSF
+!     Intercept NaNs in the coordinates
+!      write(iout,*) (var(i),i=1,nvar)
+      x_sum=0.D0
+      do i=1,n
+        x_sum=x_sum+x(i)
+      enddo
+      if (x_sum.ne.x_sum) then
+        write(iout,*)" *** grad_restr : Found NaN in coordinates"
+        call flush(iout)
+        print *," *** grad_restr : Found NaN in coordinates"
+        return
+      endif
+#endif
+      call var_to_geom_restr(n,x)
+      call chainbuild 
+!
+! Evaluate the derivatives of virtual bond lengths and SC vectors in variables.
+!
+   40 call cartder
+!
+! Convert the Cartesian gradient into internal-coordinate gradient.
+!
+
+      ig=0
+      ind=nres-2                                                                    
+      do i=2,nres-2                
+       IF (mask_phi(i+2).eq.1) THEN                                             
+        gphii=0.0D0                                                             
+        do j=i+1,nres-1                                                         
+          ind=ind+1                                 
+          do k=1,3                                                              
+            gphii=gphii+dcdv(k+3,ind)*gradc(k,j,icg)                            
+            gphii=gphii+dxdv(k+3,ind)*gradx(k,j,icg)                           
+          enddo                                                                 
+        enddo                                                                   
+        ig=ig+1
+        g(ig)=gphii
+       ELSE
+        ind=ind+nres-1-i
+       ENDIF
+      enddo                                        
+
+
+      ind=0
+      do i=1,nres-2
+       IF (mask_theta(i+2).eq.1) THEN
+        ig=ig+1
+       gthetai=0.0D0
+       do j=i+1,nres-1
+          ind=ind+1
+         do k=1,3
+            gthetai=gthetai+dcdv(k,ind)*gradc(k,j,icg)
+            gthetai=gthetai+dxdv(k,ind)*gradx(k,j,icg)
+          enddo
+        enddo
+        g(ig)=gthetai
+       ELSE
+        ind=ind+nres-1-i
+       ENDIF
+      enddo
+
+      do i=2,nres-1
+       if (itype(i).ne.10) then
+         IF (mask_side(i).eq.1) THEN
+          ig=ig+1
+          galphai=0.0D0
+         do k=1,3
+           galphai=galphai+dxds(k,i)*gradx(k,i,icg)
+          enddo
+          g(ig)=galphai
+         ENDIF
+        endif
+      enddo
+
+      
+      do i=2,nres-1
+        if (itype(i).ne.10) then
+         IF (mask_side(i).eq.1) THEN
+          ig=ig+1
+         gomegai=0.0D0
+         do k=1,3
+           gomegai=gomegai+dxds(k+3,i)*gradx(k,i,icg)
+          enddo
+         g(ig)=gomegai
+         ENDIF
+        endif
+      enddo
+
+!
+! Add the components corresponding to local energy terms.
+!
+
+      ig=0
+      igall=0
+      do i=4,nres
+        igall=igall+1
+        if (mask_phi(i).eq.1) then
+          ig=ig+1
+          g(ig)=g(ig)+gloc(igall,icg)
+        endif
+      enddo
+
+      do i=3,nres
+        igall=igall+1
+        if (mask_theta(i).eq.1) then
+          ig=ig+1
+          g(ig)=g(ig)+gloc(igall,icg)
+        endif
+      enddo
+     
+      do ij=1,2
+      do i=2,nres-1
+        if (itype(i).ne.10) then
+          igall=igall+1
+          if (mask_side(i).eq.1) then
+            ig=ig+1
+            g(ig)=g(ig)+gloc(igall,icg)
+          endif
+        endif
+      enddo
+      enddo
+
+!d      do i=1,ig
+!d        write (iout,'(a2,i5,a3,f25.8)') 'i=',i,' g=',g(i)
+!d      enddo
+      return
+      end subroutine grad_restr
+!-----------------------------------------------------------------------------
+      subroutine func_restr(n,x,nf,f,uiparm,urparm,ufparm) !from minimize_p.F
+
+      use comm_chu
+      use energy, only: zerograd,etotal,sum_gradient
+!      implicit real*8 (a-h,o-z)
+!      include 'DIMENSIONS'
+!      include 'COMMON.DERIV'
+!      include 'COMMON.IOUNITS'
+!      include 'COMMON.GEO'
+      integer :: n,nf
+!el      integer :: jjj
+!el      common /chuju/ jjj
+      real(kind=8) :: energia(0:n_ene)
+      real(kind=8) :: f
+      real(kind=8),external :: ufparm                               
+      integer :: uiparm(1)                                        
+      real(kind=8) :: urparm(1)                                     
+      real(kind=8),dimension(6*nres) :: x      !(maxvar) (maxvar=6*maxres)
+!     if (jjj.gt.0) then
+!       write (iout,'(10f8.3)') (rad2deg*x(i),i=1,n)
+!     endif
+      nfl=nf
+      icg=mod(nf,2)+1
+      call var_to_geom_restr(n,x)
+      call zerograd
+      call chainbuild
+!d    write (iout,*) 'ETOTAL called from FUNC'
+      call etotal(energia)
+      call sum_gradient
+      f=energia(0)
+!     if (jjj.gt.0) then
+!       write (iout,'(10f8.3)') (rad2deg*x(i),i=1,n)
+!       write (iout,*) 'f=',etot
+!       jjj=0
+!     endif
+      return
+      end subroutine func_restr
+!-----------------------------------------------------------------------------
+!      subroutine func(n,x,nf,f,uiparm,urparm,ufparm) in module energy
+!-----------------------------------------------------------------------------
+      subroutine x2xx(x,xx,n)
+
+!      implicit real*8 (a-h,o-z)
+!      include 'DIMENSIONS'
+!      include 'COMMON.VAR'
+!      include 'COMMON.CHAIN'
+!      include 'COMMON.INTERACT'
+      integer :: n,i,ij,ig,igall
+      real(kind=8),dimension(6*nres) :: xx,x   !(maxvar) (maxvar=6*maxres)
+
+!el      allocate(varall(nvar)) allocated in alioc_ener_arrays
+
+      do i=1,nvar
+        varall(i)=x(i)
+      enddo
+
+      ig=0                                                                      
+      igall=0                                                                   
+      do i=4,nres                                                               
+        igall=igall+1                                                           
+        if (mask_phi(i).eq.1) then                                              
+          ig=ig+1                                                               
+          xx(ig)=x(igall)                       
+        endif                                                                   
+      enddo                                                                     
+                                                                                
+      do i=3,nres                                                               
+        igall=igall+1                                                           
+        if (mask_theta(i).eq.1) then                                            
+          ig=ig+1                                                               
+          xx(ig)=x(igall)
+        endif                                                                   
+      enddo                                          
+
+      do ij=1,2                                                                 
+      do i=2,nres-1                                                             
+        if (itype(i).ne.10) then                                                
+          igall=igall+1                                                         
+          if (mask_side(i).eq.1) then                                           
+            ig=ig+1                                                             
+            xx(ig)=x(igall)
+          endif                                                                 
+        endif                                                                   
+      enddo                                                                     
+      enddo                              
+      n=ig
+
+      return
+      end subroutine x2xx
+!-----------------------------------------------------------------------------
+!el      subroutine xx2x(x,xx) in module math
+!-----------------------------------------------------------------------------
+      subroutine minim_dc(etot,iretcode,nfun)
+
+      use MPI_data
+      use energy, only: fdum,check_ecartint
+!      implicit real*8 (a-h,o-z)
+!      include 'DIMENSIONS'
+#ifdef MPI
+      include 'mpif.h'
+#endif
+      integer,parameter :: liv=60
+!      integer :: lv=(77+(6*nres)*(6*nres+17)/2) !(77+maxvar*(maxvar+17)/2)) (maxvar=6*maxres)
+!      include 'COMMON.SETUP'
+!      include 'COMMON.IOUNITS'
+!      include 'COMMON.VAR'
+!      include 'COMMON.GEO'
+!      include 'COMMON.MINIM'
+!      include 'COMMON.CHAIN'
+      integer :: iretcode,nfun,k,i,j,lv,idum(1)
+      integer,dimension(liv) :: iv                                               
+      real(kind=8) :: minval   !,v(1:77+(6*nres)*(6*nres+17)/2)        !(1:lv)
+      real(kind=8),dimension(6*nres) :: x,d,xx !(maxvar) (maxvar=6*maxres)
+!el      common /przechowalnia/ v
+
+      real(kind=8) :: energia(0:n_ene)
+!      external func_dc,grad_dc        ,fdum
+      logical :: not_done,change,reduce 
+      real(kind=8) :: g(6*nres),f1,etot,rdum(1)        !,fdum
+
+      lv=(77+(6*nres)*(6*nres+17)/2) !(77+maxvar*(maxvar+17)/2)) (maxvar=6*maxres)
+
+      if (.not. allocated(v)) allocate(v(1:lv))
+
+      call deflt(2,iv,liv,lv,v)                                         
+! 12 means fresh start, dont call deflt                                 
+      iv(1)=12                                                          
+! max num of fun calls                                                  
+      if (maxfun.eq.0) maxfun=500
+      iv(17)=maxfun
+! max num of iterations                                                 
+      if (maxmin.eq.0) maxmin=1000
+      iv(18)=maxmin
+! controls output                                                       
+      iv(19)=2                                                          
+! selects output unit                                                   
+      iv(21)=0
+      if (print_min_ini+print_min_stat+print_min_res.gt.0) iv(21)=iout
+! 1 means to print out result                                           
+      iv(22)=print_min_res
+! 1 means to print out summary stats                                    
+      iv(23)=print_min_stat
+! 1 means to print initial x and d                                      
+      iv(24)=print_min_ini
+! min val for v(radfac) default is 0.1                                  
+      v(24)=0.1D0                                                       
+! max val for v(radfac) default is 4.0                                  
+      v(25)=2.0D0                                                       
+!     v(25)=4.0D0                                                       
+! check false conv if (act fnctn decrease) .lt. v(26)*(exp decrease)    
+! the sumsl default is 0.1                                              
+      v(26)=0.1D0
+! false conv if (act fnctn decrease) .lt. v(34)                         
+! the sumsl default is 100*machep                                       
+      v(34)=v(34)/100.0D0                                               
+! absolute convergence                                                  
+      if (tolf.eq.0.0D0) tolf=1.0D-4
+      v(31)=tolf
+! relative convergence                                                  
+      if (rtolf.eq.0.0D0) rtolf=1.0D-4
+      v(32)=rtolf
+! controls initial step size                                            
+       v(35)=1.0D-1                                                    
+! large vals of d correspond to small components of step                
+      do i=1,6*nres
+        d(i)=1.0D-1
+      enddo
+
+      k=0
+      do i=1,nres-1
+        do j=1,3
+          k=k+1
+          x(k)=dc(j,i)
+        enddo
+      enddo
+      do i=2,nres-1
+        if (ialph(i,1).gt.0) then
+        do j=1,3
+          k=k+1
+          x(k)=dc(j,i+nres)
+        enddo
+        endif
+      enddo
+      call check_ecartint
+      call sumsl(k,d,x,func_dc,grad_dc,iv,liv,lv,v,idum,rdum,fdum)      
+      call check_ecartint
+      k=0
+      do i=1,nres-1
+        do j=1,3
+          k=k+1
+          dc(j,i)=x(k)
+        enddo
+      enddo
+      do i=2,nres-1
+        if (ialph(i,1).gt.0) then
+        do j=1,3
+          k=k+1
+          dc(j,i+nres)=x(k)
+        enddo
+        endif
+      enddo
+      call chainbuild_cart
+
+!d      call zerograd
+!d      nf=0
+!d      call func_dc(k,x,nf,f,idum,rdum,fdum)
+!d      call grad_dc(k,x,nf,g,idum,rdum,fdum)
+!d
+!d      do i=1,k
+!d       x(i)=x(i)+1.0D-5
+!d       call func_dc(k,x,nf,f1,idum,rdum,fdum)
+!d       x(i)=x(i)-1.0D-5
+!d       print '(i5,2f15.5)',i,g(i),(f1-f)/1.0D-5
+!d      enddo
+!el---------------------
+!      write (iout,'(/a)') &
+!        "Cartesian coordinates of the reference structure after SUMSL"
+!      write (iout,'(a,3(3x,a5),5x,3(3x,a5))') &
+!       "Residue","X(CA)","Y(CA)","Z(CA)","X(SC)","Y(SC)","Z(SC)"
+!      do i=1,nres
+!        write (iout,'(a3,1x,i3,3f8.3,5x,3f8.3)') &
+!          restyp(itype(i)),i,(c(j,i),j=1,3),&
+!          (c(j,i+nres),j=1,3)
+!      enddo
+!el----------------------------
+      etot=v(10)                                                      
+      iretcode=iv(1)
+      nfun=iv(6)
+      return
+      end subroutine  minim_dc
+!-----------------------------------------------------------------------------
+      subroutine func_dc(n,x,nf,f,uiparm,urparm,ufparm)
+
+      use MPI_data
+      use energy, only: zerograd,etotal
+!      implicit real*8 (a-h,o-z)
+!      include 'DIMENSIONS'
+#ifdef MPI
+      include 'mpif.h'
+#endif
+!      include 'COMMON.SETUP'
+!      include 'COMMON.DERIV'
+!      include 'COMMON.IOUNITS'
+!      include 'COMMON.GEO'
+!      include 'COMMON.CHAIN'
+!      include 'COMMON.VAR'
+      integer :: n,nf,k,i,j
+      real(kind=8) :: energia(0:n_ene)
+      real(kind=8),external :: ufparm
+      integer :: uiparm(1)                                                 
+      real(kind=8) :: urparm(1)                                                    
+      real(kind=8),dimension(6*nres) :: x      !(maxvar) (maxvar=6*maxres)
+      real(kind=8) :: f
+      nfl=nf
+!bad      icg=mod(nf,2)+1
+      icg=1
+
+      k=0
+      do i=1,nres-1
+        do j=1,3
+          k=k+1
+          dc(j,i)=x(k)
+        enddo
+      enddo
+      do i=2,nres-1
+        if (ialph(i,1).gt.0) then
+        do j=1,3
+          k=k+1
+          dc(j,i+nres)=x(k)
+        enddo
+        endif
+      enddo
+      call chainbuild_cart
+
+      call zerograd
+      call etotal(energia)
+      f=energia(0)
+
+!d      print *,'func_dc ',nf,nfl,f
+
+      return
+      end subroutine func_dc
+!-----------------------------------------------------------------------------
+      subroutine grad_dc(n,x,nf,g,uiparm,urparm,ufparm)
+
+      use MPI_data
+      use energy, only: cartgrad,zerograd,etotal
+!      use MD_data
+!      implicit real*8 (a-h,o-z)
+!      include 'DIMENSIONS'
+#ifdef MPI
+      include 'mpif.h'
+#endif
+!      include 'COMMON.SETUP'
+!      include 'COMMON.CHAIN'
+!      include 'COMMON.DERIV'
+!      include 'COMMON.VAR'
+!      include 'COMMON.INTERACT'
+!      include 'COMMON.FFIELD'
+!      include 'COMMON.MD'
+!      include 'COMMON.IOUNITS'
+      real(kind=8),external :: ufparm
+      integer :: n,nf,i,j,k
+      integer :: uiparm(1)
+      real(kind=8) :: urparm(1)
+      real(kind=8),dimension(6*nres) :: x,g    !(maxvar) (maxvar=6*maxres)
+      real(kind=8) :: f
+!
+!elwrite(iout,*) "jestesmy w grad dc"
+!
+!bad      icg=mod(nf,2)+1
+      icg=1
+!d      print *,'grad_dc ',nf,nfl,nf-nfl+1,icg
+!elwrite(iout,*) "jestesmy w grad dc nf-nfl+1", nf-nfl+1
+      if (nf-nfl+1) 20,30,40
+   20 call func_dc(n,x,nf,f,uiparm,urparm,ufparm)
+!d      print *,20
+      if (nf.eq.0) return
+      goto 40
+   30 continue
+!d      print *,30
+      k=0
+      do i=1,nres-1
+        do j=1,3
+          k=k+1
+          dc(j,i)=x(k)
+        enddo
+      enddo
+      do i=2,nres-1
+        if (ialph(i,1).gt.0) then
+        do j=1,3
+          k=k+1
+          dc(j,i+nres)=x(k)
+        enddo
+        endif
+      enddo
+!elwrite(iout,*) "jestesmy w grad dc"
+      call chainbuild_cart
+
+!
+! Evaluate the derivatives of virtual bond lengths and SC vectors in variables.
+!
+   40 call cartgrad
+!d      print *,40
+!elwrite(iout,*) "jestesmy w grad dc"
+      k=0
+      do i=1,nres-1
+        do j=1,3
+          k=k+1
+          g(k)=gcart(j,i)
+        enddo
+      enddo
+      do i=2,nres-1
+        if (ialph(i,1).gt.0) then
+        do j=1,3
+          k=k+1
+          g(k)=gxcart(j,i)
+        enddo
+        endif
+      enddo       
+!elwrite(iout,*) "jestesmy w grad dc"
+
+      return
+      end subroutine grad_dc
+!-----------------------------------------------------------------------------
+! minim_mcmf.F
+!-----------------------------------------------------------------------------
+#ifdef MPI
+      subroutine minim_mcmf
+
+      use MPI_data
+      use csa_data
+      use energy, only: func,gradient,fdum
+!      implicit real*8 (a-h,o-z)
+!      include 'DIMENSIONS'
+      include 'mpif.h'
+      integer,parameter :: liv=60
+!      integer :: lv=(77+(6*nres)*(6*nres+17)/2) !(77+maxvar*(maxvar+17)/2)) (maxvar=6*maxres)
+!      include 'COMMON.VAR'
+!      include 'COMMON.IOUNITS'
+!      include 'COMMON.MINIM'
+!      real(kind=8) :: fdum
+!      external func,gradient,fdum
+!el      real(kind=4) :: ran1,ran2,ran3
+!      include 'COMMON.SETUP'
+!      include 'COMMON.GEO'
+!      include 'COMMON.CHAIN'
+!      include 'COMMON.FFIELD'
+      real(kind=8),dimension(6*nres) :: var    !(maxvar) (maxvar=6*maxres)
+      real(kind=8),dimension(mxch*(mxch+1)/2+1) :: erg
+      real(kind=8),dimension(6*nres) :: d,garbage      !(maxvar) (maxvar=6*maxres)
+!el      real(kind=8) :: v(1:77+(6*nres)*(6*nres+17)/2+1)                    
+      integer,dimension(6) :: indx
+      integer,dimension(liv) :: iv                                               
+      integer :: lv,idum(1),nf !
+      real(kind=8) :: rdum(1)
+      real(kind=8) :: przes(3),obrot(3,3),eee
+      logical :: non_conv
+
+      integer,dimension(MPI_STATUS_SIZE) :: muster
+
+      integer :: ichuj,i,ierr
+      real(kind=8) :: rad,ene0
+      data rad /1.745329252d-2/
+!el      common /przechowalnia/ v
+
+      lv=(77+(6*nres)*(6*nres+17)/2) !(77+maxvar*(maxvar+17)/2)) (maxvar=6*maxres)
+      if (.not. allocated(v)) allocate(v(1:lv))
+
+      ichuj=0
+   10 continue
+      ichuj = ichuj + 1
+      call mpi_recv(indx,6,mpi_integer,king,idint,CG_COMM,&
+                    muster,ierr)
+      if (indx(1).eq.0) return
+!      print *, 'worker ',me,' received order ',n,ichuj
+      call mpi_recv(var,nvar,mpi_double_precision,&
+                    king,idreal,CG_COMM,muster,ierr)
+      call mpi_recv(ene0,1,mpi_double_precision,&
+                    king,idreal,CG_COMM,muster,ierr)
+!      print *, 'worker ',me,' var read '
+
+
+      call deflt(2,iv,liv,lv,v)                                         
+! 12 means fresh start, dont call deflt                                 
+      iv(1)=12                                                          
+! max num of fun calls                                                  
+      if (maxfun.eq.0) maxfun=500
+      iv(17)=maxfun
+! max num of iterations                                                 
+      if (maxmin.eq.0) maxmin=1000
+      iv(18)=maxmin
+! controls output                                                       
+      iv(19)=2                                                          
+! selects output unit                                                   
+!      iv(21)=iout                                                       
+      iv(21)=0
+! 1 means to print out result                                           
+      iv(22)=0                                                          
+! 1 means to print out summary stats                                    
+      iv(23)=0                                                          
+! 1 means to print initial x and d                                      
+      iv(24)=0                                                          
+! min val for v(radfac) default is 0.1                                  
+      v(24)=0.1D0                                                       
+! max val for v(radfac) default is 4.0                                  
+      v(25)=2.0D0                                                       
+! check false conv if (act fnctn decrease) .lt. v(26)*(exp decrease)    
+! the sumsl default is 0.1                                              
+      v(26)=0.1D0
+! false conv if (act fnctn decrease) .lt. v(34)                         
+! the sumsl default is 100*machep                                       
+      v(34)=v(34)/100.0D0                                               
+! absolute convergence                                                  
+      if (tolf.eq.0.0D0) tolf=1.0D-4
+      v(31)=tolf
+! relative convergence                                                  
+      if (rtolf.eq.0.0D0) rtolf=1.0D-4
+      v(32)=rtolf
+! controls initial step size                                            
+       v(35)=1.0D-1                                                    
+! large vals of d correspond to small components of step                
+      do i=1,nphi
+        d(i)=1.0D-1
+      enddo
+      do i=nphi+1,nvar
+        d(i)=1.0D-1
+      enddo
+!  minimize energy
+
+      call func(nvar,var,nf,eee,idum,rdum,fdum)
+      if(eee.gt.1.0d18) then
+!       print *,'MINIM_JLEE: ',me,' CHUJ NASTAPIL'
+!       print *,' energy before SUMSL =',eee
+!       print *,' aborting local minimization'
+       iv(1)=-1
+       v(10)=eee
+       nf=1
+       go to 201
+      endif
+
+      call sumsl(nvar,d,var,func,gradient,iv,liv,lv,v,idum,rdum,fdum)
+!  find which conformation was returned from sumsl
+        nf=iv(7)+1
+  201  continue
+! total # of ftn evaluations (for iwf=0, it includes all minimizations).
+        indx(4)=nf
+        indx(5)=iv(1)
+        eee=v(10)
+
+        call mpi_send(indx,6,mpi_integer,king,idint,CG_COMM,&
+                       ierr)
+!       print '(a5,i3,15f10.5)', 'ENEX0',indx(1),v(10)
+        call mpi_send(var,nvar,mpi_double_precision,&
+                     king,idreal,CG_COMM,ierr)
+        call mpi_send(eee,1,mpi_double_precision,king,idreal,&
+                       CG_COMM,ierr)
+        call mpi_send(ene0,1,mpi_double_precision,king,idreal,&
+                       CG_COMM,ierr)
+        go to 10
+      return
+      end subroutine minim_mcmf
+#endif
+!-----------------------------------------------------------------------------
+! rmdd.f
+!-----------------------------------------------------------------------------
+!     algorithm 611, collected algorithms from acm.
+!     algorithm appeared in acm-trans. math. software, vol.9, no. 4,
+!     dec., 1983, p. 503-524.
+      integer function imdcon(k)
+!
+      integer :: k
+!
+!  ***  return integer machine-dependent constants  ***
+!
+!     ***  k = 1 means return standard output unit number.   ***
+!     ***  k = 2 means return alternate output unit number.  ***
+!     ***  k = 3 means return  input unit number.            ***
+!          (note -- k = 2, 3 are used only by test programs.)
+!
+!  +++  port version follows...
+!     external i1mach
+!     integer i1mach
+!     integer mdperm(3)
+!     data mdperm(1)/2/, mdperm(2)/4/, mdperm(3)/1/
+!     imdcon = i1mach(mdperm(k))
+!  +++  end of port version  +++
+!
+!  +++  non-port version follows...
+      integer :: mdcon(3)
+      data mdcon(1)/6/, mdcon(2)/8/, mdcon(3)/5/
+      imdcon = mdcon(k)
+!  +++  end of non-port version  +++
+!
+ 999  return
+!  ***  last card of imdcon follows  ***
+      end function imdcon
+!-----------------------------------------------------------------------------
+      real(kind=8) function rmdcon(k)
+!
+!  ***  return machine dependent constants used by nl2sol  ***
+!
+! +++  comments below contain data statements for various machines.  +++
+! +++  to convert to another machine, place a c in column 1 of the   +++
+! +++  data statement line(s) that correspond to the current machine +++
+! +++  and remove the c from column 1 of the data statement line(s)  +++
+! +++  that correspond to the new machine.                           +++
+!
+      integer :: k
+!
+!  ***  the constant returned depends on k...
+!
+!  ***        k = 1... smallest pos. eta such that -eta exists.
+!  ***        k = 2... square root of eta.
+!  ***        k = 3... unit roundoff = smallest pos. no. machep such
+!  ***                 that 1 + machep .gt. 1 .and. 1 - machep .lt. 1.
+!  ***        k = 4... square root of machep.
+!  ***        k = 5... square root of big (see k = 6).
+!  ***        k = 6... largest machine no. big such that -big exists.
+!
+      real(kind=8) :: big, eta, machep
+      integer :: bigi(4), etai(4), machei(4)
+!/+
+!el      real(kind=8) :: dsqrt
+!/
+      equivalence (big,bigi(1)), (eta,etai(1)), (machep,machei(1))
+!
+!  +++  ibm 360, ibm 370, or xerox  +++
+!
+!     data big/z7fffffffffffffff/, eta/z0010000000000000/,
+!    1     machep/z3410000000000000/
+!
+!  +++  data general  +++
+!
+!     data big/0.7237005577d+76/, eta/0.5397605347d-78/,
+!    1     machep/2.22044605d-16/
+!
+!  +++  dec 11  +++
+!
+!     data big/1.7d+38/, eta/2.938735878d-39/, machep/2.775557562d-17/
+!
+!  +++  hp3000  +++
+!
+!     data big/1.157920892d+77/, eta/8.636168556d-78/,
+!    1     machep/5.551115124d-17/
+!
+!  +++  honeywell  +++
+!
+!     data big/1.69d+38/, eta/5.9d-39/, machep/2.1680435d-19/
+!
+!  +++  dec10  +++
+!
+!     data big/"377777100000000000000000/,
+!    1     eta/"002400400000000000000000/,
+!    2     machep/"104400000000000000000000/
+!
+!  +++  burroughs  +++
+!
+!     data big/o0777777777777777,o7777777777777777/,
+!    1     eta/o1771000000000000,o7770000000000000/,
+!    2     machep/o1451000000000000,o0000000000000000/
+!
+!  +++  control data  +++
+!
+!     data big/37767777777777777777b,37167777777777777777b/,
+!    1     eta/00014000000000000000b,00000000000000000000b/,
+!    2     machep/15614000000000000000b,15010000000000000000b/
+!
+!  +++  prime  +++
+!
+!     data big/1.0d+9786/, eta/1.0d-9860/, machep/1.4210855d-14/
+!
+!  +++  univac  +++
+!
+!     data big/8.988d+307/, eta/1.2d-308/, machep/1.734723476d-18/
+!
+!  +++  vax  +++
+!
+      data big/1.7d+38/, eta/2.939d-39/, machep/1.3877788d-17/
+!
+!  +++  cray 1  +++
+!
+!     data bigi(1)/577767777777777777777b/,
+!    1     bigi(2)/000007777777777777776b/,
+!    2     etai(1)/200004000000000000000b/,
+!    3     etai(2)/000000000000000000000b/,
+!    4     machei(1)/377224000000000000000b/,
+!    5     machei(2)/000000000000000000000b/
+!
+!  +++  port library -- requires more than just a data statement... +++
+!
+!     external d1mach
+!     double precision d1mach, zero
+!     data big/0.d+0/, eta/0.d+0/, machep/0.d+0/, zero/0.d+0/
+!     if (big .gt. zero) go to 1
+!        big = d1mach(2)
+!        eta = d1mach(1)
+!        machep = d1mach(4)
+!1    continue
+!
+!  +++ end of port +++
+!
+!-------------------------------  body  --------------------------------
+!
+      go to (10, 20, 30, 40, 50, 60), k
+!
+ 10   rmdcon = eta
+      go to 999
+!
+ 20   rmdcon = dsqrt(256.d+0*eta)/16.d+0
+      go to 999
+!
+ 30   rmdcon = machep
+      go to 999
+!
+ 40   rmdcon = dsqrt(machep)
+      go to 999
+!
+ 50   rmdcon = dsqrt(big/256.d+0)*16.d+0
+      go to 999
+!
+ 60   rmdcon = big
+!
+ 999  return
+!  ***  last card of rmdcon follows  ***
+      end function rmdcon
+!-----------------------------------------------------------------------------
+! sc_move.F
+!-----------------------------------------------------------------------------
+      subroutine sc_move(n_start,n_end,n_maxtry,e_drop,n_fun,etot)
+
+      use control
+      use random, only: iran_num
+      use energy, only: esc
+!     Perform a quick search over side-chain arrangments (over
+!     residues n_start to n_end) for a given (frozen) CA trace
+!     Only side-chains are minimized (at most n_maxtry times each),
+!     not CA positions
+!     Stops if energy drops by e_drop, otherwise tries all residues
+!     in the given range
+!     If there is an energy drop, full minimization may be useful
+!     n_start, n_end CAN be modified by this routine, but only if
+!     out of bounds (n_start <= 1, n_end >= nres, n_start < n_end)
+!     NOTE: this move should never increase the energy
+!rc      implicit none
+
+!     Includes
+!      implicit real*8 (a-h,o-z)
+!      include 'DIMENSIONS'
+      include 'mpif.h'
+!      include 'COMMON.GEO'
+!      include 'COMMON.VAR'
+!      include 'COMMON.HEADER'
+!      include 'COMMON.IOUNITS'
+!      include 'COMMON.CHAIN'
+!      include 'COMMON.FFIELD'
+
+!     External functions
+!el      integer iran_num
+!el      external iran_num
+
+!     Input arguments
+      integer :: n_start,n_end,n_maxtry
+      real(kind=8) :: e_drop
+
+!     Output arguments
+      integer :: n_fun
+      real(kind=8) :: etot
+
+!     Local variables
+!      real(kind=8) :: energy(0:n_ene)
+      real(kind=8) :: cur_alph(2:nres-1),cur_omeg(2:nres-1)
+      real(kind=8) :: orig_e,cur_e
+      integer :: n,n_steps,n_first,n_cur,n_tot !,i
+      real(kind=8) :: orig_w(0:n_ene)
+      real(kind=8) :: wtime
+
+!elwrite(iout,*) "in sc_move etot= ", etot
+!     Set non side-chain weights to zero (minimization is faster)
+!     NOTE: e(2) does not actually depend on the side-chain, only CA
+      orig_w(2)=wscp
+      orig_w(3)=welec
+      orig_w(4)=wcorr
+      orig_w(5)=wcorr5
+      orig_w(6)=wcorr6
+      orig_w(7)=wel_loc
+      orig_w(8)=wturn3
+      orig_w(9)=wturn4
+      orig_w(10)=wturn6
+      orig_w(11)=wang
+      orig_w(13)=wtor
+      orig_w(14)=wtor_d
+      orig_w(15)=wvdwpp
+
+      wscp=0.D0
+      welec=0.D0
+      wcorr=0.D0
+      wcorr5=0.D0
+      wcorr6=0.D0
+      wel_loc=0.D0
+      wturn3=0.D0
+      wturn4=0.D0
+      wturn6=0.D0
+      wang=0.D0
+      wtor=0.D0
+      wtor_d=0.D0
+      wvdwpp=0.D0
+
+!     Make sure n_start, n_end are within proper range
+      if (n_start.lt.2) n_start=2
+      if (n_end.gt.nres-1) n_end=nres-1
+!rc      if (n_start.lt.n_end) then
+      if (n_start.gt.n_end) then
+        n_start=2
+        n_end=nres-1
+      endif
+
+!     Save the initial values of energy and coordinates
+!d      call chainbuild
+!d      call etotal(energy)
+!d      write (iout,*) 'start sc ene',energy(0)
+!d      call enerprint(energy(0))
+!rc      etot=energy(0)
+       n_fun=0
+!rc      orig_e=etot
+!rc      cur_e=orig_e
+!rc      do i=2,nres-1
+!rc        cur_alph(i)=alph(i)
+!rc        cur_omeg(i)=omeg(i)
+!rc      enddo
+
+!t      wtime=MPI_WTIME()
+!     Try (one by one) all specified residues, starting from a
+!     random position in sequence
+!     Stop early if the energy has decreased by at least e_drop
+      n_tot=n_end-n_start+1
+      n_first=iran_num(0,n_tot-1)
+      n_steps=0
+      n=0
+!rc      do while (n.lt.n_tot .and. orig_e-etot.lt.e_drop)
+      do while (n.lt.n_tot)
+        n_cur=n_start+mod(n_first+n,n_tot)
+        call single_sc_move(n_cur,n_maxtry,e_drop,&
+             n_steps,n_fun,etot)
+!elwrite(iout,*) "after msingle sc_move etot= ", etot
+!     If a lower energy was found, update the current structure...
+!rc        if (etot.lt.cur_e) then
+!rc          cur_e=etot
+!rc          do i=2,nres-1
+!rc            cur_alph(i)=alph(i)
+!rc            cur_omeg(i)=omeg(i)
+!rc          enddo
+!rc        else
+!     ...else revert to the previous one
+!rc          etot=cur_e
+!rc          do i=2,nres-1
+!rc            alph(i)=cur_alph(i)
+!rc            omeg(i)=cur_omeg(i)
+!rc          enddo
+!rc        endif
+        n=n+1
+!d
+!d      call chainbuild
+!d      call etotal(energy)
+!d      print *,'running',n,energy(0)
+      enddo
+
+!d      call chainbuild
+!d      call etotal(energy)
+!d      write (iout,*) 'end   sc ene',energy(0)
+
+!     Put the original weights back to calculate the full energy
+      wscp=orig_w(2)
+      welec=orig_w(3)
+      wcorr=orig_w(4)
+      wcorr5=orig_w(5)
+      wcorr6=orig_w(6)
+      wel_loc=orig_w(7)
+      wturn3=orig_w(8)
+      wturn4=orig_w(9)
+      wturn6=orig_w(10)
+      wang=orig_w(11)
+      wtor=orig_w(13)
+      wtor_d=orig_w(14)
+      wvdwpp=orig_w(15)
+
+!rc      n_fun=n_fun+1
+!t      write (iout,*) 'sc_local time= ',MPI_WTIME()-wtime
+      return
+      end subroutine sc_move
+!-----------------------------------------------------------------------------
+      subroutine single_sc_move(res_pick,n_maxtry,e_drop,n_steps,n_fun,e_sc)
+
+!     Perturb one side-chain (res_pick) and minimize the
+!     neighbouring region, keeping all CA's and non-neighbouring
+!     side-chains fixed
+!     Try until e_drop energy improvement is achieved, or n_maxtry
+!     attempts have been made
+!     At the start, e_sc should contain the side-chain-only energy(0)
+!     nsteps and nfun for this move are ADDED to n_steps and n_fun
+!rc      implicit none
+      use energy, only: esc
+      use geometry, only:dist
+!     Includes
+!      implicit real*8 (a-h,o-z)
+!      include 'DIMENSIONS'
+!      include 'COMMON.VAR'
+!      include 'COMMON.INTERACT'
+!      include 'COMMON.CHAIN'
+!      include 'COMMON.MINIM'
+!      include 'COMMON.FFIELD'
+!      include 'COMMON.IOUNITS'
+
+!     External functions
+!el      double precision dist
+!el      external dist
+
+!     Input arguments
+      integer :: res_pick,n_maxtry
+      real(kind=8) :: e_drop
+
+!     Input/Output arguments
+      integer :: n_steps,n_fun
+      real(kind=8) :: e_sc
+
+!     Local variables
+      logical :: fail
+      integer :: i,j
+      integer :: nres_moved
+      integer :: iretcode,loc_nfun,orig_maxfun,n_try
+      real(kind=8) :: sc_dist,sc_dist_cutoff
+!      real(kind=8) :: energy_(0:n_ene)
+      real(kind=8) :: evdw,escloc,orig_e,cur_e
+      real(kind=8) :: cur_alph(2:nres-1),cur_omeg(2:nres-1)
+      real(kind=8) :: var(6*nres)      !(maxvar) (maxvar=6*maxres)
+
+      real(kind=8) :: orig_theta(1:nres),orig_phi(1:nres),&
+           orig_alph(1:nres),orig_omeg(1:nres)
+
+!elwrite(iout,*) "in sinle etot/ e_sc",e_sc
+!     Define what is meant by "neighbouring side-chain"
+      sc_dist_cutoff=5.0D0
+
+!     Don't do glycine or ends
+      i=itype(res_pick)
+      if (i.eq.10 .or. i.eq.ntyp1) return
+
+!     Freeze everything (later will relax only selected side-chains)
+      mask_r=.true.
+      do i=1,nres
+        mask_phi(i)=0
+        mask_theta(i)=0
+        mask_side(i)=0
+      enddo
+
+!     Find the neighbours of the side-chain to move
+!     and save initial variables
+!rc      orig_e=e_sc
+!rc      cur_e=orig_e
+      nres_moved=0
+      do i=2,nres-1
+!     Don't do glycine (itype(j)==10)
+        if (itype(i).ne.10) then
+          sc_dist=dist(nres+i,nres+res_pick)
+        else
+          sc_dist=sc_dist_cutoff
+        endif
+        if (sc_dist.lt.sc_dist_cutoff) then
+          nres_moved=nres_moved+1
+          mask_side(i)=1
+          cur_alph(i)=alph(i)
+          cur_omeg(i)=omeg(i)
+        endif
+      enddo
+
+      call chainbuild
+      call egb1(evdw)
+      call esc(escloc)
+!elwrite(iout,*) "in sinle etot/ e_sc",e_sc
+!elwrite(iout,*) "in sinle wsc=",wsc,"evdw",evdw,"wscloc",wscloc,"escloc",escloc
+      e_sc=wsc*evdw+wscloc*escloc
+!elwrite(iout,*) "in sinle etot/ e_sc",e_sc
+!d      call etotal(energy)
+!d      print *,'new       ',(energy(k),k=0,n_ene)
+      orig_e=e_sc
+      cur_e=orig_e
+
+      n_try=0
+      do while (n_try.lt.n_maxtry .and. orig_e-cur_e.lt.e_drop)
+!     Move the selected residue (don't worry if it fails)
+        call gen_side(iabs(itype(res_pick)),theta(res_pick+1),&
+             alph(res_pick),omeg(res_pick),fail)
+
+!     Minimize the side-chains starting from the new arrangement
+        call geom_to_var(nvar,var)
+        orig_maxfun=maxfun
+        maxfun=7
+
+!rc        do i=1,nres
+!rc          orig_theta(i)=theta(i)
+!rc          orig_phi(i)=phi(i)
+!rc          orig_alph(i)=alph(i)
+!rc          orig_omeg(i)=omeg(i)
+!rc        enddo
+
+!elwrite(iout,*) "in sinle etot/ e_sc",e_sc
+        call minimize_sc1(e_sc,var,iretcode,loc_nfun)
+        
+!elwrite(iout,*) "in sinle etot/ e_sc",e_sc
+!v        write(*,'(2i3,2f12.5,2i3)') 
+!v     &       res_pick,nres_moved,orig_e,e_sc-cur_e,
+!v     &       iretcode,loc_nfun
+
+!$$$        if (iretcode.eq.8) then
+!$$$          write(iout,*)'Coordinates just after code 8'
+!$$$          call chainbuild
+!$$$          call all_varout
+!$$$          call flush(iout)
+!$$$          do i=1,nres
+!$$$            theta(i)=orig_theta(i)
+!$$$            phi(i)=orig_phi(i)
+!$$$            alph(i)=orig_alph(i)
+!$$$            omeg(i)=orig_omeg(i)
+!$$$          enddo
+!$$$          write(iout,*)'Coordinates just before code 8'
+!$$$          call chainbuild
+!$$$          call all_varout
+!$$$          call flush(iout)
+!$$$        endif
+
+        n_fun=n_fun+loc_nfun
+        maxfun=orig_maxfun
+        call var_to_geom(nvar,var)
+
+!     If a lower energy was found, update the current structure...
+        if (e_sc.lt.cur_e) then
+!v              call chainbuild
+!v              call etotal(energy)
+!d              call egb1(evdw)
+!d              call esc(escloc)
+!d              e_sc1=wsc*evdw+wscloc*escloc
+!d              print *,'     new',e_sc1,energy(0)
+!v              print *,'new       ',energy(0)
+!d              call enerprint(energy(0))
+          cur_e=e_sc
+          do i=2,nres-1
+            if (mask_side(i).eq.1) then
+              cur_alph(i)=alph(i)
+              cur_omeg(i)=omeg(i)
+            endif
+          enddo
+        else
+!     ...else revert to the previous one
+          e_sc=cur_e
+          do i=2,nres-1
+            if (mask_side(i).eq.1) then
+              alph(i)=cur_alph(i)
+              omeg(i)=cur_omeg(i)
+            endif
+          enddo
+        endif
+        n_try=n_try+1
+
+      enddo
+      n_steps=n_steps+n_try
+
+!     Reset the minimization mask_r to false
+      mask_r=.false.
+
+      return
+      end subroutine single_sc_move
+!-----------------------------------------------------------------------------
+      subroutine sc_minimize(etot,iretcode,nfun)
+
+!     Minimizes side-chains only, leaving backbone frozen
+!rc      implicit none
+      use energy, only: etotal
+!     Includes
+!      implicit real*8 (a-h,o-z)
+!      include 'DIMENSIONS'
+!      include 'COMMON.VAR'
+!      include 'COMMON.CHAIN'
+!      include 'COMMON.FFIELD'
+
+!     Output arguments
+      real(kind=8) :: etot
+      integer :: iretcode,nfun
+
+!     Local variables
+      integer :: i
+      real(kind=8) :: orig_w(0:n_ene),energy_(0:n_ene)
+      real(kind=8) :: var(6*nres)      !(maxvar)(maxvar=6*maxres)
+
+
+!     Set non side-chain weights to zero (minimization is faster)
+!     NOTE: e(2) does not actually depend on the side-chain, only CA
+      orig_w(2)=wscp
+      orig_w(3)=welec
+      orig_w(4)=wcorr
+      orig_w(5)=wcorr5
+      orig_w(6)=wcorr6
+      orig_w(7)=wel_loc
+      orig_w(8)=wturn3
+      orig_w(9)=wturn4
+      orig_w(10)=wturn6
+      orig_w(11)=wang
+      orig_w(13)=wtor
+      orig_w(14)=wtor_d
+
+      wscp=0.D0
+      welec=0.D0
+      wcorr=0.D0
+      wcorr5=0.D0
+      wcorr6=0.D0
+      wel_loc=0.D0
+      wturn3=0.D0
+      wturn4=0.D0
+      wturn6=0.D0
+      wang=0.D0
+      wtor=0.D0
+      wtor_d=0.D0
+
+!     Prepare to freeze backbone
+      do i=1,nres
+        mask_phi(i)=0
+        mask_theta(i)=0
+        mask_side(i)=1
+      enddo
+
+!     Minimize the side-chains
+      mask_r=.true.
+      call geom_to_var(nvar,var)
+      call minimize(etot,var,iretcode,nfun)
+      call var_to_geom(nvar,var)
+      mask_r=.false.
+
+!     Put the original weights back and calculate the full energy
+      wscp=orig_w(2)
+      welec=orig_w(3)
+      wcorr=orig_w(4)
+      wcorr5=orig_w(5)
+      wcorr6=orig_w(6)
+      wel_loc=orig_w(7)
+      wturn3=orig_w(8)
+      wturn4=orig_w(9)
+      wturn6=orig_w(10)
+      wang=orig_w(11)
+      wtor=orig_w(13)
+      wtor_d=orig_w(14)
+
+      call chainbuild
+      call etotal(energy_)
+      etot=energy_(0)
+
+      return
+      end subroutine sc_minimize
+!-----------------------------------------------------------------------------
+      subroutine minimize_sc1(etot,x,iretcode,nfun)
+
+      use energy, only: func,gradient,fdum,etotal,enerprint
+      use comm_srutu
+!      implicit real*8 (a-h,o-z)
+!      include 'DIMENSIONS'
+      integer,parameter :: liv=60
+      integer :: iretcode,nfun
+!      integer :: lv=(77+(6*nres)*(6*nres+17)/2) !(77+maxvar*(maxvar+17)/2)) (maxvar=6*maxres)
+!      include 'COMMON.IOUNITS'
+!      include 'COMMON.VAR'
+!      include 'COMMON.GEO'
+!      include 'COMMON.MINIM'
+!el      integer :: icall
+!el      common /srutu/ icall
+      integer,dimension(liv) :: iv                                               
+      real(kind=8) :: minval   !,v(1:77+(6*nres)*(6*nres+17)/2)        !(1:lv)
+      real(kind=8),dimension(6*nres) :: x,d,xx !(maxvar) (maxvar=6*maxres)
+      real(kind=8) :: energia(0:n_ene)
+!el      real(kind=8) :: fdum
+!      external gradient,fdum  !func,
+!      external func_restr1,grad_restr1
+      logical :: not_done,change,reduce 
+!el      common /przechowalnia/ v
+
+      integer :: nvar_restr,lv,i,j
+      integer :: idum(1)
+      real(kind=8) :: rdum(1),etot     !,fdum
+
+      lv=(77+(6*nres)*(6*nres+17)/2) !(77+maxvar*(maxvar+17)/2)) (maxvar=6*maxres)
+      if (.not. allocated(v)) allocate(v(1:lv))
+
+      call deflt(2,iv,liv,lv,v)                                         
+! 12 means fresh start, dont call deflt                                 
+      iv(1)=12                                                          
+! max num of fun calls                                                  
+      if (maxfun.eq.0) maxfun=500
+      iv(17)=maxfun
+! max num of iterations                                                 
+      if (maxmin.eq.0) maxmin=1000
+      iv(18)=maxmin
+! controls output                                                       
+      iv(19)=2                                                          
+! selects output unit                                                   
+!     iv(21)=iout                                                       
+      iv(21)=0
+! 1 means to print out result                                           
+      iv(22)=0                                                          
+! 1 means to print out summary stats                                    
+      iv(23)=0                                                          
+! 1 means to print initial x and d                                      
+      iv(24)=0                                                          
+! min val for v(radfac) default is 0.1                                  
+      v(24)=0.1D0                                                       
+! max val for v(radfac) default is 4.0                                  
+      v(25)=2.0D0                                                       
+!     v(25)=4.0D0                                                       
+! check false conv if (act fnctn decrease) .lt. v(26)*(exp decrease)    
+! the sumsl default is 0.1                                              
+      v(26)=0.1D0
+! false conv if (act fnctn decrease) .lt. v(34)                         
+! the sumsl default is 100*machep                                       
+      v(34)=v(34)/100.0D0                                               
+! absolute convergence                                                  
+      if (tolf.eq.0.0D0) tolf=1.0D-4
+      v(31)=tolf
+! relative convergence                                                  
+      if (rtolf.eq.0.0D0) rtolf=1.0D-4
+      v(32)=rtolf
+! controls initial step size                                            
+       v(35)=1.0D-1                                                    
+! large vals of d correspond to small components of step                
+      do i=1,nphi
+        d(i)=1.0D-1
+      enddo
+      do i=nphi+1,nvar
+        d(i)=1.0D-1
+      enddo
+!elmask_r=.false.
+      IF (mask_r) THEN
+       call x2xx(x,xx,nvar_restr)
+       call sumsl(nvar_restr,d,xx,func_restr1,grad_restr1,&
+                          iv,liv,lv,v,idum,rdum,fdum)      
+       call xx2x(x,xx)
+      ELSE
+       call sumsl(nvar,d,x,func,gradient,iv,liv,lv,v,idum,rdum,fdum)      
+      ENDIF
+!el---------------------
+!      write (iout,'(/a)') &
+!        "Cartesian coordinates of the reference structure after SUMSL"
+!      write (iout,'(a,3(3x,a5),5x,3(3x,a5))') &
+!       "Residue","X(CA)","Y(CA)","Z(CA)","X(SC)","Y(SC)","Z(SC)"
+!      do i=1,nres
+!        write (iout,'(a3,1x,i3,3f8.3,5x,3f8.3)') &
+!          restyp(itype(i)),i,(c(j,i),j=1,3),&
+!          (c(j,i+nres),j=1,3)
+!      enddo
+!      call etotal(energia)
+!      call enerprint(energia)
+!el----------------------------
+      etot=v(10)                                                      
+      iretcode=iv(1)
+      nfun=iv(6)
+
+      return
+      end subroutine minimize_sc1
+!-----------------------------------------------------------------------------
+      subroutine func_restr1(n,x,nf,f,uiparm,urparm,ufparm)
+
+      use comm_chu
+      use energy, only: zerograd,esc,sc_grad
+!      implicit real*8 (a-h,o-z)
+!      include 'DIMENSIONS'
+!      include 'COMMON.DERIV'
+!      include 'COMMON.IOUNITS'
+!      include 'COMMON.GEO'
+!      include 'COMMON.FFIELD'
+!      include 'COMMON.INTERACT'
+!      include 'COMMON.TIME1'
+      integer :: n,nf,i,j
+!el      common /chuju/ jjj
+      real(kind=8) :: energia(0:n_ene),evdw,escloc
+      real(kind=8) :: e1,e2,f
+      real(kind=8),external :: ufparm                                                   
+      integer :: uiparm(1)                                                 
+      real(kind=8) :: urparm(1)                                                    
+      real(kind=8),dimension(6*nres) :: x      !(maxvar) (maxvar=6*maxres)
+      nfl=nf
+      icg=mod(nf,2)+1
+
+#ifdef OSF
+!     Intercept NaNs in the coordinates, before calling etotal
+      x_sum=0.D0
+      do i=1,n
+        x_sum=x_sum+x(i)
+      enddo
+      FOUND_NAN=.false.
+      if (x_sum.ne.x_sum) then
+        write(iout,*)"   *** func_restr1 : Found NaN in coordinates"
+        f=1.0D+73
+        FOUND_NAN=.true.
+        return
+      endif
+#endif
+
+      call var_to_geom_restr(n,x)
+      call zerograd
+      call chainbuild
+!d    write (iout,*) 'ETOTAL called from FUNC'
+      call egb1(evdw)
+      call esc(escloc)
+      f=wsc*evdw+wscloc*escloc
+!d      call etotal(energia(0))
+!d      f=wsc*energia(1)+wscloc*energia(12)
+!d      print *,f,evdw,escloc,energia(0)
+!
+! Sum up the components of the Cartesian gradient.
+!
+      do i=1,nct
+        do j=1,3
+          gradx(j,i,icg)=wsc*gvdwx(j,i)
+        enddo
+      enddo
+
+      return
+      end subroutine func_restr1
+!-----------------------------------------------------------------------------
+      subroutine grad_restr1(n,x,nf,g,uiparm,urparm,ufparm)
+
+      use energy, only: cartder,zerograd,esc,sc_grad
+!      implicit real*8 (a-h,o-z)
+!      include 'DIMENSIONS'
+!      include 'COMMON.CHAIN'
+!      include 'COMMON.DERIV'
+!      include 'COMMON.VAR'
+!      include 'COMMON.INTERACT'
+!      include 'COMMON.FFIELD'
+!      include 'COMMON.IOUNITS'
+!el      external ufparm
+      integer :: i,j,k,ind,n,nf,uiparm(1)
+      real(kind=8) :: f,urparm(1)
+      real(kind=8),dimension(6*nres) :: x,g    !(maxvar) (maxvar=6*maxres)
+      integer :: ig,igall,ij
+      real(kind=8) :: gphii,gthetai,galphai,gomegai
+      real(kind=8),external :: ufparm
+
+      icg=mod(nf,2)+1
+      if (nf-nfl+1) 20,30,40
+   20 call func_restr1(n,x,nf,f,uiparm,urparm,ufparm)
+!     write (iout,*) 'grad 20'
+      if (nf.eq.0) return
+      goto 40
+   30 call var_to_geom_restr(n,x)
+      call chainbuild 
+!
+! Evaluate the derivatives of virtual bond lengths and SC vectors in variables.
+!
+   40 call cartder
+!
+! Convert the Cartesian gradient into internal-coordinate gradient.
+!
+
+      ig=0
+      ind=nres-2                                                                    
+      do i=2,nres-2                
+       IF (mask_phi(i+2).eq.1) THEN                                             
+        gphii=0.0D0                                                             
+        do j=i+1,nres-1                                                         
+          ind=ind+1                                 
+          do k=1,3                                                              
+            gphii=gphii+dcdv(k+3,ind)*gradc(k,j,icg)                            
+            gphii=gphii+dxdv(k+3,ind)*gradx(k,j,icg)                           
+          enddo                                                                 
+        enddo                                                                   
+        ig=ig+1
+        g(ig)=gphii
+       ELSE
+        ind=ind+nres-1-i
+       ENDIF
+      enddo                                        
+
+
+      ind=0
+      do i=1,nres-2
+       IF (mask_theta(i+2).eq.1) THEN
+        ig=ig+1
+       gthetai=0.0D0
+       do j=i+1,nres-1
+          ind=ind+1
+         do k=1,3
+            gthetai=gthetai+dcdv(k,ind)*gradc(k,j,icg)
+            gthetai=gthetai+dxdv(k,ind)*gradx(k,j,icg)
+          enddo
+        enddo
+        g(ig)=gthetai
+       ELSE
+        ind=ind+nres-1-i
+       ENDIF
+      enddo
+
+      do i=2,nres-1
+       if (itype(i).ne.10) then
+         IF (mask_side(i).eq.1) THEN
+          ig=ig+1
+          galphai=0.0D0
+         do k=1,3
+           galphai=galphai+dxds(k,i)*gradx(k,i,icg)
+          enddo
+          g(ig)=galphai
+         ENDIF
+        endif
+      enddo
+
+      
+      do i=2,nres-1
+        if (itype(i).ne.10) then
+         IF (mask_side(i).eq.1) THEN
+          ig=ig+1
+         gomegai=0.0D0
+         do k=1,3
+           gomegai=gomegai+dxds(k+3,i)*gradx(k,i,icg)
+          enddo
+         g(ig)=gomegai
+         ENDIF
+        endif
+      enddo
+
+!
+! Add the components corresponding to local energy terms.
+!
+
+      ig=0
+      igall=0
+      do i=4,nres
+        igall=igall+1
+        if (mask_phi(i).eq.1) then
+          ig=ig+1
+          g(ig)=g(ig)+gloc(igall,icg)
+        endif
+      enddo
+
+      do i=3,nres
+        igall=igall+1
+        if (mask_theta(i).eq.1) then
+          ig=ig+1
+          g(ig)=g(ig)+gloc(igall,icg)
+        endif
+      enddo
+     
+      do ij=1,2
+      do i=2,nres-1
+        if (itype(i).ne.10) then
+          igall=igall+1
+          if (mask_side(i).eq.1) then
+            ig=ig+1
+            g(ig)=g(ig)+gloc(igall,icg)
+          endif
+        endif
+      enddo
+      enddo
+
+!d      do i=1,ig
+!d        write (iout,'(a2,i5,a3,f25.8)') 'i=',i,' g=',g(i)
+!d      enddo
+      return
+      end subroutine  grad_restr1
+!-----------------------------------------------------------------------------
+      subroutine egb1(evdw)
+!
+! This subroutine calculates the interaction energy of nonbonded side chains
+! assuming the Gay-Berne potential of interaction.
+!
+      use calc_data
+      use energy, only: sc_grad
+!      use control, only:stopx
+!      implicit real*8 (a-h,o-z)
+!      include 'DIMENSIONS'
+!      include 'COMMON.GEO'
+!      include 'COMMON.VAR'
+!      include 'COMMON.LOCAL'
+!      include 'COMMON.CHAIN'
+!      include 'COMMON.DERIV'
+!      include 'COMMON.NAMES'
+!      include 'COMMON.INTERACT'
+!      include 'COMMON.IOUNITS'
+!      include 'COMMON.CALC'
+!      include 'COMMON.CONTROL'
+      logical :: lprn
+      real(kind=8) :: evdw
+!el local variables
+      integer :: iint,ind,itypi,itypi1,itypj
+      real(kind=8) :: xi,yi,zi,rrij,sig,sig0ij,rij_shift,fac,e1,e2,&
+                  sigm,epsi
+!elwrite(iout,*) "check evdw"
+!     print *,'Entering EGB nnt=',nnt,' nct=',nct,' expon=',expon
+      evdw=0.0D0
+      lprn=.false.
+!     if (icall.eq.0) lprn=.true.
+      ind=0
+      do i=iatsc_s,iatsc_e
+
+        itypi=iabs(itype(i))
+        itypi1=iabs(itype(i+1))
+        xi=c(1,nres+i)
+        yi=c(2,nres+i)
+        zi=c(3,nres+i)
+        dxi=dc_norm(1,nres+i)
+        dyi=dc_norm(2,nres+i)
+        dzi=dc_norm(3,nres+i)
+        dsci_inv=dsc_inv(itypi)
+!elwrite(iout,*) itypi,itypi1,xi,yi,zi,dxi,dyi,dzi,dsci_inv
+!
+! Calculate SC interaction energy.
+!
+        do iint=1,nint_gr(i)
+          do j=istart(i,iint),iend(i,iint)
+          IF (mask_side(j).eq.1.or.mask_side(i).eq.1) THEN
+            ind=ind+1
+            itypj=iabs(itype(j))
+            dscj_inv=dsc_inv(itypj)
+            sig0ij=sigma(itypi,itypj)
+            chi1=chi(itypi,itypj)
+            chi2=chi(itypj,itypi)
+            chi12=chi1*chi2
+            chip1=chip(itypi)
+            chip2=chip(itypj)
+            chip12=chip1*chip2
+            alf1=alp(itypi)
+            alf2=alp(itypj)
+            alf12=0.5D0*(alf1+alf2)
+! For diagnostics only!!!
+!           chi1=0.0D0
+!           chi2=0.0D0
+!           chi12=0.0D0
+!           chip1=0.0D0
+!           chip2=0.0D0
+!           chip12=0.0D0
+!           alf1=0.0D0
+!           alf2=0.0D0
+!           alf12=0.0D0
+            xj=c(1,nres+j)-xi
+            yj=c(2,nres+j)-yi
+            zj=c(3,nres+j)-zi
+            dxj=dc_norm(1,nres+j)
+            dyj=dc_norm(2,nres+j)
+            dzj=dc_norm(3,nres+j)
+            rrij=1.0D0/(xj*xj+yj*yj+zj*zj)
+            rij=dsqrt(rrij)
+! Calculate angle-dependent terms of energy and contributions to their
+! derivatives.
+            call sc_angular
+            sigsq=1.0D0/sigsq
+            sig=sig0ij*dsqrt(sigsq)
+            rij_shift=1.0D0/rij-sig+sig0ij
+! I hate to put IF's in the loops, but here don't have another choice!!!!
+            if (rij_shift.le.0.0D0) then
+              evdw=1.0D20
+!d              write (iout,'(2(a3,i3,2x),17(0pf7.3))') &
+!d              restyp(itypi),i,restyp(itypj),j, &
+!d              rij_shift,1.0D0/rij,sig,sig0ij,sigsq,1-dsqrt(sigsq)
+              return
+            endif
+            sigder=-sig*sigsq
+!---------------------------------------------------------------
+            rij_shift=1.0D0/rij_shift 
+            fac=rij_shift**expon
+            e1=fac*fac*aa(itypi,itypj)
+            e2=fac*bb(itypi,itypj)
+            evdwij=eps1*eps2rt*eps3rt*(e1+e2)
+            eps2der=evdwij*eps3rt
+            eps3der=evdwij*eps2rt
+            evdwij=evdwij*eps2rt*eps3rt
+            evdw=evdw+evdwij
+            if (lprn) then
+            sigm=dabs(aa(itypi,itypj)/bb(itypi,itypj))**(1.0D0/6.0D0)
+            epsi=bb(itypi,itypj)**2/aa(itypi,itypj)
+!d            write (iout,'(2(a3,i3,2x),17(0pf7.3))') &
+!d              restyp(itypi),i,restyp(itypj),j, &
+!d              epsi,sigm,chi1,chi2,chip1,chip2, &
+!d              eps1,eps2rt**2,eps3rt**2,sig,sig0ij, &
+!d              om1,om2,om12,1.0D0/rij,1.0D0/rij_shift, &
+!d              evdwij
+            endif
+
+            if (energy_dec) write (iout,'(a6,2i5,0pf7.3)') &
+                              'evdw',i,j,evdwij
+
+! Calculate gradient components.
+            e1=e1*eps1*eps2rt**2*eps3rt**2
+            fac=-expon*(e1+evdwij)*rij_shift
+            sigder=fac*sigder
+            fac=rij*fac
+! Calculate the radial part of the gradient
+            gg(1)=xj*fac
+            gg(2)=yj*fac
+            gg(3)=zj*fac
+! Calculate angular part of the gradient.
+
+!elwrite(iout,*) evdw
+            call sc_grad
+!elwrite(iout,*) "evdw=",evdw,j,iint,i
+          ENDIF
+!elwrite(iout,*) evdw
+          enddo      ! j
+!elwrite(iout,*) evdw
+        enddo        ! iint
+!elwrite(iout,*) evdw
+      enddo          ! i
+!elwrite(iout,*) evdw,i
+      end subroutine egb1
+!-----------------------------------------------------------------------------
+! sumsld.f
+!-----------------------------------------------------------------------------
+      subroutine sumsl(n,d,x,calcf,calcg,iv,liv,lv,v,uiparm,urparm,ufparm)
+!
+!  ***  minimize general unconstrained objective function using   ***
+!  ***  analytic gradient and hessian approx. from secant update  ***
+!
+!      use control
+      integer :: n, liv, lv
+      integer :: iv(liv), uiparm(1)
+      real(kind=8) :: d(n), x(n), v(lv), urparm(1)
+      real(kind=8),external :: ufparm !funtion name as an argument
+
+!     dimension v(71 + n*(n+15)/2), uiparm(*), urparm(*)
+      external :: calcf, calcg !subroutine name as an argument
+!
+!  ***  purpose  ***
+!
+!        this routine interacts with subroutine  sumit  in an attempt
+!     to find an n-vector  x*  that minimizes the (unconstrained)
+!     objective function computed by  calcf.  (often the  x*  found is
+!     a local minimizer rather than a global one.)
+!
+!--------------------------  parameter usage  --------------------------
+!
+! n........ (input) the number of variables on which  f  depends, i.e.,
+!                  the number of components in  x.
+! d........ (input/output) a scale vector such that  d(i)*x(i),
+!                  i = 1,2,...,n,  are all in comparable units.
+!                  d can strongly affect the behavior of sumsl.
+!                  finding the best choice of d is generally a trial-
+!                  and-error process.  choosing d so that d(i)*x(i)
+!                  has about the same value for all i often works well.
+!                  the defaults provided by subroutine deflt (see i
+!                  below) require the caller to supply d.
+! x........ (input/output) before (initially) calling sumsl, the call-
+!                  er should set  x  to an initial guess at  x*.  when
+!                  sumsl returns,  x  contains the best point so far
+!                  found, i.e., the one that gives the least value so
+!                  far seen for  f(x).
+! calcf.... (input) a subroutine that, given x, computes f(x).  calcf
+!                  must be declared external in the calling program.
+!                  it is invoked by
+!                       call calcf(n, x, nf, f, uiparm, urparm, ufparm)
+!                  when calcf is called, nf is the invocation
+!                  count for calcf.  nf is included for possible use
+!                  with calcg.  if x is out of bounds (e.g., if it
+!                  would cause overflow in computing f(x)), then calcf
+!                  should set nf to 0.  this will cause a shorter step
+!                  to be attempted.  (if x is in bounds, then calcf
+!                  should not change nf.)  the other parameters are as
+!                  described above and below.  calcf should not change
+!                  n, p, or x.
+! calcg.... (input) a subroutine that, given x, computes g(x), the gra-
+!                  dient of f at x.  calcg must be declared external in
+!                  the calling program.  it is invoked by
+!                       call calcg(n, x, nf, g, uiparm, urparm, ufaprm)
+!                  when calcg is called, nf is the invocation
+!                  count for calcf at the time f(x) was evaluated.  the
+!                  x passed to calcg is usually the one passed to calcf
+!                  on either its most recent invocation or the one
+!                  prior to it.  if calcf saves intermediate results
+!                  for use by calcg, then it is possible to tell from
+!                  nf whether they are valid for the current x (or
+!                  which copy is valid if two copies are kept).  if g
+!                  cannot be computed at x, then calcg should set nf to
+!                  0.  in this case, sumsl will return with iv(1) = 65.
+!                  (if g can be computed at x, then calcg should not
+!                  changed nf.)  the other parameters to calcg are as
+!                  described above and below.  calcg should not change
+!                  n or x.
+! iv....... (input/output) an integer value array of length liv (see
+!                  below) that helps control the sumsl algorithm and
+!                  that is used to store various intermediate quanti-
+!                  ties.  of particular interest are the initialization/
+!                  return code iv(1) and the entries in iv that control
+!                  printing and limit the number of iterations and func-
+!                  tion evaluations.  see the section on iv input
+!                  values below.
+! liv...... (input) length of iv array.  must be at least 60.  if li
+!                  is too small, then sumsl returns with iv(1) = 15.
+!                  when sumsl returns, the smallest allowed value of
+!                  liv is stored in iv(lastiv) -- see the section on
+!                  iv output values below.  (this is intended for use
+!                  with extensions of sumsl that handle constraints.)
+! lv....... (input) length of v array.  must be at least 71+n*(n+15)/2.
+!                  (at least 77+n*(n+17)/2 for smsno, at least
+!                  78+n*(n+12) for humsl).  if lv is too small, then
+!                  sumsl returns with iv(1) = 16.  when sumsl returns,
+!                  the smallest allowed value of lv is stored in
+!                  iv(lastv) -- see the section on iv output values
+!                  below.
+! v........ (input/output) a floating-point value array of length l
+!                  (see below) that helps control the sumsl algorithm
+!                  and that is used to store various intermediate
+!                  quantities.  of particular interest are the entries
+!                  in v that limit the length of the first step
+!                  attempted (lmax0) and specify convergence tolerances
+!                  (afctol, lmaxs, rfctol, sctol, xctol, xftol).
+! uiparm... (input) user integer parameter array passed without change
+!                  to calcf and calcg.
+! urparm... (input) user floating-point parameter array passed without
+!                  change to calcf and calcg.
+! ufparm... (input) user external subroutine or function passed without
+!                  change to calcf and calcg.
+!
+!  ***  iv input values (from subroutine deflt)  ***
+!
+! iv(1)...  on input, iv(1) should have a value between 0 and 14......
+!             0 and 12 mean this is a fresh start.  0 means that
+!                  deflt(2, iv, liv, lv, v)
+!             is to be called to provide all default values to iv and
+!             v.  12 (the value that deflt assigns to iv(1)) means the
+!             caller has already called deflt and has possibly changed
+!             some iv and/or v entries to non-default values.
+!             13 means deflt has been called and that sumsl (and
+!             sumit) should only do their storage allocation.  that is,
+!             they should set the output components of iv that tell
+!             where various subarrays arrays of v begin, such as iv(g)
+!             (and, for humsl and humit only, iv(dtol)), and return.
+!             14 means that a storage has been allocated (by a call
+!             with iv(1) = 13) and that the algorithm should be
+!             started.  when called with iv(1) = 13, sumsl returns
+!             iv(1) = 14 unless liv or lv is too small (or n is not
+!             positive).  default = 12.
+! iv(inith).... iv(25) tells whether the hessian approximation h should
+!             be initialized.  1 (the default) means sumit should
+!             initialize h to the diagonal matrix whose i-th diagonal
+!             element is d(i)**2.  0 means the caller has supplied a
+!             cholesky factor  l  of the initial hessian approximation
+!             h = l*(l**t)  in v, starting at v(iv(lmat)) = v(iv(42))
+!             (and stored compactly by rows).  note that iv(lmat) may
+!             be initialized by calling sumsl with iv(1) = 13 (see
+!             the iv(1) discussion above).  default = 1.
+! iv(mxfcal)... iv(17) gives the maximum number of function evaluations
+!             (calls on calcf) allowed.  if this number does not suf-
+!             fice, then sumsl returns with iv(1) = 9.  default = 200.
+! iv(mxiter)... iv(18) gives the maximum number of iterations allowed.
+!             it also indirectly limits the number of gradient evalua-
+!             tions (calls on calcg) to iv(mxiter) + 1.  if iv(mxiter)
+!             iterations do not suffice, then sumsl returns with
+!             iv(1) = 10.  default = 150.
+! iv(outlev)... iv(19) controls the number and length of iteration sum-
+!             mary lines printed (by itsum).  iv(outlev) = 0 means do
+!             not print any summary lines.  otherwise, print a summary
+!             line after each abs(iv(outlev)) iterations.  if iv(outlev)
+!             is positive, then summary lines of length 78 (plus carri-
+!             age control) are printed, including the following...  the
+!             iteration and function evaluation counts, f = the current
+!             function value, relative difference in function values
+!             achieved by the latest step (i.e., reldf = (f0-v(f))/f01,
+!             where f01 is the maximum of abs(v(f)) and abs(v(f0)) and
+!             v(f0) is the function value from the previous itera-
+!             tion), the relative function reduction predicted for the
+!             step just taken (i.e., preldf = v(preduc) / f01, where
+!             v(preduc) is described below), the scaled relative change
+!             in x (see v(reldx) below), the step parameter for the
+!             step just taken (stppar = 0 means a full newton step,
+!             between 0 and 1 means a relaxed newton step, between 1
+!             and 2 means a double dogleg step, greater than 2 means
+!             a scaled down cauchy step -- see subroutine dbldog), the
+!             2-norm of the scale vector d times the step just taken
+!             (see v(dstnrm) below), and npreldf, i.e.,
+!             v(nreduc)/f01, where v(nreduc) is described below -- if
+!             npreldf is positive, then it is the relative function
+!             reduction predicted for a newton step (one with
+!             stppar = 0).  if npreldf is negative, then it is the
+!             negative of the relative function reduction predicted
+!             for a step computed with step bound v(lmaxs) for use in
+!             testing for singular convergence.
+!                  if iv(outlev) is negative, then lines of length 50
+!             are printed, including only the first 6 items listed
+!             above (through reldx).
+!             default = 1.
+! iv(parprt)... iv(20) = 1 means print any nondefault v values on a
+!             fresh start or any changed v values on a restart.
+!             iv(parprt) = 0 means skip this printing.  default = 1.
+! iv(prunit)... iv(21) is the output unit number on which all printing
+!             is done.  iv(prunit) = 0 means suppress all printing.
+!             default = standard output unit (unit 6 on most systems).
+! iv(solprt)... iv(22) = 1 means print out the value of x returned (as
+!             well as the gradient and the scale vector d).
+!             iv(solprt) = 0 means skip this printing.  default = 1.
+! iv(statpr)... iv(23) = 1 means print summary statistics upon return-
+!             ing.  these consist of the function value, the scaled
+!             relative change in x caused by the most recent step (see
+!             v(reldx) below), the number of function and gradient
+!             evaluations (calls on calcf and calcg), and the relative
+!             function reductions predicted for the last step taken and
+!             for a newton step (or perhaps a step bounded by v(lmaxs)
+!             -- see the descriptions of preldf and npreldf under
+!             iv(outlev) above).
+!             iv(statpr) = 0 means skip this printing.
+!             iv(statpr) = -1 means skip this printing as well as that
+!             of the one-line termination reason message.  default = 1.
+! iv(x0prt).... iv(24) = 1 means print the initial x and scale vector d
+!             (on a fresh start only).  iv(x0prt) = 0 means skip this
+!             printing.  default = 1.
+!
+!  ***  (selected) iv output values  ***
+!
+! iv(1)........ on output, iv(1) is a return code....
+!             3 = x-convergence.  the scaled relative difference (see
+!                  v(reldx)) between the current parameter vector x and
+!                  a locally optimal parameter vector is very likely at
+!                  most v(xctol).
+!             4 = relative function convergence.  the relative differ-
+!                  ence between the current function value and its lo-
+!                  cally optimal value is very likely at most v(rfctol).
+!             5 = both x- and relative function convergence (i.e., the
+!                  conditions for iv(1) = 3 and iv(1) = 4 both hold).
+!             6 = absolute function convergence.  the current function
+!                  value is at most v(afctol) in absolute value.
+!             7 = singular convergence.  the hessian near the current
+!                  iterate appears to be singular or nearly so, and a
+!                  step of length at most v(lmaxs) is unlikely to yield
+!                  a relative function decrease of more than v(sctol).
+!             8 = false convergence.  the iterates appear to be converg-
+!                  ing to a noncritical point.  this may mean that the
+!                  convergence tolerances (v(afctol), v(rfctol),
+!                  v(xctol)) are too small for the accuracy to which
+!                  the function and gradient are being computed, that
+!                  there is an error in computing the gradient, or that
+!                  the function or gradient is discontinuous near x.
+!             9 = function evaluation limit reached without other con-
+!                  vergence (see iv(mxfcal)).
+!            10 = iteration limit reached without other convergence
+!                  (see iv(mxiter)).
+!            11 = stopx returned .true. (external interrupt).  see the
+!                  usage notes below.
+!            14 = storage has been allocated (after a call with
+!                  iv(1) = 13).
+!            17 = restart attempted with n changed.
+!            18 = d has a negative component and iv(dtype) .le. 0.
+!            19...43 = v(iv(1)) is out of range.
+!            63 = f(x) cannot be computed at the initial x.
+!            64 = bad parameters passed to assess (which should not
+!                  occur).
+!            65 = the gradient could not be computed at x (see calcg
+!                  above).
+!            67 = bad first parameter to deflt.
+!            80 = iv(1) was out of range.
+!            81 = n is not positive.
+! iv(g)........ iv(28) is the starting subscript in v of the current
+!             gradient vector (the one corresponding to x).
+! iv(lastiv)... iv(44) is the least acceptable value of liv.  (it is
+!             only set if liv is at least 44.)
+! iv(lastv).... iv(45) is the least acceptable value of lv.  (it is
+!             only set if liv is large enough, at least iv(lastiv).)
+! iv(nfcall)... iv(6) is the number of calls so far made on calcf (i.e.,
+!             function evaluations).
+! iv(ngcall)... iv(30) is the number of gradient evaluations (calls on
+!             calcg).
+! iv(niter).... iv(31) is the number of iterations performed.
+!
+!  ***  (selected) v input values (from subroutine deflt)  ***
+!
+! v(bias)..... v(43) is the bias parameter used in subroutine dbldog --
+!             see that subroutine for details.  default = 0.8.
+! v(afctol)... v(31) is the absolute function convergence tolerance.
+!             if sumsl finds a point where the function value is less
+!             than v(afctol) in absolute value, and if sumsl does not
+!             return with iv(1) = 3, 4, or 5, then it returns with
+!             iv(1) = 6.  this test can be turned off by setting
+!             v(afctol) to zero.  default = max(10**-20, machep**2),
+!             where machep is the unit roundoff.
+! v(dinit).... v(38), if nonnegative, is the value to which the scale
+!             vector d is initialized.  default = -1.
+! v(lmax0).... v(35) gives the maximum 2-norm allowed for d times the
+!             very first step that sumsl attempts.  this parameter can
+!             markedly affect the performance of sumsl.
+! v(lmaxs).... v(36) is used in testing for singular convergence -- if
+!             the function reduction predicted for a step of length
+!             bounded by v(lmaxs) is at most v(sctol) * abs(f0), where
+!             f0  is the function value at the start of the current
+!             iteration, and if sumsl does not return with iv(1) = 3,
+!             4, 5, or 6, then it returns with iv(1) = 7.  default = 1.
+! v(rfctol)... v(32) is the relative function convergence tolerance.
+!             if the current model predicts a maximum possible function
+!             reduction (see v(nreduc)) of at most v(rfctol)*abs(f0)
+!             at the start of the current iteration, where  f0  is the
+!             then current function value, and if the last step attempt-
+!             ed achieved no more than twice the predicted function
+!             decrease, then sumsl returns with iv(1) = 4 (or 5).
+!             default = max(10**-10, machep**(2/3)), where machep is
+!             the unit roundoff.
+! v(sctol).... v(37) is the singular convergence tolerance -- see the
+!             description of v(lmaxs) above.
+! v(tuner1)... v(26) helps decide when to check for false convergence.
+!             this is done if the actual function decrease from the
+!             current step is no more than v(tuner1) times its predict-
+!             ed value.  default = 0.1.
+! v(xctol).... v(33) is the x-convergence tolerance.  if a newton step
+!             (see v(nreduc)) is tried that has v(reldx) .le. v(xctol)
+!             and if this step yields at most twice the predicted func-
+!             tion decrease, then sumsl returns with iv(1) = 3 (or 5).
+!             (see the description of v(reldx) below.)
+!             default = machep**0.5, where machep is the unit roundoff.
+! v(xftol).... v(34) is the false convergence tolerance.  if a step is
+!             tried that gives no more than v(tuner1) times the predict-
+!             ed function decrease and that has v(reldx) .le. v(xftol),
+!             and if sumsl does not return with iv(1) = 3, 4, 5, 6, or
+!             7, then it returns with iv(1) = 8.  (see the description
+!             of v(reldx) below.)  default = 100*machep, where
+!             machep is the unit roundoff.
+! v(*)........ deflt supplies to v a number of tuning constants, with
+!             which it should ordinarily be unnecessary to tinker.  see
+!             section 17 of version 2.2 of the nl2sol usage summary
+!             (i.e., the appendix to ref. 1) for details on v(i),
+!             i = decfac, incfac, phmnfc, phmxfc, rdfcmn, rdfcmx,
+!             tuner2, tuner3, tuner4, tuner5.
+!
+!  ***  (selected) v output values  ***
+!
+! v(dgnorm)... v(1) is the 2-norm of (diag(d)**-1)*g, where g is the
+!             most recently computed gradient.
+! v(dstnrm)... v(2) is the 2-norm of diag(d)*step, where step is the
+!             current step.
+! v(f)........ v(10) is the current function value.
+! v(f0)....... v(13) is the function value at the start of the current
+!             iteration.
+! v(nreduc)... v(6), if positive, is the maximum function reduction
+!             possible according to the current model, i.e., the func-
+!             tion reduction predicted for a newton step (i.e.,
+!             step = -h**-1 * g,  where  g  is the current gradient and
+!             h is the current hessian approximation).
+!                  if v(nreduc) is negative, then it is the negative of
+!             the function reduction predicted for a step computed with
+!             a step bound of v(lmaxs) for use in testing for singular
+!             convergence.
+! v(preduc)... v(7) is the function reduction predicted (by the current
+!             quadratic model) for the current step.  this (divided by
+!             v(f0)) is used in testing for relative function
+!             convergence.
+! v(reldx).... v(17) is the scaled relative change in x caused by the
+!             current step, computed as
+!                  max(abs(d(i)*(x(i)-x0(i)), 1 .le. i .le. p) /
+!                     max(d(i)*(abs(x(i))+abs(x0(i))), 1 .le. i .le. p),
+!             where x = x0 + step.
+!
+!-------------------------------  notes  -------------------------------
+!
+!  ***  algorithm notes  ***
+!
+!        this routine uses a hessian approximation computed from the
+!     bfgs update (see ref 3).  only a cholesky factor of the hessian
+!     approximation is stored, and this is updated using ideas from
+!     ref. 4.  steps are computed by the double dogleg scheme described
+!     in ref. 2.  the steps are assessed as in ref. 1.
+!
+!  ***  usage notes  ***
+!
+!        after a return with iv(1) .le. 11, it is possible to restart,
+!     i.e., to change some of the iv and v input values described above
+!     and continue the algorithm from the point where it was interrupt-
+!     ed.  iv(1) should not be changed, nor should any entries of i
+!     and v other than the input values (those supplied by deflt).
+!        those who do not wish to write a calcg which computes the
+!     gradient analytically should call smsno rather than sumsl.
+!     smsno uses finite differences to compute an approximate gradient.
+!        those who would prefer to provide f and g (the function and
+!     gradient) by reverse communication rather than by writing subrou-
+!     tines calcf and calcg may call on sumit directly.  see the com-
+!     ments at the beginning of sumit.
+!        those who use sumsl interactively may wish to supply their
+!     own stopx function, which should return .true. if the break key
+!     has been pressed since stopx was last invoked.  this makes it
+!     possible to externally interrupt sumsl (which will return with
+!     iv(1) = 11 if stopx returns .true.).
+!        storage for g is allocated at the end of v.  thus the caller
+!     may make v longer than specified above and may allow calcg to use
+!     elements of g beyond the first n as scratch storage.
+!
+!  ***  portability notes  ***
+!
+!        the sumsl distribution tape contains both single- and double-
+!     precision versions of the sumsl source code, so it should be un-
+!     necessary to change precisions.
+!        only the functions imdcon and rmdcon contain machine-dependent
+!     constants.  to change from one machine to another, it should
+!     suffice to change the (few) relevant lines in these functions.
+!        intrinsic functions are explicitly declared.  on certain com-
+!     puters (e.g. univac), it may be necessary to comment out these
+!     declarations.  so that this may be done automatically by a simple
+!     program, such declarations are preceded by a comment having c/+
+!     in columns 1-3 and blanks in columns 4-72 and are followed by
+!     a comment having c/ in columns 1 and 2 and blanks in columns 3-72.
+!        the sumsl source code is expressed in 1966 ansi standard
+!     fortran.  it may be converted to fortran 77 by commenting out all
+!     lines that fall between a line having c/6 in columns 1-3 and a
+!     line having c/7 in columns 1-3 and by removing (i.e., replacing
+!     by a blank) the c in column 1 of the lines that follow the c/7
+!     line and precede a line having c/ in columns 1-2 and blanks in
+!     columns 3-72.  these changes convert some data statements into
+!     parameter statements, convert some variables from real to
+!     character*4, and make the data statements that initialize these
+!     variables use character strings delimited by primes instead
+!     of hollerith constants.  (such variables and data statements
+!     appear only in modules itsum and parck.  parameter statements
+!     appear nearly everywhere.)  these changes also add save state-
+!     ments for variables given machine-dependent constants by rmdcon.
+!
+!  ***  references  ***
+!
+! 1.  dennis, j.e., gay, d.m., and welsch, r.e. (1981), algorithm 573 --
+!             an adaptive nonlinear least-squares algorithm, acm trans.
+!             math. software 7, pp. 369-383.
+!
+! 2.  dennis, j.e., and mei, h.h.w. (1979), two new unconstrained opti-
+!             mization algorithms which use function and gradient
+!             values, j. optim. theory applic. 28, pp. 453-482.
+!
+! 3.  dennis, j.e., and more, j.j. (1977), quasi-newton methods, motiva-
+!             tion and theory, siam rev. 19, pp. 46-89.
+!
+! 4.  goldfarb, d. (1976), factorized variable metric methods for uncon-
+!             strained optimization, math. comput. 30, pp. 796-811.
+!
+!  ***  general  ***
+!
+!     coded by david m. gay (winter 1980).  revised summer 1982.
+!     this subroutine was written in connection with research
+!     supported in part by the national science foundation under
+!     grants mcs-7600324, dcr75-10143, 76-14311dss, mcs76-11989,
+!     and mcs-7906671.
+!.
+!
+!----------------------------  declarations  ---------------------------
+!
+!el      external deflt, sumit
+!
+! deflt... supplies default iv and v input components.
+! sumit... reverse-communication routine that carries out sumsl algo-
+!             rithm.
+!
+      integer :: g1, iv1, nf
+      real(kind=8) :: f
+!
+!  ***  subscripts for iv   ***
+!
+!el      integer nextv, nfcall, nfgcal, g, toobig, vneed
+!
+!/6
+!     data nextv/47/, nfcall/6/, nfgcal/7/, g/28/, toobig/2/, vneed/4/
+!/7
+      integer,parameter :: nextv=47, nfcall=6, nfgcal=7, g=28,&
+                           toobig=2, vneed=4
+!/
+!
+!+++++++++++++++++++++++++++++++  body  ++++++++++++++++++++++++++++++++
+!
+!elwrite(iout,*) "in sumsl"
+      if (iv(1) .eq. 0) call deflt(2, iv, liv, lv, v)
+      iv1 = iv(1)
+      if (iv1 .eq. 12 .or. iv1 .eq. 13) iv(vneed) = iv(vneed) + n
+      if (iv1 .eq. 14) go to 10
+      if (iv1 .gt. 2 .and. iv1 .lt. 12) go to 10
+      g1 = 1
+      if (iv1 .eq. 12) iv(1) = 13
+      go to 20
+!
+ 10   g1 = iv(g)
+!elwrite(iout,*) "in sumsl go to 10"
+
+!
+!elwrite(iout,*) "in sumsl"
+ 20   call sumit(d, f, v(g1), iv, liv, lv, n, v, x)
+!elwrite(iout,*) "in sumsl, go to 20"
+  
+!elwrite(iout,*) "in sumsl, go to 20, po sumit"
+!elwrite(iout,*) "in sumsl iv()", iv(1)-2
+      if (iv(1) - 2) 30, 40, 50
+!
+ 30   nf = iv(nfcall)
+!elwrite(iout,*) "in sumsl iv",iv(nfcall)
+      call calcf(n, x, nf, f, uiparm, urparm, ufparm)
+!elwrite(iout,*) "in sumsl"
+      if (nf .le. 0) iv(toobig) = 1
+      go to 20
+!
+!elwrite(iout,*) "in sumsl"
+ 40   call calcg(n, x, iv(nfgcal), v(g1), uiparm, urparm, ufparm)
+!elwrite(iout,*) "in sumsl"
+      go to 20
+!
+ 50   if (iv(1) .ne. 14) go to 999
+!
+!  ***  storage allocation
+!
+      iv(g) = iv(nextv)
+      iv(nextv) = iv(g) + n
+      if (iv1 .ne. 13) go to 10
+!elwrite(iout,*) "in sumsl"
+!
+ 999  return
+!  ***  last card of sumsl follows  ***
+      end subroutine sumsl
+!-----------------------------------------------------------------------------
+      subroutine sumit(d,fx,g,iv,liv,lv,n,v,x)
+      
+      use control, only:stopx
+!
+!  ***  carry out sumsl (unconstrained minimization) iterations, using
+!  ***  double-dogleg/bfgs steps.
+!
+!  ***  parameter declarations  ***
+!
+      integer :: liv, lv, n
+      integer :: iv(liv)
+      real(kind=8) :: d(n), fx, g(n), v(lv), x(n)
+!
+!--------------------------  parameter usage  --------------------------
+!
+! d.... scale vector.
+! fx... function value.
+! g.... gradient vector.
+! iv... integer value array.
+! liv.. length of iv (at least 60).
+! lv... length of v (at least 71 + n*(n+13)/2).
+! n.... number of variables (components in x and g).
+! v.... floating-point value array.
+! x.... vector of parameters to be optimized.
+!
+!  ***  discussion  ***
+!
+!        parameters iv, n, v, and x are the same as the corresponding
+!     ones to sumsl (which see), except that v can be shorter (since
+!     the part of v that sumsl uses for storing g is not needed).
+!     moreover, compared with sumsl, iv(1) may have the two additional
+!     output values 1 and 2, which are explained below, as is the use
+!     of iv(toobig) and iv(nfgcal).  the value iv(g), which is an
+!     output value from sumsl (and smsno), is not referenced by
+!     sumit or the subroutines it calls.
+!        fx and g need not have been initialized when sumit is called
+!     with iv(1) = 12, 13, or 14.
+!
+! iv(1) = 1 means the caller should set fx to f(x), the function value
+!             at x, and call sumit again, having changed none of the
+!             other parameters.  an exception occurs if f(x) cannot be
+!             (e.g. if overflow would occur), which may happen because
+!             of an oversized step.  in this case the caller should set
+!             iv(toobig) = iv(2) to 1, which will cause sumit to ig-
+!             nore fx and try a smaller step.  the parameter nf that
+!             sumsl passes to calcf (for possible use by calcg) is a
+!             copy of iv(nfcall) = iv(6).
+! iv(1) = 2 means the caller should set g to g(x), the gradient vector
+!             of f at x, and call sumit again, having changed none of
+!             the other parameters except possibly the scale vector d
+!             when iv(dtype) = 0.  the parameter nf that sumsl passes
+!             to calcg is iv(nfgcal) = iv(7).  if g(x) cannot be
+!             evaluated, then the caller may set iv(nfgcal) to 0, in
+!             which case sumit will return with iv(1) = 65.
+!.
+!  ***  general  ***
+!
+!     coded by david m. gay (december 1979).  revised sept. 1982.
+!     this subroutine was written in connection with research supported
+!     in part by the national science foundation under grants
+!     mcs-7600324 and mcs-7906671.
+!
+!        (see sumsl for references.)
+!
+!+++++++++++++++++++++++++++  declarations  ++++++++++++++++++++++++++++
+!
+!  ***  local variables  ***
+!
+      integer :: dg1, dummy, g01, i, k, l, lstgst, nwtst1, step1,&
+              temp1, w, x01, z
+      real(kind=8) :: t
+!el      logical :: lstopx
+!
+!     ***  constants  ***
+!
+!el      real(kind=8) :: half, negone, one, onep2, zero
+!
+!  ***  no intrinsic functions  ***
+!
+!  ***  external functions and subroutines  ***
+!
+!el      external assst, dbdog, deflt, dotprd, itsum, litvmu, livmul,
+!el     1         ltvmul, lupdat, lvmul, parck, reldst, stopx, vaxpy,
+!el     2         vcopy, vscopy, vvmulp, v2norm, wzbfgs
+!el      logical stopx
+!el      real(kind=8) :: dotprd, reldst, v2norm
+!
+! assst.... assesses candidate step.
+! dbdog.... computes double-dogleg (candidate) step.
+! deflt.... supplies default iv and v input components.
+! dotprd... returns inner product of two vectors.
+! itsum.... prints iteration summary and info on initial and final x.
+! litvmu... multiplies inverse transpose of lower triangle times vector.
+! livmul... multiplies inverse of lower triangle times vector.
+! ltvmul... multiplies transpose of lower triangle times vector.
+! lupdt.... updates cholesky factor of hessian approximation.
+! lvmul.... multiplies lower triangle times vector.
+! parck.... checks validity of input iv and v values.
+! reldst... computes v(reldx) = relative step size.
+! stopx.... returns .true. if the break key has been pressed.
+! vaxpy.... computes scalar times one vector plus another.
+! vcopy.... copies one vector to another.
+! vscopy... sets all elements of a vector to a scalar.
+! vvmulp... multiplies vector by vector raised to power (componentwise).
+! v2norm... returns the 2-norm of a vector.
+! wzbfgs... computes w and z for lupdat corresponding to bfgs update.
+!
+!  ***  subscripts for iv and v  ***
+!
+!el      integer afctol
+!el      integer cnvcod, dg, dgnorm, dinit, dstnrm, dst0, f, f0, fdif,
+!el     1        gthg, gtstep, g0, incfac, inith, irc, kagqt, lmat, lmax0,
+!el     2        lmaxs, mode, model, mxfcal, mxiter, nextv, nfcall, nfgcal,
+!el     3        ngcall, niter, nreduc, nwtstp, preduc, radfac, radinc,
+!el     4        radius, rad0, reldx, restor, step, stglim, stlstg, toobig,
+!el     5        tuner4, tuner5, vneed, xirc, x0
+!
+!  ***  iv subscript values  ***
+!
+!/6
+!     data cnvcod/55/, dg/37/, g0/48/, inith/25/, irc/29/, kagqt/33/,
+!    1     mode/35/, model/5/, mxfcal/17/, mxiter/18/, nfcall/6/,
+!    2     nfgcal/7/, ngcall/30/, niter/31/, nwtstp/34/, radinc/8/,
+!    3     restor/9/, step/40/, stglim/11/, stlstg/41/, toobig/2/,
+!    4     vneed/4/, xirc/13/, x0/43/
+!/7
+      integer,parameter :: cnvcod=55, dg=37, g0=48, inith=25, irc=29, kagqt=33,&
+                 mode=35, model=5, mxfcal=17, mxiter=18, nfcall=6,&
+                 nfgcal=7, ngcall=30, niter=31, nwtstp=34, radinc=8,&
+                 restor=9, step=40, stglim=11, stlstg=41, toobig=2,&
+                 vneed=4, xirc=13, x0=43
+!/
+!
+!  ***  v subscript values  ***
+!
+!/6
+!     data afctol/31/
+!     data dgnorm/1/, dinit/38/, dstnrm/2/, dst0/3/, f/10/, f0/13/,
+!    1     fdif/11/, gthg/44/, gtstep/4/, incfac/23/, lmat/42/,
+!    2     lmax0/35/, lmaxs/36/, nextv/47/, nreduc/6/, preduc/7/,
+!    3     radfac/16/, radius/8/, rad0/9/, reldx/17/, tuner4/29/,
+!    4     tuner5/30/
+!/7
+      integer,parameter :: afctol=31
+      integer,parameter :: dgnorm=1, dinit=38, dstnrm=2, dst0=3, f=10, f0=13,&
+                 fdif=11, gthg=44, gtstep=4, incfac=23, lmat=42,&
+                 lmax0=35, lmaxs=36, nextv=47, nreduc=6, preduc=7,&
+                 radfac=16, radius=8, rad0=9, reldx=17, tuner4=29,&
+                 tuner5=30
+!/
+!
+!/6
+!     data half/0.5d+0/, negone/-1.d+0/, one/1.d+0/, onep2/1.2d+0/,
+!    1     zero/0.d+0/
+!/7
+      real(kind=8),parameter :: half=0.5d+0, negone=-1.d+0, one=1.d+0,&
+                 onep2=1.2d+0,zero=0.d+0
+!/
+!
+!+++++++++++++++++++++++++++++++  body  ++++++++++++++++++++++++++++++++
+!
+! Following SAVE statement inserted.
+      save l
+      i = iv(1)
+      if (i .eq. 1) go to 50
+      if (i .eq. 2) go to 60
+!
+!  ***  check validity of iv and v input values  ***
+!
+      if (iv(1) .eq. 0) call deflt(2, iv, liv, lv, v)
+      if (iv(1) .eq. 12 .or. iv(1) .eq. 13) &
+           iv(vneed) = iv(vneed) + n*(n+13)/2
+      call parck(2, d, iv, liv, lv, n, v)
+      i = iv(1) - 2
+      if (i .gt. 12) go to 999
+      go to (180, 180, 180, 180, 180, 180, 120, 90, 120, 10, 10, 20), i
+!
+!  ***  storage allocation  ***
+!
+10    l = iv(lmat)
+      iv(x0) = l + n*(n+1)/2
+      iv(step) = iv(x0) + n
+      iv(stlstg) = iv(step) + n
+      iv(g0) = iv(stlstg) + n
+      iv(nwtstp) = iv(g0) + n
+      iv(dg) = iv(nwtstp) + n
+      iv(nextv) = iv(dg) + n
+      if (iv(1) .ne. 13) go to 20
+         iv(1) = 14
+         go to 999
+!
+!  ***  initialization  ***
+!
+ 20   iv(niter) = 0
+      iv(nfcall) = 1
+      iv(ngcall) = 1
+      iv(nfgcal) = 1
+      iv(mode) = -1
+      iv(model) = 1
+      iv(stglim) = 1
+      iv(toobig) = 0
+      iv(cnvcod) = 0
+      iv(radinc) = 0
+      v(rad0) = zero
+      if (v(dinit) .ge. zero) call vscopy(n, d, v(dinit))
+      if (iv(inith) .ne. 1) go to 40
+!
+!     ***  set the initial hessian approximation to diag(d)**-2  ***
+!
+         l = iv(lmat)
+         call vscopy(n*(n+1)/2, v(l), zero)
+         k = l - 1
+         do 30 i = 1, n
+              k = k + i
+              t = d(i)
+              if (t .le. zero) t = one
+              v(k) = t
+ 30           continue
+!
+!  ***  compute initial function value  ***
+!
+ 40   iv(1) = 1
+      go to 999
+!
+ 50   v(f) = fx
+      if (iv(mode) .ge. 0) go to 180
+      iv(1) = 2
+      if (iv(toobig) .eq. 0) go to 999
+         iv(1) = 63
+         go to 300
+!
+!  ***  make sure gradient could be computed  ***
+!
+ 60   if (iv(nfgcal) .ne. 0) go to 70
+         iv(1) = 65
+         go to 300
+!
+ 70   dg1 = iv(dg)
+      call vvmulp(n, v(dg1), g, d, -1)
+      v(dgnorm) = v2norm(n, v(dg1))
+!
+!  ***  test norm of gradient  ***
+!
+      if (v(dgnorm) .gt. v(afctol)) go to 75
+      iv(irc) = 10
+      iv(cnvcod) = iv(irc) - 4
+!
+ 75   if (iv(cnvcod) .ne. 0) go to 290
+      if (iv(mode) .eq. 0) go to 250
+!
+!  ***  allow first step to have scaled 2-norm at most v(lmax0)  ***
+!
+      v(radius) = v(lmax0)
+!
+      iv(mode) = 0
+!
+!
+!-----------------------------  main loop  -----------------------------
+!
+!
+!  ***  print iteration summary, check iteration limit  ***
+!
+ 80   call itsum(d, g, iv, liv, lv, n, v, x)
+ 90   k = iv(niter)
+      if (k .lt. iv(mxiter)) go to 100
+         iv(1) = 10
+         go to 300
+!
+!  ***  update radius  ***
+!
+ 100  iv(niter) = k + 1
+      if(k.gt.0)v(radius) = v(radfac) * v(dstnrm)
+!
+!  ***  initialize for start of next iteration  ***
+!
+      g01 = iv(g0)
+      x01 = iv(x0)
+      v(f0) = v(f)
+      iv(irc) = 4
+      iv(kagqt) = -1
+!
+!     ***  copy x to x0, g to g0  ***
+!
+      call vcopy(n, v(x01), x)
+      call vcopy(n, v(g01), g)
+!
+!  ***  check stopx and function evaluation limit  ***
+!
+! AL 4/30/95
+      dummy=iv(nfcall)
+!el      lstopx = stopx(dummy)
+!elwrite(iout,*) "lstopx",lstopx,dummy
+ 110  if (.not. stopx(dummy)) go to 130
+         iv(1) = 11
+!         write (iout,*) "iv(1)=11 !!!!"
+         go to 140
+!
+!     ***  come here when restarting after func. eval. limit or stopx.
+!
+ 120  if (v(f) .ge. v(f0)) go to 130
+         v(radfac) = one
+         k = iv(niter)
+         go to 100
+!
+ 130  if (iv(nfcall) .lt. iv(mxfcal)) go to 150
+         iv(1) = 9
+ 140     if (v(f) .ge. v(f0)) go to 300
+!
+!        ***  in case of stopx or function evaluation limit with
+!        ***  improved v(f), evaluate the gradient at x.
+!
+              iv(cnvcod) = iv(1)
+              go to 240
+!
+!. . . . . . . . . . . . .  compute candidate step  . . . . . . . . . .
+!
+ 150  step1 = iv(step)
+      dg1 = iv(dg)
+      nwtst1 = iv(nwtstp)
+      if (iv(kagqt) .ge. 0) go to 160
+         l = iv(lmat)
+         call livmul(n, v(nwtst1), v(l), g)
+         v(nreduc) = half * dotprd(n, v(nwtst1), v(nwtst1))
+         call litvmu(n, v(nwtst1), v(l), v(nwtst1))
+         call vvmulp(n, v(step1), v(nwtst1), d, 1)
+         v(dst0) = v2norm(n, v(step1))
+         call vvmulp(n, v(dg1), v(dg1), d, -1)
+         call ltvmul(n, v(step1), v(l), v(dg1))
+         v(gthg) = v2norm(n, v(step1))
+         iv(kagqt) = 0
+ 160  call dbdog(v(dg1), lv, n, v(nwtst1), v(step1), v)
+      if (iv(irc) .eq. 6) go to 180
+!
+!  ***  check whether evaluating f(x0 + step) looks worthwhile  ***
+!
+      if (v(dstnrm) .le. zero) go to 180
+      if (iv(irc) .ne. 5) go to 170
+      if (v(radfac) .le. one) go to 170
+      if (v(preduc) .le. onep2 * v(fdif)) go to 180
+!
+!  ***  compute f(x0 + step)  ***
+!
+ 170  x01 = iv(x0)
+      step1 = iv(step)
+      call vaxpy(n, x, one, v(step1), v(x01))
+      iv(nfcall) = iv(nfcall) + 1
+      iv(1) = 1
+      iv(toobig) = 0
+      go to 999
+!
+!. . . . . . . . . . . . .  assess candidate step  . . . . . . . . . . .
+!
+ 180  x01 = iv(x0)
+      v(reldx) = reldst(n, d, x, v(x01))
+      call assst(iv, liv, lv, v)
+      step1 = iv(step)
+      lstgst = iv(stlstg)
+      if (iv(restor) .eq. 1) call vcopy(n, x, v(x01))
+      if (iv(restor) .eq. 2) call vcopy(n, v(lstgst), v(step1))
+      if (iv(restor) .ne. 3) go to 190
+         call vcopy(n, v(step1), v(lstgst))
+         call vaxpy(n, x, one, v(step1), v(x01))
+         v(reldx) = reldst(n, d, x, v(x01))
+!
+ 190  k = iv(irc)
+      go to (200,230,230,230,200,210,220,220,220,220,220,220,280,250), k
+!
+!     ***  recompute step with changed radius  ***
+!
+ 200     v(radius) = v(radfac) * v(dstnrm)
+         go to 110
+!
+!  ***  compute step of length v(lmaxs) for singular convergence test.
+!
+ 210  v(radius) = v(lmaxs)
+      go to 150
+!
+!  ***  convergence or false convergence  ***
+!
+ 220  iv(cnvcod) = k - 4
+      if (v(f) .ge. v(f0)) go to 290
+         if (iv(xirc) .eq. 14) go to 290
+              iv(xirc) = 14
+!
+!. . . . . . . . . . . .  process acceptable step  . . . . . . . . . . .
+!
+ 230  if (iv(irc) .ne. 3) go to 240
+         step1 = iv(step)
+         temp1 = iv(stlstg)
+!
+!     ***  set  temp1 = hessian * step  for use in gradient tests  ***
+!
+         l = iv(lmat)
+         call ltvmul(n, v(temp1), v(l), v(step1))
+         call lvmul(n, v(temp1), v(l), v(temp1))
+!
+!  ***  compute gradient  ***
+!
+ 240  iv(ngcall) = iv(ngcall) + 1
+      iv(1) = 2
+      go to 999
+!
+!  ***  initializations -- g0 = g - g0, etc.  ***
+!
+ 250  g01 = iv(g0)
+      call vaxpy(n, v(g01), negone, v(g01), g)
+      step1 = iv(step)
+      temp1 = iv(stlstg)
+      if (iv(irc) .ne. 3) go to 270
+!
+!  ***  set v(radfac) by gradient tests  ***
+!
+!     ***  set  temp1 = diag(d)**-1 * (hessian*step + (g(x0)-g(x)))  ***
+!
+         call vaxpy(n, v(temp1), negone, v(g01), v(temp1))
+         call vvmulp(n, v(temp1), v(temp1), d, -1)
+!
+!        ***  do gradient tests  ***
+!
+         if (v2norm(n, v(temp1)) .le. v(dgnorm) * v(tuner4)) &
+                        go to 260
+              if (dotprd(n, g, v(step1)) &
+                        .ge. v(gtstep) * v(tuner5))  go to 270
+ 260               v(radfac) = v(incfac)
+!
+!  ***  update h, loop  ***
+!
+ 270  w = iv(nwtstp)
+      z = iv(x0)
+      l = iv(lmat)
+      call wzbfgs(v(l), n, v(step1), v(w), v(g01), v(z))
+!
+!     ** use the n-vectors starting at v(step1) and v(g01) for scratch..
+      call lupdat(v(temp1), v(step1), v(l), v(g01), v(l), n, v(w), v(z))
+      iv(1) = 2
+      go to 80
+!
+!. . . . . . . . . . . . . .  misc. details  . . . . . . . . . . . . . .
+!
+!  ***  bad parameters to assess  ***
+!
+ 280  iv(1) = 64
+      go to 300
+!
+!  ***  print summary of final iteration and other requested items  ***
+!
+ 290  iv(1) = iv(cnvcod)
+      iv(cnvcod) = 0
+ 300  call itsum(d, g, iv, liv, lv, n, v, x)
+!
+ 999  return
+!
+!  ***  last line of sumit follows  ***
+      end subroutine sumit
+!-----------------------------------------------------------------------------
+      subroutine dbdog(dig,lv,n,nwtstp,step,v)
+!
+!  ***  compute double dogleg step  ***
+!
+!  ***  parameter declarations  ***
+!
+      integer :: lv, n
+      real(kind=8) :: dig(n), nwtstp(n), step(n), v(lv)
+!
+!  ***  purpose  ***
+!
+!        this subroutine computes a candidate step (for use in an uncon-
+!     strained minimization code) by the double dogleg algorithm of
+!     dennis and mei (ref. 1), which is a variation on powell*s dogleg
+!     scheme (ref. 2, p. 95).
+!
+!--------------------------  parameter usage  --------------------------
+!
+!    dig (input) diag(d)**-2 * g -- see algorithm notes.
+!      g (input) the current gradient vector.
+!     lv (input) length of v.
+!      n (input) number of components in  dig, g, nwtstp,  and  step.
+! nwtstp (input) negative newton step -- see algorithm notes.
+!   step (output) the computed step.
+!      v (i/o) values array, the following components of which are
+!             used here...
+! v(bias)   (input) bias for relaxed newton step, which is v(bias) of
+!             the way from the full newton to the fully relaxed newton
+!             step.  recommended value = 0.8 .
+! v(dgnorm) (input) 2-norm of diag(d)**-1 * g -- see algorithm notes.
+! v(dstnrm) (output) 2-norm of diag(d) * step, which is v(radius)
+!             unless v(stppar) = 0 -- see algorithm notes.
+! v(dst0) (input) 2-norm of diag(d) * nwtstp -- see algorithm notes.
+! v(grdfac) (output) the coefficient of  dig  in the step returned --
+!             step(i) = v(grdfac)*dig(i) + v(nwtfac)*nwtstp(i).
+! v(gthg)   (input) square-root of (dig**t) * (hessian) * dig -- see
+!             algorithm notes.
+! v(gtstep) (output) inner product between g and step.
+! v(nreduc) (output) function reduction predicted for the full newton
+!             step.
+! v(nwtfac) (output) the coefficient of  nwtstp  in the step returned --
+!             see v(grdfac) above.
+! v(preduc) (output) function reduction predicted for the step returned.
+! v(radius) (input) the trust region radius.  d times the step returned
+!             has 2-norm v(radius) unless v(stppar) = 0.
+! v(stppar) (output) code telling how step was computed... 0 means a
+!             full newton step.  between 0 and 1 means v(stppar) of the
+!             way from the newton to the relaxed newton step.  between
+!             1 and 2 means a true double dogleg step, v(stppar) - 1 of
+!             the way from the relaxed newton to the cauchy step.
+!             greater than 2 means 1 / (v(stppar) - 1) times the cauchy
+!             step.
+!
+!-------------------------------  notes  -------------------------------
+!
+!  ***  algorithm notes  ***
+!
+!        let  g  and  h  be the current gradient and hessian approxima-
+!     tion respectively and let d be the current scale vector.  this
+!     routine assumes dig = diag(d)**-2 * g  and  nwtstp = h**-1 * g.
+!     the step computed is the same one would get by replacing g and h
+!     by  diag(d)**-1 * g  and  diag(d)**-1 * h * diag(d)**-1,
+!     computing step, and translating step back to the original
+!     variables, i.e., premultiplying it by diag(d)**-1.
+!
+!  ***  references  ***
+!
+! 1.  dennis, j.e., and mei, h.h.w. (1979), two new unconstrained opti-
+!             mization algorithms which use function and gradient
+!             values, j. optim. theory applic. 28, pp. 453-482.
+! 2. powell, m.j.d. (1970), a hybrid method for non-linear equations,
+!             in numerical methods for non-linear equations, edited by
+!             p. rabinowitz, gordon and breach, london.
+!
+!  ***  general  ***
+!
+!     coded by david m. gay.
+!     this subroutine was written in connection with research supported
+!     by the national science foundation under grants mcs-7600324 and
+!     mcs-7906671.
+!
+!------------------------  external quantities  ------------------------
+!
+!  ***  functions and subroutines called  ***
+!
+!el      external dotprd, v2norm
+!el      real(kind=8) :: dotprd, v2norm
+!
+! dotprd... returns inner product of two vectors.
+! v2norm... returns 2-norm of a vector.
+!
+!  ***  intrinsic functions  ***
+!/+
+!el      real(kind=8) :: dsqrt
+!/
+!--------------------------  local variables  --------------------------
+!
+      integer :: i
+      real(kind=8) :: cfact, cnorm, ctrnwt, ghinvg, femnsq, gnorm,&
+                       nwtnrm, relax, rlambd, t, t1, t2
+!el      real(kind=8) :: half, one, two, zero
+!
+!  ***  v subscripts  ***
+!
+!el      integer bias, dgnorm, dstnrm, dst0, grdfac, gthg, gtstep,
+!el     1        nreduc, nwtfac, preduc, radius, stppar
+!
+!  ***  data initializations  ***
+!
+!/6
+!     data half/0.5d+0/, one/1.d+0/, two/2.d+0/, zero/0.d+0/
+!/7
+      real(kind=8),parameter :: half=0.5d+0, one=1.d+0, two=2.d+0, zero=0.d+0
+!/
+!
+!/6
+!     data bias/43/, dgnorm/1/, dstnrm/2/, dst0/3/, grdfac/45/,
+!    1     gthg/44/, gtstep/4/, nreduc/6/, nwtfac/46/, preduc/7/,
+!    2     radius/8/, stppar/5/
+!/7
+      integer,parameter :: bias=43, dgnorm=1, dstnrm=2, dst0=3, grdfac=45,&
+                 gthg=44, gtstep=4, nreduc=6, nwtfac=46, preduc=7,&
+                 radius=8, stppar=5
+!/
+!
+!+++++++++++++++++++++++++++++++  body  ++++++++++++++++++++++++++++++++
+!
+      nwtnrm = v(dst0)
+      rlambd = one
+      if (nwtnrm .gt. zero) rlambd = v(radius) / nwtnrm
+      gnorm = v(dgnorm)
+      ghinvg = two * v(nreduc)
+      v(grdfac) = zero
+      v(nwtfac) = zero
+      if (rlambd .lt. one) go to 30
+!
+!        ***  the newton step is inside the trust region  ***
+!
+         v(stppar) = zero
+         v(dstnrm) = nwtnrm
+         v(gtstep) = -ghinvg
+         v(preduc) = v(nreduc)
+         v(nwtfac) = -one
+         do 20 i = 1, n
+ 20           step(i) = -nwtstp(i)
+         go to 999
+!
+ 30   v(dstnrm) = v(radius)
+      cfact = (gnorm / v(gthg))**2
+!     ***  cauchy step = -cfact * g.
+      cnorm = gnorm * cfact
+      relax = one - v(bias) * (one - gnorm*cnorm/ghinvg)
+      if (rlambd .lt. relax) go to 50
+!
+!        ***  step is between relaxed newton and full newton steps  ***
+!
+         v(stppar)  =  one  -  (rlambd - relax) / (one - relax)
+         t = -rlambd
+         v(gtstep) = t * ghinvg
+         v(preduc) = rlambd * (one - half*rlambd) * ghinvg
+         v(nwtfac) = t
+         do 40 i = 1, n
+ 40           step(i) = t * nwtstp(i)
+         go to 999
+!
+ 50   if (cnorm .lt. v(radius)) go to 70
+!
+!        ***  the cauchy step lies outside the trust region --
+!        ***  step = scaled cauchy step  ***
+!
+         t = -v(radius) / gnorm
+         v(grdfac) = t
+         v(stppar) = one  +  cnorm / v(radius)
+         v(gtstep) = -v(radius) * gnorm
+      v(preduc) = v(radius)*(gnorm - half*v(radius)*(v(gthg)/gnorm)**2)
+         do 60 i = 1, n
+ 60           step(i) = t * dig(i)
+         go to 999
+!
+!     ***  compute dogleg step between cauchy and relaxed newton  ***
+!     ***  femur = relaxed newton step minus cauchy step  ***
+!
+ 70   ctrnwt = cfact * relax * ghinvg / gnorm
+!     *** ctrnwt = inner prod. of cauchy and relaxed newton steps,
+!     *** scaled by gnorm**-1.
+      t1 = ctrnwt - gnorm*cfact**2
+!     ***  t1 = inner prod. of femur and cauchy step, scaled by
+!     ***  gnorm**-1.
+      t2 = v(radius)*(v(radius)/gnorm) - gnorm*cfact**2
+      t = relax * nwtnrm
+      femnsq = (t/gnorm)*t - ctrnwt - t1
+!     ***  femnsq = square of 2-norm of femur, scaled by gnorm**-1.
+      t = t2 / (t1 + dsqrt(t1**2 + femnsq*t2))
+!     ***  dogleg step  =  cauchy step  +  t * femur.
+      t1 = (t - one) * cfact
+      v(grdfac) = t1
+      t2 = -t * relax
+      v(nwtfac) = t2
+      v(stppar) = two - t
+      v(gtstep) = t1*gnorm**2 + t2*ghinvg
+      v(preduc) = -t1*gnorm * ((t2 + one)*gnorm) &
+                       - t2 * (one + half*t2)*ghinvg &
+                        - half * (v(gthg)*t1)**2
+      do 80 i = 1, n
+ 80      step(i) = t1*dig(i) + t2*nwtstp(i)
+!
+ 999  return
+!  ***  last line of dbdog follows  ***
+      end subroutine dbdog
+!-----------------------------------------------------------------------------
+      subroutine ltvmul(n,x,l,y)
+!
+!  ***  compute  x = (l**t)*y, where  l  is an  n x n  lower
+!  ***  triangular matrix stored compactly by rows.  x and y may
+!  ***  occupy the same storage.  ***
+!
+      integer :: n
+!al   real(kind=8) :: x(n), l(1), y(n)
+      real(kind=8) :: x(n), l(n*(n+1)/2), y(n)
+!     dimension l(n*(n+1)/2)
+      integer :: i, ij, i0, j
+      real(kind=8) :: yi       !el, zero
+!/6
+!     data zero/0.d+0/
+!/7
+      real(kind=8),parameter :: zero=0.d+0
+!/
+!
+      i0 = 0
+      do 20 i = 1, n
+         yi = y(i)
+         x(i) = zero
+         do 10 j = 1, i
+              ij = i0 + j
+              x(j) = x(j) + yi*l(ij)
+ 10           continue
+         i0 = i0 + i
+ 20      continue
+ 999  return
+!  ***  last card of ltvmul follows  ***
+      end subroutine ltvmul
+!-----------------------------------------------------------------------------
+      subroutine lupdat(beta,gamma,l,lambda,lplus,n,w,z)
+!
+!  ***  compute lplus = secant update of l  ***
+!
+!  ***  parameter declarations  ***
+!
+      integer :: n
+!al   double precision beta(n), gamma(n), l(1), lambda(n), lplus(1),
+      real(kind=8) :: beta(n), gamma(n), l(n*(n+1)/2), lambda(n), &
+         lplus(n*(n+1)/2),w(n), z(n)
+!     dimension l(n*(n+1)/2), lplus(n*(n+1)/2)
+!
+!--------------------------  parameter usage  --------------------------
+!
+!   beta = scratch vector.
+!  gamma = scratch vector.
+!      l (input) lower triangular matrix, stored rowwise.
+! lambda = scratch vector.
+!  lplus (output) lower triangular matrix, stored rowwise, which may
+!             occupy the same storage as  l.
+!      n (input) length of vector parameters and order of matrices.
+!      w (input, destroyed on output) right singular vector of rank 1
+!             correction to  l.
+!      z (input, destroyed on output) left singular vector of rank 1
+!             correction to  l.
+!
+!-------------------------------  notes  -------------------------------
+!
+!  ***  application and usage restrictions  ***
+!
+!        this routine updates the cholesky factor  l  of a symmetric
+!     positive definite matrix to which a secant update is being
+!     applied -- it computes a cholesky factor  lplus  of
+!     l * (i + z*w**t) * (i + w*z**t) * l**t.  it is assumed that  w
+!     and  z  have been chosen so that the updated matrix is strictly
+!     positive definite.
+!
+!  ***  algorithm notes  ***
+!
+!        this code uses recurrence 3 of ref. 1 (with d(j) = 1 for all j)
+!     to compute  lplus  of the form  l * (i + z*w**t) * q,  where  q
+!     is an orthogonal matrix that makes the result lower triangular.
+!        lplus may have some negative diagonal elements.
+!
+!  ***  references  ***
+!
+! 1.  goldfarb, d. (1976), factorized variable metric methods for uncon-
+!             strained optimization, math. comput. 30, pp. 796-811.
+!
+!  ***  general  ***
+!
+!     coded by david m. gay (fall 1979).
+!     this subroutine was written in connection with research supported
+!     by the national science foundation under grants mcs-7600324 and
+!     mcs-7906671.
+!
+!------------------------  external quantities  ------------------------
+!
+!  ***  intrinsic functions  ***
+!/+
+!el      real(kind=8) :: dsqrt
+!/
+!--------------------------  local variables  --------------------------
+!
+      integer :: i, ij, j, jj, jp1, k, nm1, np1
+      real(kind=8) :: a, b, bj, eta, gj, lj, lij, ljj, nu, s, theta,&
+                       wj, zj
+!el      real(kind=8) :: one, zero
+!
+!  ***  data initializations  ***
+!
+!/6
+!     data one/1.d+0/, zero/0.d+0/
+!/7
+      real(kind=8),parameter :: one=1.d+0, zero=0.d+0
+!/
+!
+!+++++++++++++++++++++++++++++++  body  ++++++++++++++++++++++++++++++++
+!
+      nu = one
+      eta = zero
+      if (n .le. 1) go to 30
+      nm1 = n - 1
+!
+!  ***  temporarily store s(j) = sum over k = j+1 to n of w(k)**2 in
+!  ***  lambda(j).
+!
+      s = zero
+      do 10 i = 1, nm1
+         j = n - i
+         s = s + w(j+1)**2
+         lambda(j) = s
+ 10      continue
+!
+!  ***  compute lambda, gamma, and beta by goldfarb*s recurrence 3.
+!
+      do 20 j = 1, nm1
+         wj = w(j)
+         a = nu*z(j) - eta*wj
+         theta = one + a*wj
+         s = a*lambda(j)
+         lj = dsqrt(theta**2 + a*s)
+         if (theta .gt. zero) lj = -lj
+         lambda(j) = lj
+         b = theta*wj + s
+         gamma(j) = b * nu / lj
+         beta(j) = (a - b*eta) / lj
+         nu = -nu / lj
+         eta = -(eta + (a**2)/(theta - lj)) / lj
+ 20      continue
+ 30   lambda(n) = one + (nu*z(n) - eta*w(n))*w(n)
+!
+!  ***  update l, gradually overwriting  w  and  z  with  l*w  and  l*z.
+!
+      np1 = n + 1
+      jj = n * (n + 1) / 2
+      do 60 k = 1, n
+         j = np1 - k
+         lj = lambda(j)
+         ljj = l(jj)
+         lplus(jj) = lj * ljj
+         wj = w(j)
+         w(j) = ljj * wj
+         zj = z(j)
+         z(j) = ljj * zj
+         if (k .eq. 1) go to 50
+         bj = beta(j)
+         gj = gamma(j)
+         ij = jj + j
+         jp1 = j + 1
+         do 40 i = jp1, n
+              lij = l(ij)
+              lplus(ij) = lj*lij + bj*w(i) + gj*z(i)
+              w(i) = w(i) + lij*wj
+              z(i) = z(i) + lij*zj
+              ij = ij + i
+ 40           continue
+ 50      jj = jj - j
+ 60      continue
+!
+ 999  return
+!  ***  last card of lupdat follows  ***
+      end subroutine lupdat
+!-----------------------------------------------------------------------------
+      subroutine lvmul(n,x,l,y)
+!
+!  ***  compute  x = l*y, where  l  is an  n x n  lower triangular
+!  ***  matrix stored compactly by rows.  x and y may occupy the same
+!  ***  storage.  ***
+!
+      integer :: n
+!al   double precision x(n), l(1), y(n)
+      real(kind=8) :: x(n), l(n*(n+1)/2), y(n)
+!     dimension l(n*(n+1)/2)
+      integer :: i, ii, ij, i0, j, np1
+      real(kind=8) :: t        !el, zero
+!/6
+!     data zero/0.d+0/
+!/7
+      real(kind=8),parameter :: zero=0.d+0
+!/
+!
+      np1 = n + 1
+      i0 = n*(n+1)/2
+      do 20 ii = 1, n
+         i = np1 - ii
+         i0 = i0 - i
+         t = zero
+         do 10 j = 1, i
+              ij = i0 + j
+              t = t + l(ij)*y(j)
+ 10           continue
+         x(i) = t
+ 20      continue
+ 999  return
+!  ***  last card of lvmul follows  ***
+      end subroutine lvmul
+!-----------------------------------------------------------------------------
+      subroutine vvmulp(n,x,y,z,k)
+!
+! ***  set x(i) = y(i) * z(i)**k, 1 .le. i .le. n (for k = 1 or -1)  ***
+!
+      integer :: n, k
+      real(kind=8) :: x(n), y(n), z(n)
+      integer :: i
+!
+      if (k .ge. 0) go to 20
+      do 10 i = 1, n
+ 10      x(i) = y(i) / z(i)
+      go to 999
+!
+ 20   do 30 i = 1, n
+ 30      x(i) = y(i) * z(i)
+ 999  return
+!  ***  last card of vvmulp follows  ***
+      end subroutine vvmulp
+!-----------------------------------------------------------------------------
+      subroutine wzbfgs(l,n,s,w,y,z)
+!
+!  ***  compute  y  and  z  for  lupdat  corresponding to bfgs update.
+!
+      integer :: n
+!al   double precision l(1), s(n), w(n), y(n), z(n)
+      real(kind=8) :: l(n*(n+1)/2), s(n), w(n), y(n), z(n)
+!     dimension l(n*(n+1)/2)
+!
+!--------------------------  parameter usage  --------------------------
+!
+! l (i/o) cholesky factor of hessian, a lower triang. matrix stored
+!             compactly by rows.
+! n (input) order of  l  and length of  s,  w,  y,  z.
+! s (input) the step just taken.
+! w (output) right singular vector of rank 1 correction to l.
+! y (input) change in gradients corresponding to s.
+! z (output) left singular vector of rank 1 correction to l.
+!
+!-------------------------------  notes  -------------------------------
+!
+!  ***  algorithm notes  ***
+!
+!        when  s  is computed in certain ways, e.g. by  gqtstp  or
+!     dbldog,  it is possible to save n**2/2 operations since  (l**t)*s
+!     or  l*(l**t)*s is then known.
+!        if the bfgs update to l*(l**t) would reduce its determinant to
+!     less than eps times its old value, then this routine in effect
+!     replaces  y  by  theta*y + (1 - theta)*l*(l**t)*s,  where  theta
+!     (between 0 and 1) is chosen to make the reduction factor = eps.
+!
+!  ***  general  ***
+!
+!     coded by david m. gay (fall 1979).
+!     this subroutine was written in connection with research supported
+!     by the national science foundation under grants mcs-7600324 and
+!     mcs-7906671.
+!
+!------------------------  external quantities  ------------------------
+!
+!  ***  functions and subroutines called  ***
+!
+!el      external dotprd, livmul, ltvmul
+!el      real(kind=8) :: dotprd
+! dotprd returns inner product of two vectors.
+! livmul multiplies l**-1 times a vector.
+! ltvmul multiplies l**t times a vector.
+!
+!  ***  intrinsic functions  ***
+!/+
+!el      real(kind=8) :: dsqrt
+!/
+!--------------------------  local variables  --------------------------
+!
+      integer :: i
+      real(kind=8) :: cs, cy, epsrt, shs, ys, theta    !el, eps, one
+!
+!  ***  data initializations  ***
+!
+!/6
+!     data eps/0.1d+0/, one/1.d+0/
+!/7
+      real(kind=8),parameter :: eps=0.1d+0, one=1.d+0
+!/
+!
+!+++++++++++++++++++++++++++++++  body  ++++++++++++++++++++++++++++++++
+!
+      call ltvmul(n, w, l, s)
+      shs = dotprd(n, w, w)
+      ys = dotprd(n, y, s)
+      if (ys .ge. eps*shs) go to 10
+         theta = (one - eps) * shs / (shs - ys)
+         epsrt = dsqrt(eps)
+         cy = theta / (shs * epsrt)
+         cs = (one + (theta-one)/epsrt) / shs
+         go to 20
+ 10   cy = one / (dsqrt(ys) * dsqrt(shs))
+      cs = one / shs
+ 20   call livmul(n, z, l, y)
+      do 30 i = 1, n
+ 30      z(i) = cy * z(i)  -  cs * w(i)
+!
+ 999  return
+!  ***  last card of wzbfgs follows  ***
+      end subroutine wzbfgs
+!-----------------------------------------------------------------------------
+!-----------------------------------------------------------------------------
+      end module minimm