Files
cantera/ext/f2c_math/ddaspk.c
2004-08-05 19:15:05 +00:00

8784 lines
298 KiB
C

/* ddaspk.f -- translated by f2c (version 20031025).
You must link the resulting object file with libf2c:
on Microsoft Windows system, link with libf2c.lib;
on Linux or Unix systems, link with .../path/to/libf2c.a -lm
or, if you install libf2c.a in a standard place, with -lf2c -lm
-- in that order, at the end of the command line, as in
cc *.o -lf2c -lm
Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
http://www.netlib.org/f2c/libf2c.zip
*/
#ifdef _cpluscplus
extern "C" {
#endif
#include "f2c.h"
/* Table of constant values */
static integer c__49 = 49;
static integer c__201 = 201;
static integer c__0 = 0;
static doublereal c_b37 = 0.;
static integer c__47 = 47;
static integer c__202 = 202;
static integer c__1 = 1;
static integer c__41 = 41;
static integer c__203 = 203;
static integer c__4 = 4;
static doublereal c_b67 = .6667;
static integer c__9 = 9;
static integer c__5 = 5;
static integer c__56 = 56;
static integer c__501 = 501;
static integer c__2 = 2;
static integer c__502 = 502;
static integer c__503 = 503;
static integer c__38 = 38;
static integer c__610 = 610;
static integer c__48 = 48;
static integer c__611 = 611;
static integer c__620 = 620;
static integer c__621 = 621;
static integer c__45 = 45;
static integer c__622 = 622;
static integer c__630 = 630;
static integer c__28 = 28;
static integer c__631 = 631;
static integer c__44 = 44;
static integer c__640 = 640;
static integer c__57 = 57;
static integer c__641 = 641;
static integer c__650 = 650;
static integer c__651 = 651;
static integer c__40 = 40;
static integer c__652 = 652;
static integer c__655 = 655;
static integer c__46 = 46;
static integer c__656 = 656;
static integer c__660 = 660;
static integer c__661 = 661;
static integer c__670 = 670;
static integer c__671 = 671;
static integer c__672 = 672;
static integer c__675 = 675;
static integer c__51 = 51;
static integer c__676 = 676;
static integer c__677 = 677;
static integer c__680 = 680;
static integer c__36 = 36;
static integer c__681 = 681;
static integer c__685 = 685;
static integer c__686 = 686;
static integer c__690 = 690;
static integer c__35 = 35;
static integer c__691 = 691;
static integer c__695 = 695;
static integer c__50 = 50;
static integer c__696 = 696;
static integer c__25 = 25;
static integer c__34 = 34;
static integer c__3 = 3;
static integer c__60 = 60;
static integer c__39 = 39;
static integer c__6 = 6;
static integer c__7 = 7;
static integer c__8 = 8;
static integer c__54 = 54;
static integer c__10 = 10;
static integer c__11 = 11;
static integer c__29 = 29;
static integer c__12 = 12;
static integer c__13 = 13;
static integer c__14 = 14;
static integer c__15 = 15;
static integer c__52 = 52;
static integer c__17 = 17;
static integer c__18 = 18;
static integer c__19 = 19;
static integer c__20 = 20;
static integer c__21 = 21;
static integer c__22 = 22;
static integer c__58 = 58;
static integer c__23 = 23;
static integer c__24 = 24;
static integer c__26 = 26;
static integer c__27 = 27;
static integer c__701 = 701;
static integer c__702 = 702;
static integer c__901 = 901;
static integer c__902 = 902;
static integer c__903 = 903;
static integer c__904 = 904;
static integer c__43 = 43;
static integer c__905 = 905;
static integer c__42 = 42;
static integer c__906 = 906;
static integer c__921 = 921;
static integer c__922 = 922;
static integer c__923 = 923;
static integer c__924 = 924;
static integer c__925 = 925;
static integer c__926 = 926;
/* Subroutine */ int ddaspk_(U_fp res, integer *neq, doublereal *t,
doublereal *y, doublereal *yprime, doublereal *tout, integer *info,
doublereal *rtol, doublereal *atol, integer *idid, doublereal *rwork,
integer *lrw, integer *iwork, integer *liw, doublereal *rpar, integer
*ipar, U_fp jac, U_fp psol)
{
/* System generated locals */
integer i__1, i__2;
doublereal d__1, d__2;
/* Builtin functions */
/* Subroutine */ int s_copy(char *, char *, ftnlen, ftnlen);
double pow_dd(doublereal *, doublereal *), sqrt(doublereal), d_sign(
doublereal *, doublereal *);
integer s_wsle(cilist *), do_lio(integer *, integer *, char *, ftnlen),
e_wsle(void);
/* Local variables */
static doublereal h__;
static integer i__;
static doublereal r__, h0;
static integer le;
static doublereal rh, tn;
static integer ici, idi, lid, ier;
static char msg[80];
static integer lwm, lvt, lwt, nwt, nli0, nni0;
static logical lcfl, lcfn, done;
static doublereal rcfl;
static integer nnid;
static logical lavl;
static integer maxl, iret;
static doublereal hmax;
static integer lphi;
static doublereal hmin;
static integer lyic, lpwk, nstd;
static doublereal rcfn;
static integer ncfl0, ncfn0;
extern /* Subroutine */ int dnedd_();
static integer mband;
extern /* Subroutine */ int dnedk_();
static integer lenic, lenid, ncphi, lenpd, lsoff, msave, index, itemp,
leniw, nzflg;
static doublereal atoli;
static integer lypic;
static logical lwarn;
static doublereal avlin;
static integer lenwp, lenrw, mxord, nwarn;
static doublereal rtoli;
static integer lsavr;
extern doublereal d1mach_(integer *);
static doublereal tdist, tnext, fmaxl;
extern /* Subroutine */ int ddstp_(doublereal *, doublereal *, doublereal
*, integer *, U_fp, U_fp, U_fp, doublereal *, doublereal *,
doublereal *, integer *, integer *, doublereal *, integer *,
doublereal *, doublereal *, doublereal *, doublereal *,
doublereal *, integer *, doublereal *, doublereal *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *, integer *,
integer *, integer *, integer *, integer *, integer *, integer *,
integer *, U_fp);
static doublereal tstop;
extern /* Subroutine */ int dcnst0_(integer *, doublereal *, integer *,
integer *), ddasic_(doublereal *, doublereal *, doublereal *,
integer *, integer *, integer *, U_fp, U_fp, U_fp, doublereal *,
doublereal *, doublereal *, integer *, integer *, doublereal *,
integer *, doublereal *, doublereal *, doublereal *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *, integer *
, doublereal *, doublereal *, doublereal *, doublereal *,
doublereal *, doublereal *, integer *, integer *, integer *, U_fp)
;
extern /* Subroutine */ int ddasid_(), ddasik_();
static integer icnflg;
static doublereal tscale, epconi;
extern /* Subroutine */ int ddatrp_(doublereal *, doublereal *,
doublereal *, doublereal *, integer *, integer *, doublereal *,
doublereal *);
static doublereal floatn;
static integer nonneg;
extern /* Subroutine */ int ddawts_(integer *, integer *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *, integer *)
;
extern doublereal ddwnrm_(integer *, doublereal *, doublereal *,
doublereal *, integer *);
static integer leniwp;
extern /* Subroutine */ int xerrwd_(char *, integer *, integer *, integer
*, integer *, integer *, integer *, integer *, doublereal *,
doublereal *, ftnlen), dinvwt_(integer *, doublereal *, integer *)
;
static doublereal uround, ypnorm;
/* Fortran I/O blocks */
static cilist io___49 = { 0, 6, 0, 0, 0 };
static cilist io___57 = { 0, 6, 0, 0, 0 };
static cilist io___59 = { 0, 6, 0, 0, 0 };
static cilist io___60 = { 0, 6, 0, 0, 0 };
/* ***BEGIN PROLOGUE DDASPK */
/* ***DATE WRITTEN 890101 (YYMMDD) */
/* ***REVISION DATE 910624 (Added HMAX test at 525 in main driver.) */
/* ***REVISION DATE 920929 (CJ in RES call, RES counter fix.) */
/* ***REVISION DATE 921215 (Warnings on poor iteration performance) */
/* ***REVISION DATE 921216 (NRMAX as optional input) */
/* ***REVISION DATE 930315 (Name change: DDINI to DDINIT) */
/* ***REVISION DATE 940822 (Replaced initial condition calculation) */
/* ***REVISION DATE 941101 (Added linesearch in I.C. calculations) */
/* ***REVISION DATE 941220 (Misc. corrections throughout) */
/* ***REVISION DATE 950125 (Added DINVWT routine) */
/* ***REVISION DATE 950714 (Misc. corrections throughout) */
/* ***REVISION DATE 950802 (Default NRMAX = 5, based on tests.) */
/* ***REVISION DATE 950808 (Optional error test added.) */
/* ***REVISION DATE 950814 (Added I.C. constraints and INFO(14)) */
/* ***REVISION DATE 950828 (Various minor corrections.) */
/* ***REVISION DATE 951006 (Corrected WT scaling in DFNRMK.) */
/* ***REVISION DATE 951030 (Corrected history update at end of DDASTP.) */
/* ***REVISION DATE 960129 (Corrected RL bug in DLINSD, DLINSK.) */
/* ***REVISION DATE 960301 (Added NONNEG to SAVE statement.) */
/* ***REVISION DATE 000512 (Removed copyright notices.) */
/* ***REVISION DATE 000622 (Corrected LWM value using NCPHI.) */
/* ***REVISION DATE 000628 (Corrected I.C. stopping tests when index = 0.) */
/* ***REVISION DATE 000628 (Fixed alpha test in I.C. calc., Krylov case.) */
/* ***REVISION DATE 000628 (Improved restart in I.C. calc., Krylov case.) */
/* ***REVISION DATE 000628 (Minor corrections throughout.) */
/* ***REVISION DATE 000711 (Fixed Newton convergence test in DNSD, DNSK.) */
/* ***REVISION DATE 000712 (Fixed tests on TN - TOUT below 420 and 440.) */
/* ***CATEGORY NO. I1A2 */
/* ***KEYWORDS DIFFERENTIAL/ALGEBRAIC, BACKWARD DIFFERENTIATION FORMULAS, */
/* IMPLICIT DIFFERENTIAL SYSTEMS, KRYLOV ITERATION */
/* ***AUTHORS Linda R. Petzold, Peter N. Brown, Alan C. Hindmarsh, and */
/* Clement W. Ulrich */
/* Center for Computational Sciences & Engineering, L-316 */
/* Lawrence Livermore National Laboratory */
/* P.O. Box 808, */
/* Livermore, CA 94551 */
/* ***PURPOSE This code solves a system of differential/algebraic */
/* equations of the form */
/* G(t,y,y') = 0 , */
/* using a combination of Backward Differentiation Formula */
/* (BDF) methods and a choice of two linear system solution */
/* methods: direct (dense or band) or Krylov (iterative). */
/* This version is in double precision. */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* *Usage: */
/* IMPLICIT DOUBLE PRECISION(A-H,O-Z) */
/* INTEGER NEQ, INFO(N), IDID, LRW, LIW, IWORK(LIW), IPAR(*) */
/* DOUBLE PRECISION T, Y(*), YPRIME(*), TOUT, RTOL(*), ATOL(*), */
/* RWORK(LRW), RPAR(*) */
/* EXTERNAL RES, JAC, PSOL */
/* CALL DDASPK (RES, NEQ, T, Y, YPRIME, TOUT, INFO, RTOL, ATOL, */
/* * IDID, RWORK, LRW, IWORK, LIW, RPAR, IPAR, JAC, PSOL) */
/* Quantities which may be altered by the code are: */
/* T, Y(*), YPRIME(*), INFO(1), RTOL, ATOL, IDID, RWORK(*), IWORK(*) */
/* *Arguments: */
/* RES:EXT This is the name of a subroutine which you */
/* provide to define the residual function G(t,y,y') */
/* of the differential/algebraic system. */
/* NEQ:IN This is the number of equations in the system. */
/* T:INOUT This is the current value of the independent */
/* variable. */
/* Y(*):INOUT This array contains the solution components at T. */
/* YPRIME(*):INOUT This array contains the derivatives of the solution */
/* components at T. */
/* TOUT:IN This is a point at which a solution is desired. */
/* INFO(N):IN This is an integer array used to communicate details */
/* of how the solution is to be carried out, such as */
/* tolerance type, matrix structure, step size and */
/* order limits, and choice of nonlinear system method. */
/* N must be at least 20. */
/* RTOL,ATOL:INOUT These quantities represent absolute and relative */
/* error tolerances (on local error) which you provide */
/* to indicate how accurately you wish the solution to */
/* be computed. You may choose them to be both scalars */
/* or else both arrays of length NEQ. */
/* IDID:OUT This integer scalar is an indicator reporting what */
/* the code did. You must monitor this variable to */
/* decide what action to take next. */
/* RWORK:WORK A real work array of length LRW which provides the */
/* code with needed storage space. */
/* LRW:IN The length of RWORK. */
/* IWORK:WORK An integer work array of length LIW which provides */
/* the code with needed storage space. */
/* LIW:IN The length of IWORK. */
/* RPAR,IPAR:IN These are real and integer parameter arrays which */
/* you can use for communication between your calling */
/* program and the RES, JAC, and PSOL subroutines. */
/* JAC:EXT This is the name of a subroutine which you may */
/* provide (optionally) for calculating Jacobian */
/* (partial derivative) data involved in solving linear */
/* systems within DDASPK. */
/* PSOL:EXT This is the name of a subroutine which you must */
/* provide for solving linear systems if you selected */
/* a Krylov method. The purpose of PSOL is to solve */
/* linear systems involving a left preconditioner P. */
/* *Overview */
/* The DDASPK solver uses the backward differentiation formulas of */
/* orders one through five to solve a system of the form G(t,y,y') = 0 */
/* for y = Y and y' = YPRIME. Values for Y and YPRIME at the initial */
/* time must be given as input. These values should be consistent, */
/* that is, if T, Y, YPRIME are the given initial values, they should */
/* satisfy G(T,Y,YPRIME) = 0. However, if consistent values are not */
/* known, in many cases you can have DDASPK solve for them -- see INFO(11). */
/* (This and other options are described in more detail below.) */
/* Normally, DDASPK solves the system from T to TOUT. It is easy to */
/* continue the solution to get results at additional TOUT. This is */
/* the interval mode of operation. Intermediate results can also be */
/* obtained easily by specifying INFO(3). */
/* On each step taken by DDASPK, a sequence of nonlinear algebraic */
/* systems arises. These are solved by one of two types of */
/* methods: */
/* * a Newton iteration with a direct method for the linear */
/* systems involved (INFO(12) = 0), or */
/* * a Newton iteration with a preconditioned Krylov iterative */
/* method for the linear systems involved (INFO(12) = 1). */
/* The direct method choices are dense and band matrix solvers, */
/* with either a user-supplied or an internal difference quotient */
/* Jacobian matrix, as specified by INFO(5) and INFO(6). */
/* In the band case, INFO(6) = 1, you must supply half-bandwidths */
/* in IWORK(1) and IWORK(2). */
/* The Krylov method is the Generalized Minimum Residual (GMRES) */
/* method, in either complete or incomplete form, and with */
/* scaling and preconditioning. The method is implemented */
/* in an algorithm called SPIGMR. Certain options in the Krylov */
/* method case are specified by INFO(13) and INFO(15). */
/* If the Krylov method is chosen, you may supply a pair of routines, */
/* JAC and PSOL, to apply preconditioning to the linear system. */
/* If the system is A*x = b, the matrix is A = dG/dY + CJ*dG/dYPRIME */
/* (of order NEQ). This system can then be preconditioned in the form */
/* (P-inverse)*A*x = (P-inverse)*b, with left preconditioner P. */
/* (DDASPK does not allow right preconditioning.) */
/* Then the Krylov method is applied to this altered, but equivalent, */
/* linear system, hopefully with much better performance than without */
/* preconditioning. (In addition, a diagonal scaling matrix based on */
/* the tolerances is also introduced into the altered system.) */
/* The JAC routine evaluates any data needed for solving systems */
/* with coefficient matrix P, and PSOL carries out that solution. */
/* In any case, in order to improve convergence, you should try to */
/* make P approximate the matrix A as much as possible, while keeping */
/* the system P*x = b reasonably easy and inexpensive to solve for x, */
/* given a vector b. */
/* *Description */
/* ------INPUT - WHAT TO DO ON THE FIRST CALL TO DDASPK------------------- */
/* The first call of the code is defined to be the start of each new */
/* problem. Read through the descriptions of all the following items, */
/* provide sufficient storage space for designated arrays, set */
/* appropriate variables for the initialization of the problem, and */
/* give information about how you want the problem to be solved. */
/* RES -- Provide a subroutine of the form */
/* SUBROUTINE RES (T, Y, YPRIME, CJ, DELTA, IRES, RPAR, IPAR) */
/* to define the system of differential/algebraic */
/* equations which is to be solved. For the given values */
/* of T, Y and YPRIME, the subroutine should return */
/* the residual of the differential/algebraic system */
/* DELTA = G(T,Y,YPRIME) */
/* DELTA is a vector of length NEQ which is output from RES. */
/* Subroutine RES must not alter T, Y, YPRIME, or CJ. */
/* You must declare the name RES in an EXTERNAL */
/* statement in your program that calls DDASPK. */
/* You must dimension Y, YPRIME, and DELTA in RES. */
/* The input argument CJ can be ignored, or used to rescale */
/* constraint equations in the system (see Ref. 2, p. 145). */
/* Note: In this respect, DDASPK is not downward-compatible */
/* with DDASSL, which does not have the RES argument CJ. */
/* IRES is an integer flag which is always equal to zero */
/* on input. Subroutine RES should alter IRES only if it */
/* encounters an illegal value of Y or a stop condition. */
/* Set IRES = -1 if an input value is illegal, and DDASPK */
/* will try to solve the problem without getting IRES = -1. */
/* If IRES = -2, DDASPK will return control to the calling */
/* program with IDID = -11. */
/* RPAR and IPAR are real and integer parameter arrays which */
/* you can use for communication between your calling program */
/* and subroutine RES. They are not altered by DDASPK. If you */
/* do not need RPAR or IPAR, ignore these parameters by treat- */
/* ing them as dummy arguments. If you do choose to use them, */
/* dimension them in your calling program and in RES as arrays */
/* of appropriate length. */
/* NEQ -- Set it to the number of equations in the system (NEQ .GE. 1). */
/* T -- Set it to the initial point of the integration. (T must be */
/* a variable.) */
/* Y(*) -- Set this array to the initial values of the NEQ solution */
/* components at the initial point. You must dimension Y of */
/* length at least NEQ in your calling program. */
/* YPRIME(*) -- Set this array to the initial values of the NEQ first */
/* derivatives of the solution components at the initial */
/* point. You must dimension YPRIME at least NEQ in your */
/* calling program. */
/* TOUT - Set it to the first point at which a solution is desired. */
/* You cannot take TOUT = T. Integration either forward in T */
/* (TOUT .GT. T) or backward in T (TOUT .LT. T) is permitted. */
/* The code advances the solution from T to TOUT using step */
/* sizes which are automatically selected so as to achieve the */
/* desired accuracy. If you wish, the code will return with the */
/* solution and its derivative at intermediate steps (the */
/* intermediate-output mode) so that you can monitor them, */
/* but you still must provide TOUT in accord with the basic */
/* aim of the code. */
/* The first step taken by the code is a critical one because */
/* it must reflect how fast the solution changes near the */
/* initial point. The code automatically selects an initial */
/* step size which is practically always suitable for the */
/* problem. By using the fact that the code will not step past */
/* TOUT in the first step, you could, if necessary, restrict the */
/* length of the initial step. */
/* For some problems it may not be permissible to integrate */
/* past a point TSTOP, because a discontinuity occurs there */
/* or the solution or its derivative is not defined beyond */
/* TSTOP. When you have declared a TSTOP point (see INFO(4) */
/* and RWORK(1)), you have told the code not to integrate past */
/* TSTOP. In this case any tout beyond TSTOP is invalid input. */
/* INFO(*) - Use the INFO array to give the code more details about */
/* how you want your problem solved. This array should be */
/* dimensioned of length 20, though DDASPK uses only the */
/* first 15 entries. You must respond to all of the following */
/* items, which are arranged as questions. The simplest use */
/* of DDASPK corresponds to setting all entries of INFO to 0. */
/* INFO(1) - This parameter enables the code to initialize itself. */
/* You must set it to indicate the start of every new */
/* problem. */
/* **** Is this the first call for this problem ... */
/* yes - set INFO(1) = 0 */
/* no - not applicable here. */
/* See below for continuation calls. **** */
/* INFO(2) - How much accuracy you want of your solution */
/* is specified by the error tolerances RTOL and ATOL. */
/* The simplest use is to take them both to be scalars. */
/* To obtain more flexibility, they can both be arrays. */
/* The code must be told your choice. */
/* **** Are both error tolerances RTOL, ATOL scalars ... */
/* yes - set INFO(2) = 0 */
/* and input scalars for both RTOL and ATOL */
/* no - set INFO(2) = 1 */
/* and input arrays for both RTOL and ATOL **** */
/* INFO(3) - The code integrates from T in the direction of TOUT */
/* by steps. If you wish, it will return the computed */
/* solution and derivative at the next intermediate step */
/* (the intermediate-output mode) or TOUT, whichever comes */
/* first. This is a good way to proceed if you want to */
/* see the behavior of the solution. If you must have */
/* solutions at a great many specific TOUT points, this */
/* code will compute them efficiently. */
/* **** Do you want the solution only at */
/* TOUT (and not at the next intermediate step) ... */
/* yes - set INFO(3) = 0 */
/* no - set INFO(3) = 1 **** */
/* INFO(4) - To handle solutions at a great many specific */
/* values TOUT efficiently, this code may integrate past */
/* TOUT and interpolate to obtain the result at TOUT. */
/* Sometimes it is not possible to integrate beyond some */
/* point TSTOP because the equation changes there or it is */
/* not defined past TSTOP. Then you must tell the code */
/* this stop condition. */
/* **** Can the integration be carried out without any */
/* restrictions on the independent variable T ... */
/* yes - set INFO(4) = 0 */
/* no - set INFO(4) = 1 */
/* and define the stopping point TSTOP by */
/* setting RWORK(1) = TSTOP **** */
/* INFO(5) - used only when INFO(12) = 0 (direct methods). */
/* To solve differential/algebraic systems you may wish */
/* to use a matrix of partial derivatives of the */
/* system of differential equations. If you do not */
/* provide a subroutine to evaluate it analytically (see */
/* description of the item JAC in the call list), it will */
/* be approximated by numerical differencing in this code. */
/* Although it is less trouble for you to have the code */
/* compute partial derivatives by numerical differencing, */
/* the solution will be more reliable if you provide the */
/* derivatives via JAC. Usually numerical differencing is */
/* more costly than evaluating derivatives in JAC, but */
/* sometimes it is not - this depends on your problem. */
/* **** Do you want the code to evaluate the partial deriv- */
/* atives automatically by numerical differences ... */
/* yes - set INFO(5) = 0 */
/* no - set INFO(5) = 1 */
/* and provide subroutine JAC for evaluating the */
/* matrix of partial derivatives **** */
/* INFO(6) - used only when INFO(12) = 0 (direct methods). */
/* DDASPK will perform much better if the matrix of */
/* partial derivatives, dG/dY + CJ*dG/dYPRIME (here CJ is */
/* a scalar determined by DDASPK), is banded and the code */
/* is told this. In this case, the storage needed will be */
/* greatly reduced, numerical differencing will be performed */
/* much cheaper, and a number of important algorithms will */
/* execute much faster. The differential equation is said */
/* to have half-bandwidths ML (lower) and MU (upper) if */
/* equation i involves only unknowns Y(j) with */
/* i-ML .le. j .le. i+MU . */
/* For all i=1,2,...,NEQ. Thus, ML and MU are the widths */
/* of the lower and upper parts of the band, respectively, */
/* with the main diagonal being excluded. If you do not */
/* indicate that the equation has a banded matrix of partial */
/* derivatives the code works with a full matrix of NEQ**2 */
/* elements (stored in the conventional way). Computations */
/* with banded matrices cost less time and storage than with */
/* full matrices if 2*ML+MU .lt. NEQ. If you tell the */
/* code that the matrix of partial derivatives has a banded */
/* structure and you want to provide subroutine JAC to */
/* compute the partial derivatives, then you must be careful */
/* to store the elements of the matrix in the special form */
/* indicated in the description of JAC. */
/* **** Do you want to solve the problem using a full (dense) */
/* matrix (and not a special banded structure) ... */
/* yes - set INFO(6) = 0 */
/* no - set INFO(6) = 1 */
/* and provide the lower (ML) and upper (MU) */
/* bandwidths by setting */
/* IWORK(1)=ML */
/* IWORK(2)=MU **** */
/* INFO(7) - You can specify a maximum (absolute value of) */
/* stepsize, so that the code will avoid passing over very */
/* large regions. */
/* **** Do you want the code to decide on its own the maximum */
/* stepsize ... */
/* yes - set INFO(7) = 0 */
/* no - set INFO(7) = 1 */
/* and define HMAX by setting */
/* RWORK(2) = HMAX **** */
/* INFO(8) - Differential/algebraic problems may occasionally */
/* suffer from severe scaling difficulties on the first */
/* step. If you know a great deal about the scaling of */
/* your problem, you can help to alleviate this problem */
/* by specifying an initial stepsize H0. */
/* **** Do you want the code to define its own initial */
/* stepsize ... */
/* yes - set INFO(8) = 0 */
/* no - set INFO(8) = 1 */
/* and define H0 by setting */
/* RWORK(3) = H0 **** */
/* INFO(9) - If storage is a severe problem, you can save some */
/* storage by restricting the maximum method order MAXORD. */
/* The default value is 5. For each order decrease below 5, */
/* the code requires NEQ fewer locations, but it is likely */
/* to be slower. In any case, you must have */
/* 1 .le. MAXORD .le. 5. */
/* **** Do you want the maximum order to default to 5 ... */
/* yes - set INFO(9) = 0 */
/* no - set INFO(9) = 1 */
/* and define MAXORD by setting */
/* IWORK(3) = MAXORD **** */
/* INFO(10) - If you know that certain components of the */
/* solutions to your equations are always nonnegative */
/* (or nonpositive), it may help to set this */
/* parameter. There are three options that are */
/* available: */
/* 1. To have constraint checking only in the initial */
/* condition calculation. */
/* 2. To enforce nonnegativity in Y during the integration. */
/* 3. To enforce both options 1 and 2. */
/* When selecting option 2 or 3, it is probably best to try the */
/* code without using this option first, and only use */
/* this option if that does not work very well. */
/* **** Do you want the code to solve the problem without */
/* invoking any special inequality constraints ... */
/* yes - set INFO(10) = 0 */
/* no - set INFO(10) = 1 to have option 1 enforced */
/* no - set INFO(10) = 2 to have option 2 enforced */
/* no - set INFO(10) = 3 to have option 3 enforced **** */
/* If you have specified INFO(10) = 1 or 3, then you */
/* will also need to identify how each component of Y */
/* in the initial condition calculation is constrained. */
/* You must set: */
/* IWORK(40+I) = +1 if Y(I) must be .GE. 0, */
/* IWORK(40+I) = +2 if Y(I) must be .GT. 0, */
/* IWORK(40+I) = -1 if Y(I) must be .LE. 0, while */
/* IWORK(40+I) = -2 if Y(I) must be .LT. 0, while */
/* IWORK(40+I) = 0 if Y(I) is not constrained. */
/* INFO(11) - DDASPK normally requires the initial T, Y, and */
/* YPRIME to be consistent. That is, you must have */
/* G(T,Y,YPRIME) = 0 at the initial T. If you do not know */
/* the initial conditions precisely, in some cases */
/* DDASPK may be able to compute it. */
/* Denoting the differential variables in Y by Y_d */
/* and the algebraic variables by Y_a, DDASPK can solve */
/* one of two initialization problems: */
/* 1. Given Y_d, calculate Y_a and Y'_d, or */
/* 2. Given Y', calculate Y. */
/* In either case, initial values for the given */
/* components are input, and initial guesses for */
/* the unknown components must also be provided as input. */
/* **** Are the initial T, Y, YPRIME consistent ... */
/* yes - set INFO(11) = 0 */
/* no - set INFO(11) = 1 to calculate option 1 above, */
/* or set INFO(11) = 2 to calculate option 2 **** */
/* If you have specified INFO(11) = 1, then you */
/* will also need to identify which are the */
/* differential and which are the algebraic */
/* components (algebraic components are components */
/* whose derivatives do not appear explicitly */
/* in the function G(T,Y,YPRIME)). You must set: */
/* IWORK(LID+I) = +1 if Y(I) is a differential variable */
/* IWORK(LID+I) = -1 if Y(I) is an algebraic variable, */
/* where LID = 40 if INFO(10) = 0 or 2 and LID = 40+NEQ */
/* if INFO(10) = 1 or 3. */
/* INFO(12) - Except for the addition of the RES argument CJ, */
/* DDASPK by default is downward-compatible with DDASSL, */
/* which uses only direct (dense or band) methods to solve */
/* the linear systems involved. You must set INFO(12) to */
/* indicate whether you want the direct methods or the */
/* Krylov iterative method. */
/* **** Do you want DDASPK to use standard direct methods */
/* (dense or band) or the Krylov (iterative) method ... */
/* direct methods - set INFO(12) = 0. */
/* Krylov method - set INFO(12) = 1, */
/* and check the settings of INFO(13) and INFO(15). */
/* INFO(13) - used when INFO(12) = 1 (Krylov methods). */
/* DDASPK uses scalars MAXL, KMP, NRMAX, and EPLI for the */
/* iterative solution of linear systems. INFO(13) allows */
/* you to override the default values of these parameters. */
/* These parameters and their defaults are as follows: */
/* MAXL = maximum number of iterations in the SPIGMR */
/* algorithm (MAXL .le. NEQ). The default is */
/* MAXL = MIN(5,NEQ). */
/* KMP = number of vectors on which orthogonalization is */
/* done in the SPIGMR algorithm. The default is */
/* KMP = MAXL, which corresponds to complete GMRES */
/* iteration, as opposed to the incomplete form. */
/* NRMAX = maximum number of restarts of the SPIGMR */
/* algorithm per nonlinear iteration. The default is */
/* NRMAX = 5. */
/* EPLI = convergence test constant in SPIGMR algorithm. */
/* The default is EPLI = 0.05. */
/* Note that the length of RWORK depends on both MAXL */
/* and KMP. See the definition of LRW below. */
/* **** Are MAXL, KMP, and EPLI to be given their */
/* default values ... */
/* yes - set INFO(13) = 0 */
/* no - set INFO(13) = 1, */
/* and set all of the following: */
/* IWORK(24) = MAXL (1 .le. MAXL .le. NEQ) */
/* IWORK(25) = KMP (1 .le. KMP .le. MAXL) */
/* IWORK(26) = NRMAX (NRMAX .ge. 0) */
/* RWORK(10) = EPLI (0 .lt. EPLI .lt. 1.0) **** */
/* INFO(14) - used with INFO(11) > 0 (initial condition */
/* calculation is requested). In this case, you may */
/* request control to be returned to the calling program */
/* immediately after the initial condition calculation, */
/* before proceeding to the integration of the system */
/* (e.g. to examine the computed Y and YPRIME). */
/* If this is done, and if the initialization succeeded */
/* (IDID = 4), you should reset INFO(11) to 0 for the */
/* next call, to prevent the solver from repeating the */
/* initialization (and to avoid an infinite loop). */
/* **** Do you want to proceed to the integration after */
/* the initial condition calculation is done ... */
/* yes - set INFO(14) = 0 */
/* no - set INFO(14) = 1 **** */
/* INFO(15) - used when INFO(12) = 1 (Krylov methods). */
/* When using preconditioning in the Krylov method, */
/* you must supply a subroutine, PSOL, which solves the */
/* associated linear systems using P. */
/* The usage of DDASPK is simpler if PSOL can carry out */
/* the solution without any prior calculation of data. */
/* However, if some partial derivative data is to be */
/* calculated in advance and used repeatedly in PSOL, */
/* then you must supply a JAC routine to do this, */
/* and set INFO(15) to indicate that JAC is to be called */
/* for this purpose. For example, P might be an */
/* approximation to a part of the matrix A which can be */
/* calculated and LU-factored for repeated solutions of */
/* the preconditioner system. The arrays WP and IWP */
/* (described under JAC and PSOL) can be used to */
/* communicate data between JAC and PSOL. */
/* **** Does PSOL operate with no prior preparation ... */
/* yes - set INFO(15) = 0 (no JAC routine) */
/* no - set INFO(15) = 1 */
/* and supply a JAC routine to evaluate and */
/* preprocess any required Jacobian data. **** */
/* INFO(16) - option to exclude algebraic variables from */
/* the error test. */
/* **** Do you wish to control errors locally on */
/* all the variables... */
/* yes - set INFO(16) = 0 */
/* no - set INFO(16) = 1 */
/* If you have specified INFO(16) = 1, then you */
/* will also need to identify which are the */
/* differential and which are the algebraic */
/* components (algebraic components are components */
/* whose derivatives do not appear explicitly */
/* in the function G(T,Y,YPRIME)). You must set: */
/* IWORK(LID+I) = +1 if Y(I) is a differential */
/* variable, and */
/* IWORK(LID+I) = -1 if Y(I) is an algebraic */
/* variable, */
/* where LID = 40 if INFO(10) = 0 or 2 and */
/* LID = 40 + NEQ if INFO(10) = 1 or 3. */
/* INFO(17) - used when INFO(11) > 0 (DDASPK is to do an */
/* initial condition calculation). */
/* DDASPK uses several heuristic control quantities in the */
/* initial condition calculation. They have default values, */
/* but can also be set by the user using INFO(17). */
/* These parameters and their defaults are as follows: */
/* MXNIT = maximum number of Newton iterations */
/* per Jacobian or preconditioner evaluation. */
/* The default is: */
/* MXNIT = 5 in the direct case (INFO(12) = 0), and */
/* MXNIT = 15 in the Krylov case (INFO(12) = 1). */
/* MXNJ = maximum number of Jacobian or preconditioner */
/* evaluations. The default is: */
/* MXNJ = 6 in the direct case (INFO(12) = 0), and */
/* MXNJ = 2 in the Krylov case (INFO(12) = 1). */
/* MXNH = maximum number of values of the artificial */
/* stepsize parameter H to be tried if INFO(11) = 1. */
/* The default is MXNH = 5. */
/* NOTE: the maximum number of Newton iterations */
/* allowed in all is MXNIT*MXNJ*MXNH if INFO(11) = 1, */
/* and MXNIT*MXNJ if INFO(11) = 2. */
/* LSOFF = flag to turn off the linesearch algorithm */
/* (LSOFF = 0 means linesearch is on, LSOFF = 1 means */
/* it is turned off). The default is LSOFF = 0. */
/* STPTOL = minimum scaled step in linesearch algorithm. */
/* The default is STPTOL = (unit roundoff)**(2/3). */
/* EPINIT = swing factor in the Newton iteration convergence */
/* test. The test is applied to the residual vector, */
/* premultiplied by the approximate Jacobian (in the */
/* direct case) or the preconditioner (in the Krylov */
/* case). For convergence, the weighted RMS norm of */
/* this vector (scaled by the error weights) must be */
/* less than EPINIT*EPCON, where EPCON = .33 is the */
/* analogous test constant used in the time steps. */
/* The default is EPINIT = .01. */
/* **** Are the initial condition heuristic controls to be */
/* given their default values... */
/* yes - set INFO(17) = 0 */
/* no - set INFO(17) = 1, */
/* and set all of the following: */
/* IWORK(32) = MXNIT (.GT. 0) */
/* IWORK(33) = MXNJ (.GT. 0) */
/* IWORK(34) = MXNH (.GT. 0) */
/* IWORK(35) = LSOFF ( = 0 or 1) */
/* RWORK(14) = STPTOL (.GT. 0.0) */
/* RWORK(15) = EPINIT (.GT. 0.0) **** */
/* INFO(18) - option to get extra printing in initial condition */
/* calculation. */
/* **** Do you wish to have extra printing... */
/* no - set INFO(18) = 0 */
/* yes - set INFO(18) = 1 for minimal printing, or */
/* set INFO(18) = 2 for full printing. */
/* If you have specified INFO(18) .ge. 1, data */
/* will be printed with the error handler routines. */
/* To print to a non-default unit number L, include */
/* the line CALL XSETUN(L) in your program. **** */
/* RTOL, ATOL -- You must assign relative (RTOL) and absolute (ATOL) */
/* error tolerances to tell the code how accurately you */
/* want the solution to be computed. They must be defined */
/* as variables because the code may change them. */
/* you have two choices -- */
/* Both RTOL and ATOL are scalars (INFO(2) = 0), or */
/* both RTOL and ATOL are vectors (INFO(2) = 1). */
/* In either case all components must be non-negative. */
/* The tolerances are used by the code in a local error */
/* test at each step which requires roughly that */
/* abs(local error in Y(i)) .le. EWT(i) , */
/* where EWT(i) = RTOL*abs(Y(i)) + ATOL is an error weight */
/* quantity, for each vector component. */
/* (More specifically, a root-mean-square norm is used to */
/* measure the size of vectors, and the error test uses the */
/* magnitude of the solution at the beginning of the step.) */
/* The true (global) error is the difference between the */
/* true solution of the initial value problem and the */
/* computed approximation. Practically all present day */
/* codes, including this one, control the local error at */
/* each step and do not even attempt to control the global */
/* error directly. */
/* Usually, but not always, the true accuracy of */
/* the computed Y is comparable to the error tolerances. */
/* This code will usually, but not always, deliver a more */
/* accurate solution if you reduce the tolerances and */
/* integrate again. By comparing two such solutions you */
/* can get a fairly reliable idea of the true error in the */
/* solution at the larger tolerances. */
/* Setting ATOL = 0. results in a pure relative error test */
/* on that component. Setting RTOL = 0. results in a pure */
/* absolute error test on that component. A mixed test */
/* with non-zero RTOL and ATOL corresponds roughly to a */
/* relative error test when the solution component is */
/* much bigger than ATOL and to an absolute error test */
/* when the solution component is smaller than the */
/* threshold ATOL. */
/* The code will not attempt to compute a solution at an */
/* accuracy unreasonable for the machine being used. It */
/* will advise you if you ask for too much accuracy and */
/* inform you as to the maximum accuracy it believes */
/* possible. */
/* RWORK(*) -- a real work array, which should be dimensioned in your */
/* calling program with a length equal to the value of */
/* LRW (or greater). */
/* LRW -- Set it to the declared length of the RWORK array. The */
/* minimum length depends on the options you have selected, */
/* given by a base value plus additional storage as described */
/* below. */
/* If INFO(12) = 0 (standard direct method), the base value is */
/* base = 50 + max(MAXORD+4,7)*NEQ. */
/* The default value is MAXORD = 5 (see INFO(9)). With the */
/* default MAXORD, base = 50 + 9*NEQ. */
/* Additional storage must be added to the base value for */
/* any or all of the following options: */
/* if INFO(6) = 0 (dense matrix), add NEQ**2 */
/* if INFO(6) = 1 (banded matrix), then */
/* if INFO(5) = 0, add (2*ML+MU+1)*NEQ + 2*(NEQ/(ML+MU+1)+1), */
/* if INFO(5) = 1, add (2*ML+MU+1)*NEQ, */
/* if INFO(16) = 1, add NEQ. */
/* If INFO(12) = 1 (Krylov method), the base value is */
/* base = 50 + (MAXORD+5)*NEQ + (MAXL+3+MIN0(1,MAXL-KMP))*NEQ + */
/* + (MAXL+3)*MAXL + 1 + LENWP. */
/* See PSOL for description of LENWP. The default values are: */
/* MAXORD = 5 (see INFO(9)), MAXL = min(5,NEQ) and KMP = MAXL */
/* (see INFO(13)). */
/* With the default values for MAXORD, MAXL and KMP, */
/* base = 91 + 18*NEQ + LENWP. */
/* Additional storage must be added to the base value for */
/* any or all of the following options: */
/* if INFO(16) = 1, add NEQ. */
/* IWORK(*) -- an integer work array, which should be dimensioned in */
/* your calling program with a length equal to the value */
/* of LIW (or greater). */
/* LIW -- Set it to the declared length of the IWORK array. The */
/* minimum length depends on the options you have selected, */
/* given by a base value plus additional storage as described */
/* below. */
/* If INFO(12) = 0 (standard direct method), the base value is */
/* base = 40 + NEQ. */
/* IF INFO(10) = 1 or 3, add NEQ to the base value. */
/* If INFO(11) = 1 or INFO(16) =1, add NEQ to the base value. */
/* If INFO(12) = 1 (Krylov method), the base value is */
/* base = 40 + LENIWP. */
/* See PSOL for description of LENIWP. */
/* IF INFO(10) = 1 or 3, add NEQ to the base value. */
/* If INFO(11) = 1 or INFO(16) = 1, add NEQ to the base value. */
/* RPAR, IPAR -- These are arrays of double precision and integer type, */
/* respectively, which are available for you to use */
/* for communication between your program that calls */
/* DDASPK and the RES subroutine (and the JAC and PSOL */
/* subroutines). They are not altered by DDASPK. */
/* If you do not need RPAR or IPAR, ignore these */
/* parameters by treating them as dummy arguments. */
/* If you do choose to use them, dimension them in */
/* your calling program and in RES (and in JAC and PSOL) */
/* as arrays of appropriate length. */
/* JAC -- This is the name of a routine that you may supply */
/* (optionally) that relates to the Jacobian matrix of the */
/* nonlinear system that the code must solve at each T step. */
/* The role of JAC (and its call sequence) depends on whether */
/* a direct (INFO(12) = 0) or Krylov (INFO(12) = 1) method */
/* is selected. */
/* **** INFO(12) = 0 (direct methods): */
/* If you are letting the code generate partial derivatives */
/* numerically (INFO(5) = 0), then JAC can be absent */
/* (or perhaps a dummy routine to satisfy the loader). */
/* Otherwise you must supply a JAC routine to compute */
/* the matrix A = dG/dY + CJ*dG/dYPRIME. It must have */
/* the form */
/* SUBROUTINE JAC (T, Y, YPRIME, PD, CJ, RPAR, IPAR) */
/* The JAC routine must dimension Y, YPRIME, and PD (and RPAR */
/* and IPAR if used). CJ is a scalar which is input to JAC. */
/* For the given values of T, Y, and YPRIME, the JAC routine */
/* must evaluate the nonzero elements of the matrix A, and */
/* store these values in the array PD. The elements of PD are */
/* set to zero before each call to JAC, so that only nonzero */
/* elements need to be defined. */
/* The way you store the elements into the PD array depends */
/* on the structure of the matrix indicated by INFO(6). */
/* *** INFO(6) = 0 (full or dense matrix) *** */
/* Give PD a first dimension of NEQ. When you evaluate the */
/* nonzero partial derivatives of equation i (i.e. of G(i)) */
/* with respect to component j (of Y and YPRIME), you must */
/* store the element in PD according to */
/* PD(i,j) = dG(i)/dY(j) + CJ*dG(i)/dYPRIME(j). */
/* *** INFO(6) = 1 (banded matrix with half-bandwidths ML, MU */
/* as described under INFO(6)) *** */
/* Give PD a first dimension of 2*ML+MU+1. When you */
/* evaluate the nonzero partial derivatives of equation i */
/* (i.e. of G(i)) with respect to component j (of Y and */
/* YPRIME), you must store the element in PD according to */
/* IROW = i - j + ML + MU + 1 */
/* PD(IROW,j) = dG(i)/dY(j) + CJ*dG(i)/dYPRIME(j). */
/* **** INFO(12) = 1 (Krylov method): */
/* If you are not calculating Jacobian data in advance for use */
/* in PSOL (INFO(15) = 0), JAC can be absent (or perhaps a */
/* dummy routine to satisfy the loader). Otherwise, you may */
/* supply a JAC routine to compute and preprocess any parts of */
/* of the Jacobian matrix A = dG/dY + CJ*dG/dYPRIME that are */
/* involved in the preconditioner matrix P. */
/* It is to have the form */
/* SUBROUTINE JAC (RES, IRES, NEQ, T, Y, YPRIME, REWT, SAVR, */
/* WK, H, CJ, WP, IWP, IER, RPAR, IPAR) */
/* The JAC routine must dimension Y, YPRIME, REWT, SAVR, WK, */
/* and (if used) WP, IWP, RPAR, and IPAR. */
/* The Y, YPRIME, and SAVR arrays contain the current values */
/* of Y, YPRIME, and the residual G, respectively. */
/* The array WK is work space of length NEQ. */
/* H is the step size. CJ is a scalar, input to JAC, that is */
/* normally proportional to 1/H. REWT is an array of */
/* reciprocal error weights, 1/EWT(i), where EWT(i) is */
/* RTOL*abs(Y(i)) + ATOL (unless you supplied routine DDAWTS */
/* instead), for use in JAC if needed. For example, if JAC */
/* computes difference quotient approximations to partial */
/* derivatives, the REWT array may be useful in setting the */
/* increments used. The JAC routine should do any */
/* factorization operations called for, in preparation for */
/* solving linear systems in PSOL. The matrix P should */
/* be an approximation to the Jacobian, */
/* A = dG/dY + CJ*dG/dYPRIME. */
/* WP and IWP are real and integer work arrays which you may */
/* use for communication between your JAC routine and your */
/* PSOL routine. These may be used to store elements of the */
/* preconditioner P, or related matrix data (such as factored */
/* forms). They are not altered by DDASPK. */
/* If you do not need WP or IWP, ignore these parameters by */
/* treating them as dummy arguments. If you do use them, */
/* dimension them appropriately in your JAC and PSOL routines. */
/* See the PSOL description for instructions on setting */
/* the lengths of WP and IWP. */
/* On return, JAC should set the error flag IER as follows.. */
/* IER = 0 if JAC was successful, */
/* IER .ne. 0 if JAC was unsuccessful (e.g. if Y or YPRIME */
/* was illegal, or a singular matrix is found). */
/* (If IER .ne. 0, a smaller stepsize will be tried.) */
/* IER = 0 on entry to JAC, so need be reset only on a failure. */
/* If RES is used within JAC, then a nonzero value of IRES will */
/* override any nonzero value of IER (see the RES description). */
/* Regardless of the method type, subroutine JAC must not */
/* alter T, Y(*), YPRIME(*), H, CJ, or REWT(*). */
/* You must declare the name JAC in an EXTERNAL statement in */
/* your program that calls DDASPK. */
/* PSOL -- This is the name of a routine you must supply if you have */
/* selected a Krylov method (INFO(12) = 1) with preconditioning. */
/* In the direct case (INFO(12) = 0), PSOL can be absent */
/* (a dummy routine may have to be supplied to satisfy the */
/* loader). Otherwise, you must provide a PSOL routine to */
/* solve linear systems arising from preconditioning. */
/* When supplied with INFO(12) = 1, the PSOL routine is to */
/* have the form */
/* SUBROUTINE PSOL (NEQ, T, Y, YPRIME, SAVR, WK, CJ, WGHT, */
/* WP, IWP, B, EPLIN, IER, RPAR, IPAR) */
/* The PSOL routine must solve linear systems of the form */
/* P*x = b where P is the left preconditioner matrix. */
/* The right-hand side vector b is in the B array on input, and */
/* PSOL must return the solution vector x in B. */
/* The Y, YPRIME, and SAVR arrays contain the current values */
/* of Y, YPRIME, and the residual G, respectively. */
/* Work space required by JAC and/or PSOL, and space for data to */
/* be communicated from JAC to PSOL is made available in the form */
/* of arrays WP and IWP, which are parts of the RWORK and IWORK */
/* arrays, respectively. The lengths of these real and integer */
/* work spaces WP and IWP must be supplied in LENWP and LENIWP, */
/* respectively, as follows.. */
/* IWORK(27) = LENWP = length of real work space WP */
/* IWORK(28) = LENIWP = length of integer work space IWP. */
/* WK is a work array of length NEQ for use by PSOL. */
/* CJ is a scalar, input to PSOL, that is normally proportional */
/* to 1/H (H = stepsize). If the old value of CJ */
/* (at the time of the last JAC call) is needed, it must have */
/* been saved by JAC in WP. */
/* WGHT is an array of weights, to be used if PSOL uses an */
/* iterative method and performs a convergence test. (In terms */
/* of the argument REWT to JAC, WGHT is REWT/sqrt(NEQ).) */
/* If PSOL uses an iterative method, it should use EPLIN */
/* (a heuristic parameter) as the bound on the weighted norm of */
/* the residual for the computed solution. Specifically, the */
/* residual vector R should satisfy */
/* SQRT (SUM ( (R(i)*WGHT(i))**2 ) ) .le. EPLIN */
/* PSOL must not alter NEQ, T, Y, YPRIME, SAVR, CJ, WGHT, EPLIN. */
/* On return, PSOL should set the error flag IER as follows.. */
/* IER = 0 if PSOL was successful, */
/* IER .lt. 0 if an unrecoverable error occurred, meaning */
/* control will be passed to the calling routine, */
/* IER .gt. 0 if a recoverable error occurred, meaning that */
/* the step will be retried with the same step size */
/* but with a call to JAC to update necessary data, */
/* unless the Jacobian data is current, in which case */
/* the step will be retried with a smaller step size. */
/* IER = 0 on entry to PSOL so need be reset only on a failure. */
/* You must declare the name PSOL in an EXTERNAL statement in */
/* your program that calls DDASPK. */
/* OPTIONALLY REPLACEABLE SUBROUTINE: */
/* DDASPK uses a weighted root-mean-square norm to measure the */
/* size of various error vectors. The weights used in this norm */
/* are set in the following subroutine: */
/* SUBROUTINE DDAWTS (NEQ, IWT, RTOL, ATOL, Y, EWT, RPAR, IPAR) */
/* DIMENSION RTOL(*), ATOL(*), Y(*), EWT(*), RPAR(*), IPAR(*) */
/* A DDAWTS routine has been included with DDASPK which sets the */
/* weights according to */
/* EWT(I) = RTOL*ABS(Y(I)) + ATOL */
/* in the case of scalar tolerances (IWT = 0) or */
/* EWT(I) = RTOL(I)*ABS(Y(I)) + ATOL(I) */
/* in the case of array tolerances (IWT = 1). (IWT is INFO(2).) */
/* In some special cases, it may be appropriate for you to define */
/* your own error weights by writing a subroutine DDAWTS to be */
/* called instead of the version supplied. However, this should */
/* be attempted only after careful thought and consideration. */
/* If you supply this routine, you may use the tolerances and Y */
/* as appropriate, but do not overwrite these variables. You */
/* may also use RPAR and IPAR to communicate data as appropriate. */
/* ***Note: Aside from the values of the weights, the choice of */
/* norm used in DDASPK (weighted root-mean-square) is not subject */
/* to replacement by the user. In this respect, DDASPK is not */
/* downward-compatible with the original DDASSL solver (in which */
/* the norm routine was optionally user-replaceable). */
/* ------OUTPUT - AFTER ANY RETURN FROM DDASPK---------------------------- */
/* The principal aim of the code is to return a computed solution at */
/* T = TOUT, although it is also possible to obtain intermediate */
/* results along the way. To find out whether the code achieved its */
/* goal or if the integration process was interrupted before the task */
/* was completed, you must check the IDID parameter. */
/* T -- The output value of T is the point to which the solution */
/* was successfully advanced. */
/* Y(*) -- contains the computed solution approximation at T. */
/* YPRIME(*) -- contains the computed derivative approximation at T. */
/* IDID -- reports what the code did, described as follows: */
/* *** TASK COMPLETED *** */
/* Reported by positive values of IDID */
/* IDID = 1 -- a step was successfully taken in the */
/* intermediate-output mode. The code has not */
/* yet reached TOUT. */
/* IDID = 2 -- the integration to TSTOP was successfully */
/* completed (T = TSTOP) by stepping exactly to TSTOP. */
/* IDID = 3 -- the integration to TOUT was successfully */
/* completed (T = TOUT) by stepping past TOUT. */
/* Y(*) and YPRIME(*) are obtained by interpolation. */
/* IDID = 4 -- the initial condition calculation, with */
/* INFO(11) > 0, was successful, and INFO(14) = 1. */
/* No integration steps were taken, and the solution */
/* is not considered to have been started. */
/* *** TASK INTERRUPTED *** */
/* Reported by negative values of IDID */
/* IDID = -1 -- a large amount of work has been expended */
/* (about 500 steps). */
/* IDID = -2 -- the error tolerances are too stringent. */
/* IDID = -3 -- the local error test cannot be satisfied */
/* because you specified a zero component in ATOL */
/* and the corresponding computed solution component */
/* is zero. Thus, a pure relative error test is */
/* impossible for this component. */
/* IDID = -5 -- there were repeated failures in the evaluation */
/* or processing of the preconditioner (in JAC). */
/* IDID = -6 -- DDASPK had repeated error test failures on the */
/* last attempted step. */
/* IDID = -7 -- the nonlinear system solver in the time integration */
/* could not converge. */
/* IDID = -8 -- the matrix of partial derivatives appears */
/* to be singular (direct method). */
/* IDID = -9 -- the nonlinear system solver in the time integration */
/* failed to achieve convergence, and there were repeated */
/* error test failures in this step. */
/* IDID =-10 -- the nonlinear system solver in the time integration */
/* failed to achieve convergence because IRES was equal */
/* to -1. */
/* IDID =-11 -- IRES = -2 was encountered and control is */
/* being returned to the calling program. */
/* IDID =-12 -- DDASPK failed to compute the initial Y, YPRIME. */
/* IDID =-13 -- unrecoverable error encountered inside user's */
/* PSOL routine, and control is being returned to */
/* the calling program. */
/* IDID =-14 -- the Krylov linear system solver could not */
/* achieve convergence. */
/* IDID =-15,..,-32 -- Not applicable for this code. */
/* *** TASK TERMINATED *** */
/* reported by the value of IDID=-33 */
/* IDID = -33 -- the code has encountered trouble from which */
/* it cannot recover. A message is printed */
/* explaining the trouble and control is returned */
/* to the calling program. For example, this occurs */
/* when invalid input is detected. */
/* RTOL, ATOL -- these quantities remain unchanged except when */
/* IDID = -2. In this case, the error tolerances have been */
/* increased by the code to values which are estimated to */
/* be appropriate for continuing the integration. However, */
/* the reported solution at T was obtained using the input */
/* values of RTOL and ATOL. */
/* RWORK, IWORK -- contain information which is usually of no interest */
/* to the user but necessary for subsequent calls. */
/* However, you may be interested in the performance data */
/* listed below. These quantities are accessed in RWORK */
/* and IWORK but have internal mnemonic names, as follows.. */
/* RWORK(3)--contains H, the step size h to be attempted */
/* on the next step. */
/* RWORK(4)--contains TN, the current value of the */
/* independent variable, i.e. the farthest point */
/* integration has reached. This will differ */
/* from T if interpolation has been performed */
/* (IDID = 3). */
/* RWORK(7)--contains HOLD, the stepsize used on the last */
/* successful step. If INFO(11) = INFO(14) = 1, */
/* this contains the value of H used in the */
/* initial condition calculation. */
/* IWORK(7)--contains K, the order of the method to be */
/* attempted on the next step. */
/* IWORK(8)--contains KOLD, the order of the method used */
/* on the last step. */
/* IWORK(11)--contains NST, the number of steps (in T) */
/* taken so far. */
/* IWORK(12)--contains NRE, the number of calls to RES */
/* so far. */
/* IWORK(13)--contains NJE, the number of calls to JAC so */
/* far (Jacobian or preconditioner evaluations). */
/* IWORK(14)--contains NETF, the total number of error test */
/* failures so far. */
/* IWORK(15)--contains NCFN, the total number of nonlinear */
/* convergence failures so far (includes counts */
/* of singular iteration matrix or singular */
/* preconditioners). */
/* IWORK(16)--contains NCFL, the number of convergence */
/* failures of the linear iteration so far. */
/* IWORK(17)--contains LENIW, the length of IWORK actually */
/* required. This is defined on normal returns */
/* and on an illegal input return for */
/* insufficient storage. */
/* IWORK(18)--contains LENRW, the length of RWORK actually */
/* required. This is defined on normal returns */
/* and on an illegal input return for */
/* insufficient storage. */
/* IWORK(19)--contains NNI, the total number of nonlinear */
/* iterations so far (each of which calls a */
/* linear solver). */
/* IWORK(20)--contains NLI, the total number of linear */
/* (Krylov) iterations so far. */
/* IWORK(21)--contains NPS, the number of PSOL calls so */
/* far, for preconditioning solve operations or */
/* for solutions with the user-supplied method. */
/* Note: The various counters in IWORK do not include */
/* counts during a call made with INFO(11) > 0 and */
/* INFO(14) = 1. */
/* ------INPUT - WHAT TO DO TO CONTINUE THE INTEGRATION ----------------- */
/* (CALLS AFTER THE FIRST) */
/* This code is organized so that subsequent calls to continue the */
/* integration involve little (if any) additional effort on your */
/* part. You must monitor the IDID parameter in order to determine */
/* what to do next. */
/* Recalling that the principal task of the code is to integrate */
/* from T to TOUT (the interval mode), usually all you will need */
/* to do is specify a new TOUT upon reaching the current TOUT. */
/* Do not alter any quantity not specifically permitted below. In */
/* particular do not alter NEQ, T, Y(*), YPRIME(*), RWORK(*), */
/* IWORK(*), or the differential equation in subroutine RES. Any */
/* such alteration constitutes a new problem and must be treated */
/* as such, i.e. you must start afresh. */
/* You cannot change from array to scalar error control or vice */
/* versa (INFO(2)), but you can change the size of the entries of */
/* RTOL or ATOL. Increasing a tolerance makes the equation easier */
/* to integrate. Decreasing a tolerance will make the equation */
/* harder to integrate and should generally be avoided. */
/* You can switch from the intermediate-output mode to the */
/* interval mode (INFO(3)) or vice versa at any time. */
/* If it has been necessary to prevent the integration from going */
/* past a point TSTOP (INFO(4), RWORK(1)), keep in mind that the */
/* code will not integrate to any TOUT beyond the currently */
/* specified TSTOP. Once TSTOP has been reached, you must change */
/* the value of TSTOP or set INFO(4) = 0. You may change INFO(4) */
/* or TSTOP at any time but you must supply the value of TSTOP in */
/* RWORK(1) whenever you set INFO(4) = 1. */
/* Do not change INFO(5), INFO(6), INFO(12-17) or their associated */
/* IWORK/RWORK locations unless you are going to restart the code. */
/* *** FOLLOWING A COMPLETED TASK *** */
/* If.. */
/* IDID = 1, call the code again to continue the integration */
/* another step in the direction of TOUT. */
/* IDID = 2 or 3, define a new TOUT and call the code again. */
/* TOUT must be different from T. You cannot change */
/* the direction of integration without restarting. */
/* IDID = 4, reset INFO(11) = 0 and call the code again to begin */
/* the integration. (If you leave INFO(11) > 0 and */
/* INFO(14) = 1, you may generate an infinite loop.) */
/* In this situation, the next call to DASPK is */
/* considered to be the first call for the problem, */
/* in that all initializations are done. */
/* *** FOLLOWING AN INTERRUPTED TASK *** */
/* To show the code that you realize the task was interrupted and */
/* that you want to continue, you must take appropriate action and */
/* set INFO(1) = 1. */
/* If.. */
/* IDID = -1, the code has taken about 500 steps. If you want to */
/* continue, set INFO(1) = 1 and call the code again. */
/* An additional 500 steps will be allowed. */
/* IDID = -2, the error tolerances RTOL, ATOL have been increased */
/* to values the code estimates appropriate for */
/* continuing. You may want to change them yourself. */
/* If you are sure you want to continue with relaxed */
/* error tolerances, set INFO(1) = 1 and call the code */
/* again. */
/* IDID = -3, a solution component is zero and you set the */
/* corresponding component of ATOL to zero. If you */
/* are sure you want to continue, you must first alter */
/* the error criterion to use positive values of ATOL */
/* for those components corresponding to zero solution */
/* components, then set INFO(1) = 1 and call the code */
/* again. */
/* IDID = -4 --- cannot occur with this code. */
/* IDID = -5, your JAC routine failed with the Krylov method. Check */
/* for errors in JAC and restart the integration. */
/* IDID = -6, repeated error test failures occurred on the last */
/* attempted step in DDASPK. A singularity in the */
/* solution may be present. If you are absolutely */
/* certain you want to continue, you should restart */
/* the integration. (Provide initial values of Y and */
/* YPRIME which are consistent.) */
/* IDID = -7, repeated convergence test failures occurred on the last */
/* attempted step in DDASPK. An inaccurate or ill- */
/* conditioned Jacobian or preconditioner may be the */
/* problem. If you are absolutely certain you want */
/* to continue, you should restart the integration. */
/* IDID = -8, the matrix of partial derivatives is singular, with */
/* the use of direct methods. Some of your equations */
/* may be redundant. DDASPK cannot solve the problem */
/* as stated. It is possible that the redundant */
/* equations could be removed, and then DDASPK could */
/* solve the problem. It is also possible that a */
/* solution to your problem either does not exist */
/* or is not unique. */
/* IDID = -9, DDASPK had multiple convergence test failures, preceded */
/* by multiple error test failures, on the last */
/* attempted step. It is possible that your problem is */
/* ill-posed and cannot be solved using this code. Or, */
/* there may be a discontinuity or a singularity in the */
/* solution. If you are absolutely certain you want to */
/* continue, you should restart the integration. */
/* IDID = -10, DDASPK had multiple convergence test failures */
/* because IRES was equal to -1. If you are */
/* absolutely certain you want to continue, you */
/* should restart the integration. */
/* IDID = -11, there was an unrecoverable error (IRES = -2) from RES */
/* inside the nonlinear system solver. Determine the */
/* cause before trying again. */
/* IDID = -12, DDASPK failed to compute the initial Y and YPRIME */
/* vectors. This could happen because the initial */
/* approximation to Y or YPRIME was not very good, or */
/* because no consistent values of these vectors exist. */
/* The problem could also be caused by an inaccurate or */
/* singular iteration matrix, or a poor preconditioner. */
/* IDID = -13, there was an unrecoverable error encountered inside */
/* your PSOL routine. Determine the cause before */
/* trying again. */
/* IDID = -14, the Krylov linear system solver failed to achieve */
/* convergence. This may be due to ill-conditioning */
/* in the iteration matrix, or a singularity in the */
/* preconditioner (if one is being used). */
/* Another possibility is that there is a better */
/* choice of Krylov parameters (see INFO(13)). */
/* Possibly the failure is caused by redundant equations */
/* in the system, or by inconsistent equations. */
/* In that case, reformulate the system to make it */
/* consistent and non-redundant. */
/* IDID = -15,..,-32 --- Cannot occur with this code. */
/* *** FOLLOWING A TERMINATED TASK *** */
/* If IDID = -33, you cannot continue the solution of this problem. */
/* An attempt to do so will result in your run being */
/* terminated. */
/* --------------------------------------------------------------------- */
/* ***REFERENCES */
/* 1. L. R. Petzold, A Description of DASSL: A Differential/Algebraic */
/* System Solver, in Scientific Computing, R. S. Stepleman et al. */
/* (Eds.), North-Holland, Amsterdam, 1983, pp. 65-68. */
/* 2. K. E. Brenan, S. L. Campbell, and L. R. Petzold, Numerical */
/* Solution of Initial-Value Problems in Differential-Algebraic */
/* Equations, Elsevier, New York, 1989. */
/* 3. P. N. Brown and A. C. Hindmarsh, Reduced Storage Matrix Methods */
/* in Stiff ODE Systems, J. Applied Mathematics and Computation, */
/* 31 (1989), pp. 40-91. */
/* 4. P. N. Brown, A. C. Hindmarsh, and L. R. Petzold, Using Krylov */
/* Methods in the Solution of Large-Scale Differential-Algebraic */
/* Systems, SIAM J. Sci. Comp., 15 (1994), pp. 1467-1488. */
/* 5. P. N. Brown, A. C. Hindmarsh, and L. R. Petzold, Consistent */
/* Initial Condition Calculation for Differential-Algebraic */
/* Systems, SIAM J. Sci. Comp. 19 (1998), pp. 1495-1512. */
/* ***ROUTINES CALLED */
/* The following are all the subordinate routines used by DDASPK. */
/* DDASIC computes consistent initial conditions. */
/* DYYPNW updates Y and YPRIME in linesearch for initial condition */
/* calculation. */
/* DDSTP carries out one step of the integration. */
/* DCNSTR/DCNST0 check the current solution for constraint violations. */
/* DDAWTS sets error weight quantities. */
/* DINVWT tests and inverts the error weights. */
/* DDATRP performs interpolation to get an output solution. */
/* DDWNRM computes the weighted root-mean-square norm of a vector. */
/* D1MACH provides the unit roundoff of the computer. */
/* XERRWD/XSETF/XSETUN/IXSAV is a package to handle error messages. */
/* DDASID nonlinear equation driver to initialize Y and YPRIME using */
/* direct linear system solver methods. Interfaces to Newton */
/* solver (direct case). */
/* DNSID solves the nonlinear system for unknown initial values by */
/* modified Newton iteration and direct linear system methods. */
/* DLINSD carries out linesearch algorithm for initial condition */
/* calculation (direct case). */
/* DFNRMD calculates weighted norm of preconditioned residual in */
/* initial condition calculation (direct case). */
/* DNEDD nonlinear equation driver for direct linear system solver */
/* methods. Interfaces to Newton solver (direct case). */
/* DMATD assembles the iteration matrix (direct case). */
/* DNSD solves the associated nonlinear system by modified */
/* Newton iteration and direct linear system methods. */
/* DSLVD interfaces to linear system solver (direct case). */
/* DDASIK nonlinear equation driver to initialize Y and YPRIME using */
/* Krylov iterative linear system methods. Interfaces to */
/* Newton solver (Krylov case). */
/* DNSIK solves the nonlinear system for unknown initial values by */
/* Newton iteration and Krylov iterative linear system methods. */
/* DLINSK carries out linesearch algorithm for initial condition */
/* calculation (Krylov case). */
/* DFNRMK calculates weighted norm of preconditioned residual in */
/* initial condition calculation (Krylov case). */
/* DNEDK nonlinear equation driver for iterative linear system solver */
/* methods. Interfaces to Newton solver (Krylov case). */
/* DNSK solves the associated nonlinear system by Inexact Newton */
/* iteration and (linear) Krylov iteration. */
/* DSLVK interfaces to linear system solver (Krylov case). */
/* DSPIGM solves a linear system by SPIGMR algorithm. */
/* DATV computes matrix-vector product in Krylov algorithm. */
/* DORTH performs orthogonalization of Krylov basis vectors. */
/* DHEQR performs QR factorization of Hessenberg matrix. */
/* DHELS finds least-squares solution of Hessenberg linear system. */
/* DGEFA, DGESL, DGBFA, DGBSL are LINPACK routines for solving */
/* linear systems (dense or band direct methods). */
/* DAXPY, DCOPY, DDOT, DNRM2, DSCAL are Basic Linear Algebra (BLAS) */
/* routines. */
/* The routines called directly by DDASPK are: */
/* DCNST0, DDAWTS, DINVWT, D1MACH, DDWNRM, DDASIC, DDATRP, DDSTP, */
/* XERRWD */
/* ***END PROLOGUE DDASPK */
/* Set pointers into IWORK. */
/* Set pointers into RWORK. */
/* ***FIRST EXECUTABLE STATEMENT DDASPK */
/* Parameter adjustments */
--y;
--yprime;
--info;
--rtol;
--atol;
--rwork;
--iwork;
--rpar;
--ipar;
/* Function Body */
if (info[1] != 0) {
goto L100;
}
/* ----------------------------------------------------------------------- */
/* This block is executed for the initial call only. */
/* It contains checking of inputs and initializations. */
/* ----------------------------------------------------------------------- */
/* First check INFO array to make sure all elements of INFO */
/* Are within the proper range. (INFO(1) is checked later, because */
/* it must be tested on every call.) ITEMP holds the location */
/* within INFO which may be out of range. */
for (i__ = 2; i__ <= 9; ++i__) {
itemp = i__;
if (info[i__] != 0 && info[i__] != 1) {
goto L701;
}
/* L10: */
}
itemp = 10;
if (info[10] < 0 || info[10] > 3) {
goto L701;
}
itemp = 11;
if (info[11] < 0 || info[11] > 2) {
goto L701;
}
for (i__ = 12; i__ <= 17; ++i__) {
itemp = i__;
if (info[i__] != 0 && info[i__] != 1) {
goto L701;
}
/* L15: */
}
itemp = 18;
if (info[18] < 0 || info[18] > 2) {
goto L701;
}
/* Check NEQ to see if it is positive. */
if (*neq <= 0) {
goto L702;
}
/* Check and compute maximum order. */
mxord = 5;
if (info[9] != 0) {
mxord = iwork[3];
if (mxord < 1 || mxord > 5) {
goto L703;
}
}
iwork[3] = mxord;
/* Set and/or check inputs for constraint checking (INFO(10) .NE. 0). */
/* Set values for ICNFLG, NONNEG, and pointer LID. */
icnflg = 0;
nonneg = 0;
lid = 41;
if (info[10] == 0) {
goto L20;
}
if (info[10] == 1) {
icnflg = 1;
nonneg = 0;
lid = *neq + 41;
} else if (info[10] == 2) {
icnflg = 0;
nonneg = 1;
} else {
icnflg = 1;
nonneg = 1;
lid = *neq + 41;
}
L20:
/* Set and/or check inputs for Krylov solver (INFO(12) .NE. 0). */
/* If indicated, set default values for MAXL, KMP, NRMAX, and EPLI. */
/* Otherwise, verify inputs required for iterative solver. */
if (info[12] == 0) {
goto L25;
}
iwork[23] = info[12];
if (info[13] == 0) {
iwork[24] = min(5,*neq);
iwork[25] = iwork[24];
iwork[26] = 5;
rwork[10] = .05;
} else {
if (iwork[24] < 1 || iwork[24] > *neq) {
goto L720;
}
if (iwork[25] < 1 || iwork[25] > iwork[24]) {
goto L721;
}
if (iwork[26] < 0) {
goto L722;
}
if (rwork[10] <= 0. || rwork[10] >= 1.) {
goto L723;
}
}
L25:
/* Set and/or check controls for the initial condition calculation */
/* (INFO(11) .GT. 0). If indicated, set default values. */
/* Otherwise, verify inputs required for iterative solver. */
if (info[11] == 0) {
goto L30;
}
if (info[17] == 0) {
iwork[32] = 5;
if (info[12] > 0) {
iwork[32] = 15;
}
iwork[33] = 6;
if (info[12] > 0) {
iwork[33] = 2;
}
iwork[34] = 5;
iwork[35] = 0;
rwork[15] = .01;
} else {
if (iwork[32] <= 0) {
goto L725;
}
if (iwork[33] <= 0) {
goto L725;
}
if (iwork[34] <= 0) {
goto L725;
}
lsoff = iwork[35];
if (lsoff < 0 || lsoff > 1) {
goto L725;
}
if (rwork[15] <= 0.) {
goto L725;
}
}
L30:
/* Below is the computation and checking of the work array lengths */
/* LENIW and LENRW, using direct methods (INFO(12) = 0) or */
/* the Krylov methods (INFO(12) = 1). */
lenic = 0;
if (info[10] == 1 || info[10] == 3) {
lenic = *neq;
}
lenid = 0;
if (info[11] == 1 || info[16] == 1) {
lenid = *neq;
}
if (info[12] == 0) {
/* Compute MTYPE, etc. Check ML and MU. */
/* Computing MAX */
i__1 = mxord + 1;
ncphi = max(i__1,4);
if (info[6] == 0) {
/* Computing 2nd power */
i__1 = *neq;
lenpd = i__1 * i__1;
lenrw = (ncphi + 3) * *neq + 50 + lenpd;
if (info[5] == 0) {
iwork[4] = 2;
} else {
iwork[4] = 1;
}
} else {
if (iwork[1] < 0 || iwork[1] >= *neq) {
goto L717;
}
if (iwork[2] < 0 || iwork[2] >= *neq) {
goto L718;
}
lenpd = ((iwork[1] << 1) + iwork[2] + 1) * *neq;
if (info[5] == 0) {
iwork[4] = 5;
mband = iwork[1] + iwork[2] + 1;
msave = *neq / mband + 1;
lenrw = (ncphi + 3) * *neq + 50 + lenpd + (msave << 1);
} else {
iwork[4] = 4;
lenrw = (ncphi + 3) * *neq + 50 + lenpd;
}
}
/* Compute LENIW, LENWP, LENIWP. */
leniw = lenic + 40 + lenid + *neq;
lenwp = 0;
leniwp = 0;
} else if (info[12] == 1) {
ncphi = mxord + 1;
maxl = iwork[24];
lenwp = iwork[27];
leniwp = iwork[28];
/* Computing MIN */
i__1 = 1, i__2 = maxl - iwork[25];
lenpd = (maxl + 3 + min(i__1,i__2)) * *neq + (maxl + 3) * maxl + 1 +
lenwp;
lenrw = (mxord + 5) * *neq + 50 + lenpd;
leniw = lenic + 40 + lenid + leniwp;
}
if (info[16] != 0) {
lenrw += *neq;
}
/* Check lengths of RWORK and IWORK. */
iwork[17] = leniw;
iwork[18] = lenrw;
iwork[22] = lenpd;
iwork[29] = lenpd - lenwp + 1;
if (*lrw < lenrw) {
goto L704;
}
if (*liw < leniw) {
goto L705;
}
/* Check ICNSTR for legality. */
if (lenic > 0) {
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
ici = iwork[i__ + 40];
if (ici < -2 || ici > 2) {
goto L726;
}
/* L40: */
}
}
/* Check Y for consistency with constraints. */
if (lenic > 0) {
dcnst0_(neq, &y[1], &iwork[41], &iret);
if (iret != 0) {
goto L727;
}
}
/* Check ID for legality and set INDEX = 0 or 1. */
index = 1;
if (lenid > 0) {
index = 0;
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
idi = iwork[lid - 1 + i__];
if (idi != 1 && idi != -1) {
goto L724;
}
if (idi == -1) {
index = 1;
}
/* L50: */
}
}
/* Check to see that TOUT is different from T. */
if (*tout == *t) {
goto L719;
}
/* Check HMAX. */
if (info[7] != 0) {
hmax = rwork[2];
if (hmax <= 0.) {
goto L710;
}
}
/* Initialize counters and other flags. */
iwork[11] = 0;
iwork[12] = 0;
iwork[13] = 0;
iwork[14] = 0;
iwork[15] = 0;
iwork[19] = 0;
iwork[20] = 0;
iwork[21] = 0;
iwork[16] = 0;
iwork[31] = info[18];
*idid = 1;
goto L200;
/* ----------------------------------------------------------------------- */
/* This block is for continuation calls only. */
/* Here we check INFO(1), and if the last step was interrupted, */
/* we check whether appropriate action was taken. */
/* ----------------------------------------------------------------------- */
L100:
if (info[1] == 1) {
goto L110;
}
itemp = 1;
if (info[1] != -1) {
goto L701;
}
/* If we are here, the last step was interrupted by an error */
/* condition from DDSTP, and appropriate action was not taken. */
/* This is a fatal error. */
s_copy(msg, "DASPK-- THE LAST STEP TERMINATED WITH A NEGATIVE", (ftnlen)
80, (ftnlen)49);
xerrwd_(msg, &c__49, &c__201, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
s_copy(msg, "DASPK-- VALUE (=I1) OF IDID AND NO APPROPRIATE", (ftnlen)80,
(ftnlen)47);
xerrwd_(msg, &c__47, &c__202, &c__0, &c__1, idid, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
s_copy(msg, "DASPK-- ACTION WAS TAKEN. RUN TERMINATED", (ftnlen)80, (
ftnlen)41);
xerrwd_(msg, &c__41, &c__203, &c__1, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
return 0;
L110:
/* ----------------------------------------------------------------------- */
/* This block is executed on all calls. */
/* Counters are saved for later checks of performance. */
/* Then the error tolerance parameters are checked, and the */
/* work array pointers are set. */
/* ----------------------------------------------------------------------- */
L200:
/* Save counters for use later. */
iwork[10] = iwork[11];
nli0 = iwork[20];
nni0 = iwork[19];
ncfn0 = iwork[15];
ncfl0 = iwork[16];
nwarn = 0;
/* Check RTOL and ATOL. */
nzflg = 0;
rtoli = rtol[1];
atoli = atol[1];
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
if (info[2] == 1) {
rtoli = rtol[i__];
}
if (info[2] == 1) {
atoli = atol[i__];
}
if (rtoli > 0. || atoli > 0.) {
nzflg = 1;
}
if (rtoli < 0.) {
goto L706;
}
if (atoli < 0.) {
goto L707;
}
/* L210: */
}
if (nzflg == 0) {
goto L708;
}
/* Set pointers to RWORK and IWORK segments. */
/* For direct methods, SAVR is not used. */
iwork[30] = lid + lenid;
lsavr = 51;
if (info[12] != 0) {
lsavr = *neq + 51;
}
le = lsavr + *neq;
lwt = le + *neq;
lvt = lwt;
if (info[16] != 0) {
lvt = lwt + *neq;
}
lphi = lvt + *neq;
lwm = lphi + ncphi * *neq;
if (info[1] == 1) {
goto L400;
}
/* ----------------------------------------------------------------------- */
/* This block is executed on the initial call only. */
/* Set the initial step size, the error weight vector, and PHI. */
/* Compute unknown initial components of Y and YPRIME, if requested. */
/* ----------------------------------------------------------------------- */
/* L300: */
tn = *t;
*idid = 1;
/* Set error weight array WT and altered weight array VT. */
ddawts_(neq, &info[2], &rtol[1], &atol[1], &y[1], &rwork[lwt], &rpar[1], &
ipar[1]);
dinvwt_(neq, &rwork[lwt], &ier);
if (ier != 0) {
goto L713;
}
if (info[16] != 0) {
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L305: */
/* Computing MAX */
i__2 = iwork[lid + i__ - 1];
rwork[lvt + i__ - 1] = max(i__2,0) * rwork[lwt + i__ - 1];
}
}
/* Compute unit roundoff and HMIN. */
uround = d1mach_(&c__4);
rwork[9] = uround;
/* Computing MAX */
d__1 = abs(*t), d__2 = abs(*tout);
hmin = uround * 4. * max(d__1,d__2);
/* Set/check STPTOL control for initial condition calculation. */
if (info[11] != 0) {
if (info[17] == 0) {
rwork[14] = pow_dd(&uround, &c_b67);
} else {
if (rwork[14] <= 0.) {
goto L725;
}
}
}
/* Compute EPCON and square root of NEQ and its reciprocal, used */
/* inside iterative solver. */
rwork[13] = .33;
floatn = (doublereal) (*neq);
rwork[11] = sqrt(floatn);
rwork[12] = 1. / rwork[11];
/* Check initial interval to see that it is long enough. */
tdist = (d__1 = *tout - *t, abs(d__1));
if (tdist < hmin) {
goto L714;
}
/* Check H0, if this was input. */
if (info[8] == 0) {
goto L310;
}
h0 = rwork[3];
if ((*tout - *t) * h0 < 0.) {
goto L711;
}
if (h0 == 0.) {
goto L712;
}
goto L320;
L310:
/* Compute initial stepsize, to be used by either */
/* DDSTP or DDASIC, depending on INFO(11). */
h0 = tdist * .001;
ypnorm = ddwnrm_(neq, &yprime[1], &rwork[lvt], &rpar[1], &ipar[1]);
if (ypnorm > .5 / h0) {
h0 = .5 / ypnorm;
}
d__1 = *tout - *t;
h0 = d_sign(&h0, &d__1);
/* Adjust H0 if necessary to meet HMAX bound. */
L320:
if (info[7] == 0) {
goto L330;
}
rh = abs(h0) / rwork[2];
if (rh > 1.) {
h0 /= rh;
}
/* Check against TSTOP, if applicable. */
L330:
if (info[4] == 0) {
goto L340;
}
tstop = rwork[1];
s_wsle(&io___49);
do_lio(&c__9, &c__1, "tstop = ", (ftnlen)8);
do_lio(&c__5, &c__1, (char *)&tstop, (ftnlen)sizeof(doublereal));
e_wsle();
if ((tstop - *t) * h0 < 0.) {
goto L715;
}
if ((*t + h0 - tstop) * h0 > 0.) {
h0 = tstop - *t;
}
if ((tstop - *tout) * h0 < 0.) {
goto L709;
}
L340:
if (info[11] == 0) {
goto L370;
}
/* Compute unknown components of initial Y and YPRIME, depending */
/* on INFO(11) and INFO(12). INFO(12) represents the nonlinear */
/* solver type (direct/Krylov). Pass the name of the specific */
/* nonlinear solver, depending on INFO(12). The location of the work */
/* arrays SAVR, YIC, YPIC, PWK also differ in the two cases. */
/* For use in stopping tests, pass TSCALE = TDIST if INDEX = 0. */
nwt = 1;
epconi = rwork[15] * rwork[13];
tscale = 0.;
if (index == 0) {
tscale = tdist;
}
L350:
if (info[12] == 0) {
lyic = lphi + (*neq << 1);
lypic = lyic + *neq;
lpwk = lypic;
ddasic_(&tn, &y[1], &yprime[1], neq, &info[11], &iwork[lid], (U_fp)
res, (U_fp)jac, (U_fp)psol, &h0, &tscale, &rwork[lwt], &nwt,
idid, &rpar[1], &ipar[1], &rwork[lphi], &rwork[lsavr], &rwork[
51], &rwork[le], &rwork[lyic], &rwork[lypic], &rwork[lpwk], &
rwork[lwm], &iwork[1], &rwork[9], &rwork[10], &rwork[11], &
rwork[12], &epconi, &rwork[14], &info[15], &icnflg, &iwork[41]
, (U_fp)ddasid_);
} else if (info[12] == 1) {
lyic = lwm;
lypic = lyic + *neq;
lpwk = lypic + *neq;
ddasic_(&tn, &y[1], &yprime[1], neq, &info[11], &iwork[lid], (U_fp)
res, (U_fp)jac, (U_fp)psol, &h0, &tscale, &rwork[lwt], &nwt,
idid, &rpar[1], &ipar[1], &rwork[lphi], &rwork[lsavr], &rwork[
51], &rwork[le], &rwork[lyic], &rwork[lypic], &rwork[lpwk], &
rwork[lwm], &iwork[1], &rwork[9], &rwork[10], &rwork[11], &
rwork[12], &epconi, &rwork[14], &info[15], &icnflg, &iwork[41]
, (U_fp)ddasik_);
}
if (*idid < 0) {
goto L600;
}
/* DDASIC was successful. If this was the first call to DDASIC, */
/* update the WT array (with the current Y) and call it again. */
if (nwt == 2) {
goto L355;
}
nwt = 2;
ddawts_(neq, &info[2], &rtol[1], &atol[1], &y[1], &rwork[lwt], &rpar[1], &
ipar[1]);
dinvwt_(neq, &rwork[lwt], &ier);
if (ier != 0) {
goto L713;
}
goto L350;
/* If INFO(14) = 1, return now with IDID = 4. */
L355:
if (info[14] == 1) {
*idid = 4;
h__ = h0;
if (info[11] == 1) {
rwork[7] = h0;
}
goto L590;
}
/* Update the WT and VT arrays one more time, with the new Y. */
ddawts_(neq, &info[2], &rtol[1], &atol[1], &y[1], &rwork[lwt], &rpar[1], &
ipar[1]);
dinvwt_(neq, &rwork[lwt], &ier);
if (ier != 0) {
goto L713;
}
if (info[16] != 0) {
i__2 = *neq;
for (i__ = 1; i__ <= i__2; ++i__) {
/* L357: */
/* Computing MAX */
i__1 = iwork[lid + i__ - 1];
rwork[lvt + i__ - 1] = max(i__1,0) * rwork[lwt + i__ - 1];
}
}
/* Reset the initial stepsize to be used by DDSTP. */
/* Use H0, if this was input. Otherwise, recompute H0, */
/* and adjust it if necessary to meet HMAX bound. */
if (info[8] != 0) {
h0 = rwork[3];
goto L360;
}
h0 = tdist * .001;
ypnorm = ddwnrm_(neq, &yprime[1], &rwork[lvt], &rpar[1], &ipar[1]);
if (ypnorm > .5 / h0) {
h0 = .5 / ypnorm;
}
d__1 = *tout - *t;
h0 = d_sign(&h0, &d__1);
L360:
if (info[7] != 0) {
rh = abs(h0) / rwork[2];
if (rh > 1.) {
h0 /= rh;
}
}
/* Check against TSTOP, if applicable. */
if (info[4] != 0) {
tstop = rwork[1];
s_wsle(&io___57);
do_lio(&c__9, &c__1, "tstop = ", (ftnlen)8);
do_lio(&c__5, &c__1, (char *)&tstop, (ftnlen)sizeof(doublereal));
e_wsle();
if ((*t + h0 - tstop) * h0 > 0.) {
h0 = tstop - *t;
}
}
/* Load H and RWORK(LH) with H0. */
L370:
h__ = h0;
rwork[3] = h__;
/* Load Y and H*YPRIME into PHI(*,1) and PHI(*,2). */
itemp = lphi + *neq;
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
rwork[lphi + i__ - 1] = y[i__];
/* L380: */
rwork[itemp + i__ - 1] = h__ * yprime[i__];
}
goto L500;
/* ----------------------------------------------------------------------- */
/* This block is for continuation calls only. */
/* Its purpose is to check stop conditions before taking a step. */
/* Adjust H if necessary to meet HMAX bound. */
/* ----------------------------------------------------------------------- */
L400:
uround = rwork[9];
done = FALSE_;
tn = rwork[4];
h__ = rwork[3];
if (info[7] == 0) {
goto L410;
}
rh = abs(h__) / rwork[2];
if (rh > 1.) {
h__ /= rh;
}
L410:
if (*t == *tout) {
goto L719;
}
if ((*t - *tout) * h__ > 0.) {
goto L711;
}
if (info[4] == 1) {
goto L430;
}
if (info[3] == 1) {
goto L420;
}
if ((tn - *tout) * h__ < 0.) {
goto L490;
}
ddatrp_(&tn, tout, &y[1], &yprime[1], neq, &iwork[8], &rwork[lphi], &
rwork[39]);
*t = *tout;
*idid = 3;
done = TRUE_;
goto L490;
L420:
if ((tn - *t) * h__ <= 0.) {
goto L490;
}
if ((tn - *tout) * h__ >= 0.) {
goto L425;
}
ddatrp_(&tn, &tn, &y[1], &yprime[1], neq, &iwork[8], &rwork[lphi], &rwork[
39]);
*t = tn;
*idid = 1;
done = TRUE_;
goto L490;
L425:
ddatrp_(&tn, tout, &y[1], &yprime[1], neq, &iwork[8], &rwork[lphi], &
rwork[39]);
*t = *tout;
*idid = 3;
done = TRUE_;
goto L490;
L430:
if (info[3] == 1) {
goto L440;
}
tstop = rwork[1];
s_wsle(&io___59);
do_lio(&c__9, &c__1, "tstop = ", (ftnlen)8);
do_lio(&c__5, &c__1, (char *)&tstop, (ftnlen)sizeof(doublereal));
e_wsle();
if ((tn - tstop) * h__ > 0.) {
goto L715;
}
if ((tstop - *tout) * h__ < 0.) {
goto L709;
}
if ((tn - *tout) * h__ < 0.) {
goto L450;
}
ddatrp_(&tn, tout, &y[1], &yprime[1], neq, &iwork[8], &rwork[lphi], &
rwork[39]);
*t = *tout;
*idid = 3;
done = TRUE_;
goto L490;
L440:
tstop = rwork[1];
s_wsle(&io___60);
do_lio(&c__9, &c__1, "tstop = ", (ftnlen)8);
do_lio(&c__5, &c__1, (char *)&tstop, (ftnlen)sizeof(doublereal));
e_wsle();
if ((tn - tstop) * h__ > 0.) {
goto L715;
}
if ((tstop - *tout) * h__ < 0.) {
goto L709;
}
if ((tn - *t) * h__ <= 0.) {
goto L450;
}
if ((tn - *tout) * h__ >= 0.) {
goto L445;
}
ddatrp_(&tn, &tn, &y[1], &yprime[1], neq, &iwork[8], &rwork[lphi], &rwork[
39]);
*t = tn;
*idid = 1;
done = TRUE_;
goto L490;
L445:
ddatrp_(&tn, tout, &y[1], &yprime[1], neq, &iwork[8], &rwork[lphi], &
rwork[39]);
*t = *tout;
*idid = 3;
done = TRUE_;
goto L490;
L450:
/* Check whether we are within roundoff of TSTOP. */
if ((d__1 = tn - tstop, abs(d__1)) > uround * 100. * (abs(tn) + abs(h__)))
{
goto L460;
}
ddatrp_(&tn, &tstop, &y[1], &yprime[1], neq, &iwork[8], &rwork[lphi], &
rwork[39]);
*idid = 2;
*t = tstop;
done = TRUE_;
goto L490;
L460:
tnext = tn + h__;
if ((tnext - tstop) * h__ <= 0.) {
goto L490;
}
h__ = tstop - tn;
rwork[3] = h__;
L490:
if (done) {
goto L590;
}
/* ----------------------------------------------------------------------- */
/* The next block contains the call to the one-step integrator DDSTP. */
/* This is a looping point for the integration steps. */
/* Check for too many steps. */
/* Check for poor Newton/Krylov performance. */
/* Update WT. Check for too much accuracy requested. */
/* Compute minimum stepsize. */
/* ----------------------------------------------------------------------- */
L500:
/* Check for too many steps. */
if (iwork[11] - iwork[10] < 500) {
goto L505;
}
*idid = -1;
goto L527;
/* Check for poor Newton/Krylov performance. */
L505:
if (info[12] == 0) {
goto L510;
}
nstd = iwork[11] - iwork[10];
nnid = iwork[19] - nni0;
if (nstd < 10 || nnid == 0) {
goto L510;
}
avlin = (real) (iwork[20] - nli0) / (real) nnid;
rcfn = (real) (iwork[15] - ncfn0) / (real) nstd;
rcfl = (real) (iwork[16] - ncfl0) / (real) nnid;
fmaxl = (doublereal) iwork[24];
lavl = avlin > fmaxl;
lcfn = rcfn > .9;
lcfl = rcfl > .9;
lwarn = lavl || lcfn || lcfl;
if (! lwarn) {
goto L510;
}
++nwarn;
if (nwarn > 10) {
goto L510;
}
if (lavl) {
s_copy(msg, "DASPK-- Warning. Poor iterative algorithm performance "
, (ftnlen)80, (ftnlen)56);
xerrwd_(msg, &c__56, &c__501, &c__0, &c__0, &c__0, &c__0, &c__0, &
c_b37, &c_b37, (ftnlen)80);
s_copy(msg, " at T = R1. Average no. of linear iterations = R2 "
, (ftnlen)80, (ftnlen)56);
xerrwd_(msg, &c__56, &c__501, &c__0, &c__0, &c__0, &c__0, &c__2, &tn,
&avlin, (ftnlen)80);
}
if (lcfn) {
s_copy(msg, "DASPK-- Warning. Poor iterative algorithm performance "
, (ftnlen)80, (ftnlen)56);
xerrwd_(msg, &c__56, &c__502, &c__0, &c__0, &c__0, &c__0, &c__0, &
c_b37, &c_b37, (ftnlen)80);
s_copy(msg, " at T = R1. Nonlinear convergence failure rate = R2"
, (ftnlen)80, (ftnlen)56);
xerrwd_(msg, &c__56, &c__502, &c__0, &c__0, &c__0, &c__0, &c__2, &tn,
&rcfn, (ftnlen)80);
}
if (lcfl) {
s_copy(msg, "DASPK-- Warning. Poor iterative algorithm performance "
, (ftnlen)80, (ftnlen)56);
xerrwd_(msg, &c__56, &c__503, &c__0, &c__0, &c__0, &c__0, &c__0, &
c_b37, &c_b37, (ftnlen)80);
s_copy(msg, " at T = R1. Linear convergence failure rate = R2 "
, (ftnlen)80, (ftnlen)56);
xerrwd_(msg, &c__56, &c__503, &c__0, &c__0, &c__0, &c__0, &c__2, &tn,
&rcfl, (ftnlen)80);
}
/* Update WT and VT, if this is not the first call. */
L510:
ddawts_(neq, &info[2], &rtol[1], &atol[1], &rwork[lphi], &rwork[lwt], &
rpar[1], &ipar[1]);
dinvwt_(neq, &rwork[lwt], &ier);
if (ier != 0) {
*idid = -3;
goto L527;
}
if (info[16] != 0) {
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L515: */
/* Computing MAX */
i__2 = iwork[lid + i__ - 1];
rwork[lvt + i__ - 1] = max(i__2,0) * rwork[lwt + i__ - 1];
}
}
/* Test for too much accuracy requested. */
r__ = ddwnrm_(neq, &rwork[lphi], &rwork[lwt], &rpar[1], &ipar[1]) * 100. *
uround;
if (r__ <= 1.) {
goto L525;
}
/* Multiply RTOL and ATOL by R and return. */
if (info[2] == 1) {
goto L523;
}
rtol[1] = r__ * rtol[1];
atol[1] = r__ * atol[1];
*idid = -2;
goto L527;
L523:
i__2 = *neq;
for (i__ = 1; i__ <= i__2; ++i__) {
rtol[i__] = r__ * rtol[i__];
/* L524: */
atol[i__] = r__ * atol[i__];
}
*idid = -2;
goto L527;
L525:
/* Compute minimum stepsize. */
/* Computing MAX */
d__1 = abs(tn), d__2 = abs(*tout);
hmin = uround * 4. * max(d__1,d__2);
/* Test H vs. HMAX */
if (info[7] != 0) {
rh = abs(h__) / rwork[2];
if (rh > 1.) {
h__ /= rh;
}
}
/* Call the one-step integrator. */
/* Note that INFO(12) represents the nonlinear solver type. */
/* Pass the required nonlinear solver, depending upon INFO(12). */
if (info[12] == 0) {
ddstp_(&tn, &y[1], &yprime[1], neq, (U_fp)res, (U_fp)jac, (U_fp)psol,
&h__, &rwork[lwt], &rwork[lvt], &info[1], idid, &rpar[1], &
ipar[1], &rwork[lphi], &rwork[lsavr], &rwork[51], &rwork[le],
&rwork[lwm], &iwork[1], &rwork[21], &rwork[27], &rwork[33], &
rwork[39], &rwork[45], &rwork[5], &rwork[6], &rwork[7], &
rwork[8], &hmin, &rwork[9], &rwork[10], &rwork[11], &rwork[12]
, &rwork[13], &iwork[6], &iwork[5], &info[15], &iwork[7], &
iwork[8], &iwork[9], &nonneg, &info[12], (U_fp)dnedd_);
} else if (info[12] == 1) {
ddstp_(&tn, &y[1], &yprime[1], neq, (U_fp)res, (U_fp)jac, (U_fp)psol,
&h__, &rwork[lwt], &rwork[lvt], &info[1], idid, &rpar[1], &
ipar[1], &rwork[lphi], &rwork[lsavr], &rwork[51], &rwork[le],
&rwork[lwm], &iwork[1], &rwork[21], &rwork[27], &rwork[33], &
rwork[39], &rwork[45], &rwork[5], &rwork[6], &rwork[7], &
rwork[8], &hmin, &rwork[9], &rwork[10], &rwork[11], &rwork[12]
, &rwork[13], &iwork[6], &iwork[5], &info[15], &iwork[7], &
iwork[8], &iwork[9], &nonneg, &info[12], (U_fp)dnedk_);
}
L527:
if (*idid < 0) {
goto L600;
}
/* ----------------------------------------------------------------------- */
/* This block handles the case of a successful return from DDSTP */
/* (IDID=1). Test for stop conditions. */
/* ----------------------------------------------------------------------- */
if (info[4] != 0) {
goto L540;
}
if (info[3] != 0) {
goto L530;
}
if ((tn - *tout) * h__ < 0.) {
goto L500;
}
ddatrp_(&tn, tout, &y[1], &yprime[1], neq, &iwork[8], &rwork[lphi], &
rwork[39]);
*idid = 3;
*t = *tout;
goto L580;
L530:
if ((tn - *tout) * h__ >= 0.) {
goto L535;
}
*t = tn;
*idid = 1;
goto L580;
L535:
ddatrp_(&tn, tout, &y[1], &yprime[1], neq, &iwork[8], &rwork[lphi], &
rwork[39]);
*idid = 3;
*t = *tout;
goto L580;
L540:
if (info[3] != 0) {
goto L550;
}
if ((tn - *tout) * h__ < 0.) {
goto L542;
}
ddatrp_(&tn, tout, &y[1], &yprime[1], neq, &iwork[8], &rwork[lphi], &
rwork[39]);
*t = *tout;
*idid = 3;
goto L580;
L542:
if ((d__1 = tn - tstop, abs(d__1)) <= uround * 100. * (abs(tn) + abs(h__))
) {
goto L545;
}
tnext = tn + h__;
if ((tnext - tstop) * h__ <= 0.) {
goto L500;
}
h__ = tstop - tn;
goto L500;
L545:
ddatrp_(&tn, &tstop, &y[1], &yprime[1], neq, &iwork[8], &rwork[lphi], &
rwork[39]);
*idid = 2;
*t = tstop;
goto L580;
L550:
if ((tn - *tout) * h__ >= 0.) {
goto L555;
}
if ((d__1 = tn - tstop, abs(d__1)) <= uround * 100. * (abs(tn) + abs(h__))
) {
goto L552;
}
*t = tn;
*idid = 1;
goto L580;
L552:
ddatrp_(&tn, &tstop, &y[1], &yprime[1], neq, &iwork[8], &rwork[lphi], &
rwork[39]);
*idid = 2;
*t = tstop;
goto L580;
L555:
ddatrp_(&tn, tout, &y[1], &yprime[1], neq, &iwork[8], &rwork[lphi], &
rwork[39]);
*t = *tout;
*idid = 3;
L580:
/* ----------------------------------------------------------------------- */
/* All successful returns from DDASPK are made from this block. */
/* ----------------------------------------------------------------------- */
L590:
rwork[4] = tn;
rwork[3] = h__;
return 0;
/* ----------------------------------------------------------------------- */
/* This block handles all unsuccessful returns other than for */
/* illegal input. */
/* ----------------------------------------------------------------------- */
L600:
itemp = -(*idid);
switch (itemp) {
case 1: goto L610;
case 2: goto L620;
case 3: goto L630;
case 4: goto L700;
case 5: goto L655;
case 6: goto L640;
case 7: goto L650;
case 8: goto L660;
case 9: goto L670;
case 10: goto L675;
case 11: goto L680;
case 12: goto L685;
case 13: goto L690;
case 14: goto L695;
}
/* The maximum number of steps was taken before */
/* reaching tout. */
L610:
s_copy(msg, "DASPK-- AT CURRENT T (=R1) 500 STEPS", (ftnlen)80, (ftnlen)
38);
xerrwd_(msg, &c__38, &c__610, &c__0, &c__0, &c__0, &c__0, &c__1, &tn, &
c_b37, (ftnlen)80);
s_copy(msg, "DASPK-- TAKEN ON THIS CALL BEFORE REACHING TOUT", (ftnlen)
80, (ftnlen)48);
xerrwd_(msg, &c__48, &c__611, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L700;
/* Too much accuracy for machine precision. */
L620:
s_copy(msg, "DASPK-- AT T (=R1) TOO MUCH ACCURACY REQUESTED", (ftnlen)80,
(ftnlen)47);
xerrwd_(msg, &c__47, &c__620, &c__0, &c__0, &c__0, &c__0, &c__1, &tn, &
c_b37, (ftnlen)80);
s_copy(msg, "DASPK-- FOR PRECISION OF MACHINE. RTOL AND ATOL", (ftnlen)
80, (ftnlen)48);
xerrwd_(msg, &c__48, &c__621, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
s_copy(msg, "DASPK-- WERE INCREASED TO APPROPRIATE VALUES", (ftnlen)80, (
ftnlen)45);
xerrwd_(msg, &c__45, &c__622, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L700;
/* WT(I) .LE. 0.0D0 for some I (not at start of problem). */
L630:
s_copy(msg, "DASPK-- AT T (=R1) SOME ELEMENT OF WT", (ftnlen)80, (ftnlen)
38);
xerrwd_(msg, &c__38, &c__630, &c__0, &c__0, &c__0, &c__0, &c__1, &tn, &
c_b37, (ftnlen)80);
s_copy(msg, "DASPK-- HAS BECOME .LE. 0.0", (ftnlen)80, (ftnlen)28);
xerrwd_(msg, &c__28, &c__631, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L700;
/* Error test failed repeatedly or with H=HMIN. */
L640:
s_copy(msg, "DASPK-- AT T (=R1) AND STEPSIZE H (=R2) THE", (ftnlen)80, (
ftnlen)44);
xerrwd_(msg, &c__44, &c__640, &c__0, &c__0, &c__0, &c__0, &c__2, &tn, &
h__, (ftnlen)80);
s_copy(msg, "DASPK-- ERROR TEST FAILED REPEATEDLY OR WITH ABS(H)=HMIN", (
ftnlen)80, (ftnlen)57);
xerrwd_(msg, &c__57, &c__641, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L700;
/* Nonlinear solver failed to converge repeatedly or with H=HMIN. */
L650:
s_copy(msg, "DASPK-- AT T (=R1) AND STEPSIZE H (=R2) THE", (ftnlen)80, (
ftnlen)44);
xerrwd_(msg, &c__44, &c__650, &c__0, &c__0, &c__0, &c__0, &c__2, &tn, &
h__, (ftnlen)80);
s_copy(msg, "DASPK-- NONLINEAR SOLVER FAILED TO CONVERGE", (ftnlen)80, (
ftnlen)44);
xerrwd_(msg, &c__44, &c__651, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
s_copy(msg, "DASPK-- REPEATEDLY OR WITH ABS(H)=HMIN", (ftnlen)80, (
ftnlen)39);
xerrwd_(msg, &c__40, &c__652, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L700;
/* The preconditioner had repeated failures. */
L655:
s_copy(msg, "DASPK-- AT T (=R1) AND STEPSIZE H (=R2) THE", (ftnlen)80, (
ftnlen)44);
xerrwd_(msg, &c__44, &c__655, &c__0, &c__0, &c__0, &c__0, &c__2, &tn, &
h__, (ftnlen)80);
s_copy(msg, "DASPK-- PRECONDITIONER HAD REPEATED FAILURES.", (ftnlen)80,
(ftnlen)46);
xerrwd_(msg, &c__46, &c__656, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L700;
/* The iteration matrix is singular. */
L660:
s_copy(msg, "DASPK-- AT T (=R1) AND STEPSIZE H (=R2) THE", (ftnlen)80, (
ftnlen)44);
xerrwd_(msg, &c__44, &c__660, &c__0, &c__0, &c__0, &c__0, &c__2, &tn, &
h__, (ftnlen)80);
s_copy(msg, "DASPK-- ITERATION MATRIX IS SINGULAR.", (ftnlen)80, (ftnlen)
38);
xerrwd_(msg, &c__38, &c__661, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L700;
/* Nonlinear system failure preceded by error test failures. */
L670:
s_copy(msg, "DASPK-- AT T (=R1) AND STEPSIZE H (=R2) THE", (ftnlen)80, (
ftnlen)44);
xerrwd_(msg, &c__44, &c__670, &c__0, &c__0, &c__0, &c__0, &c__2, &tn, &
h__, (ftnlen)80);
s_copy(msg, "DASPK-- NONLINEAR SOLVER COULD NOT CONVERGE.", (ftnlen)80, (
ftnlen)45);
xerrwd_(msg, &c__45, &c__671, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
s_copy(msg, "DASPK-- ALSO, THE ERROR TEST FAILED REPEATEDLY.", (ftnlen)
80, (ftnlen)48);
xerrwd_(msg, &c__49, &c__672, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L700;
/* Nonlinear system failure because IRES = -1. */
L675:
s_copy(msg, "DASPK-- AT T (=R1) AND STEPSIZE H (=R2) THE", (ftnlen)80, (
ftnlen)44);
xerrwd_(msg, &c__44, &c__675, &c__0, &c__0, &c__0, &c__0, &c__2, &tn, &
h__, (ftnlen)80);
s_copy(msg, "DASPK-- NONLINEAR SYSTEM SOLVER COULD NOT CONVERGE", (
ftnlen)80, (ftnlen)51);
xerrwd_(msg, &c__51, &c__676, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
s_copy(msg, "DASPK-- BECAUSE IRES WAS EQUAL TO MINUS ONE", (ftnlen)80, (
ftnlen)44);
xerrwd_(msg, &c__44, &c__677, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L700;
/* Failure because IRES = -2. */
L680:
s_copy(msg, "DASPK-- AT T (=R1) AND STEPSIZE H (=R2)", (ftnlen)80, (
ftnlen)40);
xerrwd_(msg, &c__40, &c__680, &c__0, &c__0, &c__0, &c__0, &c__2, &tn, &
h__, (ftnlen)80);
s_copy(msg, "DASPK-- IRES WAS EQUAL TO MINUS TWO", (ftnlen)80, (ftnlen)
36);
xerrwd_(msg, &c__36, &c__681, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L700;
/* Failed to compute initial YPRIME. */
L685:
s_copy(msg, "DASPK-- AT T (=R1) AND STEPSIZE H (=R2) THE", (ftnlen)80, (
ftnlen)44);
xerrwd_(msg, &c__44, &c__685, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
s_copy(msg, "DASPK-- INITIAL (Y,YPRIME) COULD NOT BE COMPUTED", (ftnlen)
80, (ftnlen)49);
xerrwd_(msg, &c__49, &c__686, &c__0, &c__0, &c__0, &c__0, &c__2, &tn, &h0,
(ftnlen)80);
goto L700;
/* Failure because IER was negative from PSOL. */
L690:
s_copy(msg, "DASPK-- AT T (=R1) AND STEPSIZE H (=R2)", (ftnlen)80, (
ftnlen)40);
xerrwd_(msg, &c__40, &c__690, &c__0, &c__0, &c__0, &c__0, &c__2, &tn, &
h__, (ftnlen)80);
s_copy(msg, "DASPK-- IER WAS NEGATIVE FROM PSOL", (ftnlen)80, (ftnlen)35)
;
xerrwd_(msg, &c__35, &c__691, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L700;
/* Failure because the linear system solver could not converge. */
L695:
s_copy(msg, "DASPK-- AT T (=R1) AND STEPSIZE H (=R2) THE", (ftnlen)80, (
ftnlen)44);
xerrwd_(msg, &c__44, &c__695, &c__0, &c__0, &c__0, &c__0, &c__2, &tn, &
h__, (ftnlen)80);
s_copy(msg, "DASPK-- LINEAR SYSTEM SOLVER COULD NOT CONVERGE.", (ftnlen)
80, (ftnlen)49);
xerrwd_(msg, &c__50, &c__696, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L700;
L700:
info[1] = -1;
*t = tn;
rwork[4] = tn;
rwork[3] = h__;
return 0;
/* ----------------------------------------------------------------------- */
/* This block handles all error returns due to illegal input, */
/* as detected before calling DDSTP. */
/* First the error message routine is called. If this happens */
/* twice in succession, execution is terminated. */
/* ----------------------------------------------------------------------- */
L701:
s_copy(msg, "DASPK-- ELEMENT (=I1) OF INFO VECTOR IS NOT VALID", (ftnlen)
80, (ftnlen)50);
xerrwd_(msg, &c__50, &c__1, &c__0, &c__1, &itemp, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L750;
L702:
s_copy(msg, "DASPK-- NEQ (=I1) .LE. 0", (ftnlen)80, (ftnlen)25);
xerrwd_(msg, &c__25, &c__2, &c__0, &c__1, neq, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L750;
L703:
s_copy(msg, "DASPK-- MAXORD (=I1) NOT IN RANGE", (ftnlen)80, (ftnlen)34);
xerrwd_(msg, &c__34, &c__3, &c__0, &c__1, &mxord, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L750;
L704:
s_copy(msg, "DASPK-- RWORK LENGTH NEEDED, LENRW (=I1), EXCEEDS LRW (=I2)"
, (ftnlen)80, (ftnlen)60);
xerrwd_(msg, &c__60, &c__4, &c__0, &c__2, &lenrw, lrw, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L750;
L705:
s_copy(msg, "DASPK-- IWORK LENGTH NEEDED, LENIW (=I1), EXCEEDS LIW (=I2)"
, (ftnlen)80, (ftnlen)60);
xerrwd_(msg, &c__60, &c__5, &c__0, &c__2, &leniw, liw, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L750;
L706:
s_copy(msg, "DASPK-- SOME ELEMENT OF RTOL IS .LT. 0", (ftnlen)80, (
ftnlen)39);
xerrwd_(msg, &c__39, &c__6, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L750;
L707:
s_copy(msg, "DASPK-- SOME ELEMENT OF ATOL IS .LT. 0", (ftnlen)80, (
ftnlen)39);
xerrwd_(msg, &c__39, &c__7, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L750;
L708:
s_copy(msg, "DASPK-- ALL ELEMENTS OF RTOL AND ATOL ARE ZERO", (ftnlen)80,
(ftnlen)47);
xerrwd_(msg, &c__47, &c__8, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L750;
L709:
s_copy(msg, "DASPK-- INFO(4) = 1 AND TSTOP (=R1) BEHIND TOUT (=R2)", (
ftnlen)80, (ftnlen)54);
xerrwd_(msg, &c__54, &c__9, &c__0, &c__0, &c__0, &c__0, &c__2, &tstop,
tout, (ftnlen)80);
goto L750;
L710:
s_copy(msg, "DASPK-- HMAX (=R1) .LT. 0.0", (ftnlen)80, (ftnlen)28);
xerrwd_(msg, &c__28, &c__10, &c__0, &c__0, &c__0, &c__0, &c__1, &hmax, &
c_b37, (ftnlen)80);
goto L750;
L711:
s_copy(msg, "DASPK-- TOUT (=R1) BEHIND T (=R2)", (ftnlen)80, (ftnlen)34);
xerrwd_(msg, &c__34, &c__11, &c__0, &c__0, &c__0, &c__0, &c__2, tout, t, (
ftnlen)80);
goto L750;
L712:
s_copy(msg, "DASPK-- INFO(8)=1 AND H0=0.0", (ftnlen)80, (ftnlen)29);
xerrwd_(msg, &c__29, &c__12, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L750;
L713:
s_copy(msg, "DASPK-- SOME ELEMENT OF WT IS .LE. 0.0", (ftnlen)80, (
ftnlen)39);
xerrwd_(msg, &c__39, &c__13, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L750;
L714:
s_copy(msg, "DASPK-- TOUT (=R1) TOO CLOSE TO T (=R2) TO START INTEGRATION"
, (ftnlen)80, (ftnlen)60);
xerrwd_(msg, &c__60, &c__14, &c__0, &c__0, &c__0, &c__0, &c__2, tout, t, (
ftnlen)80);
goto L750;
L715:
s_copy(msg, "DASPK-- INFO(4)=1 AND TSTOP (=R1) BEHIND T (=R2)", (ftnlen)
80, (ftnlen)49);
xerrwd_(msg, &c__49, &c__15, &c__0, &c__0, &c__0, &c__0, &c__2, &tstop, t,
(ftnlen)80);
goto L750;
L717:
s_copy(msg, "DASPK-- ML (=I1) ILLEGAL. EITHER .LT. 0 OR .GT. NEQ", (
ftnlen)80, (ftnlen)52);
xerrwd_(msg, &c__52, &c__17, &c__0, &c__1, &iwork[1], &c__0, &c__0, &
c_b37, &c_b37, (ftnlen)80);
goto L750;
L718:
s_copy(msg, "DASPK-- MU (=I1) ILLEGAL. EITHER .LT. 0 OR .GT. NEQ", (
ftnlen)80, (ftnlen)52);
xerrwd_(msg, &c__52, &c__18, &c__0, &c__1, &iwork[2], &c__0, &c__0, &
c_b37, &c_b37, (ftnlen)80);
goto L750;
L719:
s_copy(msg, "DASPK-- TOUT (=R1) IS EQUAL TO T (=R2)", (ftnlen)80, (
ftnlen)39);
xerrwd_(msg, &c__39, &c__19, &c__0, &c__0, &c__0, &c__0, &c__2, tout, t, (
ftnlen)80);
goto L750;
L720:
s_copy(msg, "DASPK-- MAXL (=I1) ILLEGAL. EITHER .LT. 1 OR .GT. NEQ", (
ftnlen)80, (ftnlen)54);
xerrwd_(msg, &c__54, &c__20, &c__0, &c__1, &iwork[24], &c__0, &c__0, &
c_b37, &c_b37, (ftnlen)80);
goto L750;
L721:
s_copy(msg, "DASPK-- KMP (=I1) ILLEGAL. EITHER .LT. 1 OR .GT. MAXL", (
ftnlen)80, (ftnlen)54);
xerrwd_(msg, &c__54, &c__21, &c__0, &c__1, &iwork[25], &c__0, &c__0, &
c_b37, &c_b37, (ftnlen)80);
goto L750;
L722:
s_copy(msg, "DASPK-- NRMAX (=I1) ILLEGAL. .LT. 0", (ftnlen)80, (ftnlen)
36);
xerrwd_(msg, &c__36, &c__22, &c__0, &c__1, &iwork[26], &c__0, &c__0, &
c_b37, &c_b37, (ftnlen)80);
goto L750;
L723:
s_copy(msg, "DASPK-- EPLI (=R1) ILLEGAL. EITHER .LE. 0.D0 OR .GE. 1.D0",
(ftnlen)80, (ftnlen)58);
xerrwd_(msg, &c__58, &c__23, &c__0, &c__0, &c__0, &c__0, &c__1, &rwork[10]
, &c_b37, (ftnlen)80);
goto L750;
L724:
s_copy(msg, "DASPK-- ILLEGAL IWORK VALUE FOR INFO(11) .NE. 0", (ftnlen)
80, (ftnlen)48);
xerrwd_(msg, &c__48, &c__24, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L750;
L725:
s_copy(msg, "DASPK-- ONE OF THE INPUTS FOR INFO(17) = 1 IS ILLEGAL", (
ftnlen)80, (ftnlen)54);
xerrwd_(msg, &c__54, &c__25, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L750;
L726:
s_copy(msg, "DASPK-- ILLEGAL IWORK VALUE FOR INFO(10) .NE. 0", (ftnlen)
80, (ftnlen)48);
xerrwd_(msg, &c__48, &c__26, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L750;
L727:
s_copy(msg, "DASPK-- Y(I) AND IWORK(40+I) (I=I1) INCONSISTENT", (ftnlen)
80, (ftnlen)49);
xerrwd_(msg, &c__49, &c__27, &c__0, &c__1, &iret, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
goto L750;
L750:
if (info[1] == -1) {
goto L760;
}
info[1] = -1;
*idid = -33;
return 0;
L760:
s_copy(msg, "DASPK-- REPEATED OCCURRENCES OF ILLEGAL INPUT", (ftnlen)80,
(ftnlen)46);
xerrwd_(msg, &c__46, &c__701, &c__0, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
/* L770: */
s_copy(msg, "DASPK-- RUN TERMINATED. APPARENT INFINITE LOOP", (ftnlen)80,
(ftnlen)47);
xerrwd_(msg, &c__47, &c__702, &c__1, &c__0, &c__0, &c__0, &c__0, &c_b37, &
c_b37, (ftnlen)80);
return 0;
/* ------END OF SUBROUTINE DDASPK----------------------------------------- */
} /* ddaspk_ */
/* Subroutine */ int ddasic_(doublereal *x, doublereal *y, doublereal *yprime,
integer *neq, integer *icopt, integer *id, U_fp res, U_fp jac, U_fp
psol, doublereal *h__, doublereal *tscale, doublereal *wt, integer *
nic, integer *idid, doublereal *rpar, integer *ipar, doublereal *phi,
doublereal *savr, doublereal *delta, doublereal *e, doublereal *yic,
doublereal *ypic, doublereal *pwk, doublereal *wm, integer *iwm,
doublereal *uround, doublereal *epli, doublereal *sqrtn, doublereal *
rsqrtn, doublereal *epconi, doublereal *stptol, integer *jflg,
integer *icnflg, integer *icnstr, S_fp nlsic)
{
/* Initialized data */
static doublereal rhcut = .1;
static doublereal ratemx = .8;
/* System generated locals */
integer phi_dim1, phi_offset;
/* Local variables */
static doublereal cj;
static integer nh, mxnh;
extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *,
doublereal *, integer *);
static integer jskip, iernls;
/* ***BEGIN PROLOGUE DDASIC */
/* ***REFER TO DDASPK */
/* ***DATE WRITTEN 940628 (YYMMDD) */
/* ***REVISION DATE 941206 (YYMMDD) */
/* ***REVISION DATE 950714 (YYMMDD) */
/* ***REVISION DATE 000628 TSCALE argument added. */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* DDASIC is a driver routine to compute consistent initial values */
/* for Y and YPRIME. There are two different options: */
/* Denoting the differential variables in Y by Y_d, and */
/* the algebraic variables by Y_a, the problem solved is either: */
/* 1. Given Y_d, calculate Y_a and Y_d', or */
/* 2. Given Y', calculate Y. */
/* In either case, initial values for the given components */
/* are input, and initial guesses for the unknown components */
/* must also be provided as input. */
/* The external routine NLSIC solves the resulting nonlinear system. */
/* The parameters represent */
/* X -- Independent variable. */
/* Y -- Solution vector at X. */
/* YPRIME -- Derivative of solution vector. */
/* NEQ -- Number of equations to be integrated. */
/* ICOPT -- Flag indicating initial condition option chosen. */
/* ICOPT = 1 for option 1 above. */
/* ICOPT = 2 for option 2. */
/* ID -- Array of dimension NEQ, which must be initialized */
/* if option 1 is chosen. */
/* ID(i) = +1 if Y_i is a differential variable, */
/* ID(i) = -1 if Y_i is an algebraic variable. */
/* RES -- External user-supplied subroutine to evaluate the */
/* residual. See RES description in DDASPK prologue. */
/* JAC -- External user-supplied routine to update Jacobian */
/* or preconditioner information in the nonlinear solver */
/* (optional). See JAC description in DDASPK prologue. */
/* PSOL -- External user-supplied routine to solve */
/* a linear system using preconditioning. */
/* See PSOL in DDASPK prologue. */
/* H -- Scaling factor in iteration matrix. DDASIC may */
/* reduce H to achieve convergence. */
/* TSCALE -- Scale factor in T, used for stopping tests if nonzero. */
/* WT -- Vector of weights for error criterion. */
/* NIC -- Input number of initial condition calculation call */
/* (= 1 or 2). */
/* IDID -- Completion code. See IDID in DDASPK prologue. */
/* RPAR,IPAR -- Real and integer parameter arrays that */
/* are used for communication between the */
/* calling program and external user routines. */
/* They are not altered by DNSK */
/* PHI -- Work space for DDASIC of length at least 2*NEQ. */
/* SAVR -- Work vector for DDASIC of length NEQ. */
/* DELTA -- Work vector for DDASIC of length NEQ. */
/* E -- Work vector for DDASIC of length NEQ. */
/* YIC,YPIC -- Work vectors for DDASIC, each of length NEQ. */
/* PWK -- Work vector for DDASIC of length NEQ. */
/* WM,IWM -- Real and integer arrays storing */
/* information required by the linear solver. */
/* EPCONI -- Test constant for Newton iteration convergence. */
/* ICNFLG -- Flag showing whether constraints on Y are to apply. */
/* ICNSTR -- Integer array of length NEQ with constraint types. */
/* The other parameters are for use internally by DDASIC. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED */
/* DCOPY, NLSIC */
/* ***END PROLOGUE DDASIC */
/* The following parameters are data-loaded here: */
/* RHCUT = factor by which H is reduced on retry of Newton solve. */
/* RATEMX = maximum convergence rate for which Newton iteration */
/* is considered converging. */
/* Parameter adjustments */
--y;
--yprime;
phi_dim1 = *neq;
phi_offset = 1 + phi_dim1;
phi -= phi_offset;
--id;
--wt;
--rpar;
--ipar;
--savr;
--delta;
--e;
--yic;
--ypic;
--pwk;
--wm;
--iwm;
--icnstr;
/* Function Body */
/* ----------------------------------------------------------------------- */
/* BLOCK 1. */
/* Initializations. */
/* JSKIP is a flag set to 1 when NIC = 2 and NH = 1, to signal that */
/* the initial call to the JAC routine is to be skipped then. */
/* Save Y and YPRIME in PHI. Initialize IDID, NH, and CJ. */
/* ----------------------------------------------------------------------- */
mxnh = iwm[34];
*idid = 1;
nh = 1;
jskip = 0;
if (*nic == 2) {
jskip = 1;
}
dcopy_(neq, &y[1], &c__1, &phi[phi_dim1 + 1], &c__1);
dcopy_(neq, &yprime[1], &c__1, &phi[(phi_dim1 << 1) + 1], &c__1);
if (*icopt == 2) {
cj = 0.;
} else {
cj = 1. / *h__;
}
/* ----------------------------------------------------------------------- */
/* BLOCK 2 */
/* Call the nonlinear system solver to obtain */
/* consistent initial values for Y and YPRIME. */
/* ----------------------------------------------------------------------- */
L200:
(*nlsic)(x, &y[1], &yprime[1], neq, icopt, &id[1], (U_fp)res, (U_fp)jac, (
U_fp)psol, h__, tscale, &wt[1], &jskip, &rpar[1], &ipar[1], &savr[
1], &delta[1], &e[1], &yic[1], &ypic[1], &pwk[1], &wm[1], &iwm[1],
&cj, uround, epli, sqrtn, rsqrtn, epconi, &ratemx, stptol, jflg,
icnflg, &icnstr[1], &iernls);
if (iernls == 0) {
return 0;
}
/* ----------------------------------------------------------------------- */
/* BLOCK 3 */
/* The nonlinear solver was unsuccessful. Increment NCFN. */
/* Return with IDID = -12 if either */
/* IERNLS = -1: error is considered unrecoverable, */
/* ICOPT = 2: we are doing initialization problem type 2, or */
/* NH = MXNH: the maximum number of H values has been tried. */
/* Otherwise (problem 1 with IERNLS .GE. 1), reduce H and try again. */
/* If IERNLS > 1, restore Y and YPRIME to their original values. */
/* ----------------------------------------------------------------------- */
++iwm[15];
jskip = 0;
if (iernls == -1) {
goto L350;
}
if (*icopt == 2) {
goto L350;
}
if (nh == mxnh) {
goto L350;
}
++nh;
*h__ *= rhcut;
cj = 1. / *h__;
if (iernls == 1) {
goto L200;
}
dcopy_(neq, &phi[phi_dim1 + 1], &c__1, &y[1], &c__1);
dcopy_(neq, &phi[(phi_dim1 << 1) + 1], &c__1, &yprime[1], &c__1);
goto L200;
L350:
*idid = -12;
return 0;
/* ------END OF SUBROUTINE DDASIC----------------------------------------- */
} /* ddasic_ */
/* Subroutine */ int dyypnw_(integer *neq, doublereal *y, doublereal *yprime,
doublereal *cj, doublereal *rl, doublereal *p, integer *icopt,
integer *id, doublereal *ynew, doublereal *ypnew)
{
/* System generated locals */
integer i__1;
/* Local variables */
static integer i__;
/* ***BEGIN PROLOGUE DYYPNW */
/* ***REFER TO DLINSK */
/* ***DATE WRITTEN 940830 (YYMMDD) */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* DYYPNW calculates the new (Y,YPRIME) pair needed in the */
/* linesearch algorithm based on the current lambda value. It is */
/* called by DLINSK and DLINSD. Based on the ICOPT and ID values, */
/* the corresponding entry in Y or YPRIME is updated. */
/* In addition to the parameters described in the calling programs, */
/* the parameters represent */
/* P -- Array of length NEQ that contains the current */
/* approximate Newton step. */
/* RL -- Scalar containing the current lambda value. */
/* YNEW -- Array of length NEQ containing the updated Y vector. */
/* YPNEW -- Array of length NEQ containing the updated YPRIME */
/* vector. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED (NONE) */
/* ***END PROLOGUE DYYPNW */
/* Parameter adjustments */
--ypnew;
--ynew;
--id;
--p;
--yprime;
--y;
/* Function Body */
if (*icopt == 1) {
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
if (id[i__] < 0) {
ynew[i__] = y[i__] - *rl * p[i__];
ypnew[i__] = yprime[i__];
} else {
ynew[i__] = y[i__];
ypnew[i__] = yprime[i__] - *rl * *cj * p[i__];
}
/* L10: */
}
} else {
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
ynew[i__] = y[i__] - *rl * p[i__];
ypnew[i__] = yprime[i__];
/* L20: */
}
}
return 0;
/* ----------------------- END OF SUBROUTINE DYYPNW ---------------------- */
} /* dyypnw_ */
/* Subroutine */ int ddstp_(doublereal *x, doublereal *y, doublereal *yprime,
integer *neq, U_fp res, U_fp jac, U_fp psol, doublereal *h__,
doublereal *wt, doublereal *vt, integer *jstart, integer *idid,
doublereal *rpar, integer *ipar, doublereal *phi, doublereal *savr,
doublereal *delta, doublereal *e, doublereal *wm, integer *iwm,
doublereal *alpha, doublereal *beta, doublereal *gamma, doublereal *
psi, doublereal *sigma, doublereal *cj, doublereal *cjold, doublereal
*hold, doublereal *s, doublereal *hmin, doublereal *uround,
doublereal *epli, doublereal *sqrtn, doublereal *rsqrtn, doublereal *
epcon, integer *iphase, integer *jcalc, integer *jflg, integer *k,
integer *kold, integer *ns, integer *nonneg, integer *ntype, S_fp nls)
{
/* System generated locals */
integer phi_dim1, phi_offset, i__1, i__2;
doublereal d__1, d__2;
/* Builtin functions */
double pow_dd(doublereal *, doublereal *);
/* Local variables */
static integer i__, j;
static doublereal r__;
static integer j1;
static doublereal ck;
static integer km1, kp1, kp2, ncf, nef;
static doublereal erk, err, est;
static integer nsp1;
static doublereal hnew, terk, xold;
static integer knew;
static doublereal erkm1, erkm2, erkp1, temp1, temp2;
static integer kdiff;
static doublereal enorm, alpha0, terkm1, terkm2, terkp1, alphas;
extern /* Subroutine */ int ddatrp_(doublereal *, doublereal *,
doublereal *, doublereal *, integer *, integer *, doublereal *,
doublereal *);
static doublereal cjlast;
extern doublereal ddwnrm_(integer *, doublereal *, doublereal *,
doublereal *, integer *);
static integer iernls;
/* ***BEGIN PROLOGUE DDSTP */
/* ***REFER TO DDASPK */
/* ***DATE WRITTEN 890101 (YYMMDD) */
/* ***REVISION DATE 900926 (YYMMDD) */
/* ***REVISION DATE 940909 (YYMMDD) (Reset PSI(1), PHI(*,2) at 690) */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* DDSTP solves a system of differential/algebraic equations of */
/* the form G(X,Y,YPRIME) = 0, for one step (normally from X to X+H). */
/* The methods used are modified divided difference, fixed leading */
/* coefficient forms of backward differentiation formulas. */
/* The code adjusts the stepsize and order to control the local error */
/* per step. */
/* The parameters represent */
/* X -- Independent variable. */
/* Y -- Solution vector at X. */
/* YPRIME -- Derivative of solution vector */
/* after successful step. */
/* NEQ -- Number of equations to be integrated. */
/* RES -- External user-supplied subroutine */
/* to evaluate the residual. See RES description */
/* in DDASPK prologue. */
/* JAC -- External user-supplied routine to update */
/* Jacobian or preconditioner information in the */
/* nonlinear solver. See JAC description in DDASPK */
/* prologue. */
/* PSOL -- External user-supplied routine to solve */
/* a linear system using preconditioning. */
/* (This is optional). See PSOL in DDASPK prologue. */
/* H -- Appropriate step size for next step. */
/* Normally determined by the code. */
/* WT -- Vector of weights for error criterion used in Newton test. */
/* VT -- Masked vector of weights used in error test. */
/* JSTART -- Integer variable set 0 for */
/* first step, 1 otherwise. */
/* IDID -- Completion code returned from the nonlinear solver. */
/* See IDID description in DDASPK prologue. */
/* RPAR,IPAR -- Real and integer parameter arrays that */
/* are used for communication between the */
/* calling program and external user routines. */
/* They are not altered by DNSK */
/* PHI -- Array of divided differences used by */
/* DDSTP. The length is NEQ*(K+1), where */
/* K is the maximum order. */
/* SAVR -- Work vector for DDSTP of length NEQ. */
/* DELTA,E -- Work vectors for DDSTP of length NEQ. */
/* WM,IWM -- Real and integer arrays storing */
/* information required by the linear solver. */
/* The other parameters are information */
/* which is needed internally by DDSTP to */
/* continue from step to step. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED */
/* NLS, DDWNRM, DDATRP */
/* ***END PROLOGUE DDSTP */
/* ----------------------------------------------------------------------- */
/* BLOCK 1. */
/* Initialize. On the first call, set */
/* the order to 1 and initialize */
/* other variables. */
/* ----------------------------------------------------------------------- */
/* Initializations for all calls */
/* Parameter adjustments */
--y;
--yprime;
phi_dim1 = *neq;
phi_offset = 1 + phi_dim1;
phi -= phi_offset;
--wt;
--vt;
--rpar;
--ipar;
--savr;
--delta;
--e;
--wm;
--iwm;
--alpha;
--beta;
--gamma;
--psi;
--sigma;
/* Function Body */
xold = *x;
ncf = 0;
nef = 0;
if (*jstart != 0) {
goto L120;
}
/* If this is the first step, perform */
/* other initializations */
*k = 1;
*kold = 0;
*hold = 0.;
psi[1] = *h__;
*cj = 1. / *h__;
*iphase = 0;
*ns = 0;
L120:
/* ----------------------------------------------------------------------- */
/* BLOCK 2 */
/* Compute coefficients of formulas for */
/* this step. */
/* ----------------------------------------------------------------------- */
L200:
kp1 = *k + 1;
kp2 = *k + 2;
km1 = *k - 1;
if (*h__ != *hold || *k != *kold) {
*ns = 0;
}
/* Computing MIN */
i__1 = *ns + 1, i__2 = *kold + 2;
*ns = min(i__1,i__2);
nsp1 = *ns + 1;
if (kp1 < *ns) {
goto L230;
}
beta[1] = 1.;
alpha[1] = 1.;
temp1 = *h__;
gamma[1] = 0.;
sigma[1] = 1.;
i__1 = kp1;
for (i__ = 2; i__ <= i__1; ++i__) {
temp2 = psi[i__ - 1];
psi[i__ - 1] = temp1;
beta[i__] = beta[i__ - 1] * psi[i__ - 1] / temp2;
temp1 = temp2 + *h__;
alpha[i__] = *h__ / temp1;
sigma[i__] = (i__ - 1) * sigma[i__ - 1] * alpha[i__];
gamma[i__] = gamma[i__ - 1] + alpha[i__ - 1] / *h__;
/* L210: */
}
psi[kp1] = temp1;
L230:
/* Compute ALPHAS, ALPHA0 */
alphas = 0.;
alpha0 = 0.;
i__1 = *k;
for (i__ = 1; i__ <= i__1; ++i__) {
alphas -= 1. / i__;
alpha0 -= alpha[i__];
/* L240: */
}
/* Compute leading coefficient CJ */
cjlast = *cj;
*cj = -alphas / *h__;
/* Compute variable stepsize error coefficient CK */
ck = (d__1 = alpha[kp1] + alphas - alpha0, abs(d__1));
/* Computing MAX */
d__1 = ck, d__2 = alpha[kp1];
ck = max(d__1,d__2);
/* Change PHI to PHI STAR */
if (kp1 < nsp1) {
goto L280;
}
i__1 = kp1;
for (j = nsp1; j <= i__1; ++j) {
i__2 = *neq;
for (i__ = 1; i__ <= i__2; ++i__) {
/* L260: */
phi[i__ + j * phi_dim1] = beta[j] * phi[i__ + j * phi_dim1];
}
/* L270: */
}
L280:
/* Update time */
*x += *h__;
/* Initialize IDID to 1 */
*idid = 1;
/* ----------------------------------------------------------------------- */
/* BLOCK 3 */
/* Call the nonlinear system solver to obtain the solution and */
/* derivative. */
/* ----------------------------------------------------------------------- */
(*nls)(x, &y[1], &yprime[1], neq, (U_fp)res, (U_fp)jac, (U_fp)psol, h__, &
wt[1], jstart, idid, &rpar[1], &ipar[1], &phi[phi_offset], &gamma[
1], &savr[1], &delta[1], &e[1], &wm[1], &iwm[1], cj, cjold, &
cjlast, s, uround, epli, sqrtn, rsqrtn, epcon, jcalc, jflg, &kp1,
nonneg, ntype, &iernls);
if (iernls != 0) {
goto L600;
}
/* ----------------------------------------------------------------------- */
/* BLOCK 4 */
/* Estimate the errors at orders K,K-1,K-2 */
/* as if constant stepsize was used. Estimate */
/* the local error at order K and test */
/* whether the current step is successful. */
/* ----------------------------------------------------------------------- */
/* Estimate errors at orders K,K-1,K-2 */
enorm = ddwnrm_(neq, &e[1], &vt[1], &rpar[1], &ipar[1]);
erk = sigma[*k + 1] * enorm;
terk = (*k + 1) * erk;
est = erk;
knew = *k;
if (*k == 1) {
goto L430;
}
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L405: */
delta[i__] = phi[i__ + kp1 * phi_dim1] + e[i__];
}
erkm1 = sigma[*k] * ddwnrm_(neq, &delta[1], &vt[1], &rpar[1], &ipar[1]);
terkm1 = *k * erkm1;
if (*k > 2) {
goto L410;
}
if (terkm1 <= terk * .5f) {
goto L420;
}
goto L430;
L410:
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L415: */
delta[i__] = phi[i__ + *k * phi_dim1] + delta[i__];
}
erkm2 = sigma[*k - 1] * ddwnrm_(neq, &delta[1], &vt[1], &rpar[1], &ipar[1]
);
terkm2 = (*k - 1) * erkm2;
if (max(terkm1,terkm2) > terk) {
goto L430;
}
/* Lower the order */
L420:
knew = *k - 1;
est = erkm1;
/* Calculate the local error for the current step */
/* to see if the step was successful */
L430:
err = ck * enorm;
if (err > 1.) {
goto L600;
}
/* ----------------------------------------------------------------------- */
/* BLOCK 5 */
/* The step is successful. Determine */
/* the best order and stepsize for */
/* the next step. Update the differences */
/* for the next step. */
/* ----------------------------------------------------------------------- */
*idid = 1;
++iwm[11];
kdiff = *k - *kold;
*kold = *k;
*hold = *h__;
/* Estimate the error at order K+1 unless */
/* already decided to lower order, or */
/* already using maximum order, or */
/* stepsize not constant, or */
/* order raised in previous step */
if (knew == km1 || *k == iwm[3]) {
*iphase = 1;
}
if (*iphase == 0) {
goto L545;
}
if (knew == km1) {
goto L540;
}
if (*k == iwm[3]) {
goto L550;
}
if (kp1 >= *ns || kdiff == 1) {
goto L550;
}
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L510: */
delta[i__] = e[i__] - phi[i__ + kp2 * phi_dim1];
}
erkp1 = 1. / (*k + 2) * ddwnrm_(neq, &delta[1], &vt[1], &rpar[1], &ipar[1]
);
terkp1 = (*k + 2) * erkp1;
if (*k > 1) {
goto L520;
}
if (terkp1 >= terk * .5) {
goto L550;
}
goto L530;
L520:
if (terkm1 <= min(terk,terkp1)) {
goto L540;
}
if (terkp1 >= terk || *k == iwm[3]) {
goto L550;
}
/* Raise order */
L530:
*k = kp1;
est = erkp1;
goto L550;
/* Lower order */
L540:
*k = km1;
est = erkm1;
goto L550;
/* If IPHASE = 0, increase order by one and multiply stepsize by */
/* factor two */
L545:
*k = kp1;
hnew = *h__ * 2.;
*h__ = hnew;
goto L575;
/* Determine the appropriate stepsize for */
/* the next step. */
L550:
hnew = *h__;
temp2 = (doublereal) (*k + 1);
d__1 = est * 2. + 1e-4;
d__2 = -1. / temp2;
r__ = pow_dd(&d__1, &d__2);
if (r__ < 2.) {
goto L555;
}
hnew = *h__ * 2.;
goto L560;
L555:
if (r__ > 1.) {
goto L560;
}
/* Computing MAX */
d__1 = .5, d__2 = min(.9,r__);
r__ = max(d__1,d__2);
hnew = *h__ * r__;
L560:
*h__ = hnew;
/* Update differences for next step */
L575:
if (*kold == iwm[3]) {
goto L585;
}
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L580: */
phi[i__ + kp2 * phi_dim1] = e[i__];
}
L585:
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L590: */
phi[i__ + kp1 * phi_dim1] += e[i__];
}
i__1 = kp1;
for (j1 = 2; j1 <= i__1; ++j1) {
j = kp1 - j1 + 1;
i__2 = *neq;
for (i__ = 1; i__ <= i__2; ++i__) {
/* L595: */
phi[i__ + j * phi_dim1] += phi[i__ + (j + 1) * phi_dim1];
}
}
*jstart = 1;
return 0;
/* ----------------------------------------------------------------------- */
/* BLOCK 6 */
/* The step is unsuccessful. Restore X,PSI,PHI */
/* Determine appropriate stepsize for */
/* continuing the integration, or exit with */
/* an error flag if there have been many */
/* failures. */
/* ----------------------------------------------------------------------- */
L600:
*iphase = 1;
/* Restore X,PHI,PSI */
*x = xold;
if (kp1 < nsp1) {
goto L630;
}
i__2 = kp1;
for (j = nsp1; j <= i__2; ++j) {
temp1 = 1. / beta[j];
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L610: */
phi[i__ + j * phi_dim1] = temp1 * phi[i__ + j * phi_dim1];
}
/* L620: */
}
L630:
i__2 = kp1;
for (i__ = 2; i__ <= i__2; ++i__) {
/* L640: */
psi[i__ - 1] = psi[i__] - *h__;
}
/* Test whether failure is due to nonlinear solver */
/* or error test */
if (iernls == 0) {
goto L660;
}
++iwm[15];
/* The nonlinear solver failed to converge. */
/* Determine the cause of the failure and take appropriate action. */
/* If IERNLS .LT. 0, then return. Otherwise, reduce the stepsize */
/* and try again, unless too many failures have occurred. */
if (iernls < 0) {
goto L675;
}
++ncf;
r__ = .25;
*h__ *= r__;
if (ncf < 10 && abs(*h__) >= *hmin) {
goto L690;
}
if (*idid == 1) {
*idid = -7;
}
if (nef >= 3) {
*idid = -9;
}
goto L675;
/* The nonlinear solver converged, and the cause */
/* of the failure was the error estimate */
/* exceeding the tolerance. */
L660:
++nef;
++iwm[14];
if (nef > 1) {
goto L665;
}
/* On first error test failure, keep current order or lower */
/* order by one. Compute new stepsize based on differences */
/* of the solution. */
*k = knew;
temp2 = (doublereal) (*k + 1);
d__1 = est * 2. + 1e-4;
d__2 = -1. / temp2;
r__ = pow_dd(&d__1, &d__2) * .9;
/* Computing MAX */
d__1 = .25, d__2 = min(.9,r__);
r__ = max(d__1,d__2);
*h__ *= r__;
if (abs(*h__) >= *hmin) {
goto L690;
}
*idid = -6;
goto L675;
/* On second error test failure, use the current order or */
/* decrease order by one. Reduce the stepsize by a factor of */
/* one quarter. */
L665:
if (nef > 2) {
goto L670;
}
*k = knew;
r__ = .25;
*h__ = r__ * *h__;
if (abs(*h__) >= *hmin) {
goto L690;
}
*idid = -6;
goto L675;
/* On third and subsequent error test failures, set the order to */
/* one, and reduce the stepsize by a factor of one quarter. */
L670:
*k = 1;
r__ = .25;
*h__ = r__ * *h__;
if (abs(*h__) >= *hmin) {
goto L690;
}
*idid = -6;
goto L675;
/* For all crashes, restore Y to its last value, */
/* interpolate to find YPRIME at last X, and return. */
/* Before returning, verify that the user has not set */
/* IDID to a nonnegative value. If the user has set IDID */
/* to a nonnegative value, then reset IDID to be -7, indicating */
/* a failure in the nonlinear system solver. */
L675:
ddatrp_(x, x, &y[1], &yprime[1], neq, k, &phi[phi_offset], &psi[1]);
*jstart = 1;
if (*idid >= 0) {
*idid = -7;
}
return 0;
/* Go back and try this step again. */
/* If this is the first step, reset PSI(1) and rescale PHI(*,2). */
L690:
if (*kold == 0) {
psi[1] = *h__;
i__2 = *neq;
for (i__ = 1; i__ <= i__2; ++i__) {
/* L695: */
phi[i__ + (phi_dim1 << 1)] = r__ * phi[i__ + (phi_dim1 << 1)];
}
}
goto L200;
/* ------END OF SUBROUTINE DDSTP------------------------------------------ */
} /* ddstp_ */
/* Subroutine */ int dcnstr_(integer *neq, doublereal *y, doublereal *ynew,
integer *icnstr, doublereal *tau, doublereal *rlx, integer *iret,
integer *ivar)
{
/* Initialized data */
static doublereal fac = .6;
static doublereal fac2 = .9;
static doublereal zero = 0.;
/* System generated locals */
integer i__1;
doublereal d__1;
/* Local variables */
static integer i__;
static doublereal rdy, rdymx;
/* ***BEGIN PROLOGUE DCNSTR */
/* ***DATE WRITTEN 950808 (YYMMDD) */
/* ***REVISION DATE 950814 (YYMMDD) */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* This subroutine checks for constraint violations in the proposed */
/* new approximate solution YNEW. */
/* If a constraint violation occurs, then a new step length, TAU, */
/* is calculated, and this value is to be given to the linesearch routine */
/* to calculate a new approximate solution YNEW. */
/* On entry: */
/* NEQ -- size of the nonlinear system, and the length of arrays */
/* Y, YNEW and ICNSTR. */
/* Y -- real array containing the current approximate y. */
/* YNEW -- real array containing the new approximate y. */
/* ICNSTR -- INTEGER array of length NEQ containing flags indicating */
/* which entries in YNEW are to be constrained. */
/* if ICNSTR(I) = 2, then YNEW(I) must be .GT. 0, */
/* if ICNSTR(I) = 1, then YNEW(I) must be .GE. 0, */
/* if ICNSTR(I) = -1, then YNEW(I) must be .LE. 0, while */
/* if ICNSTR(I) = -2, then YNEW(I) must be .LT. 0, while */
/* if ICNSTR(I) = 0, then YNEW(I) is not constrained. */
/* RLX -- real scalar restricting update, if ICNSTR(I) = 2 or -2, */
/* to ABS( (YNEW-Y)/Y ) < FAC2*RLX in component I. */
/* TAU -- the current size of the step length for the linesearch. */
/* On return */
/* TAU -- the adjusted size of the step length if a constraint */
/* violation occurred (otherwise, it is unchanged). it is */
/* the step length to give to the linesearch routine. */
/* IRET -- output flag. */
/* IRET=0 means that YNEW satisfied all constraints. */
/* IRET=1 means that YNEW failed to satisfy all the */
/* constraints, and a new linesearch step */
/* must be computed. */
/* IVAR -- index of variable causing constraint to be violated. */
/* ----------------------------------------------------------------------- */
/* Parameter adjustments */
--icnstr;
--ynew;
--y;
/* Function Body */
/* ----------------------------------------------------------------------- */
/* Check constraints for proposed new step YNEW. If a constraint has */
/* been violated, then calculate a new step length, TAU, to be */
/* used in the linesearch routine. */
/* ----------------------------------------------------------------------- */
*iret = 0;
rdymx = zero;
*ivar = 0;
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
if (icnstr[i__] == 2) {
rdy = (d__1 = (ynew[i__] - y[i__]) / y[i__], abs(d__1));
if (rdy > rdymx) {
rdymx = rdy;
*ivar = i__;
}
if (ynew[i__] <= zero) {
*tau = fac * *tau;
*ivar = i__;
*iret = 1;
return 0;
}
} else if (icnstr[i__] == 1) {
if (ynew[i__] < zero) {
*tau = fac * *tau;
*ivar = i__;
*iret = 1;
return 0;
}
} else if (icnstr[i__] == -1) {
if (ynew[i__] > zero) {
*tau = fac * *tau;
*ivar = i__;
*iret = 1;
return 0;
}
} else if (icnstr[i__] == -2) {
rdy = (d__1 = (ynew[i__] - y[i__]) / y[i__], abs(d__1));
if (rdy > rdymx) {
rdymx = rdy;
*ivar = i__;
}
if (ynew[i__] >= zero) {
*tau = fac * *tau;
*ivar = i__;
*iret = 1;
return 0;
}
}
/* L100: */
}
if (rdymx >= *rlx) {
*tau = fac2 * *tau * *rlx / rdymx;
*iret = 1;
}
return 0;
/* ----------------------- END OF SUBROUTINE DCNSTR ---------------------- */
} /* dcnstr_ */
/* Subroutine */ int dcnst0_(integer *neq, doublereal *y, integer *icnstr,
integer *iret)
{
/* Initialized data */
static doublereal zero = 0.;
/* System generated locals */
integer i__1;
/* Local variables */
static integer i__;
/* ***BEGIN PROLOGUE DCNST0 */
/* ***DATE WRITTEN 950808 (YYMMDD) */
/* ***REVISION DATE 950808 (YYMMDD) */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* This subroutine checks for constraint violations in the initial */
/* approximate solution u. */
/* On entry */
/* NEQ -- size of the nonlinear system, and the length of arrays */
/* Y and ICNSTR. */
/* Y -- real array containing the initial approximate root. */
/* ICNSTR -- INTEGER array of length NEQ containing flags indicating */
/* which entries in Y are to be constrained. */
/* if ICNSTR(I) = 2, then Y(I) must be .GT. 0, */
/* if ICNSTR(I) = 1, then Y(I) must be .GE. 0, */
/* if ICNSTR(I) = -1, then Y(I) must be .LE. 0, while */
/* if ICNSTR(I) = -2, then Y(I) must be .LT. 0, while */
/* if ICNSTR(I) = 0, then Y(I) is not constrained. */
/* On return */
/* IRET -- output flag. */
/* IRET=0 means that u satisfied all constraints. */
/* IRET.NE.0 means that Y(IRET) failed to satisfy its */
/* constraint. */
/* ----------------------------------------------------------------------- */
/* Parameter adjustments */
--icnstr;
--y;
/* Function Body */
/* ----------------------------------------------------------------------- */
/* Check constraints for initial Y. If a constraint has been violated, */
/* set IRET = I to signal an error return to calling routine. */
/* ----------------------------------------------------------------------- */
*iret = 0;
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
if (icnstr[i__] == 2) {
if (y[i__] <= zero) {
*iret = i__;
return 0;
}
} else if (icnstr[i__] == 1) {
if (y[i__] < zero) {
*iret = i__;
return 0;
}
} else if (icnstr[i__] == -1) {
if (y[i__] > zero) {
*iret = i__;
return 0;
}
} else if (icnstr[i__] == -2) {
if (y[i__] >= zero) {
*iret = i__;
return 0;
}
}
/* L100: */
}
return 0;
/* ----------------------- END OF SUBROUTINE DCNST0 ---------------------- */
} /* dcnst0_ */
/* Subroutine */ int ddawts_(integer *neq, integer *iwt, doublereal *rtol,
doublereal *atol, doublereal *y, doublereal *wt, doublereal *rpar,
integer *ipar)
{
/* System generated locals */
integer i__1;
doublereal d__1;
/* Local variables */
static integer i__;
static doublereal atoli, rtoli;
/* ***BEGIN PROLOGUE DDAWTS */
/* ***REFER TO DDASPK */
/* ***ROUTINES CALLED (NONE) */
/* ***DATE WRITTEN 890101 (YYMMDD) */
/* ***REVISION DATE 900926 (YYMMDD) */
/* ***END PROLOGUE DDAWTS */
/* ----------------------------------------------------------------------- */
/* This subroutine sets the error weight vector, */
/* WT, according to WT(I)=RTOL(I)*ABS(Y(I))+ATOL(I), */
/* I = 1 to NEQ. */
/* RTOL and ATOL are scalars if IWT = 0, */
/* and vectors if IWT = 1. */
/* ----------------------------------------------------------------------- */
/* Parameter adjustments */
--ipar;
--rpar;
--wt;
--y;
--atol;
--rtol;
/* Function Body */
rtoli = rtol[1];
atoli = atol[1];
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
if (*iwt == 0) {
goto L10;
}
rtoli = rtol[i__];
atoli = atol[i__];
L10:
wt[i__] = rtoli * (d__1 = y[i__], abs(d__1)) + atoli;
/* L20: */
}
return 0;
/* ------END OF SUBROUTINE DDAWTS----------------------------------------- */
} /* ddawts_ */
/* Subroutine */ int dinvwt_(integer *neq, doublereal *wt, integer *ier)
{
/* System generated locals */
integer i__1;
/* Local variables */
static integer i__;
/* ***BEGIN PROLOGUE DINVWT */
/* ***REFER TO DDASPK */
/* ***ROUTINES CALLED (NONE) */
/* ***DATE WRITTEN 950125 (YYMMDD) */
/* ***END PROLOGUE DINVWT */
/* ----------------------------------------------------------------------- */
/* This subroutine checks the error weight vector WT, of length NEQ, */
/* for components that are .le. 0, and if none are found, it */
/* inverts the WT(I) in place. This replaces division operations */
/* with multiplications in all norm evaluations. */
/* IER is returned as 0 if all WT(I) were found positive, */
/* and the first I with WT(I) .le. 0.0 otherwise. */
/* ----------------------------------------------------------------------- */
/* Parameter adjustments */
--wt;
/* Function Body */
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
if (wt[i__] <= 0.) {
goto L30;
}
/* L10: */
}
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L20: */
wt[i__] = 1. / wt[i__];
}
*ier = 0;
return 0;
L30:
*ier = i__;
return 0;
/* ------END OF SUBROUTINE DINVWT----------------------------------------- */
} /* dinvwt_ */
/* Subroutine */ int ddatrp_(doublereal *x, doublereal *xout, doublereal *
yout, doublereal *ypout, integer *neq, integer *kold, doublereal *phi,
doublereal *psi)
{
/* System generated locals */
integer phi_dim1, phi_offset, i__1, i__2;
/* Local variables */
static doublereal c__, d__;
static integer i__, j;
static doublereal temp1, gamma;
static integer koldp1;
/* ***BEGIN PROLOGUE DDATRP */
/* ***REFER TO DDASPK */
/* ***ROUTINES CALLED (NONE) */
/* ***DATE WRITTEN 890101 (YYMMDD) */
/* ***REVISION DATE 900926 (YYMMDD) */
/* ***END PROLOGUE DDATRP */
/* ----------------------------------------------------------------------- */
/* The methods in subroutine DDSTP use polynomials */
/* to approximate the solution. DDATRP approximates the */
/* solution and its derivative at time XOUT by evaluating */
/* one of these polynomials, and its derivative, there. */
/* Information defining this polynomial is passed from */
/* DDSTP, so DDATRP cannot be used alone. */
/* The parameters are */
/* X The current time in the integration. */
/* XOUT The time at which the solution is desired. */
/* YOUT The interpolated approximation to Y at XOUT. */
/* (This is output.) */
/* YPOUT The interpolated approximation to YPRIME at XOUT. */
/* (This is output.) */
/* NEQ Number of equations. */
/* KOLD Order used on last successful step. */
/* PHI Array of scaled divided differences of Y. */
/* PSI Array of past stepsize history. */
/* ----------------------------------------------------------------------- */
/* Parameter adjustments */
--yout;
--ypout;
phi_dim1 = *neq;
phi_offset = 1 + phi_dim1;
phi -= phi_offset;
--psi;
/* Function Body */
koldp1 = *kold + 1;
temp1 = *xout - *x;
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
yout[i__] = phi[i__ + phi_dim1];
/* L10: */
ypout[i__] = 0.;
}
c__ = 1.;
d__ = 0.;
gamma = temp1 / psi[1];
i__1 = koldp1;
for (j = 2; j <= i__1; ++j) {
d__ = d__ * gamma + c__ / psi[j - 1];
c__ *= gamma;
gamma = (temp1 + psi[j - 1]) / psi[j];
i__2 = *neq;
for (i__ = 1; i__ <= i__2; ++i__) {
yout[i__] += c__ * phi[i__ + j * phi_dim1];
/* L20: */
ypout[i__] += d__ * phi[i__ + j * phi_dim1];
}
/* L30: */
}
return 0;
/* ------END OF SUBROUTINE DDATRP----------------------------------------- */
} /* ddatrp_ */
doublereal ddwnrm_(integer *neq, doublereal *v, doublereal *rwt, doublereal *
rpar, integer *ipar)
{
/* System generated locals */
integer i__1;
doublereal ret_val, d__1, d__2;
/* Builtin functions */
double sqrt(doublereal);
/* Local variables */
static integer i__;
static doublereal sum, vmax;
/* ***BEGIN PROLOGUE DDWNRM */
/* ***ROUTINES CALLED (NONE) */
/* ***DATE WRITTEN 890101 (YYMMDD) */
/* ***REVISION DATE 900926 (YYMMDD) */
/* ***END PROLOGUE DDWNRM */
/* ----------------------------------------------------------------------- */
/* This function routine computes the weighted */
/* root-mean-square norm of the vector of length */
/* NEQ contained in the array V, with reciprocal weights */
/* contained in the array RWT of length NEQ. */
/* DDWNRM=SQRT((1/NEQ)*SUM(V(I)*RWT(I))**2) */
/* ----------------------------------------------------------------------- */
/* Parameter adjustments */
--ipar;
--rpar;
--rwt;
--v;
/* Function Body */
ret_val = 0.;
vmax = 0.;
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
if ((d__1 = v[i__] * rwt[i__], abs(d__1)) > vmax) {
vmax = (d__2 = v[i__] * rwt[i__], abs(d__2));
}
/* L10: */
}
if (vmax <= 0.) {
goto L30;
}
sum = 0.;
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L20: */
/* Computing 2nd power */
d__1 = v[i__] * rwt[i__] / vmax;
sum += d__1 * d__1;
}
ret_val = vmax * sqrt(sum / *neq);
L30:
return ret_val;
/* ------END OF FUNCTION DDWNRM------------------------------------------- */
} /* ddwnrm_ */
/* Subroutine */ int ddasid_(doublereal *x, doublereal *y, doublereal *yprime,
integer *neq, integer *icopt, integer *id, S_fp res, U_fp jacd,
doublereal *pdum, doublereal *h__, doublereal *tscale, doublereal *wt,
integer *jsdum, doublereal *rpar, integer *ipar, doublereal *dumsvr,
doublereal *delta, doublereal *r__, doublereal *yic, doublereal *ypic,
doublereal *dumpwk, doublereal *wm, integer *iwm, doublereal *cj,
doublereal *uround, doublereal *dume, doublereal *dums, doublereal *
dumr, doublereal *epcon, doublereal *ratemx, doublereal *stptol,
integer *jfdum, integer *icnflg, integer *icnstr, integer *iernls)
{
static integer nj, ierj, ires, mxnj;
extern /* Subroutine */ int dmatd_(integer *, doublereal *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *, integer *,
doublereal *, doublereal *, doublereal *, integer *, S_fp,
integer *, doublereal *, U_fp, doublereal *, integer *), dnsid_(
doublereal *, doublereal *, doublereal *, integer *, integer *,
integer *, S_fp, doublereal *, doublereal *, integer *,
doublereal *, doublereal *, doublereal *, doublereal *,
doublereal *, integer *, doublereal *, doublereal *, doublereal *,
doublereal *, integer *, doublereal *, integer *, integer *,
integer *);
static integer mxnit, iernew;
/* ***BEGIN PROLOGUE DDASID */
/* ***REFER TO DDASPK */
/* ***DATE WRITTEN 940701 (YYMMDD) */
/* ***REVISION DATE 950808 (YYMMDD) */
/* ***REVISION DATE 951110 Removed unreachable block 390. */
/* ***REVISION DATE 000628 TSCALE argument added. */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* DDASID solves a nonlinear system of algebraic equations of the */
/* form G(X,Y,YPRIME) = 0 for the unknown parts of Y and YPRIME in */
/* the initial conditions. */
/* The method used is a modified Newton scheme. */
/* The parameters represent */
/* X -- Independent variable. */
/* Y -- Solution vector. */
/* YPRIME -- Derivative of solution vector. */
/* NEQ -- Number of unknowns. */
/* ICOPT -- Initial condition option chosen (1 or 2). */
/* ID -- Array of dimension NEQ, which must be initialized */
/* if ICOPT = 1. See DDASIC. */
/* RES -- External user-supplied subroutine to evaluate the */
/* residual. See RES description in DDASPK prologue. */
/* JACD -- External user-supplied routine to evaluate the */
/* Jacobian. See JAC description for the case */
/* INFO(12) = 0 in the DDASPK prologue. */
/* PDUM -- Dummy argument. */
/* H -- Scaling factor for this initial condition calc. */
/* TSCALE -- Scale factor in T, used for stopping tests if nonzero. */
/* WT -- Vector of weights for error criterion. */
/* JSDUM -- Dummy argument. */
/* RPAR,IPAR -- Real and integer arrays used for communication */
/* between the calling program and external user */
/* routines. They are not altered within DASPK. */
/* DUMSVR -- Dummy argument. */
/* DELTA -- Work vector for NLS of length NEQ. */
/* R -- Work vector for NLS of length NEQ. */
/* YIC,YPIC -- Work vectors for NLS, each of length NEQ. */
/* DUMPWK -- Dummy argument. */
/* WM,IWM -- Real and integer arrays storing matrix information */
/* such as the matrix of partial derivatives, */
/* permutation vector, and various other information. */
/* CJ -- Matrix parameter = 1/H (ICOPT = 1) or 0 (ICOPT = 2). */
/* UROUND -- Unit roundoff. */
/* DUME -- Dummy argument. */
/* DUMS -- Dummy argument. */
/* DUMR -- Dummy argument. */
/* EPCON -- Tolerance to test for convergence of the Newton */
/* iteration. */
/* RATEMX -- Maximum convergence rate for which Newton iteration */
/* is considered converging. */
/* JFDUM -- Dummy argument. */
/* STPTOL -- Tolerance used in calculating the minimum lambda */
/* value allowed. */
/* ICNFLG -- Integer scalar. If nonzero, then constraint */
/* violations in the proposed new approximate solution */
/* will be checked for, and the maximum step length */
/* will be adjusted accordingly. */
/* ICNSTR -- Integer array of length NEQ containing flags for */
/* checking constraints. */
/* IERNLS -- Error flag for nonlinear solver. */
/* 0 ==> nonlinear solver converged. */
/* 1,2 ==> recoverable error inside nonlinear solver. */
/* 1 => retry with current Y, YPRIME */
/* 2 => retry with original Y, YPRIME */
/* -1 ==> unrecoverable error in nonlinear solver. */
/* All variables with "DUM" in their names are dummy variables */
/* which are not used in this routine. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED */
/* RES, DMATD, DNSID */
/* ***END PROLOGUE DDASID */
/* Perform initializations. */
/* Parameter adjustments */
--icnstr;
--iwm;
--wm;
--ypic;
--yic;
--r__;
--delta;
--ipar;
--rpar;
--wt;
--id;
--yprime;
--y;
/* Function Body */
mxnit = iwm[32];
mxnj = iwm[33];
*iernls = 0;
nj = 0;
/* Call RES to initialize DELTA. */
ires = 0;
++iwm[12];
(*res)(x, &y[1], &yprime[1], cj, &delta[1], &ires, &rpar[1], &ipar[1]);
if (ires < 0) {
goto L370;
}
/* Looping point for updating the Jacobian. */
L300:
/* Initialize all error flags to zero. */
ierj = 0;
ires = 0;
iernew = 0;
/* Reevaluate the iteration matrix, J = dG/dY + CJ*dG/dYPRIME, */
/* where G(X,Y,YPRIME) = 0. */
++nj;
++iwm[13];
dmatd_(neq, x, &y[1], &yprime[1], &delta[1], cj, h__, &ierj, &wt[1], &r__[
1], &wm[1], &iwm[1], (S_fp)res, &ires, uround, (U_fp)jacd, &rpar[
1], &ipar[1]);
if (ires < 0 || ierj != 0) {
goto L370;
}
/* Call the nonlinear Newton solver for up to MXNIT iterations. */
dnsid_(x, &y[1], &yprime[1], neq, icopt, &id[1], (S_fp)res, &wt[1], &rpar[
1], &ipar[1], &delta[1], &r__[1], &yic[1], &ypic[1], &wm[1], &iwm[
1], cj, tscale, epcon, ratemx, &mxnit, stptol, icnflg, &icnstr[1],
&iernew);
if (iernew == 1 && nj < mxnj) {
/* MXNIT iterations were done, the convergence rate is < 1, */
/* and the number of Jacobian evaluations is less than MXNJ. */
/* Call RES, reevaluate the Jacobian, and try again. */
++iwm[12];
(*res)(x, &y[1], &yprime[1], cj, &delta[1], &ires, &rpar[1], &ipar[1])
;
if (ires < 0) {
goto L370;
}
goto L300;
}
if (iernew != 0) {
goto L380;
}
return 0;
/* Unsuccessful exits from nonlinear solver. */
/* Compute IERNLS accordingly. */
L370:
*iernls = 2;
if (ires <= -2) {
*iernls = -1;
}
return 0;
L380:
*iernls = min(iernew,2);
return 0;
/* ------END OF SUBROUTINE DDASID----------------------------------------- */
} /* ddasid_ */
/* Subroutine */ int dnsid_(doublereal *x, doublereal *y, doublereal *yprime,
integer *neq, integer *icopt, integer *id, S_fp res, doublereal *wt,
doublereal *rpar, integer *ipar, doublereal *delta, doublereal *r__,
doublereal *yic, doublereal *ypic, doublereal *wm, integer *iwm,
doublereal *cj, doublereal *tscale, doublereal *epcon, doublereal *
ratemx, integer *maxit, doublereal *stptol, integer *icnflg, integer *
icnstr, integer *iernew)
{
static integer m;
static doublereal rlx, rate, fnrm;
static integer iret, ires, lsoff;
extern /* Subroutine */ int dslvd_(integer *, doublereal *, doublereal *,
integer *), dcopy_(integer *, doublereal *, integer *, doublereal
*, integer *), dlinsd_(integer *, doublereal *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *,
doublereal *, doublereal *, integer *, doublereal *, integer *,
S_fp, integer *, doublereal *, integer *, doublereal *, integer *,
integer *, doublereal *, doublereal *, doublereal *, integer *,
integer *, doublereal *, doublereal *, integer *);
static doublereal oldfnm, delnrm;
extern doublereal ddwnrm_(integer *, doublereal *, doublereal *,
doublereal *, integer *);
/* ***BEGIN PROLOGUE DNSID */
/* ***REFER TO DDASPK */
/* ***DATE WRITTEN 940701 (YYMMDD) */
/* ***REVISION DATE 950713 (YYMMDD) */
/* ***REVISION DATE 000628 TSCALE argument added. */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* DNSID solves a nonlinear system of algebraic equations of the */
/* form G(X,Y,YPRIME) = 0 for the unknown parts of Y and YPRIME */
/* in the initial conditions. */
/* The method used is a modified Newton scheme. */
/* The parameters represent */
/* X -- Independent variable. */
/* Y -- Solution vector. */
/* YPRIME -- Derivative of solution vector. */
/* NEQ -- Number of unknowns. */
/* ICOPT -- Initial condition option chosen (1 or 2). */
/* ID -- Array of dimension NEQ, which must be initialized */
/* if ICOPT = 1. See DDASIC. */
/* RES -- External user-supplied subroutine to evaluate the */
/* residual. See RES description in DDASPK prologue. */
/* WT -- Vector of weights for error criterion. */
/* RPAR,IPAR -- Real and integer arrays used for communication */
/* between the calling program and external user */
/* routines. They are not altered within DASPK. */
/* DELTA -- Residual vector on entry, and work vector of */
/* length NEQ for DNSID. */
/* WM,IWM -- Real and integer arrays storing matrix information */
/* such as the matrix of partial derivatives, */
/* permutation vector, and various other information. */
/* CJ -- Matrix parameter = 1/H (ICOPT = 1) or 0 (ICOPT = 2). */
/* TSCALE -- Scale factor in T, used for stopping tests if nonzero. */
/* R -- Array of length NEQ used as workspace by the */
/* linesearch routine DLINSD. */
/* YIC,YPIC -- Work vectors for DLINSD, each of length NEQ. */
/* EPCON -- Tolerance to test for convergence of the Newton */
/* iteration. */
/* RATEMX -- Maximum convergence rate for which Newton iteration */
/* is considered converging. */
/* MAXIT -- Maximum allowed number of Newton iterations. */
/* STPTOL -- Tolerance used in calculating the minimum lambda */
/* value allowed. */
/* ICNFLG -- Integer scalar. If nonzero, then constraint */
/* violations in the proposed new approximate solution */
/* will be checked for, and the maximum step length */
/* will be adjusted accordingly. */
/* ICNSTR -- Integer array of length NEQ containing flags for */
/* checking constraints. */
/* IERNEW -- Error flag for Newton iteration. */
/* 0 ==> Newton iteration converged. */
/* 1 ==> failed to converge, but RATE .le. RATEMX. */
/* 2 ==> failed to converge, RATE .gt. RATEMX. */
/* 3 ==> other recoverable error (IRES = -1, or */
/* linesearch failed). */
/* -1 ==> unrecoverable error (IRES = -2). */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED */
/* DSLVD, DDWNRM, DLINSD, DCOPY */
/* ***END PROLOGUE DNSID */
/* Initializations. M is the Newton iteration counter. */
/* Parameter adjustments */
--icnstr;
--iwm;
--wm;
--ypic;
--yic;
--r__;
--delta;
--ipar;
--rpar;
--wt;
--id;
--yprime;
--y;
/* Function Body */
lsoff = iwm[35];
m = 0;
rate = 1.;
rlx = .4;
/* Compute a new step vector DELTA by back-substitution. */
dslvd_(neq, &delta[1], &wm[1], &iwm[1]);
/* Get norm of DELTA. Return now if norm(DELTA) .le. EPCON. */
delnrm = ddwnrm_(neq, &delta[1], &wt[1], &rpar[1], &ipar[1]);
fnrm = delnrm;
if (*tscale > 0.) {
fnrm = fnrm * *tscale * abs(*cj);
}
if (fnrm <= *epcon) {
return 0;
}
/* Newton iteration loop. */
L300:
++iwm[19];
/* Call linesearch routine for global strategy and set RATE */
oldfnm = fnrm;
dlinsd_(neq, &y[1], x, &yprime[1], cj, tscale, &delta[1], &delnrm, &wt[1],
&lsoff, stptol, &iret, (S_fp)res, &ires, &wm[1], &iwm[1], &fnrm,
icopt, &id[1], &r__[1], &yic[1], &ypic[1], icnflg, &icnstr[1], &
rlx, &rpar[1], &ipar[1]);
rate = fnrm / oldfnm;
/* Check for error condition from linesearch. */
if (iret != 0) {
goto L390;
}
/* Test for convergence of the iteration, and return or loop. */
if (fnrm <= *epcon) {
return 0;
}
/* The iteration has not yet converged. Update M. */
/* Test whether the maximum number of iterations have been tried. */
++m;
if (m >= *maxit) {
goto L380;
}
/* Copy the residual to DELTA and its norm to DELNRM, and loop for */
/* another iteration. */
dcopy_(neq, &r__[1], &c__1, &delta[1], &c__1);
delnrm = fnrm;
goto L300;
/* The maximum number of iterations was done. Set IERNEW and return. */
L380:
if (rate <= *ratemx) {
*iernew = 1;
} else {
*iernew = 2;
}
return 0;
L390:
if (ires <= -2) {
*iernew = -1;
} else {
*iernew = 3;
}
return 0;
/* ------END OF SUBROUTINE DNSID------------------------------------------ */
} /* dnsid_ */
/* Subroutine */ int dlinsd_(integer *neq, doublereal *y, doublereal *t,
doublereal *yprime, doublereal *cj, doublereal *tscale, doublereal *p,
doublereal *pnrm, doublereal *wt, integer *lsoff, doublereal *stptol,
integer *iret, S_fp res, integer *ires, doublereal *wm, integer *iwm,
doublereal *fnrm, integer *icopt, integer *id, doublereal *r__,
doublereal *ynew, doublereal *ypnew, integer *icnflg, integer *icnstr,
doublereal *rlx, doublereal *rpar, integer *ipar)
{
/* Initialized data */
static doublereal alpha = 1e-4;
static doublereal one = 1.;
static doublereal two = 2.;
/* System generated locals */
integer i__1;
/* Builtin functions */
/* Subroutine */ int s_copy(char *, char *, ftnlen, ftnlen);
/* Local variables */
static integer i__;
static doublereal rl;
static char msg[80];
static doublereal tau;
static integer ivar;
static doublereal slpi, f1nrm, ratio;
extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *,
doublereal *, integer *);
static doublereal rlmin, fnrmp;
static integer kprin;
static doublereal ratio1, f1nrmp;
extern /* Subroutine */ int dfnrmd_(integer *, doublereal *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *,
doublereal *, S_fp, integer *, doublereal *, doublereal *,
integer *, doublereal *, integer *), dcnstr_(integer *,
doublereal *, doublereal *, integer *, doublereal *, doublereal *,
integer *, integer *), xerrwd_(char *, integer *, integer *,
integer *, integer *, integer *, integer *, integer *, doublereal
*, doublereal *, ftnlen), dyypnw_(integer *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *, integer *,
integer *, doublereal *, doublereal *);
/* ***BEGIN PROLOGUE DLINSD */
/* ***REFER TO DNSID */
/* ***DATE WRITTEN 941025 (YYMMDD) */
/* ***REVISION DATE 941215 (YYMMDD) */
/* ***REVISION DATE 960129 Moved line RL = ONE to top block. */
/* ***REVISION DATE 000628 TSCALE argument added. */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* DLINSD uses a linesearch algorithm to calculate a new (Y,YPRIME) */
/* pair (YNEW,YPNEW) such that */
/* f(YNEW,YPNEW) .le. (1 - 2*ALPHA*RL)*f(Y,YPRIME) , */
/* where 0 < RL <= 1. Here, f(y,y') is defined as */
/* f(y,y') = (1/2)*norm( (J-inverse)*G(t,y,y') )**2 , */
/* where norm() is the weighted RMS vector norm, G is the DAE */
/* system residual function, and J is the system iteration matrix */
/* (Jacobian). */
/* In addition to the parameters defined elsewhere, we have */
/* TSCALE -- Scale factor in T, used for stopping tests if nonzero. */
/* P -- Approximate Newton step used in backtracking. */
/* PNRM -- Weighted RMS norm of P. */
/* LSOFF -- Flag showing whether the linesearch algorithm is */
/* to be invoked. 0 means do the linesearch, and */
/* 1 means turn off linesearch. */
/* STPTOL -- Tolerance used in calculating the minimum lambda */
/* value allowed. */
/* ICNFLG -- Integer scalar. If nonzero, then constraint violations */
/* in the proposed new approximate solution will be */
/* checked for, and the maximum step length will be */
/* adjusted accordingly. */
/* ICNSTR -- Integer array of length NEQ containing flags for */
/* checking constraints. */
/* RLX -- Real scalar restricting update size in DCNSTR. */
/* YNEW -- Array of length NEQ used to hold the new Y in */
/* performing the linesearch. */
/* YPNEW -- Array of length NEQ used to hold the new YPRIME in */
/* performing the linesearch. */
/* Y -- Array of length NEQ containing the new Y (i.e.,=YNEW). */
/* YPRIME -- Array of length NEQ containing the new YPRIME */
/* (i.e.,=YPNEW). */
/* FNRM -- Real scalar containing SQRT(2*f(Y,YPRIME)) for the */
/* current (Y,YPRIME) on input and output. */
/* R -- Work array of length NEQ, containing the scaled */
/* residual (J-inverse)*G(t,y,y') on return. */
/* IRET -- Return flag. */
/* IRET=0 means that a satisfactory (Y,YPRIME) was found. */
/* IRET=1 means that the routine failed to find a new */
/* (Y,YPRIME) that was sufficiently distinct from */
/* the current (Y,YPRIME) pair. */
/* IRET=2 means IRES .ne. 0 from RES. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED */
/* DFNRMD, DYYPNW, DCNSTR, DCOPY, XERRWD */
/* ***END PROLOGUE DLINSD */
/* Parameter adjustments */
--ipar;
--rpar;
--icnstr;
--ypnew;
--ynew;
--r__;
--id;
--iwm;
--wm;
--wt;
--p;
--yprime;
--y;
/* Function Body */
kprin = iwm[31];
f1nrm = *fnrm * *fnrm / two;
ratio = one;
if (kprin >= 2) {
s_copy(msg, "------ IN ROUTINE DLINSD-- PNRM = (R1)", (ftnlen)80, (
ftnlen)38);
xerrwd_(msg, &c__38, &c__901, &c__0, &c__0, &c__0, &c__0, &c__1, pnrm,
&c_b37, (ftnlen)80);
}
tau = *pnrm;
rl = one;
/* ----------------------------------------------------------------------- */
/* Check for violations of the constraints, if any are imposed. */
/* If any violations are found, the step vector P is rescaled, and the */
/* constraint check is repeated, until no violations are found. */
/* ----------------------------------------------------------------------- */
if (*icnflg != 0) {
L10:
dyypnw_(neq, &y[1], &yprime[1], cj, &rl, &p[1], icopt, &id[1], &ynew[
1], &ypnew[1]);
dcnstr_(neq, &y[1], &ynew[1], &icnstr[1], &tau, rlx, iret, &ivar);
if (*iret == 1) {
ratio1 = tau / *pnrm;
ratio *= ratio1;
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L20: */
p[i__] *= ratio1;
}
*pnrm = tau;
if (kprin >= 2) {
s_copy(msg, "------ CONSTRAINT VIOL., PNRM = (R1), INDEX = ("
"I1)", (ftnlen)80, (ftnlen)50);
xerrwd_(msg, &c__50, &c__902, &c__0, &c__1, &ivar, &c__0, &
c__1, pnrm, &c_b37, (ftnlen)80);
}
if (*pnrm <= *stptol) {
*iret = 1;
return 0;
}
goto L10;
}
}
slpi = -two * f1nrm * ratio;
rlmin = *stptol / *pnrm;
if (*lsoff == 0 && kprin >= 2) {
s_copy(msg, "------ MIN. LAMBDA = (R1)", (ftnlen)80, (ftnlen)25);
xerrwd_(msg, &c__25, &c__903, &c__0, &c__0, &c__0, &c__0, &c__1, &
rlmin, &c_b37, (ftnlen)80);
}
/* ----------------------------------------------------------------------- */
/* Begin iteration to find RL value satisfying alpha-condition. */
/* If RL becomes less than RLMIN, then terminate with IRET = 1. */
/* ----------------------------------------------------------------------- */
L100:
dyypnw_(neq, &y[1], &yprime[1], cj, &rl, &p[1], icopt, &id[1], &ynew[1], &
ypnew[1]);
dfnrmd_(neq, &ynew[1], t, &ypnew[1], &r__[1], cj, tscale, &wt[1], (S_fp)
res, ires, &fnrmp, &wm[1], &iwm[1], &rpar[1], &ipar[1]);
++iwm[12];
if (*ires != 0) {
*iret = 2;
return 0;
}
if (*lsoff == 1) {
goto L150;
}
f1nrmp = fnrmp * fnrmp / two;
if (kprin >= 2) {
s_copy(msg, "------ LAMBDA = (R1)", (ftnlen)80, (ftnlen)20);
xerrwd_(msg, &c__20, &c__904, &c__0, &c__0, &c__0, &c__0, &c__1, &rl,
&c_b37, (ftnlen)80);
s_copy(msg, "------ NORM(F1) = (R1), NORM(F1NEW) = (R2)", (ftnlen)80,
(ftnlen)43);
xerrwd_(msg, &c__43, &c__905, &c__0, &c__0, &c__0, &c__0, &c__2, &
f1nrm, &f1nrmp, (ftnlen)80);
}
if (f1nrmp > f1nrm + alpha * slpi * rl) {
goto L200;
}
/* ----------------------------------------------------------------------- */
/* Alpha-condition is satisfied, or linesearch is turned off. */
/* Copy YNEW,YPNEW to Y,YPRIME and return. */
/* ----------------------------------------------------------------------- */
L150:
*iret = 0;
dcopy_(neq, &ynew[1], &c__1, &y[1], &c__1);
dcopy_(neq, &ypnew[1], &c__1, &yprime[1], &c__1);
*fnrm = fnrmp;
if (kprin >= 1) {
s_copy(msg, "------ LEAVING ROUTINE DLINSD, FNRM = (R1)", (ftnlen)80,
(ftnlen)42);
xerrwd_(msg, &c__42, &c__906, &c__0, &c__0, &c__0, &c__0, &c__1, fnrm,
&c_b37, (ftnlen)80);
}
return 0;
/* ----------------------------------------------------------------------- */
/* Alpha-condition not satisfied. Perform backtrack to compute new RL */
/* value. If no satisfactory YNEW,YPNEW can be found sufficiently */
/* distinct from Y,YPRIME, then return IRET = 1. */
/* ----------------------------------------------------------------------- */
L200:
if (rl < rlmin) {
*iret = 1;
return 0;
}
rl /= two;
goto L100;
/* ----------------------- END OF SUBROUTINE DLINSD ---------------------- */
} /* dlinsd_ */
/* Subroutine */ int dfnrmd_(integer *neq, doublereal *y, doublereal *t,
doublereal *yprime, doublereal *r__, doublereal *cj, doublereal *
tscale, doublereal *wt, S_fp res, integer *ires, doublereal *fnorm,
doublereal *wm, integer *iwm, doublereal *rpar, integer *ipar)
{
extern /* Subroutine */ int dslvd_(integer *, doublereal *, doublereal *,
integer *);
extern doublereal ddwnrm_(integer *, doublereal *, doublereal *,
doublereal *, integer *);
/* ***BEGIN PROLOGUE DFNRMD */
/* ***REFER TO DLINSD */
/* ***DATE WRITTEN 941025 (YYMMDD) */
/* ***REVISION DATE 000628 TSCALE argument added. */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* DFNRMD calculates the scaled preconditioned norm of the nonlinear */
/* function used in the nonlinear iteration for obtaining consistent */
/* initial conditions. Specifically, DFNRMD calculates the weighted */
/* root-mean-square norm of the vector (J-inverse)*G(T,Y,YPRIME), */
/* where J is the Jacobian matrix. */
/* In addition to the parameters described in the calling program */
/* DLINSD, the parameters represent */
/* R -- Array of length NEQ that contains */
/* (J-inverse)*G(T,Y,YPRIME) on return. */
/* TSCALE -- Scale factor in T, used for stopping tests if nonzero. */
/* FNORM -- Scalar containing the weighted norm of R on return. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED */
/* RES, DSLVD, DDWNRM */
/* ***END PROLOGUE DFNRMD */
/* ----------------------------------------------------------------------- */
/* Call RES routine. */
/* ----------------------------------------------------------------------- */
/* Parameter adjustments */
--ipar;
--rpar;
--iwm;
--wm;
--wt;
--r__;
--yprime;
--y;
/* Function Body */
*ires = 0;
(*res)(t, &y[1], &yprime[1], cj, &r__[1], ires, &rpar[1], &ipar[1]);
if (*ires < 0) {
return 0;
}
/* ----------------------------------------------------------------------- */
/* Apply inverse of Jacobian to vector R. */
/* ----------------------------------------------------------------------- */
dslvd_(neq, &r__[1], &wm[1], &iwm[1]);
/* ----------------------------------------------------------------------- */
/* Calculate norm of R. */
/* ----------------------------------------------------------------------- */
*fnorm = ddwnrm_(neq, &r__[1], &wt[1], &rpar[1], &ipar[1]);
if (*tscale > 0.) {
*fnorm = *fnorm * *tscale * abs(*cj);
}
return 0;
/* ----------------------- END OF SUBROUTINE DFNRMD ---------------------- */
} /* dfnrmd_ */
/* Subroutine */ int dnedd_(doublereal *x, doublereal *y, doublereal *yprime,
integer *neq, S_fp res, U_fp jacd, doublereal *pdum, doublereal *h__,
doublereal *wt, integer *jstart, integer *idid, doublereal *rpar,
integer *ipar, doublereal *phi, doublereal *gamma, doublereal *dumsvr,
doublereal *delta, doublereal *e, doublereal *wm, integer *iwm,
doublereal *cj, doublereal *cjold, doublereal *cjlast, doublereal *s,
doublereal *uround, doublereal *dume, doublereal *dums, doublereal *
dumr, doublereal *epcon, integer *jcalc, integer *jfdum, integer *kp1,
integer *nonneg, integer *ntype, integer *iernls)
{
/* Initialized data */
static integer muldel = 1;
static integer maxit = 4;
static doublereal xrate = .25;
/* System generated locals */
integer phi_dim1, phi_offset, i__1, i__2;
doublereal d__1;
/* Local variables */
static integer i__, j, ierj;
extern /* Subroutine */ int dnsd_(doublereal *, doublereal *, doublereal *
, integer *, S_fp, doublereal *, doublereal *, doublereal *,
integer *, doublereal *, doublereal *, doublereal *, doublereal *,
integer *, doublereal *, doublereal *, doublereal *, doublereal *
, doublereal *, doublereal *, doublereal *, doublereal *, integer
*, integer *, integer *, integer *, integer *);
static integer idum, ires;
static doublereal temp1, temp2;
extern /* Subroutine */ int dmatd_(integer *, doublereal *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *, integer *,
doublereal *, doublereal *, doublereal *, integer *, S_fp,
integer *, doublereal *, U_fp, doublereal *, integer *);
static doublereal pnorm, delnrm;
static integer iernew;
extern doublereal ddwnrm_(integer *, doublereal *, doublereal *,
doublereal *, integer *);
static doublereal tolnew;
static integer iertyp;
/* ***BEGIN PROLOGUE DNEDD */
/* ***REFER TO DDASPK */
/* ***DATE WRITTEN 891219 (YYMMDD) */
/* ***REVISION DATE 900926 (YYMMDD) */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* DNEDD solves a nonlinear system of */
/* algebraic equations of the form */
/* G(X,Y,YPRIME) = 0 for the unknown Y. */
/* The method used is a modified Newton scheme. */
/* The parameters represent */
/* X -- Independent variable. */
/* Y -- Solution vector. */
/* YPRIME -- Derivative of solution vector. */
/* NEQ -- Number of unknowns. */
/* RES -- External user-supplied subroutine */
/* to evaluate the residual. See RES description */
/* in DDASPK prologue. */
/* JACD -- External user-supplied routine to evaluate the */
/* Jacobian. See JAC description for the case */
/* INFO(12) = 0 in the DDASPK prologue. */
/* PDUM -- Dummy argument. */
/* H -- Appropriate step size for next step. */
/* WT -- Vector of weights for error criterion. */
/* JSTART -- Indicates first call to this routine. */
/* If JSTART = 0, then this is the first call, */
/* otherwise it is not. */
/* IDID -- Completion flag, output by DNEDD. */
/* See IDID description in DDASPK prologue. */
/* RPAR,IPAR -- Real and integer arrays used for communication */
/* between the calling program and external user */
/* routines. They are not altered within DASPK. */
/* PHI -- Array of divided differences used by */
/* DNEDD. The length is NEQ*(K+1),where */
/* K is the maximum order. */
/* GAMMA -- Array used to predict Y and YPRIME. The length */
/* is MAXORD+1 where MAXORD is the maximum order. */
/* DUMSVR -- Dummy argument. */
/* DELTA -- Work vector for NLS of length NEQ. */
/* E -- Error accumulation vector for NLS of length NEQ. */
/* WM,IWM -- Real and integer arrays storing */
/* matrix information such as the matrix */
/* of partial derivatives, permutation */
/* vector, and various other information. */
/* CJ -- Parameter always proportional to 1/H. */
/* CJOLD -- Saves the value of CJ as of the last call to DMATD. */
/* Accounts for changes in CJ needed to */
/* decide whether to call DMATD. */
/* CJLAST -- Previous value of CJ. */
/* S -- A scalar determined by the approximate rate */
/* of convergence of the Newton iteration and used */
/* in the convergence test for the Newton iteration. */
/* If RATE is defined to be an estimate of the */
/* rate of convergence of the Newton iteration, */
/* then S = RATE/(1.D0-RATE). */
/* The closer RATE is to 0., the faster the Newton */
/* iteration is converging; the closer RATE is to 1., */
/* the slower the Newton iteration is converging. */
/* On the first Newton iteration with an up-dated */
/* preconditioner S = 100.D0, Thus the initial */
/* RATE of convergence is approximately 1. */
/* S is preserved from call to call so that the rate */
/* estimate from a previous step can be applied to */
/* the current step. */
/* UROUND -- Unit roundoff. */
/* DUME -- Dummy argument. */
/* DUMS -- Dummy argument. */
/* DUMR -- Dummy argument. */
/* EPCON -- Tolerance to test for convergence of the Newton */
/* iteration. */
/* JCALC -- Flag used to determine when to update */
/* the Jacobian matrix. In general: */
/* JCALC = -1 ==> Call the DMATD routine to update */
/* the Jacobian matrix. */
/* JCALC = 0 ==> Jacobian matrix is up-to-date. */
/* JCALC = 1 ==> Jacobian matrix is out-dated, */
/* but DMATD will not be called unless */
/* JCALC is set to -1. */
/* JFDUM -- Dummy argument. */
/* KP1 -- The current order(K) + 1; updated across calls. */
/* NONNEG -- Flag to determine nonnegativity constraints. */
/* NTYPE -- Identification code for the NLS routine. */
/* 0 ==> modified Newton; direct solver. */
/* IERNLS -- Error flag for nonlinear solver. */
/* 0 ==> nonlinear solver converged. */
/* 1 ==> recoverable error inside nonlinear solver. */
/* -1 ==> unrecoverable error inside nonlinear solver. */
/* All variables with "DUM" in their names are dummy variables */
/* which are not used in this routine. */
/* Following is a list and description of local variables which */
/* may not have an obvious usage. They are listed in roughly the */
/* order they occur in this subroutine. */
/* The following group of variables are passed as arguments to */
/* the Newton iteration solver. They are explained in greater detail */
/* in DNSD: */
/* TOLNEW, MULDEL, MAXIT, IERNEW */
/* IERTYP -- Flag which tells whether this subroutine is correct. */
/* 0 ==> correct subroutine. */
/* 1 ==> incorrect subroutine. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED */
/* DDWNRM, RES, DMATD, DNSD */
/* ***END PROLOGUE DNEDD */
/* Parameter adjustments */
--y;
--yprime;
phi_dim1 = *neq;
phi_offset = 1 + phi_dim1;
phi -= phi_offset;
--wt;
--rpar;
--ipar;
--gamma;
--delta;
--e;
--wm;
--iwm;
/* Function Body */
/* Verify that this is the correct subroutine. */
iertyp = 0;
if (*ntype != 0) {
iertyp = 1;
goto L380;
}
/* If this is the first step, perform initializations. */
if (*jstart == 0) {
*cjold = *cj;
*jcalc = -1;
}
/* Perform all other initializations. */
*iernls = 0;
/* Decide whether new Jacobian is needed. */
temp1 = (1. - xrate) / (xrate + 1.);
temp2 = 1. / temp1;
if (*cj / *cjold < temp1 || *cj / *cjold > temp2) {
*jcalc = -1;
}
if (*cj != *cjlast) {
*s = 100.;
}
/* ----------------------------------------------------------------------- */
/* Entry point for updating the Jacobian with current */
/* stepsize. */
/* ----------------------------------------------------------------------- */
L300:
/* Initialize all error flags to zero. */
ierj = 0;
ires = 0;
iernew = 0;
/* Predict the solution and derivative and compute the tolerance */
/* for the Newton iteration. */
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
y[i__] = phi[i__ + phi_dim1];
/* L310: */
yprime[i__] = 0.;
}
i__1 = *kp1;
for (j = 2; j <= i__1; ++j) {
i__2 = *neq;
for (i__ = 1; i__ <= i__2; ++i__) {
y[i__] += phi[i__ + j * phi_dim1];
/* L320: */
yprime[i__] += gamma[j] * phi[i__ + j * phi_dim1];
}
/* L330: */
}
pnorm = ddwnrm_(neq, &y[1], &wt[1], &rpar[1], &ipar[1]);
tolnew = *uround * 100. * pnorm;
/* Call RES to initialize DELTA. */
++iwm[12];
(*res)(x, &y[1], &yprime[1], cj, &delta[1], &ires, &rpar[1], &ipar[1]);
if (ires < 0) {
goto L380;
}
/* If indicated, reevaluate the iteration matrix */
/* J = dG/dY + CJ*dG/dYPRIME (where G(X,Y,YPRIME)=0). */
/* Set JCALC to 0 as an indicator that this has been done. */
if (*jcalc == -1) {
++iwm[13];
*jcalc = 0;
dmatd_(neq, x, &y[1], &yprime[1], &delta[1], cj, h__, &ierj, &wt[1], &
e[1], &wm[1], &iwm[1], (S_fp)res, &ires, uround, (U_fp)jacd, &
rpar[1], &ipar[1]);
*cjold = *cj;
*s = 100.;
if (ires < 0) {
goto L380;
}
if (ierj != 0) {
goto L380;
}
}
/* Call the nonlinear Newton solver. */
temp1 = 2. / (*cj / *cjold + 1.);
dnsd_(x, &y[1], &yprime[1], neq, (S_fp)res, pdum, &wt[1], &rpar[1], &ipar[
1], dumsvr, &delta[1], &e[1], &wm[1], &iwm[1], cj, dums, dumr,
dume, epcon, s, &temp1, &tolnew, &muldel, &maxit, &ires, &idum, &
iernew);
if (iernew > 0 && *jcalc != 0) {
/* The Newton iteration had a recoverable failure with an old */
/* iteration matrix. Retry the step with a new iteration matrix. */
*jcalc = -1;
goto L300;
}
if (iernew != 0) {
goto L380;
}
/* The Newton iteration has converged. If nonnegativity of */
/* solution is required, set the solution nonnegative, if the */
/* perturbation to do it is small enough. If the change is too */
/* large, then consider the corrector iteration to have failed. */
/* L375: */
if (*nonneg == 0) {
goto L390;
}
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L377: */
/* Computing MIN */
d__1 = y[i__];
delta[i__] = min(d__1,0.);
}
delnrm = ddwnrm_(neq, &delta[1], &wt[1], &rpar[1], &ipar[1]);
if (delnrm > *epcon) {
goto L380;
}
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L378: */
e[i__] -= delta[i__];
}
goto L390;
/* Exits from nonlinear solver. */
/* No convergence with current iteration */
/* matrix, or singular iteration matrix. */
/* Compute IERNLS and IDID accordingly. */
L380:
if (ires <= -2 || iertyp != 0) {
*iernls = -1;
if (ires <= -2) {
*idid = -11;
}
if (iertyp != 0) {
*idid = -15;
}
} else {
*iernls = 1;
if (ires < 0) {
*idid = -10;
}
if (ierj != 0) {
*idid = -8;
}
}
L390:
*jcalc = 1;
return 0;
/* ------END OF SUBROUTINE DNEDD------------------------------------------ */
} /* dnedd_ */
/* Subroutine */ int dnsd_(doublereal *x, doublereal *y, doublereal *yprime,
integer *neq, S_fp res, doublereal *pdum, doublereal *wt, doublereal *
rpar, integer *ipar, doublereal *dumsvr, doublereal *delta,
doublereal *e, doublereal *wm, integer *iwm, doublereal *cj,
doublereal *dums, doublereal *dumr, doublereal *dume, doublereal *
epcon, doublereal *s, doublereal *confac, doublereal *tolnew, integer
*muldel, integer *maxit, integer *ires, integer *idum, integer *
iernew)
{
/* System generated locals */
integer i__1;
doublereal d__1, d__2;
/* Builtin functions */
double pow_dd(doublereal *, doublereal *);
/* Local variables */
static integer i__, m;
static doublereal rate;
extern /* Subroutine */ int dslvd_(integer *, doublereal *, doublereal *,
integer *);
static doublereal delnrm;
extern doublereal ddwnrm_(integer *, doublereal *, doublereal *,
doublereal *, integer *);
static doublereal oldnrm;
/* ***BEGIN PROLOGUE DNSD */
/* ***REFER TO DDASPK */
/* ***DATE WRITTEN 891219 (YYMMDD) */
/* ***REVISION DATE 900926 (YYMMDD) */
/* ***REVISION DATE 950126 (YYMMDD) */
/* ***REVISION DATE 000711 (YYMMDD) */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* DNSD solves a nonlinear system of */
/* algebraic equations of the form */
/* G(X,Y,YPRIME) = 0 for the unknown Y. */
/* The method used is a modified Newton scheme. */
/* The parameters represent */
/* X -- Independent variable. */
/* Y -- Solution vector. */
/* YPRIME -- Derivative of solution vector. */
/* NEQ -- Number of unknowns. */
/* RES -- External user-supplied subroutine */
/* to evaluate the residual. See RES description */
/* in DDASPK prologue. */
/* PDUM -- Dummy argument. */
/* WT -- Vector of weights for error criterion. */
/* RPAR,IPAR -- Real and integer arrays used for communication */
/* between the calling program and external user */
/* routines. They are not altered within DASPK. */
/* DUMSVR -- Dummy argument. */
/* DELTA -- Work vector for DNSD of length NEQ. */
/* E -- Error accumulation vector for DNSD of length NEQ. */
/* WM,IWM -- Real and integer arrays storing */
/* matrix information such as the matrix */
/* of partial derivatives, permutation */
/* vector, and various other information. */
/* CJ -- Parameter always proportional to 1/H (step size). */
/* DUMS -- Dummy argument. */
/* DUMR -- Dummy argument. */
/* DUME -- Dummy argument. */
/* EPCON -- Tolerance to test for convergence of the Newton */
/* iteration. */
/* S -- Used for error convergence tests. */
/* In the Newton iteration: S = RATE/(1 - RATE), */
/* where RATE is the estimated rate of convergence */
/* of the Newton iteration. */
/* The calling routine passes the initial value */
/* of S to the Newton iteration. */
/* CONFAC -- A residual scale factor to improve convergence. */
/* TOLNEW -- Tolerance on the norm of Newton correction in */
/* alternative Newton convergence test. */
/* MULDEL -- A flag indicating whether or not to multiply */
/* DELTA by CONFAC. */
/* 0 ==> do not scale DELTA by CONFAC. */
/* 1 ==> scale DELTA by CONFAC. */
/* MAXIT -- Maximum allowed number of Newton iterations. */
/* IRES -- Error flag returned from RES. See RES description */
/* in DDASPK prologue. If IRES = -1, then IERNEW */
/* will be set to 1. */
/* If IRES < -1, then IERNEW will be set to -1. */
/* IDUM -- Dummy argument. */
/* IERNEW -- Error flag for Newton iteration. */
/* 0 ==> Newton iteration converged. */
/* 1 ==> recoverable error inside Newton iteration. */
/* -1 ==> unrecoverable error inside Newton iteration. */
/* All arguments with "DUM" in their names are dummy arguments */
/* which are not used in this routine. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED */
/* DSLVD, DDWNRM, RES */
/* ***END PROLOGUE DNSD */
/* Initialize Newton counter M and accumulation vector E. */
/* Parameter adjustments */
--iwm;
--wm;
--e;
--delta;
--ipar;
--rpar;
--wt;
--yprime;
--y;
/* Function Body */
m = 0;
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L100: */
e[i__] = 0.;
}
/* Corrector loop. */
L300:
++iwm[19];
/* If necessary, multiply residual by convergence factor. */
if (*muldel == 1) {
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L320: */
delta[i__] *= *confac;
}
}
/* Compute a new iterate (back-substitution). */
/* Store the correction in DELTA. */
dslvd_(neq, &delta[1], &wm[1], &iwm[1]);
/* Update Y, E, and YPRIME. */
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
y[i__] -= delta[i__];
e[i__] -= delta[i__];
/* L340: */
yprime[i__] -= *cj * delta[i__];
}
/* Test for convergence of the iteration. */
delnrm = ddwnrm_(neq, &delta[1], &wt[1], &rpar[1], &ipar[1]);
if (m == 0) {
oldnrm = delnrm;
if (delnrm <= *tolnew) {
goto L370;
}
} else {
d__1 = delnrm / oldnrm;
d__2 = 1. / m;
rate = pow_dd(&d__1, &d__2);
if (rate > .9) {
goto L380;
}
*s = rate / (1. - rate);
}
if (*s * delnrm <= *epcon) {
goto L370;
}
/* The corrector has not yet converged. */
/* Update M and test whether the */
/* maximum number of iterations have */
/* been tried. */
++m;
if (m >= *maxit) {
goto L380;
}
/* Evaluate the residual, */
/* and go back to do another iteration. */
++iwm[12];
(*res)(x, &y[1], &yprime[1], cj, &delta[1], ires, &rpar[1], &ipar[1]);
if (*ires < 0) {
goto L380;
}
goto L300;
/* The iteration has converged. */
L370:
return 0;
/* The iteration has not converged. Set IERNEW appropriately. */
L380:
if (*ires <= -2) {
*iernew = -1;
} else {
*iernew = 1;
}
return 0;
/* ------END OF SUBROUTINE DNSD------------------------------------------- */
} /* dnsd_ */
/* Subroutine */ int dmatd_(integer *neq, doublereal *x, doublereal *y,
doublereal *yprime, doublereal *delta, doublereal *cj, doublereal *
h__, integer *ier, doublereal *ewt, doublereal *e, doublereal *wm,
integer *iwm, S_fp res, integer *ires, doublereal *uround, S_fp jacd,
doublereal *rpar, integer *ipar)
{
/* System generated locals */
integer i__1, i__2, i__3, i__4, i__5;
doublereal d__1, d__2, d__3, d__4, d__5;
/* Builtin functions */
double sqrt(doublereal), d_sign(doublereal *, doublereal *);
/* Local variables */
static integer i__, j, k, l, n, i1, i2, ii, mba;
static doublereal del;
static integer meb1, nrow;
static doublereal squr;
extern /* Subroutine */ int dgbfa_(doublereal *, integer *, integer *,
integer *, integer *, integer *, integer *), dgefa_(doublereal *,
integer *, integer *, integer *, integer *);
static integer mband, lenpd, isave, msave;
static doublereal ysave;
static integer lipvt, mtype, meband;
static doublereal delinv;
static integer ipsave;
static doublereal ypsave;
/* ***BEGIN PROLOGUE DMATD */
/* ***REFER TO DDASPK */
/* ***DATE WRITTEN 890101 (YYMMDD) */
/* ***REVISION DATE 900926 (YYMMDD) */
/* ***REVISION DATE 940701 (YYMMDD) (new LIPVT) */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* This routine computes the iteration matrix */
/* J = dG/dY+CJ*dG/dYPRIME (where G(X,Y,YPRIME)=0). */
/* Here J is computed by: */
/* the user-supplied routine JACD if IWM(MTYPE) is 1 or 4, or */
/* by numerical difference quotients if IWM(MTYPE) is 2 or 5. */
/* The parameters have the following meanings. */
/* X = Independent variable. */
/* Y = Array containing predicted values. */
/* YPRIME = Array containing predicted derivatives. */
/* DELTA = Residual evaluated at (X,Y,YPRIME). */
/* (Used only if IWM(MTYPE)=2 or 5). */
/* CJ = Scalar parameter defining iteration matrix. */
/* H = Current stepsize in integration. */
/* IER = Variable which is .NE. 0 if iteration matrix */
/* is singular, and 0 otherwise. */
/* EWT = Vector of error weights for computing norms. */
/* E = Work space (temporary) of length NEQ. */
/* WM = Real work space for matrices. On output */
/* it contains the LU decomposition */
/* of the iteration matrix. */
/* IWM = Integer work space containing */
/* matrix information. */
/* RES = External user-supplied subroutine */
/* to evaluate the residual. See RES description */
/* in DDASPK prologue. */
/* IRES = Flag which is equal to zero if no illegal values */
/* in RES, and less than zero otherwise. (If IRES */
/* is less than zero, the matrix was not completed). */
/* In this case (if IRES .LT. 0), then IER = 0. */
/* UROUND = The unit roundoff error of the machine being used. */
/* JACD = Name of the external user-supplied routine */
/* to evaluate the iteration matrix. (This routine */
/* is only used if IWM(MTYPE) is 1 or 4) */
/* See JAC description for the case INFO(12) = 0 */
/* in DDASPK prologue. */
/* RPAR,IPAR= Real and integer parameter arrays that */
/* are used for communication between the */
/* calling program and external user routines. */
/* They are not altered by DMATD. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED */
/* JACD, RES, DGEFA, DGBFA */
/* ***END PROLOGUE DMATD */
/* Parameter adjustments */
--ipar;
--rpar;
--iwm;
--wm;
--e;
--ewt;
--delta;
--yprime;
--y;
/* Function Body */
lipvt = iwm[30];
*ier = 0;
mtype = iwm[4];
switch (mtype) {
case 1: goto L100;
case 2: goto L200;
case 3: goto L300;
case 4: goto L400;
case 5: goto L500;
}
/* Dense user-supplied matrix. */
L100:
lenpd = iwm[22];
i__1 = lenpd;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L110: */
wm[i__] = 0.;
}
(*jacd)(x, &y[1], &yprime[1], &wm[1], cj, &rpar[1], &ipar[1]);
goto L230;
/* Dense finite-difference-generated matrix. */
L200:
*ires = 0;
nrow = 0;
squr = sqrt(*uround);
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* Computing MAX */
d__4 = (d__1 = y[i__], abs(d__1)), d__5 = (d__2 = *h__ * yprime[i__],
abs(d__2)), d__4 = max(d__4,d__5), d__5 = (d__3 = 1. / ewt[
i__], abs(d__3));
del = squr * max(d__4,d__5);
d__1 = *h__ * yprime[i__];
del = d_sign(&del, &d__1);
del = y[i__] + del - y[i__];
ysave = y[i__];
ypsave = yprime[i__];
y[i__] += del;
yprime[i__] += *cj * del;
++iwm[12];
(*res)(x, &y[1], &yprime[1], cj, &e[1], ires, &rpar[1], &ipar[1]);
if (*ires < 0) {
return 0;
}
delinv = 1. / del;
i__2 = *neq;
for (l = 1; l <= i__2; ++l) {
/* L220: */
wm[nrow + l] = (e[l] - delta[l]) * delinv;
}
nrow += *neq;
y[i__] = ysave;
yprime[i__] = ypsave;
/* L210: */
}
/* Do dense-matrix LU decomposition on J. */
L230:
dgefa_(&wm[1], neq, neq, &iwm[lipvt], ier);
return 0;
/* Dummy section for IWM(MTYPE)=3. */
L300:
return 0;
/* Banded user-supplied matrix. */
L400:
lenpd = iwm[22];
i__1 = lenpd;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L410: */
wm[i__] = 0.;
}
(*jacd)(x, &y[1], &yprime[1], &wm[1], cj, &rpar[1], &ipar[1]);
meband = (iwm[1] << 1) + iwm[2] + 1;
goto L550;
/* Banded finite-difference-generated matrix. */
L500:
mband = iwm[1] + iwm[2] + 1;
mba = min(mband,*neq);
meband = mband + iwm[1];
meb1 = meband - 1;
msave = *neq / mband + 1;
isave = iwm[22];
ipsave = isave + msave;
*ires = 0;
squr = sqrt(*uround);
i__1 = mba;
for (j = 1; j <= i__1; ++j) {
i__2 = *neq;
i__3 = mband;
for (n = j; i__3 < 0 ? n >= i__2 : n <= i__2; n += i__3) {
k = (n - j) / mband + 1;
wm[isave + k] = y[n];
wm[ipsave + k] = yprime[n];
/* Computing MAX */
d__4 = (d__1 = y[n], abs(d__1)), d__5 = (d__2 = *h__ * yprime[n],
abs(d__2)), d__4 = max(d__4,d__5), d__5 = (d__3 = 1. /
ewt[n], abs(d__3));
del = squr * max(d__4,d__5);
d__1 = *h__ * yprime[n];
del = d_sign(&del, &d__1);
del = y[n] + del - y[n];
y[n] += del;
/* L510: */
yprime[n] += *cj * del;
}
++iwm[12];
(*res)(x, &y[1], &yprime[1], cj, &e[1], ires, &rpar[1], &ipar[1]);
if (*ires < 0) {
return 0;
}
i__3 = *neq;
i__2 = mband;
for (n = j; i__2 < 0 ? n >= i__3 : n <= i__3; n += i__2) {
k = (n - j) / mband + 1;
y[n] = wm[isave + k];
yprime[n] = wm[ipsave + k];
/* Computing MAX */
d__4 = (d__1 = y[n], abs(d__1)), d__5 = (d__2 = *h__ * yprime[n],
abs(d__2)), d__4 = max(d__4,d__5), d__5 = (d__3 = 1. /
ewt[n], abs(d__3));
del = squr * max(d__4,d__5);
d__1 = *h__ * yprime[n];
del = d_sign(&del, &d__1);
del = y[n] + del - y[n];
delinv = 1. / del;
/* Computing MAX */
i__4 = 1, i__5 = n - iwm[2];
i1 = max(i__4,i__5);
/* Computing MIN */
i__4 = *neq, i__5 = n + iwm[1];
i2 = min(i__4,i__5);
ii = n * meb1 - iwm[1];
i__4 = i2;
for (i__ = i1; i__ <= i__4; ++i__) {
/* L520: */
wm[ii + i__] = (e[i__] - delta[i__]) * delinv;
}
/* L530: */
}
/* L540: */
}
/* Do LU decomposition of banded J. */
L550:
dgbfa_(&wm[1], &meband, neq, &iwm[1], &iwm[2], &iwm[lipvt], ier);
return 0;
/* ------END OF SUBROUTINE DMATD------------------------------------------ */
} /* dmatd_ */
/* Subroutine */ int dslvd_(integer *neq, doublereal *delta, doublereal *wm,
integer *iwm)
{
extern /* Subroutine */ int dgbsl_(doublereal *, integer *, integer *,
integer *, integer *, integer *, doublereal *, integer *), dgesl_(
doublereal *, integer *, integer *, integer *, doublereal *,
integer *);
static integer lipvt, mtype, meband;
/* ***BEGIN PROLOGUE DSLVD */
/* ***REFER TO DDASPK */
/* ***DATE WRITTEN 890101 (YYMMDD) */
/* ***REVISION DATE 900926 (YYMMDD) */
/* ***REVISION DATE 940701 (YYMMDD) (new LIPVT) */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* This routine manages the solution of the linear */
/* system arising in the Newton iteration. */
/* Real matrix information and real temporary storage */
/* is stored in the array WM. */
/* Integer matrix information is stored in the array IWM. */
/* For a dense matrix, the LINPACK routine DGESL is called. */
/* For a banded matrix, the LINPACK routine DGBSL is called. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED */
/* DGESL, DGBSL */
/* ***END PROLOGUE DSLVD */
/* Parameter adjustments */
--iwm;
--wm;
--delta;
/* Function Body */
lipvt = iwm[30];
mtype = iwm[4];
switch (mtype) {
case 1: goto L100;
case 2: goto L100;
case 3: goto L300;
case 4: goto L400;
case 5: goto L400;
}
/* Dense matrix. */
L100:
dgesl_(&wm[1], neq, neq, &iwm[lipvt], &delta[1], &c__0);
return 0;
/* Dummy section for MTYPE=3. */
L300:
return 0;
/* Banded matrix. */
L400:
meband = (iwm[1] << 1) + iwm[2] + 1;
dgbsl_(&wm[1], &meband, neq, &iwm[1], &iwm[2], &iwm[lipvt], &delta[1], &
c__0);
return 0;
/* ------END OF SUBROUTINE DSLVD------------------------------------------ */
} /* dslvd_ */
/* Subroutine */ int ddasik_(doublereal *x, doublereal *y, doublereal *yprime,
integer *neq, integer *icopt, integer *id, S_fp res, S_fp jack, U_fp
psol, doublereal *h__, doublereal *tscale, doublereal *wt, integer *
jskip, doublereal *rpar, integer *ipar, doublereal *savr, doublereal *
delta, doublereal *r__, doublereal *yic, doublereal *ypic, doublereal
*pwk, doublereal *wm, integer *iwm, doublereal *cj, doublereal *
uround, doublereal *epli, doublereal *sqrtn, doublereal *rsqrtn,
doublereal *epcon, doublereal *ratemx, doublereal *stptol, integer *
jflg, integer *icnflg, integer *icnstr, integer *iernls)
{
static integer nj, lwp, ires, liwp, mxnj;
static doublereal eplin;
extern /* Subroutine */ int dnsik_(doublereal *, doublereal *, doublereal
*, integer *, integer *, integer *, S_fp, U_fp, doublereal *,
doublereal *, integer *, doublereal *, doublereal *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *, integer *
, doublereal *, doublereal *, doublereal *, doublereal *,
doublereal *, doublereal *, doublereal *, integer *, doublereal *,
integer *, integer *, integer *);
static integer ierpj;
extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *,
doublereal *, integer *);
static integer mxnit, iernew;
/* ***BEGIN PROLOGUE DDASIK */
/* ***REFER TO DDASPK */
/* ***DATE WRITTEN 941026 (YYMMDD) */
/* ***REVISION DATE 950808 (YYMMDD) */
/* ***REVISION DATE 951110 Removed unreachable block 390. */
/* ***REVISION DATE 000628 TSCALE argument added. */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* DDASIK solves a nonlinear system of algebraic equations of the */
/* form G(X,Y,YPRIME) = 0 for the unknown parts of Y and YPRIME in */
/* the initial conditions. */
/* An initial value for Y and initial guess for YPRIME are input. */
/* The method used is a Newton scheme with Krylov iteration and a */
/* linesearch algorithm. */
/* The parameters represent */
/* X -- Independent variable. */
/* Y -- Solution vector at x. */
/* YPRIME -- Derivative of solution vector. */
/* NEQ -- Number of equations to be integrated. */
/* ICOPT -- Initial condition option chosen (1 or 2). */
/* ID -- Array of dimension NEQ, which must be initialized */
/* if ICOPT = 1. See DDASIC. */
/* RES -- External user-supplied subroutine */
/* to evaluate the residual. See RES description */
/* in DDASPK prologue. */
/* JACK -- External user-supplied routine to update */
/* the preconditioner. (This is optional). */
/* See JAC description for the case */
/* INFO(12) = 1 in the DDASPK prologue. */
/* PSOL -- External user-supplied routine to solve */
/* a linear system using preconditioning. */
/* (This is optional). See explanation inside DDASPK. */
/* H -- Scaling factor for this initial condition calc. */
/* TSCALE -- Scale factor in T, used for stopping tests if nonzero. */
/* WT -- Vector of weights for error criterion. */
/* JSKIP -- input flag to signal if initial JAC call is to be */
/* skipped. 1 => skip the call, 0 => do not skip call. */
/* RPAR,IPAR -- Real and integer arrays used for communication */
/* between the calling program and external user */
/* routines. They are not altered within DASPK. */
/* SAVR -- Work vector for DDASIK of length NEQ. */
/* DELTA -- Work vector for DDASIK of length NEQ. */
/* R -- Work vector for DDASIK of length NEQ. */
/* YIC,YPIC -- Work vectors for DDASIK, each of length NEQ. */
/* PWK -- Work vector for DDASIK of length NEQ. */
/* WM,IWM -- Real and integer arrays storing */
/* matrix information for linear system */
/* solvers, and various other information. */
/* CJ -- Matrix parameter = 1/H (ICOPT = 1) or 0 (ICOPT = 2). */
/* UROUND -- Unit roundoff. Not used here. */
/* EPLI -- convergence test constant. */
/* See DDASPK prologue for more details. */
/* SQRTN -- Square root of NEQ. */
/* RSQRTN -- reciprical of square root of NEQ. */
/* EPCON -- Tolerance to test for convergence of the Newton */
/* iteration. */
/* RATEMX -- Maximum convergence rate for which Newton iteration */
/* is considered converging. */
/* JFLG -- Flag showing whether a Jacobian routine is supplied. */
/* ICNFLG -- Integer scalar. If nonzero, then constraint */
/* violations in the proposed new approximate solution */
/* will be checked for, and the maximum step length */
/* will be adjusted accordingly. */
/* ICNSTR -- Integer array of length NEQ containing flags for */
/* checking constraints. */
/* IERNLS -- Error flag for nonlinear solver. */
/* 0 ==> nonlinear solver converged. */
/* 1,2 ==> recoverable error inside nonlinear solver. */
/* 1 => retry with current Y, YPRIME */
/* 2 => retry with original Y, YPRIME */
/* -1 ==> unrecoverable error in nonlinear solver. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED */
/* RES, JACK, DNSIK, DCOPY */
/* ***END PROLOGUE DDASIK */
/* Perform initializations. */
/* Parameter adjustments */
--icnstr;
--iwm;
--wm;
--pwk;
--ypic;
--yic;
--r__;
--delta;
--savr;
--ipar;
--rpar;
--wt;
--id;
--yprime;
--y;
/* Function Body */
lwp = iwm[29];
liwp = iwm[30];
mxnit = iwm[32];
mxnj = iwm[33];
*iernls = 0;
nj = 0;
eplin = *epli * *epcon;
/* Call RES to initialize DELTA. */
ires = 0;
++iwm[12];
(*res)(x, &y[1], &yprime[1], cj, &delta[1], &ires, &rpar[1], &ipar[1]);
if (ires < 0) {
goto L370;
}
/* Looping point for updating the preconditioner. */
L300:
/* Initialize all error flags to zero. */
ierpj = 0;
ires = 0;
iernew = 0;
/* If a Jacobian routine was supplied, call it. */
if (*jflg == 1 && *jskip == 0) {
++nj;
++iwm[13];
(*jack)((S_fp)res, &ires, neq, x, &y[1], &yprime[1], &wt[1], &delta[1]
, &r__[1], h__, cj, &wm[lwp], &iwm[liwp], &ierpj, &rpar[1], &
ipar[1]);
if (ires < 0 || ierpj != 0) {
goto L370;
}
}
*jskip = 0;
/* Call the nonlinear Newton solver for up to MXNIT iterations. */
dnsik_(x, &y[1], &yprime[1], neq, icopt, &id[1], (S_fp)res, (U_fp)psol, &
wt[1], &rpar[1], &ipar[1], &savr[1], &delta[1], &r__[1], &yic[1],
&ypic[1], &pwk[1], &wm[1], &iwm[1], cj, tscale, sqrtn, rsqrtn, &
eplin, epcon, ratemx, &mxnit, stptol, icnflg, &icnstr[1], &iernew)
;
if (iernew == 1 && nj < mxnj && *jflg == 1) {
/* Up to MXNIT iterations were done, the convergence rate is < 1, */
/* a Jacobian routine is supplied, and the number of JACK calls */
/* is less than MXNJ. */
/* Copy the residual SAVR to DELTA, call JACK, and try again. */
dcopy_(neq, &savr[1], &c__1, &delta[1], &c__1);
goto L300;
}
if (iernew != 0) {
goto L380;
}
return 0;
/* Unsuccessful exits from nonlinear solver. */
/* Set IERNLS accordingly. */
L370:
*iernls = 2;
if (ires <= -2) {
*iernls = -1;
}
return 0;
L380:
*iernls = min(iernew,2);
return 0;
/* ----------------------- END OF SUBROUTINE DDASIK----------------------- */
} /* ddasik_ */
/* Subroutine */ int dnsik_(doublereal *x, doublereal *y, doublereal *yprime,
integer *neq, integer *icopt, integer *id, S_fp res, U_fp psol,
doublereal *wt, doublereal *rpar, integer *ipar, doublereal *savr,
doublereal *delta, doublereal *r__, doublereal *yic, doublereal *ypic,
doublereal *pwk, doublereal *wm, integer *iwm, doublereal *cj,
doublereal *tscale, doublereal *sqrtn, doublereal *rsqrtn, doublereal
*eplin, doublereal *epcon, doublereal *ratemx, integer *maxit,
doublereal *stptol, integer *icnflg, integer *icnstr, integer *iernew)
{
static integer m, ier, lwp;
static doublereal rlx, rate;
static integer ires;
static doublereal fnrm, rhok;
static integer iret, liwp;
static doublereal fnrm0;
static integer lsoff;
extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *,
doublereal *, integer *);
static integer iersl;
extern /* Subroutine */ int dslvk_(integer *, doublereal *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *,
doublereal *, integer *, S_fp, integer *, U_fp, integer *,
doublereal *, doublereal *, doublereal *, doublereal *,
doublereal *, doublereal *, integer *);
static doublereal oldfnm;
extern /* Subroutine */ int dfnrmk_(integer *, doublereal *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *, S_fp,
integer *, U_fp, integer *, integer *, doublereal *, doublereal *,
doublereal *, integer *, doublereal *, doublereal *, integer *);
static doublereal delnrm;
extern /* Subroutine */ int dlinsk_(integer *, doublereal *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *,
doublereal *, integer *, doublereal *, integer *, S_fp, integer *,
U_fp, doublereal *, integer *, doublereal *, doublereal *,
integer *, integer *, doublereal *, integer *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *, integer *,
integer *, doublereal *, doublereal *, integer *);
extern doublereal ddwnrm_(integer *, doublereal *, doublereal *,
doublereal *, integer *);
/* ***BEGIN PROLOGUE DNSIK */
/* ***REFER TO DDASPK */
/* ***DATE WRITTEN 940701 (YYMMDD) */
/* ***REVISION DATE 950714 (YYMMDD) */
/* ***REVISION DATE 000628 TSCALE argument added. */
/* ***REVISION DATE 000628 Added criterion for IERNEW = 1 return. */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* DNSIK solves a nonlinear system of algebraic equations of the */
/* form G(X,Y,YPRIME) = 0 for the unknown parts of Y and YPRIME in */
/* the initial conditions. */
/* The method used is a Newton scheme combined with a linesearch */
/* algorithm, using Krylov iterative linear system methods. */
/* The parameters represent */
/* X -- Independent variable. */
/* Y -- Solution vector. */
/* YPRIME -- Derivative of solution vector. */
/* NEQ -- Number of unknowns. */
/* ICOPT -- Initial condition option chosen (1 or 2). */
/* ID -- Array of dimension NEQ, which must be initialized */
/* if ICOPT = 1. See DDASIC. */
/* RES -- External user-supplied subroutine */
/* to evaluate the residual. See RES description */
/* in DDASPK prologue. */
/* PSOL -- External user-supplied routine to solve */
/* a linear system using preconditioning. */
/* See explanation inside DDASPK. */
/* WT -- Vector of weights for error criterion. */
/* RPAR,IPAR -- Real and integer arrays used for communication */
/* between the calling program and external user */
/* routines. They are not altered within DASPK. */
/* SAVR -- Work vector for DNSIK of length NEQ. */
/* DELTA -- Residual vector on entry, and work vector of */
/* length NEQ for DNSIK. */
/* R -- Work vector for DNSIK of length NEQ. */
/* YIC,YPIC -- Work vectors for DNSIK, each of length NEQ. */
/* PWK -- Work vector for DNSIK of length NEQ. */
/* WM,IWM -- Real and integer arrays storing */
/* matrix information such as the matrix */
/* of partial derivatives, permutation */
/* vector, and various other information. */
/* CJ -- Matrix parameter = 1/H (ICOPT = 1) or 0 (ICOPT = 2). */
/* TSCALE -- Scale factor in T, used for stopping tests if nonzero. */
/* SQRTN -- Square root of NEQ. */
/* RSQRTN -- reciprical of square root of NEQ. */
/* EPLIN -- Tolerance for linear system solver. */
/* EPCON -- Tolerance to test for convergence of the Newton */
/* iteration. */
/* RATEMX -- Maximum convergence rate for which Newton iteration */
/* is considered converging. */
/* MAXIT -- Maximum allowed number of Newton iterations. */
/* STPTOL -- Tolerance used in calculating the minimum lambda */
/* value allowed. */
/* ICNFLG -- Integer scalar. If nonzero, then constraint */
/* violations in the proposed new approximate solution */
/* will be checked for, and the maximum step length */
/* will be adjusted accordingly. */
/* ICNSTR -- Integer array of length NEQ containing flags for */
/* checking constraints. */
/* IERNEW -- Error flag for Newton iteration. */
/* 0 ==> Newton iteration converged. */
/* 1 ==> failed to converge, but RATE .lt. 1, or the */
/* residual norm was reduced by a factor of .1. */
/* 2 ==> failed to converge, RATE .gt. RATEMX. */
/* 3 ==> other recoverable error. */
/* -1 ==> unrecoverable error inside Newton iteration. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED */
/* DFNRMK, DSLVK, DDWNRM, DLINSK, DCOPY */
/* ***END PROLOGUE DNSIK */
/* Initializations. M is the Newton iteration counter. */
/* Parameter adjustments */
--icnstr;
--iwm;
--wm;
--pwk;
--ypic;
--yic;
--r__;
--delta;
--savr;
--ipar;
--rpar;
--wt;
--id;
--yprime;
--y;
/* Function Body */
lsoff = iwm[35];
m = 0;
rate = 1.;
lwp = iwm[29];
liwp = iwm[30];
rlx = .4;
/* Save residual in SAVR. */
dcopy_(neq, &delta[1], &c__1, &savr[1], &c__1);
/* Compute norm of (P-inverse)*(residual). */
dfnrmk_(neq, &y[1], x, &yprime[1], &savr[1], &r__[1], cj, tscale, &wt[1],
sqrtn, rsqrtn, (S_fp)res, &ires, (U_fp)psol, &c__1, &ier, &fnrm,
eplin, &wm[lwp], &iwm[liwp], &pwk[1], &rpar[1], &ipar[1]);
++iwm[21];
if (ier != 0) {
*iernew = 3;
return 0;
}
/* Return now if residual norm is .le. EPCON. */
if (fnrm <= *epcon) {
return 0;
}
/* Newton iteration loop. */
fnrm0 = fnrm;
L300:
++iwm[19];
/* Compute a new step vector DELTA. */
dslvk_(neq, &y[1], x, &yprime[1], &savr[1], &delta[1], &wt[1], &wm[1], &
iwm[1], (S_fp)res, &ires, (U_fp)psol, &iersl, cj, eplin, sqrtn,
rsqrtn, &rhok, &rpar[1], &ipar[1]);
if (ires != 0 || iersl != 0) {
goto L390;
}
/* Get norm of DELTA. Return now if DELTA is zero. */
delnrm = ddwnrm_(neq, &delta[1], &wt[1], &rpar[1], &ipar[1]);
if (delnrm == 0.) {
return 0;
}
/* Call linesearch routine for global strategy and set RATE. */
oldfnm = fnrm;
dlinsk_(neq, &y[1], x, &yprime[1], &savr[1], cj, tscale, &delta[1], &
delnrm, &wt[1], sqrtn, rsqrtn, &lsoff, stptol, &iret, (S_fp)res, &
ires, (U_fp)psol, &wm[1], &iwm[1], &rhok, &fnrm, icopt, &id[1], &
wm[lwp], &iwm[liwp], &r__[1], eplin, &yic[1], &ypic[1], &pwk[1],
icnflg, &icnstr[1], &rlx, &rpar[1], &ipar[1]);
rate = fnrm / oldfnm;
/* Check for error condition from linesearch. */
if (iret != 0) {
goto L390;
}
/* Test for convergence of the iteration, and return or loop. */
if (fnrm <= *epcon) {
return 0;
}
/* The iteration has not yet converged. Update M. */
/* Test whether the maximum number of iterations have been tried. */
++m;
if (m >= *maxit) {
goto L380;
}
/* Copy the residual SAVR to DELTA and loop for another iteration. */
dcopy_(neq, &savr[1], &c__1, &delta[1], &c__1);
goto L300;
/* The maximum number of iterations was done. Set IERNEW and return. */
L380:
if (rate <= *ratemx || fnrm <= fnrm0 * .1) {
*iernew = 1;
} else {
*iernew = 2;
}
return 0;
L390:
if (ires <= -2 || iersl < 0) {
*iernew = -1;
} else {
*iernew = 3;
if (ires == 0 && iersl == 1 && m >= 2 && rate < 1.) {
*iernew = 1;
}
}
return 0;
/* ----------------------- END OF SUBROUTINE DNSIK------------------------ */
} /* dnsik_ */
/* Subroutine */ int dlinsk_(integer *neq, doublereal *y, doublereal *t,
doublereal *yprime, doublereal *savr, doublereal *cj, doublereal *
tscale, doublereal *p, doublereal *pnrm, doublereal *wt, doublereal *
sqrtn, doublereal *rsqrtn, integer *lsoff, doublereal *stptol,
integer *iret, S_fp res, integer *ires, U_fp psol, doublereal *wm,
integer *iwm, doublereal *rhok, doublereal *fnrm, integer *icopt,
integer *id, doublereal *wp, integer *iwp, doublereal *r__,
doublereal *eplin, doublereal *ynew, doublereal *ypnew, doublereal *
pwk, integer *icnflg, integer *icnstr, doublereal *rlx, doublereal *
rpar, integer *ipar)
{
/* Initialized data */
static doublereal alpha = 1e-4;
static doublereal one = 1.;
static doublereal two = 2.;
/* System generated locals */
integer i__1;
/* Builtin functions */
/* Subroutine */ int s_copy(char *, char *, ftnlen, ftnlen);
/* Local variables */
static integer i__;
static doublereal rl;
static integer ier;
static char msg[80];
static doublereal tau;
static integer ivar;
static doublereal slpi, f1nrm, ratio;
extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *,
doublereal *, integer *);
static doublereal rlmin, fnrmp;
static integer kprin;
static doublereal ratio1, f1nrmp;
extern /* Subroutine */ int dfnrmk_(integer *, doublereal *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *, S_fp,
integer *, U_fp, integer *, integer *, doublereal *, doublereal *,
doublereal *, integer *, doublereal *, doublereal *, integer *),
dcnstr_(integer *, doublereal *, doublereal *, integer *,
doublereal *, doublereal *, integer *, integer *), xerrwd_(char *,
integer *, integer *, integer *, integer *, integer *, integer *,
integer *, doublereal *, doublereal *, ftnlen), dyypnw_(integer *
, doublereal *, doublereal *, doublereal *, doublereal *,
doublereal *, integer *, integer *, doublereal *, doublereal *);
/* ***BEGIN PROLOGUE DLINSK */
/* ***REFER TO DNSIK */
/* ***DATE WRITTEN 940830 (YYMMDD) */
/* ***REVISION DATE 951006 (Arguments SQRTN, RSQRTN added.) */
/* ***REVISION DATE 960129 Moved line RL = ONE to top block. */
/* ***REVISION DATE 000628 TSCALE argument added. */
/* ***REVISION DATE 000628 RHOK*RHOK term removed in alpha test. */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* DLINSK uses a linesearch algorithm to calculate a new (Y,YPRIME) */
/* pair (YNEW,YPNEW) such that */
/* f(YNEW,YPNEW) .le. (1 - 2*ALPHA*RL)*f(Y,YPRIME) */
/* where 0 < RL <= 1, and RHOK is the scaled preconditioned norm of */
/* the final residual vector in the Krylov iteration. */
/* Here, f(y,y') is defined as */
/* f(y,y') = (1/2)*norm( (P-inverse)*G(t,y,y') )**2 , */
/* where norm() is the weighted RMS vector norm, G is the DAE */
/* system residual function, and P is the preconditioner used */
/* in the Krylov iteration. */
/* In addition to the parameters defined elsewhere, we have */
/* SAVR -- Work array of length NEQ, containing the residual */
/* vector G(t,y,y') on return. */
/* TSCALE -- Scale factor in T, used for stopping tests if nonzero. */
/* P -- Approximate Newton step used in backtracking. */
/* PNRM -- Weighted RMS norm of P. */
/* LSOFF -- Flag showing whether the linesearch algorithm is */
/* to be invoked. 0 means do the linesearch, */
/* 1 means turn off linesearch. */
/* STPTOL -- Tolerance used in calculating the minimum lambda */
/* value allowed. */
/* ICNFLG -- Integer scalar. If nonzero, then constraint violations */
/* in the proposed new approximate solution will be */
/* checked for, and the maximum step length will be */
/* adjusted accordingly. */
/* ICNSTR -- Integer array of length NEQ containing flags for */
/* checking constraints. */
/* RHOK -- Weighted norm of preconditioned Krylov residual. */
/* RLX -- Real scalar restricting update size in DCNSTR. */
/* YNEW -- Array of length NEQ used to hold the new Y in */
/* performing the linesearch. */
/* YPNEW -- Array of length NEQ used to hold the new YPRIME in */
/* performing the linesearch. */
/* PWK -- Work vector of length NEQ for use in PSOL. */
/* Y -- Array of length NEQ containing the new Y (i.e.,=YNEW). */
/* YPRIME -- Array of length NEQ containing the new YPRIME */
/* (i.e.,=YPNEW). */
/* FNRM -- Real scalar containing SQRT(2*f(Y,YPRIME)) for the */
/* current (Y,YPRIME) on input and output. */
/* R -- Work space length NEQ for residual vector. */
/* IRET -- Return flag. */
/* IRET=0 means that a satisfactory (Y,YPRIME) was found. */
/* IRET=1 means that the routine failed to find a new */
/* (Y,YPRIME) that was sufficiently distinct from */
/* the current (Y,YPRIME) pair. */
/* IRET=2 means a failure in RES or PSOL. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED */
/* DFNRMK, DYYPNW, DCNSTR, DCOPY, XERRWD */
/* ***END PROLOGUE DLINSK */
/* Parameter adjustments */
--ipar;
--rpar;
--icnstr;
--pwk;
--ypnew;
--ynew;
--r__;
--iwp;
--wp;
--id;
--iwm;
--wm;
--wt;
--p;
--savr;
--yprime;
--y;
/* Function Body */
kprin = iwm[31];
f1nrm = *fnrm * *fnrm / two;
ratio = one;
if (kprin >= 2) {
s_copy(msg, "------ IN ROUTINE DLINSK-- PNRM = (R1)", (ftnlen)80, (
ftnlen)38);
xerrwd_(msg, &c__38, &c__921, &c__0, &c__0, &c__0, &c__0, &c__1, pnrm,
&c_b37, (ftnlen)80);
}
tau = *pnrm;
rl = one;
/* ----------------------------------------------------------------------- */
/* Check for violations of the constraints, if any are imposed. */
/* If any violations are found, the step vector P is rescaled, and the */
/* constraint check is repeated, until no violations are found. */
/* ----------------------------------------------------------------------- */
if (*icnflg != 0) {
L10:
dyypnw_(neq, &y[1], &yprime[1], cj, &rl, &p[1], icopt, &id[1], &ynew[
1], &ypnew[1]);
dcnstr_(neq, &y[1], &ynew[1], &icnstr[1], &tau, rlx, iret, &ivar);
if (*iret == 1) {
ratio1 = tau / *pnrm;
ratio *= ratio1;
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L20: */
p[i__] *= ratio1;
}
*pnrm = tau;
if (kprin >= 2) {
s_copy(msg, "------ CONSTRAINT VIOL., PNRM = (R1), INDEX = ("
"I1)", (ftnlen)80, (ftnlen)50);
xerrwd_(msg, &c__50, &c__922, &c__0, &c__1, &ivar, &c__0, &
c__1, pnrm, &c_b37, (ftnlen)80);
}
if (*pnrm <= *stptol) {
*iret = 1;
return 0;
}
goto L10;
}
}
slpi = -two * f1nrm * ratio;
rlmin = *stptol / *pnrm;
if (*lsoff == 0 && kprin >= 2) {
s_copy(msg, "------ MIN. LAMBDA = (R1)", (ftnlen)80, (ftnlen)25);
xerrwd_(msg, &c__25, &c__923, &c__0, &c__0, &c__0, &c__0, &c__1, &
rlmin, &c_b37, (ftnlen)80);
}
/* ----------------------------------------------------------------------- */
/* Begin iteration to find RL value satisfying alpha-condition. */
/* Update YNEW and YPNEW, then compute norm of new scaled residual and */
/* perform alpha condition test. */
/* ----------------------------------------------------------------------- */
L100:
dyypnw_(neq, &y[1], &yprime[1], cj, &rl, &p[1], icopt, &id[1], &ynew[1], &
ypnew[1]);
dfnrmk_(neq, &ynew[1], t, &ypnew[1], &savr[1], &r__[1], cj, tscale, &wt[1]
, sqrtn, rsqrtn, (S_fp)res, ires, (U_fp)psol, &c__0, &ier, &fnrmp,
eplin, &wp[1], &iwp[1], &pwk[1], &rpar[1], &ipar[1]);
++iwm[12];
if (*ires >= 0) {
++iwm[21];
}
if (*ires != 0 || ier != 0) {
*iret = 2;
return 0;
}
if (*lsoff == 1) {
goto L150;
}
f1nrmp = fnrmp * fnrmp / two;
if (kprin >= 2) {
s_copy(msg, "------ LAMBDA = (R1)", (ftnlen)80, (ftnlen)20);
xerrwd_(msg, &c__20, &c__924, &c__0, &c__0, &c__0, &c__0, &c__1, &rl,
&c_b37, (ftnlen)80);
s_copy(msg, "------ NORM(F1) = (R1), NORM(F1NEW) = (R2)", (ftnlen)80,
(ftnlen)43);
xerrwd_(msg, &c__43, &c__925, &c__0, &c__0, &c__0, &c__0, &c__2, &
f1nrm, &f1nrmp, (ftnlen)80);
}
if (f1nrmp > f1nrm + alpha * slpi * rl) {
goto L200;
}
/* ----------------------------------------------------------------------- */
/* Alpha-condition is satisfied, or linesearch is turned off. */
/* Copy YNEW,YPNEW to Y,YPRIME and return. */
/* ----------------------------------------------------------------------- */
L150:
*iret = 0;
dcopy_(neq, &ynew[1], &c__1, &y[1], &c__1);
dcopy_(neq, &ypnew[1], &c__1, &yprime[1], &c__1);
*fnrm = fnrmp;
if (kprin >= 1) {
s_copy(msg, "------ LEAVING ROUTINE DLINSK, FNRM = (R1)", (ftnlen)80,
(ftnlen)42);
xerrwd_(msg, &c__42, &c__926, &c__0, &c__0, &c__0, &c__0, &c__1, fnrm,
&c_b37, (ftnlen)80);
}
return 0;
/* ----------------------------------------------------------------------- */
/* Alpha-condition not satisfied. Perform backtrack to compute new RL */
/* value. If RL is less than RLMIN, i.e. no satisfactory YNEW,YPNEW can */
/* be found sufficiently distinct from Y,YPRIME, then return IRET = 1. */
/* ----------------------------------------------------------------------- */
L200:
if (rl < rlmin) {
*iret = 1;
return 0;
}
rl /= two;
goto L100;
/* ----------------------- END OF SUBROUTINE DLINSK ---------------------- */
} /* dlinsk_ */
/* Subroutine */ int dfnrmk_(integer *neq, doublereal *y, doublereal *t,
doublereal *yprime, doublereal *savr, doublereal *r__, doublereal *cj,
doublereal *tscale, doublereal *wt, doublereal *sqrtn, doublereal *
rsqrtn, S_fp res, integer *ires, S_fp psol, integer *irin, integer *
ier, doublereal *fnorm, doublereal *eplin, doublereal *wp, integer *
iwp, doublereal *pwk, doublereal *rpar, integer *ipar)
{
extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *,
integer *), dcopy_(integer *, doublereal *, integer *, doublereal
*, integer *);
extern doublereal ddwnrm_(integer *, doublereal *, doublereal *,
doublereal *, integer *);
/* ***BEGIN PROLOGUE DFNRMK */
/* ***REFER TO DLINSK */
/* ***DATE WRITTEN 940830 (YYMMDD) */
/* ***REVISION DATE 951006 (SQRTN, RSQRTN, and scaling of WT added.) */
/* ***REVISION DATE 000628 TSCALE argument added. */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* DFNRMK calculates the scaled preconditioned norm of the nonlinear */
/* function used in the nonlinear iteration for obtaining consistent */
/* initial conditions. Specifically, DFNRMK calculates the weighted */
/* root-mean-square norm of the vector (P-inverse)*G(T,Y,YPRIME), */
/* where P is the preconditioner matrix. */
/* In addition to the parameters described in the calling program */
/* DLINSK, the parameters represent */
/* TSCALE -- Scale factor in T, used for stopping tests if nonzero. */
/* IRIN -- Flag showing whether the current residual vector is */
/* input in SAVR. 1 means it is, 0 means it is not. */
/* R -- Array of length NEQ that contains */
/* (P-inverse)*G(T,Y,YPRIME) on return. */
/* FNORM -- Scalar containing the weighted norm of R on return. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED */
/* RES, DCOPY, DSCAL, PSOL, DDWNRM */
/* ***END PROLOGUE DFNRMK */
/* ----------------------------------------------------------------------- */
/* Call RES routine if IRIN = 0. */
/* ----------------------------------------------------------------------- */
/* Parameter adjustments */
--ipar;
--rpar;
--pwk;
--iwp;
--wp;
--wt;
--r__;
--savr;
--yprime;
--y;
/* Function Body */
if (*irin == 0) {
*ires = 0;
(*res)(t, &y[1], &yprime[1], cj, &savr[1], ires, &rpar[1], &ipar[1]);
if (*ires < 0) {
return 0;
}
}
/* ----------------------------------------------------------------------- */
/* Apply inverse of left preconditioner to vector R. */
/* First scale WT array by 1/sqrt(N), and undo scaling afterward. */
/* ----------------------------------------------------------------------- */
dcopy_(neq, &savr[1], &c__1, &r__[1], &c__1);
dscal_(neq, rsqrtn, &wt[1], &c__1);
*ier = 0;
(*psol)(neq, t, &y[1], &yprime[1], &savr[1], &pwk[1], cj, &wt[1], &wp[1],
&iwp[1], &r__[1], eplin, ier, &rpar[1], &ipar[1]);
dscal_(neq, sqrtn, &wt[1], &c__1);
if (*ier != 0) {
return 0;
}
/* ----------------------------------------------------------------------- */
/* Calculate norm of R. */
/* ----------------------------------------------------------------------- */
*fnorm = ddwnrm_(neq, &r__[1], &wt[1], &rpar[1], &ipar[1]);
if (*tscale > 0.) {
*fnorm = *fnorm * *tscale * abs(*cj);
}
return 0;
/* ----------------------- END OF SUBROUTINE DFNRMK ---------------------- */
} /* dfnrmk_ */
/* Subroutine */ int dnedk_(doublereal *x, doublereal *y, doublereal *yprime,
integer *neq, S_fp res, S_fp jack, U_fp psol, doublereal *h__,
doublereal *wt, integer *jstart, integer *idid, doublereal *rpar,
integer *ipar, doublereal *phi, doublereal *gamma, doublereal *savr,
doublereal *delta, doublereal *e, doublereal *wm, integer *iwm,
doublereal *cj, doublereal *cjold, doublereal *cjlast, doublereal *s,
doublereal *uround, doublereal *epli, doublereal *sqrtn, doublereal *
rsqrtn, doublereal *epcon, integer *jcalc, integer *jflg, integer *
kp1, integer *nonneg, integer *ntype, integer *iernls)
{
/* Initialized data */
static integer muldel = 0;
static integer maxit = 4;
static doublereal xrate = .25;
/* System generated locals */
integer phi_dim1, phi_offset, i__1, i__2;
doublereal d__1;
/* Local variables */
static integer i__, j, lwp;
extern /* Subroutine */ int dnsk_(doublereal *, doublereal *, doublereal *
, integer *, S_fp, U_fp, doublereal *, doublereal *, integer *,
doublereal *, doublereal *, doublereal *, doublereal *, integer *,
doublereal *, doublereal *, doublereal *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *, integer *,
integer *, integer *, integer *, integer *);
static integer ires, liwp;
static doublereal temp1, temp2, eplin;
static integer ierpj, iersl;
static doublereal delnrm;
static integer iernew;
extern doublereal ddwnrm_(integer *, doublereal *, doublereal *,
doublereal *, integer *);
static doublereal tolnew;
static integer iertyp;
/* ***BEGIN PROLOGUE DNEDK */
/* ***REFER TO DDASPK */
/* ***DATE WRITTEN 891219 (YYMMDD) */
/* ***REVISION DATE 900926 (YYMMDD) */
/* ***REVISION DATE 940701 (YYMMDD) */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* DNEDK solves a nonlinear system of */
/* algebraic equations of the form */
/* G(X,Y,YPRIME) = 0 for the unknown Y. */
/* The method used is a matrix-free Newton scheme. */
/* The parameters represent */
/* X -- Independent variable. */
/* Y -- Solution vector at x. */
/* YPRIME -- Derivative of solution vector */
/* after successful step. */
/* NEQ -- Number of equations to be integrated. */
/* RES -- External user-supplied subroutine */
/* to evaluate the residual. See RES description */
/* in DDASPK prologue. */
/* JACK -- External user-supplied routine to update */
/* the preconditioner. (This is optional). */
/* See JAC description for the case */
/* INFO(12) = 1 in the DDASPK prologue. */
/* PSOL -- External user-supplied routine to solve */
/* a linear system using preconditioning. */
/* (This is optional). See explanation inside DDASPK. */
/* H -- Appropriate step size for this step. */
/* WT -- Vector of weights for error criterion. */
/* JSTART -- Indicates first call to this routine. */
/* If JSTART = 0, then this is the first call, */
/* otherwise it is not. */
/* IDID -- Completion flag, output by DNEDK. */
/* See IDID description in DDASPK prologue. */
/* RPAR,IPAR -- Real and integer arrays used for communication */
/* between the calling program and external user */
/* routines. They are not altered within DASPK. */
/* PHI -- Array of divided differences used by */
/* DNEDK. The length is NEQ*(K+1), where */
/* K is the maximum order. */
/* GAMMA -- Array used to predict Y and YPRIME. The length */
/* is K+1, where K is the maximum order. */
/* SAVR -- Work vector for DNEDK of length NEQ. */
/* DELTA -- Work vector for DNEDK of length NEQ. */
/* E -- Error accumulation vector for DNEDK of length NEQ. */
/* WM,IWM -- Real and integer arrays storing */
/* matrix information for linear system */
/* solvers, and various other information. */
/* CJ -- Parameter always proportional to 1/H. */
/* CJOLD -- Saves the value of CJ as of the last call to DITMD. */
/* Accounts for changes in CJ needed to */
/* decide whether to call DITMD. */
/* CJLAST -- Previous value of CJ. */
/* S -- A scalar determined by the approximate rate */
/* of convergence of the Newton iteration and used */
/* in the convergence test for the Newton iteration. */
/* If RATE is defined to be an estimate of the */
/* rate of convergence of the Newton iteration, */
/* then S = RATE/(1.D0-RATE). */
/* The closer RATE is to 0., the faster the Newton */
/* iteration is converging; the closer RATE is to 1., */
/* the slower the Newton iteration is converging. */
/* On the first Newton iteration with an up-dated */
/* preconditioner S = 100.D0, Thus the initial */
/* RATE of convergence is approximately 1. */
/* S is preserved from call to call so that the rate */
/* estimate from a previous step can be applied to */
/* the current step. */
/* UROUND -- Unit roundoff. Not used here. */
/* EPLI -- convergence test constant. */
/* See DDASPK prologue for more details. */
/* SQRTN -- Square root of NEQ. */
/* RSQRTN -- reciprical of square root of NEQ. */
/* EPCON -- Tolerance to test for convergence of the Newton */
/* iteration. */
/* JCALC -- Flag used to determine when to update */
/* the Jacobian matrix. In general: */
/* JCALC = -1 ==> Call the DITMD routine to update */
/* the Jacobian matrix. */
/* JCALC = 0 ==> Jacobian matrix is up-to-date. */
/* JCALC = 1 ==> Jacobian matrix is out-dated, */
/* but DITMD will not be called unless */
/* JCALC is set to -1. */
/* JFLG -- Flag showing whether a Jacobian routine is supplied. */
/* KP1 -- The current order + 1; updated across calls. */
/* NONNEG -- Flag to determine nonnegativity constraints. */
/* NTYPE -- Identification code for the DNEDK routine. */
/* 1 ==> modified Newton; iterative linear solver. */
/* 2 ==> modified Newton; user-supplied linear solver. */
/* IERNLS -- Error flag for nonlinear solver. */
/* 0 ==> nonlinear solver converged. */
/* 1 ==> recoverable error inside non-linear solver. */
/* -1 ==> unrecoverable error inside non-linear solver. */
/* The following group of variables are passed as arguments to */
/* the Newton iteration solver. They are explained in greater detail */
/* in DNSK: */
/* TOLNEW, MULDEL, MAXIT, IERNEW */
/* IERTYP -- Flag which tells whether this subroutine is correct. */
/* 0 ==> correct subroutine. */
/* 1 ==> incorrect subroutine. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED */
/* RES, JACK, DDWNRM, DNSK */
/* ***END PROLOGUE DNEDK */
/* Parameter adjustments */
--y;
--yprime;
phi_dim1 = *neq;
phi_offset = 1 + phi_dim1;
phi -= phi_offset;
--wt;
--rpar;
--ipar;
--gamma;
--savr;
--delta;
--e;
--wm;
--iwm;
/* Function Body */
/* Verify that this is the correct subroutine. */
iertyp = 0;
if (*ntype != 1) {
iertyp = 1;
goto L380;
}
/* If this is the first step, perform initializations. */
if (*jstart == 0) {
*cjold = *cj;
*jcalc = -1;
*s = 100.;
}
/* Perform all other initializations. */
*iernls = 0;
lwp = iwm[29];
liwp = iwm[30];
/* Decide whether to update the preconditioner. */
if (*jflg != 0) {
temp1 = (1. - xrate) / (xrate + 1.);
temp2 = 1. / temp1;
if (*cj / *cjold < temp1 || *cj / *cjold > temp2) {
*jcalc = -1;
}
if (*cj != *cjlast) {
*s = 100.;
}
} else {
*jcalc = 0;
}
/* Looping point for updating preconditioner with current stepsize. */
L300:
/* Initialize all error flags to zero. */
ierpj = 0;
ires = 0;
iersl = 0;
iernew = 0;
/* Predict the solution and derivative and compute the tolerance */
/* for the Newton iteration. */
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
y[i__] = phi[i__ + phi_dim1];
/* L310: */
yprime[i__] = 0.;
}
i__1 = *kp1;
for (j = 2; j <= i__1; ++j) {
i__2 = *neq;
for (i__ = 1; i__ <= i__2; ++i__) {
y[i__] += phi[i__ + j * phi_dim1];
/* L320: */
yprime[i__] += gamma[j] * phi[i__ + j * phi_dim1];
}
/* L330: */
}
eplin = *epli * *epcon;
tolnew = eplin;
/* Call RES to initialize DELTA. */
++iwm[12];
(*res)(x, &y[1], &yprime[1], cj, &delta[1], &ires, &rpar[1], &ipar[1]);
if (ires < 0) {
goto L380;
}
/* If indicated, update the preconditioner. */
/* Set JCALC to 0 as an indicator that this has been done. */
if (*jcalc == -1) {
++iwm[13];
*jcalc = 0;
(*jack)((S_fp)res, &ires, neq, x, &y[1], &yprime[1], &wt[1], &delta[1]
, &e[1], h__, cj, &wm[lwp], &iwm[liwp], &ierpj, &rpar[1], &
ipar[1]);
*cjold = *cj;
*s = 100.;
if (ires < 0) {
goto L380;
}
if (ierpj != 0) {
goto L380;
}
}
/* Call the nonlinear Newton solver. */
dnsk_(x, &y[1], &yprime[1], neq, (S_fp)res, (U_fp)psol, &wt[1], &rpar[1],
&ipar[1], &savr[1], &delta[1], &e[1], &wm[1], &iwm[1], cj, sqrtn,
rsqrtn, &eplin, epcon, s, &temp1, &tolnew, &muldel, &maxit, &ires,
&iersl, &iernew);
if (iernew > 0 && *jcalc != 0) {
/* The Newton iteration had a recoverable failure with an old */
/* preconditioner. Retry the step with a new preconditioner. */
*jcalc = -1;
goto L300;
}
if (iernew != 0) {
goto L380;
}
/* The Newton iteration has converged. If nonnegativity of */
/* solution is required, set the solution nonnegative, if the */
/* perturbation to do it is small enough. If the change is too */
/* large, then consider the corrector iteration to have failed. */
if (*nonneg == 0) {
goto L390;
}
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L360: */
/* Computing MIN */
d__1 = y[i__];
delta[i__] = min(d__1,0.);
}
delnrm = ddwnrm_(neq, &delta[1], &wt[1], &rpar[1], &ipar[1]);
if (delnrm > *epcon) {
goto L380;
}
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L370: */
e[i__] -= delta[i__];
}
goto L390;
/* Exits from nonlinear solver. */
/* No convergence with current preconditioner. */
/* Compute IERNLS and IDID accordingly. */
L380:
if (ires <= -2 || iersl < 0 || iertyp != 0) {
*iernls = -1;
if (ires <= -2) {
*idid = -11;
}
if (iersl < 0) {
*idid = -13;
}
if (iertyp != 0) {
*idid = -15;
}
} else {
*iernls = 1;
if (ires == -1) {
*idid = -10;
}
if (ierpj != 0) {
*idid = -5;
}
if (iersl > 0) {
*idid = -14;
}
}
L390:
*jcalc = 1;
return 0;
/* ------END OF SUBROUTINE DNEDK------------------------------------------ */
} /* dnedk_ */
/* Subroutine */ int dnsk_(doublereal *x, doublereal *y, doublereal *yprime,
integer *neq, S_fp res, U_fp psol, doublereal *wt, doublereal *rpar,
integer *ipar, doublereal *savr, doublereal *delta, doublereal *e,
doublereal *wm, integer *iwm, doublereal *cj, doublereal *sqrtn,
doublereal *rsqrtn, doublereal *eplin, doublereal *epcon, doublereal *
s, doublereal *confac, doublereal *tolnew, integer *muldel, integer *
maxit, integer *ires, integer *iersl, integer *iernew)
{
/* System generated locals */
integer i__1;
doublereal d__1, d__2;
/* Builtin functions */
double pow_dd(doublereal *, doublereal *);
/* Local variables */
static integer i__, m;
static doublereal rate, rhok;
extern /* Subroutine */ int dslvk_(integer *, doublereal *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *,
doublereal *, integer *, S_fp, integer *, U_fp, integer *,
doublereal *, doublereal *, doublereal *, doublereal *,
doublereal *, doublereal *, integer *);
static doublereal delnrm;
extern doublereal ddwnrm_(integer *, doublereal *, doublereal *,
doublereal *, integer *);
static doublereal oldnrm;
/* ***BEGIN PROLOGUE DNSK */
/* ***REFER TO DDASPK */
/* ***DATE WRITTEN 891219 (YYMMDD) */
/* ***REVISION DATE 900926 (YYMMDD) */
/* ***REVISION DATE 950126 (YYMMDD) */
/* ***REVISION DATE 000711 (YYMMDD) */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* DNSK solves a nonlinear system of */
/* algebraic equations of the form */
/* G(X,Y,YPRIME) = 0 for the unknown Y. */
/* The method used is a modified Newton scheme. */
/* The parameters represent */
/* X -- Independent variable. */
/* Y -- Solution vector. */
/* YPRIME -- Derivative of solution vector. */
/* NEQ -- Number of unknowns. */
/* RES -- External user-supplied subroutine */
/* to evaluate the residual. See RES description */
/* in DDASPK prologue. */
/* PSOL -- External user-supplied routine to solve */
/* a linear system using preconditioning. */
/* See explanation inside DDASPK. */
/* WT -- Vector of weights for error criterion. */
/* RPAR,IPAR -- Real and integer arrays used for communication */
/* between the calling program and external user */
/* routines. They are not altered within DASPK. */
/* SAVR -- Work vector for DNSK of length NEQ. */
/* DELTA -- Work vector for DNSK of length NEQ. */
/* E -- Error accumulation vector for DNSK of length NEQ. */
/* WM,IWM -- Real and integer arrays storing */
/* matrix information such as the matrix */
/* of partial derivatives, permutation */
/* vector, and various other information. */
/* CJ -- Parameter always proportional to 1/H (step size). */
/* SQRTN -- Square root of NEQ. */
/* RSQRTN -- reciprical of square root of NEQ. */
/* EPLIN -- Tolerance for linear system solver. */
/* EPCON -- Tolerance to test for convergence of the Newton */
/* iteration. */
/* S -- Used for error convergence tests. */
/* In the Newton iteration: S = RATE/(1.D0-RATE), */
/* where RATE is the estimated rate of convergence */
/* of the Newton iteration. */
/* The closer RATE is to 0., the faster the Newton */
/* iteration is converging; the closer RATE is to 1., */
/* the slower the Newton iteration is converging. */
/* The calling routine sends the initial value */
/* of S to the Newton iteration. */
/* CONFAC -- A residual scale factor to improve convergence. */
/* TOLNEW -- Tolerance on the norm of Newton correction in */
/* alternative Newton convergence test. */
/* MULDEL -- A flag indicating whether or not to multiply */
/* DELTA by CONFAC. */
/* 0 ==> do not scale DELTA by CONFAC. */
/* 1 ==> scale DELTA by CONFAC. */
/* MAXIT -- Maximum allowed number of Newton iterations. */
/* IRES -- Error flag returned from RES. See RES description */
/* in DDASPK prologue. If IRES = -1, then IERNEW */
/* will be set to 1. */
/* If IRES < -1, then IERNEW will be set to -1. */
/* IERSL -- Error flag for linear system solver. */
/* See IERSL description in subroutine DSLVK. */
/* If IERSL = 1, then IERNEW will be set to 1. */
/* If IERSL < 0, then IERNEW will be set to -1. */
/* IERNEW -- Error flag for Newton iteration. */
/* 0 ==> Newton iteration converged. */
/* 1 ==> recoverable error inside Newton iteration. */
/* -1 ==> unrecoverable error inside Newton iteration. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED */
/* RES, DSLVK, DDWNRM */
/* ***END PROLOGUE DNSK */
/* Initialize Newton counter M and accumulation vector E. */
/* Parameter adjustments */
--iwm;
--wm;
--e;
--delta;
--savr;
--ipar;
--rpar;
--wt;
--yprime;
--y;
/* Function Body */
m = 0;
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L100: */
e[i__] = 0.;
}
/* Corrector loop. */
L300:
++iwm[19];
/* If necessary, multiply residual by convergence factor. */
if (*muldel == 1) {
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L320: */
delta[i__] *= *confac;
}
}
/* Save residual in SAVR. */
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L340: */
savr[i__] = delta[i__];
}
/* Compute a new iterate. Store the correction in DELTA. */
dslvk_(neq, &y[1], x, &yprime[1], &savr[1], &delta[1], &wt[1], &wm[1], &
iwm[1], (S_fp)res, ires, (U_fp)psol, iersl, cj, eplin, sqrtn,
rsqrtn, &rhok, &rpar[1], &ipar[1]);
if (*ires != 0 || *iersl != 0) {
goto L380;
}
/* Update Y, E, and YPRIME. */
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
y[i__] -= delta[i__];
e[i__] -= delta[i__];
/* L360: */
yprime[i__] -= *cj * delta[i__];
}
/* Test for convergence of the iteration. */
delnrm = ddwnrm_(neq, &delta[1], &wt[1], &rpar[1], &ipar[1]);
if (m == 0) {
oldnrm = delnrm;
if (delnrm <= *tolnew) {
goto L370;
}
} else {
d__1 = delnrm / oldnrm;
d__2 = 1. / m;
rate = pow_dd(&d__1, &d__2);
if (rate > .9) {
goto L380;
}
*s = rate / (1. - rate);
}
if (*s * delnrm <= *epcon) {
goto L370;
}
/* The corrector has not yet converged. Update M and test whether */
/* the maximum number of iterations have been tried. */
++m;
if (m >= *maxit) {
goto L380;
}
/* Evaluate the residual, and go back to do another iteration. */
++iwm[12];
(*res)(x, &y[1], &yprime[1], cj, &delta[1], ires, &rpar[1], &ipar[1]);
if (*ires < 0) {
goto L380;
}
goto L300;
/* The iteration has converged. */
L370:
return 0;
/* The iteration has not converged. Set IERNEW appropriately. */
L380:
if (*ires <= -2 || *iersl < 0) {
*iernew = -1;
} else {
*iernew = 1;
}
return 0;
/* ------END OF SUBROUTINE DNSK------------------------------------------- */
} /* dnsk_ */
/* Subroutine */ int dslvk_(integer *neq, doublereal *y, doublereal *tn,
doublereal *yprime, doublereal *savr, doublereal *x, doublereal *ewt,
doublereal *wm, integer *iwm, S_fp res, integer *ires, U_fp psol,
integer *iersl, doublereal *cj, doublereal *eplin, doublereal *sqrtn,
doublereal *rsqrtn, doublereal *rhok, doublereal *rpar, integer *ipar)
{
/* Initialized data */
static integer irst = 1;
/* System generated locals */
integer i__1, i__2;
/* Local variables */
static integer i__, lq, lr, lv, lz, ldl, nli, nre, kmp, lwk, nps, lwp,
ncfl, lhes, lgmr, maxl, nres, npsl, liwp, iflag;
extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *,
integer *), dcopy_(integer *, doublereal *, integer *, doublereal
*, integer *);
static integer miter, nrmax, nrsts, maxlp1;
extern /* Subroutine */ int dspigm_(integer *, doublereal *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *, integer *
, integer *, integer *, doublereal *, doublereal *, S_fp, integer
*, integer *, U_fp, integer *, doublereal *, doublereal *,
doublereal *, doublereal *, integer *, doublereal *, integer *,
doublereal *, doublereal *, doublereal *, integer *, integer *,
integer *, doublereal *, integer *);
/* ***BEGIN PROLOGUE DSLVK */
/* ***REFER TO DDASPK */
/* ***DATE WRITTEN 890101 (YYMMDD) */
/* ***REVISION DATE 900926 (YYMMDD) */
/* ***REVISION DATE 940928 Removed MNEWT and added RHOK in call list. */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* DSLVK uses a restart algorithm and interfaces to DSPIGM for */
/* the solution of the linear system arising from a Newton iteration. */
/* In addition to variables described elsewhere, */
/* communication with DSLVK uses the following variables.. */
/* WM = Real work space containing data for the algorithm */
/* (Krylov basis vectors, Hessenberg matrix, etc.). */
/* IWM = Integer work space containing data for the algorithm. */
/* X = The right-hand side vector on input, and the solution vector */
/* on output, of length NEQ. */
/* IRES = Error flag from RES. */
/* IERSL = Output flag .. */
/* IERSL = 0 means no trouble occurred (or user RES routine */
/* returned IRES < 0) */
/* IERSL = 1 means the iterative method failed to converge */
/* (DSPIGM returned IFLAG > 0.) */
/* IERSL = -1 means there was a nonrecoverable error in the */
/* iterative solver, and an error exit will occur. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED */
/* DSCAL, DCOPY, DSPIGM */
/* ***END PROLOGUE DSLVK */
/* ----------------------------------------------------------------------- */
/* IRST is set to 1, to indicate restarting is in effect. */
/* NRMAX is the maximum number of restarts. */
/* ----------------------------------------------------------------------- */
/* Parameter adjustments */
--ipar;
--rpar;
--iwm;
--wm;
--ewt;
--x;
--savr;
--yprime;
--y;
/* Function Body */
liwp = iwm[30];
nli = iwm[20];
nps = iwm[21];
ncfl = iwm[16];
nre = iwm[12];
lwp = iwm[29];
maxl = iwm[24];
kmp = iwm[25];
nrmax = iwm[26];
miter = iwm[23];
*iersl = 0;
*ires = 0;
/* ----------------------------------------------------------------------- */
/* Use a restarting strategy to solve the linear system */
/* P*X = -F. Parse the work vector, and perform initializations. */
/* Note that zero is the initial guess for X. */
/* ----------------------------------------------------------------------- */
maxlp1 = maxl + 1;
lv = 1;
lr = lv + *neq * maxl;
lhes = lr + *neq + 1;
lq = lhes + maxl * maxlp1;
lwk = lq + (maxl << 1);
/* Computing MIN */
i__1 = 1, i__2 = maxl - kmp;
ldl = lwk + min(i__1,i__2) * *neq;
lz = ldl + *neq;
dscal_(neq, rsqrtn, &ewt[1], &c__1);
dcopy_(neq, &x[1], &c__1, &wm[lr], &c__1);
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L110: */
x[i__] = 0.;
}
/* ----------------------------------------------------------------------- */
/* Top of loop for the restart algorithm. Initial pass approximates */
/* X and sets up a transformed system to perform subsequent restarts */
/* to update X. NRSTS is initialized to -1, because restarting */
/* does not occur until after the first pass. */
/* Update NRSTS; conditionally copy DL to R; call the DSPIGM */
/* algorithm to solve A*Z = R; updated counters; update X with */
/* the residual solution. */
/* Note: if convergence is not achieved after NRMAX restarts, */
/* then the linear solver is considered to have failed. */
/* ----------------------------------------------------------------------- */
nrsts = -1;
L115:
++nrsts;
if (nrsts > 0) {
dcopy_(neq, &wm[ldl], &c__1, &wm[lr], &c__1);
}
dspigm_(neq, tn, &y[1], &yprime[1], &savr[1], &wm[lr], &ewt[1], &maxl, &
maxlp1, &kmp, eplin, cj, (S_fp)res, ires, &nres, (U_fp)psol, &
npsl, &wm[lz], &wm[lv], &wm[lhes], &wm[lq], &lgmr, &wm[lwp], &iwm[
liwp], &wm[lwk], &wm[ldl], rhok, &iflag, &irst, &nrsts, &rpar[1],
&ipar[1]);
nli += lgmr;
nps += npsl;
nre += nres;
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L120: */
x[i__] += wm[lz + i__ - 1];
}
if (iflag == 1 && nrsts < nrmax && *ires == 0) {
goto L115;
}
/* ----------------------------------------------------------------------- */
/* The restart scheme is finished. Test IRES and IFLAG to see if */
/* convergence was not achieved, and set flags accordingly. */
/* ----------------------------------------------------------------------- */
if (*ires < 0) {
++ncfl;
} else if (iflag != 0) {
++ncfl;
if (iflag > 0) {
*iersl = 1;
}
if (iflag < 0) {
*iersl = -1;
}
}
/* ----------------------------------------------------------------------- */
/* Update IWM with counters, rescale EWT, and return. */
/* ----------------------------------------------------------------------- */
iwm[20] = nli;
iwm[21] = nps;
iwm[16] = ncfl;
iwm[12] = nre;
dscal_(neq, sqrtn, &ewt[1], &c__1);
return 0;
/* ------END OF SUBROUTINE DSLVK------------------------------------------ */
} /* dslvk_ */
/* Subroutine */ int dspigm_(integer *neq, doublereal *tn, doublereal *y,
doublereal *yprime, doublereal *savr, doublereal *r__, doublereal *
wght, integer *maxl, integer *maxlp1, integer *kmp, doublereal *eplin,
doublereal *cj, S_fp res, integer *ires, integer *nre, S_fp psol,
integer *npsl, doublereal *z__, doublereal *v, doublereal *hes,
doublereal *q, integer *lgmr, doublereal *wp, integer *iwp,
doublereal *wk, doublereal *dl, doublereal *rhok, integer *iflag,
integer *irst, integer *nrsts, doublereal *rpar, integer *ipar)
{
/* System generated locals */
integer v_dim1, v_offset, hes_dim1, hes_offset, i__1, i__2, i__3;
doublereal d__1;
/* Local variables */
static doublereal c__;
static integer i__, j, k;
static doublereal s;
static integer i2, ll, ip1, ier;
static doublereal tem, rho;
static integer llp1, info;
extern /* Subroutine */ int datv_(integer *, doublereal *, doublereal *,
doublereal *, doublereal *, doublereal *, doublereal *,
doublereal *, S_fp, integer *, S_fp, doublereal *, doublereal *,
doublereal *, integer *, doublereal *, doublereal *, integer *,
integer *, integer *, doublereal *, integer *);
static doublereal prod, rnrm;
extern doublereal dnrm2_(integer *, doublereal *, integer *);
extern /* Subroutine */ int dscal_(integer *, doublereal *, doublereal *,
integer *), dhels_(doublereal *, integer *, integer *, doublereal
*, doublereal *), dheqr_(doublereal *, integer *, integer *,
doublereal *, integer *, integer *);
static doublereal dlnrm;
extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *,
doublereal *, integer *), dorth_(doublereal *, doublereal *,
doublereal *, integer *, integer *, integer *, integer *,
doublereal *), daxpy_(integer *, doublereal *, doublereal *,
integer *, doublereal *, integer *);
static integer maxlm1;
static doublereal snormw;
/* ***BEGIN PROLOGUE DSPIGM */
/* ***DATE WRITTEN 890101 (YYMMDD) */
/* ***REVISION DATE 900926 (YYMMDD) */
/* ***REVISION DATE 940927 Removed MNEWT and added RHOK in call list. */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* This routine solves the linear system A * Z = R using a scaled */
/* preconditioned version of the generalized minimum residual method. */
/* An initial guess of Z = 0 is assumed. */
/* On entry */
/* NEQ = Problem size, passed to PSOL. */
/* TN = Current Value of T. */
/* Y = Array Containing current dependent variable vector. */
/* YPRIME = Array Containing current first derivative of Y. */
/* SAVR = Array containing current value of G(T,Y,YPRIME). */
/* R = The right hand side of the system A*Z = R. */
/* R is also used as work space when computing */
/* the final approximation and will therefore be */
/* destroyed. */
/* (R is the same as V(*,MAXL+1) in the call to DSPIGM.) */
/* WGHT = The vector of length NEQ containing the nonzero */
/* elements of the diagonal scaling matrix. */
/* MAXL = The maximum allowable order of the matrix H. */
/* MAXLP1 = MAXL + 1, used for dynamic dimensioning of HES. */
/* KMP = The number of previous vectors the new vector, VNEW, */
/* must be made orthogonal to. (KMP .LE. MAXL.) */
/* EPLIN = Tolerance on residuals R-A*Z in weighted rms norm. */
/* CJ = Scalar proportional to current value of */
/* 1/(step size H). */
/* WK = Real work array used by routine DATV and PSOL. */
/* DL = Real work array used for calculation of the residual */
/* norm RHO when the method is incomplete (KMP.LT.MAXL) */
/* and/or when using restarting. */
/* WP = Real work array used by preconditioner PSOL. */
/* IWP = Integer work array used by preconditioner PSOL. */
/* IRST = Method flag indicating if restarting is being */
/* performed. IRST .GT. 0 means restarting is active, */
/* while IRST = 0 means restarting is not being used. */
/* NRSTS = Counter for the number of restarts on the current */
/* call to DSPIGM. If NRSTS .GT. 0, then the residual */
/* R is already scaled, and so scaling of R is not */
/* necessary. */
/* On Return */
/* Z = The final computed approximation to the solution */
/* of the system A*Z = R. */
/* LGMR = The number of iterations performed and */
/* the current order of the upper Hessenberg */
/* matrix HES. */
/* NRE = The number of calls to RES (i.e. DATV) */
/* NPSL = The number of calls to PSOL. */
/* V = The neq by (LGMR+1) array containing the LGMR */
/* orthogonal vectors V(*,1) to V(*,LGMR). */
/* HES = The upper triangular factor of the QR decomposition */
/* of the (LGMR+1) by LGMR upper Hessenberg matrix whose */
/* entries are the scaled inner-products of A*V(*,I) */
/* and V(*,K). */
/* Q = Real array of length 2*MAXL containing the components */
/* of the givens rotations used in the QR decomposition */
/* of HES. It is loaded in DHEQR and used in DHELS. */
/* IRES = Error flag from RES. */
/* DL = Scaled preconditioned residual, */
/* (D-inverse)*(P-inverse)*(R-A*Z). Only loaded when */
/* performing restarts of the Krylov iteration. */
/* RHOK = Weighted norm of final preconditioned residual. */
/* IFLAG = Integer error flag.. */
/* 0 Means convergence in LGMR iterations, LGMR.LE.MAXL. */
/* 1 Means the convergence test did not pass in MAXL */
/* iterations, but the new residual norm (RHO) is */
/* .LT. the old residual norm (RNRM), and so Z is */
/* computed. */
/* 2 Means the convergence test did not pass in MAXL */
/* iterations, new residual norm (RHO) .GE. old residual */
/* norm (RNRM), and the initial guess, Z = 0, is */
/* returned. */
/* 3 Means there was a recoverable error in PSOL */
/* caused by the preconditioner being out of date. */
/* -1 Means there was an unrecoverable error in PSOL. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED */
/* PSOL, DNRM2, DSCAL, DATV, DORTH, DHEQR, DCOPY, DHELS, DAXPY */
/* ***END PROLOGUE DSPIGM */
/* Parameter adjustments */
v_dim1 = *neq;
v_offset = 1 + v_dim1;
v -= v_offset;
--y;
--yprime;
--savr;
--r__;
--wght;
hes_dim1 = *maxlp1;
hes_offset = 1 + hes_dim1;
hes -= hes_offset;
--z__;
--q;
--wp;
--iwp;
--wk;
--dl;
--rpar;
--ipar;
/* Function Body */
ier = 0;
*iflag = 0;
*lgmr = 0;
*npsl = 0;
*nre = 0;
/* ----------------------------------------------------------------------- */
/* The initial guess for Z is 0. The initial residual is therefore */
/* the vector R. Initialize Z to 0. */
/* ----------------------------------------------------------------------- */
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L10: */
z__[i__] = 0.;
}
/* ----------------------------------------------------------------------- */
/* Apply inverse of left preconditioner to vector R if NRSTS .EQ. 0. */
/* Form V(*,1), the scaled preconditioned right hand side. */
/* ----------------------------------------------------------------------- */
if (*nrsts == 0) {
(*psol)(neq, tn, &y[1], &yprime[1], &savr[1], &wk[1], cj, &wght[1], &
wp[1], &iwp[1], &r__[1], eplin, &ier, &rpar[1], &ipar[1]);
*npsl = 1;
if (ier != 0) {
goto L300;
}
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L30: */
v[i__ + v_dim1] = r__[i__] * wght[i__];
}
} else {
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L35: */
v[i__ + v_dim1] = r__[i__];
}
}
/* ----------------------------------------------------------------------- */
/* Calculate norm of scaled vector V(*,1) and normalize it */
/* If, however, the norm of V(*,1) (i.e. the norm of the preconditioned */
/* residual) is .le. EPLIN, then return with Z=0. */
/* ----------------------------------------------------------------------- */
rnrm = dnrm2_(neq, &v[v_offset], &c__1);
if (rnrm <= *eplin) {
*rhok = rnrm;
return 0;
}
tem = 1. / rnrm;
dscal_(neq, &tem, &v[v_dim1 + 1], &c__1);
/* ----------------------------------------------------------------------- */
/* Zero out the HES array. */
/* ----------------------------------------------------------------------- */
i__1 = *maxl;
for (j = 1; j <= i__1; ++j) {
i__2 = *maxlp1;
for (i__ = 1; i__ <= i__2; ++i__) {
/* L60: */
hes[i__ + j * hes_dim1] = 0.;
}
/* L65: */
}
/* ----------------------------------------------------------------------- */
/* Main loop to compute the vectors V(*,2) to V(*,MAXL). */
/* The running product PROD is needed for the convergence test. */
/* ----------------------------------------------------------------------- */
prod = 1.;
i__1 = *maxl;
for (ll = 1; ll <= i__1; ++ll) {
*lgmr = ll;
/* ----------------------------------------------------------------------- */
/* Call routine DATV to compute VNEW = ABAR*V(LL), where ABAR is */
/* the matrix A with scaling and inverse preconditioner factors applied. */
/* Call routine DORTH to orthogonalize the new vector VNEW = V(*,LL+1). */
/* call routine DHEQR to update the factors of HES. */
/* ----------------------------------------------------------------------- */
datv_(neq, &y[1], tn, &yprime[1], &savr[1], &v[ll * v_dim1 + 1], &
wght[1], &z__[1], (S_fp)res, ires, (S_fp)psol, &v[(ll + 1) *
v_dim1 + 1], &wk[1], &wp[1], &iwp[1], cj, eplin, &ier, nre,
npsl, &rpar[1], &ipar[1]);
if (*ires < 0) {
return 0;
}
if (ier != 0) {
goto L300;
}
dorth_(&v[(ll + 1) * v_dim1 + 1], &v[v_offset], &hes[hes_offset], neq,
&ll, maxlp1, kmp, &snormw);
hes[ll + 1 + ll * hes_dim1] = snormw;
dheqr_(&hes[hes_offset], maxlp1, &ll, &q[1], &info, &ll);
if (info == ll) {
goto L120;
}
/* ----------------------------------------------------------------------- */
/* Update RHO, the estimate of the norm of the residual R - A*ZL. */
/* If KMP .LT. MAXL, then the vectors V(*,1),...,V(*,LL+1) are not */
/* necessarily orthogonal for LL .GT. KMP. The vector DL must then */
/* be computed, and its norm used in the calculation of RHO. */
/* ----------------------------------------------------------------------- */
prod *= q[ll * 2];
rho = (d__1 = prod * rnrm, abs(d__1));
if (ll > *kmp && *kmp < *maxl) {
if (ll == *kmp + 1) {
dcopy_(neq, &v[v_dim1 + 1], &c__1, &dl[1], &c__1);
i__2 = *kmp;
for (i__ = 1; i__ <= i__2; ++i__) {
ip1 = i__ + 1;
i2 = i__ << 1;
s = q[i2];
c__ = q[i2 - 1];
i__3 = *neq;
for (k = 1; k <= i__3; ++k) {
/* L70: */
dl[k] = s * dl[k] + c__ * v[k + ip1 * v_dim1];
}
/* L75: */
}
}
s = q[ll * 2];
c__ = q[(ll << 1) - 1] / snormw;
llp1 = ll + 1;
i__2 = *neq;
for (k = 1; k <= i__2; ++k) {
/* L80: */
dl[k] = s * dl[k] + c__ * v[k + llp1 * v_dim1];
}
dlnrm = dnrm2_(neq, &dl[1], &c__1);
rho *= dlnrm;
}
/* ----------------------------------------------------------------------- */
/* Test for convergence. If passed, compute approximation ZL. */
/* If failed and LL .LT. MAXL, then continue iterating. */
/* ----------------------------------------------------------------------- */
if (rho <= *eplin) {
goto L200;
}
if (ll == *maxl) {
goto L100;
}
/* ----------------------------------------------------------------------- */
/* Rescale so that the norm of V(1,LL+1) is one. */
/* ----------------------------------------------------------------------- */
tem = 1. / snormw;
dscal_(neq, &tem, &v[(ll + 1) * v_dim1 + 1], &c__1);
/* L90: */
}
L100:
if (rho < rnrm) {
goto L150;
}
L120:
*iflag = 2;
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L130: */
z__[i__] = 0.;
}
return 0;
L150:
*iflag = 1;
/* ----------------------------------------------------------------------- */
/* The tolerance was not met, but the residual norm was reduced. */
/* If performing restarting (IRST .gt. 0) calculate the residual vector */
/* RL and store it in the DL array. If the incomplete version is */
/* being used (KMP .lt. MAXL) then DL has already been calculated. */
/* ----------------------------------------------------------------------- */
if (*irst > 0) {
if (*kmp == *maxl) {
/* Calculate DL from the V(I)'s. */
dcopy_(neq, &v[v_dim1 + 1], &c__1, &dl[1], &c__1);
maxlm1 = *maxl - 1;
i__1 = maxlm1;
for (i__ = 1; i__ <= i__1; ++i__) {
ip1 = i__ + 1;
i2 = i__ << 1;
s = q[i2];
c__ = q[i2 - 1];
i__2 = *neq;
for (k = 1; k <= i__2; ++k) {
/* L170: */
dl[k] = s * dl[k] + c__ * v[k + ip1 * v_dim1];
}
/* L175: */
}
s = q[*maxl * 2];
c__ = q[(*maxl << 1) - 1] / snormw;
i__1 = *neq;
for (k = 1; k <= i__1; ++k) {
/* L180: */
dl[k] = s * dl[k] + c__ * v[k + *maxlp1 * v_dim1];
}
}
/* Scale DL by RNRM*PROD to obtain the residual RL. */
tem = rnrm * prod;
dscal_(neq, &tem, &dl[1], &c__1);
}
/* ----------------------------------------------------------------------- */
/* Compute the approximation ZL to the solution. */
/* Since the vector Z was used as work space, and the initial guess */
/* of the Newton correction is zero, Z must be reset to zero. */
/* ----------------------------------------------------------------------- */
L200:
ll = *lgmr;
llp1 = ll + 1;
i__1 = llp1;
for (k = 1; k <= i__1; ++k) {
/* L210: */
r__[k] = 0.;
}
r__[1] = rnrm;
dhels_(&hes[hes_offset], maxlp1, &ll, &q[1], &r__[1]);
i__1 = *neq;
for (k = 1; k <= i__1; ++k) {
/* L220: */
z__[k] = 0.;
}
i__1 = ll;
for (i__ = 1; i__ <= i__1; ++i__) {
daxpy_(neq, &r__[i__], &v[i__ * v_dim1 + 1], &c__1, &z__[1], &c__1);
/* L230: */
}
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L240: */
z__[i__] /= wght[i__];
}
/* Load RHO into RHOK. */
*rhok = rho;
return 0;
/* ----------------------------------------------------------------------- */
/* This block handles error returns forced by routine PSOL. */
/* ----------------------------------------------------------------------- */
L300:
if (ier < 0) {
*iflag = -1;
}
if (ier > 0) {
*iflag = 3;
}
return 0;
/* ------END OF SUBROUTINE DSPIGM----------------------------------------- */
} /* dspigm_ */
/* Subroutine */ int datv_(integer *neq, doublereal *y, doublereal *tn,
doublereal *yprime, doublereal *savr, doublereal *v, doublereal *wght,
doublereal *yptem, S_fp res, integer *ires, S_fp psol, doublereal *
z__, doublereal *vtem, doublereal *wp, integer *iwp, doublereal *cj,
doublereal *eplin, integer *ier, integer *nre, integer *npsl,
doublereal *rpar, integer *ipar)
{
/* System generated locals */
integer i__1;
/* Local variables */
static integer i__;
/* ***BEGIN PROLOGUE DATV */
/* ***DATE WRITTEN 890101 (YYMMDD) */
/* ***REVISION DATE 900926 (YYMMDD) */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* This routine computes the product */
/* Z = (D-inverse)*(P-inverse)*(dF/dY)*(D*V), */
/* where F(Y) = G(T, Y, CJ*(Y-A)), CJ is a scalar proportional to 1/H, */
/* and A involves the past history of Y. The quantity CJ*(Y-A) is */
/* an approximation to the first derivative of Y and is stored */
/* in the array YPRIME. Note that dF/dY = dG/dY + CJ*dG/dYPRIME. */
/* D is a diagonal scaling matrix, and P is the left preconditioning */
/* matrix. V is assumed to have L2 norm equal to 1. */
/* The product is stored in Z and is computed by means of a */
/* difference quotient, a call to RES, and one call to PSOL. */
/* On entry */
/* NEQ = Problem size, passed to RES and PSOL. */
/* Y = Array containing current dependent variable vector. */
/* YPRIME = Array containing current first derivative of y. */
/* SAVR = Array containing current value of G(T,Y,YPRIME). */
/* V = Real array of length NEQ (can be the same array as Z). */
/* WGHT = Array of length NEQ containing scale factors. */
/* 1/WGHT(I) are the diagonal elements of the matrix D. */
/* YPTEM = Work array of length NEQ. */
/* VTEM = Work array of length NEQ used to store the */
/* unscaled version of V. */
/* WP = Real work array used by preconditioner PSOL. */
/* IWP = Integer work array used by preconditioner PSOL. */
/* CJ = Scalar proportional to current value of */
/* 1/(step size H). */
/* On return */
/* Z = Array of length NEQ containing desired scaled */
/* matrix-vector product. */
/* IRES = Error flag from RES. */
/* IER = Error flag from PSOL. */
/* NRE = The number of calls to RES. */
/* NPSL = The number of calls to PSOL. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED */
/* RES, PSOL */
/* ***END PROLOGUE DATV */
/* Parameter adjustments */
--ipar;
--rpar;
--iwp;
--wp;
--vtem;
--z__;
--yptem;
--wght;
--v;
--savr;
--yprime;
--y;
/* Function Body */
*ires = 0;
/* ----------------------------------------------------------------------- */
/* Set VTEM = D * V. */
/* ----------------------------------------------------------------------- */
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L10: */
vtem[i__] = v[i__] / wght[i__];
}
*ier = 0;
/* ----------------------------------------------------------------------- */
/* Store Y in Z and increment Z by VTEM. */
/* Store YPRIME in YPTEM and increment YPTEM by VTEM*CJ. */
/* ----------------------------------------------------------------------- */
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
yptem[i__] = yprime[i__] + vtem[i__] * *cj;
/* L20: */
z__[i__] = y[i__] + vtem[i__];
}
/* ----------------------------------------------------------------------- */
/* Call RES with incremented Y, YPRIME arguments */
/* stored in Z, YPTEM. VTEM is overwritten with new residual. */
/* ----------------------------------------------------------------------- */
(*res)(tn, &z__[1], &yptem[1], cj, &vtem[1], ires, &rpar[1], &ipar[1]);
++(*nre);
if (*ires < 0) {
return 0;
}
/* ----------------------------------------------------------------------- */
/* Set Z = (dF/dY) * VBAR using difference quotient. */
/* (VBAR is old value of VTEM before calling RES) */
/* ----------------------------------------------------------------------- */
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L70: */
z__[i__] = vtem[i__] - savr[i__];
}
/* ----------------------------------------------------------------------- */
/* Apply inverse of left preconditioner to Z. */
/* ----------------------------------------------------------------------- */
(*psol)(neq, tn, &y[1], &yprime[1], &savr[1], &yptem[1], cj, &wght[1], &
wp[1], &iwp[1], &z__[1], eplin, ier, &rpar[1], &ipar[1]);
++(*npsl);
if (*ier != 0) {
return 0;
}
/* ----------------------------------------------------------------------- */
/* Apply D-inverse to Z and return. */
/* ----------------------------------------------------------------------- */
i__1 = *neq;
for (i__ = 1; i__ <= i__1; ++i__) {
/* L90: */
z__[i__] *= wght[i__];
}
return 0;
/* ------END OF SUBROUTINE DATV------------------------------------------- */
} /* datv_ */
/* Subroutine */ int dorth_(doublereal *vnew, doublereal *v, doublereal *hes,
integer *n, integer *ll, integer *ldhes, integer *kmp, doublereal *
snormw)
{
/* System generated locals */
integer v_dim1, v_offset, hes_dim1, hes_offset, i__1, i__2;
doublereal d__1, d__2, d__3;
/* Builtin functions */
double sqrt(doublereal);
/* Local variables */
static integer i__, i0;
static doublereal arg, tem;
extern doublereal ddot_(integer *, doublereal *, integer *, doublereal *,
integer *);
static doublereal vnrm;
extern doublereal dnrm2_(integer *, doublereal *, integer *);
extern /* Subroutine */ int daxpy_(integer *, doublereal *, doublereal *,
integer *, doublereal *, integer *);
static doublereal sumdsq;
/* ***BEGIN PROLOGUE DORTH */
/* ***DATE WRITTEN 890101 (YYMMDD) */
/* ***REVISION DATE 900926 (YYMMDD) */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* This routine orthogonalizes the vector VNEW against the previous */
/* KMP vectors in the V array. It uses a modified Gram-Schmidt */
/* orthogonalization procedure with conditional reorthogonalization. */
/* On entry */
/* VNEW = The vector of length N containing a scaled product */
/* OF The Jacobian and the vector V(*,LL). */
/* V = The N x LL array containing the previous LL */
/* orthogonal vectors V(*,1) to V(*,LL). */
/* HES = An LL x LL upper Hessenberg matrix containing, */
/* in HES(I,K), K.LT.LL, scaled inner products of */
/* A*V(*,K) and V(*,I). */
/* LDHES = The leading dimension of the HES array. */
/* N = The order of the matrix A, and the length of VNEW. */
/* LL = The current order of the matrix HES. */
/* KMP = The number of previous vectors the new vector VNEW */
/* must be made orthogonal to (KMP .LE. MAXL). */
/* On return */
/* VNEW = The new vector orthogonal to V(*,I0), */
/* where I0 = MAX(1, LL-KMP+1). */
/* HES = Upper Hessenberg matrix with column LL filled in with */
/* scaled inner products of A*V(*,LL) and V(*,I). */
/* SNORMW = L-2 norm of VNEW. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED */
/* DDOT, DNRM2, DAXPY */
/* ***END PROLOGUE DORTH */
/* ----------------------------------------------------------------------- */
/* Get norm of unaltered VNEW for later use. */
/* ----------------------------------------------------------------------- */
/* Parameter adjustments */
--vnew;
v_dim1 = *n;
v_offset = 1 + v_dim1;
v -= v_offset;
hes_dim1 = *ldhes;
hes_offset = 1 + hes_dim1;
hes -= hes_offset;
/* Function Body */
vnrm = dnrm2_(n, &vnew[1], &c__1);
/* ----------------------------------------------------------------------- */
/* Do Modified Gram-Schmidt on VNEW = A*V(LL). */
/* Scaled inner products give new column of HES. */
/* Projections of earlier vectors are subtracted from VNEW. */
/* ----------------------------------------------------------------------- */
/* Computing MAX */
i__1 = 1, i__2 = *ll - *kmp + 1;
i0 = max(i__1,i__2);
i__1 = *ll;
for (i__ = i0; i__ <= i__1; ++i__) {
hes[i__ + *ll * hes_dim1] = ddot_(n, &v[i__ * v_dim1 + 1], &c__1, &
vnew[1], &c__1);
tem = -hes[i__ + *ll * hes_dim1];
daxpy_(n, &tem, &v[i__ * v_dim1 + 1], &c__1, &vnew[1], &c__1);
/* L10: */
}
/* ----------------------------------------------------------------------- */
/* Compute SNORMW = norm of VNEW. */
/* If VNEW is small compared to its input value (in norm), then */
/* Reorthogonalize VNEW to V(*,1) through V(*,LL). */
/* Correct if relative correction exceeds 1000*(unit roundoff). */
/* Finally, correct SNORMW using the dot products involved. */
/* ----------------------------------------------------------------------- */
*snormw = dnrm2_(n, &vnew[1], &c__1);
if (vnrm + *snormw * .001 != vnrm) {
return 0;
}
sumdsq = 0.;
i__1 = *ll;
for (i__ = i0; i__ <= i__1; ++i__) {
tem = -ddot_(n, &v[i__ * v_dim1 + 1], &c__1, &vnew[1], &c__1);
if (hes[i__ + *ll * hes_dim1] + tem * .001 == hes[i__ + *ll *
hes_dim1]) {
goto L30;
}
hes[i__ + *ll * hes_dim1] -= tem;
daxpy_(n, &tem, &v[i__ * v_dim1 + 1], &c__1, &vnew[1], &c__1);
/* Computing 2nd power */
d__1 = tem;
sumdsq += d__1 * d__1;
L30:
;
}
if (sumdsq == 0.) {
return 0;
}
/* Computing MAX */
/* Computing 2nd power */
d__3 = *snormw;
d__1 = 0., d__2 = d__3 * d__3 - sumdsq;
arg = max(d__1,d__2);
*snormw = sqrt(arg);
return 0;
/* ------END OF SUBROUTINE DORTH------------------------------------------ */
} /* dorth_ */
/* Subroutine */ int dheqr_(doublereal *a, integer *lda, integer *n,
doublereal *q, integer *info, integer *ijob)
{
/* System generated locals */
integer a_dim1, a_offset, i__1, i__2;
/* Builtin functions */
double sqrt(doublereal);
/* Local variables */
static doublereal c__;
static integer i__, j, k;
static doublereal s, t, t1, t2;
static integer iq, km1, kp1, nm1;
/* ***BEGIN PROLOGUE DHEQR */
/* ***DATE WRITTEN 890101 (YYMMDD) */
/* ***REVISION DATE 900926 (YYMMDD) */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* This routine performs a QR decomposition of an upper */
/* Hessenberg matrix A. There are two options available: */
/* (1) performing a fresh decomposition */
/* (2) updating the QR factors by adding a row and A */
/* column to the matrix A. */
/* DHEQR decomposes an upper Hessenberg matrix by using Givens */
/* rotations. */
/* On entry */
/* A DOUBLE PRECISION(LDA, N) */
/* The matrix to be decomposed. */
/* LDA INTEGER */
/* The leading dimension of the array A. */
/* N INTEGER */
/* A is an (N+1) by N Hessenberg matrix. */
/* IJOB INTEGER */
/* = 1 Means that a fresh decomposition of the */
/* matrix A is desired. */
/* .GE. 2 Means that the current decomposition of A */
/* will be updated by the addition of a row */
/* and a column. */
/* On return */
/* A The upper triangular matrix R. */
/* The factorization can be written Q*A = R, where */
/* Q is a product of Givens rotations and R is upper */
/* triangular. */
/* Q DOUBLE PRECISION(2*N) */
/* The factors C and S of each Givens rotation used */
/* in decomposing A. */
/* INFO INTEGER */
/* = 0 normal value. */
/* = K If A(K,K) .EQ. 0.0. This is not an error */
/* condition for this subroutine, but it does */
/* indicate that DHELS will divide by zero */
/* if called. */
/* Modification of LINPACK. */
/* Peter Brown, Lawrence Livermore Natl. Lab. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED (NONE) */
/* ***END PROLOGUE DHEQR */
/* Parameter adjustments */
a_dim1 = *lda;
a_offset = 1 + a_dim1;
a -= a_offset;
--q;
/* Function Body */
if (*ijob > 1) {
goto L70;
}
/* ----------------------------------------------------------------------- */
/* A new factorization is desired. */
/* ----------------------------------------------------------------------- */
/* QR decomposition without pivoting. */
*info = 0;
i__1 = *n;
for (k = 1; k <= i__1; ++k) {
km1 = k - 1;
kp1 = k + 1;
/* Compute Kth column of R. */
/* First, multiply the Kth column of A by the previous */
/* K-1 Givens rotations. */
if (km1 < 1) {
goto L20;
}
i__2 = km1;
for (j = 1; j <= i__2; ++j) {
i__ = (j - 1 << 1) + 1;
t1 = a[j + k * a_dim1];
t2 = a[j + 1 + k * a_dim1];
c__ = q[i__];
s = q[i__ + 1];
a[j + k * a_dim1] = c__ * t1 - s * t2;
a[j + 1 + k * a_dim1] = s * t1 + c__ * t2;
/* L10: */
}
/* Compute Givens components C and S. */
L20:
iq = (km1 << 1) + 1;
t1 = a[k + k * a_dim1];
t2 = a[kp1 + k * a_dim1];
if (t2 != 0.) {
goto L30;
}
c__ = 1.;
s = 0.;
goto L50;
L30:
if (abs(t2) < abs(t1)) {
goto L40;
}
t = t1 / t2;
s = -1. / sqrt(t * t + 1.);
c__ = -s * t;
goto L50;
L40:
t = t2 / t1;
c__ = 1. / sqrt(t * t + 1.);
s = -c__ * t;
L50:
q[iq] = c__;
q[iq + 1] = s;
a[k + k * a_dim1] = c__ * t1 - s * t2;
if (a[k + k * a_dim1] == 0.) {
*info = k;
}
/* L60: */
}
return 0;
/* ----------------------------------------------------------------------- */
/* The old factorization of A will be updated. A row and a column */
/* has been added to the matrix A. */
/* N by N-1 is now the old size of the matrix. */
/* ----------------------------------------------------------------------- */
L70:
nm1 = *n - 1;
/* ----------------------------------------------------------------------- */
/* Multiply the new column by the N previous Givens rotations. */
/* ----------------------------------------------------------------------- */
i__1 = nm1;
for (k = 1; k <= i__1; ++k) {
i__ = (k - 1 << 1) + 1;
t1 = a[k + *n * a_dim1];
t2 = a[k + 1 + *n * a_dim1];
c__ = q[i__];
s = q[i__ + 1];
a[k + *n * a_dim1] = c__ * t1 - s * t2;
a[k + 1 + *n * a_dim1] = s * t1 + c__ * t2;
/* L100: */
}
/* ----------------------------------------------------------------------- */
/* Complete update of decomposition by forming last Givens rotation, */
/* and multiplying it times the column vector (A(N,N),A(NP1,N)). */
/* ----------------------------------------------------------------------- */
*info = 0;
t1 = a[*n + *n * a_dim1];
t2 = a[*n + 1 + *n * a_dim1];
if (t2 != 0.) {
goto L110;
}
c__ = 1.;
s = 0.;
goto L130;
L110:
if (abs(t2) < abs(t1)) {
goto L120;
}
t = t1 / t2;
s = -1. / sqrt(t * t + 1.);
c__ = -s * t;
goto L130;
L120:
t = t2 / t1;
c__ = 1. / sqrt(t * t + 1.);
s = -c__ * t;
L130:
iq = (*n << 1) - 1;
q[iq] = c__;
q[iq + 1] = s;
a[*n + *n * a_dim1] = c__ * t1 - s * t2;
if (a[*n + *n * a_dim1] == 0.) {
*info = *n;
}
return 0;
/* ------END OF SUBROUTINE DHEQR------------------------------------------ */
} /* dheqr_ */
/* Subroutine */ int dhels_(doublereal *a, integer *lda, integer *n,
doublereal *q, doublereal *b)
{
/* System generated locals */
integer a_dim1, a_offset, i__1, i__2;
/* Local variables */
static doublereal c__;
static integer k;
static doublereal s, t, t1, t2;
static integer kb, iq, kp1;
extern /* Subroutine */ int daxpy_(integer *, doublereal *, doublereal *,
integer *, doublereal *, integer *);
/* ***BEGIN PROLOGUE DHELS */
/* ***DATE WRITTEN 890101 (YYMMDD) */
/* ***REVISION DATE 900926 (YYMMDD) */
/* ----------------------------------------------------------------------- */
/* ***DESCRIPTION */
/* This is similar to the LINPACK routine DGESL except that */
/* A is an upper Hessenberg matrix. */
/* DHELS solves the least squares problem */
/* MIN (B-A*X,B-A*X) */
/* using the factors computed by DHEQR. */
/* On entry */
/* A DOUBLE PRECISION (LDA, N) */
/* The output from DHEQR which contains the upper */
/* triangular factor R in the QR decomposition of A. */
/* LDA INTEGER */
/* The leading dimension of the array A . */
/* N INTEGER */
/* A is originally an (N+1) by N matrix. */
/* Q DOUBLE PRECISION(2*N) */
/* The coefficients of the N givens rotations */
/* used in the QR factorization of A. */
/* B DOUBLE PRECISION(N+1) */
/* The right hand side vector. */
/* On return */
/* B The solution vector X. */
/* Modification of LINPACK. */
/* Peter Brown, Lawrence Livermore Natl. Lab. */
/* ----------------------------------------------------------------------- */
/* ***ROUTINES CALLED */
/* DAXPY */
/* ***END PROLOGUE DHELS */
/* Minimize (B-A*X,B-A*X). */
/* First form Q*B. */
/* Parameter adjustments */
a_dim1 = *lda;
a_offset = 1 + a_dim1;
a -= a_offset;
--q;
--b;
/* Function Body */
i__1 = *n;
for (k = 1; k <= i__1; ++k) {
kp1 = k + 1;
iq = (k - 1 << 1) + 1;
c__ = q[iq];
s = q[iq + 1];
t1 = b[k];
t2 = b[kp1];
b[k] = c__ * t1 - s * t2;
b[kp1] = s * t1 + c__ * t2;
/* L20: */
}
/* Now solve R*X = Q*B. */
i__1 = *n;
for (kb = 1; kb <= i__1; ++kb) {
k = *n + 1 - kb;
b[k] /= a[k + k * a_dim1];
t = -b[k];
i__2 = k - 1;
daxpy_(&i__2, &t, &a[k * a_dim1 + 1], &c__1, &b[1], &c__1);
/* L40: */
}
return 0;
/* ------END OF SUBROUTINE DHELS------------------------------------------ */
} /* dhels_ */
#ifdef _cpluscplus
}
#endif