# HG changeset patch # User David Bateman # Date 1210539110 -7200 # Node ID 96ba591be50ffcc2ccd0d630b0a05e4b65ad2d63 # Parent 39c1026191e93605b94bad19be3bae85c80e10ff Add some more support for single precision to libcruft functions diff --git a/libcruft/ChangeLog b/libcruft/ChangeLog --- a/libcruft/ChangeLog +++ b/libcruft/ChangeLog @@ -1,3 +1,17 @@ +2008-05-21 David Bateman + + * odepack/scfode.f, odepack/sewset.f, odepack/sintdy.f, + odepack/slsode.f, odepack/sprepj.f, odepack/ssolsy.f, + odepack/sstode.f, odepack/svnorm.f: New files. + * odepack/Makefile.in (FSRC): Add them. + + * ordered-qz/sexchqz.f, ordered-qz/ssubsp.f: New files. + * ordered-qz/Makefile.in (FSRC): Add them. + * quadpack/qagi.f, quadpack/qagie.f, quadpack/qagp.f, + quadpack/qagpe.f, quadpack/qelg.f, quadpack/qk15i.f, + quadpack/qk21.f, quadpack/qpsrt.f: New files. + * quadpack/Makefile.in (FSRC): Add them. + 2008-05-20 Jaroslav Hajek * qrupdate/cch1dn.f, qrupdate/cchinx.f, qrupdate/cqhqr.f, diff --git a/libcruft/odepack/Makefile.in b/libcruft/odepack/Makefile.in --- a/libcruft/odepack/Makefile.in +++ b/libcruft/odepack/Makefile.in @@ -26,7 +26,8 @@ EXTERNAL_DISTFILES = $(DISTFILES) -FSRC = cfode.f dlsode.f ewset.f intdy.f prepj.f solsy.f stode.f vnorm.f +FSRC = cfode.f dlsode.f ewset.f intdy.f prepj.f solsy.f stode.f vnorm.f \ + scfode.f sewset.f sintdy.f slsode.f sprepj.f ssolsy.f sstode.f svnorm.f include $(TOPDIR)/Makeconf diff --git a/libcruft/odepack/scfode.f b/libcruft/odepack/scfode.f new file mode 100644 --- /dev/null +++ b/libcruft/odepack/scfode.f @@ -0,0 +1,127 @@ + SUBROUTINE SCFODE (METH, ELCO, TESCO) +C***BEGIN PROLOGUE SCFODE +C***SUBSIDIARY +C***PURPOSE Set ODE integrator coefficients. +C***TYPE SINGLE PRECISION (SCFODE-S, DCFODE-D) +C***AUTHOR Hindmarsh, Alan C., (LLNL) +C***DESCRIPTION +C +C SCFODE is called by the integrator routine to set coefficients +C needed there. The coefficients for the current method, as +C given by the value of METH, are set for all orders and saved. +C The maximum order assumed here is 12 if METH = 1 and 5 if METH = 2. +C (A smaller value of the maximum order is also allowed.) +C SCFODE is called once at the beginning of the problem, +C and is not called again unless and until METH is changed. +C +C The ELCO array contains the basic method coefficients. +C The coefficients el(i), 1 .le. i .le. nq+1, for the method of +C order nq are stored in ELCO(i,nq). They are given by a genetrating +C polynomial, i.e., +C l(x) = el(1) + el(2)*x + ... + el(nq+1)*x**nq. +C For the implicit Adams methods, l(x) is given by +C dl/dx = (x+1)*(x+2)*...*(x+nq-1)/factorial(nq-1), l(-1) = 0. +C For the BDF methods, l(x) is given by +C l(x) = (x+1)*(x+2)* ... *(x+nq)/K, +C where K = factorial(nq)*(1 + 1/2 + ... + 1/nq). +C +C The TESCO array contains test constants used for the +C local error test and the selection of step size and/or order. +C At order nq, TESCO(k,nq) is used for the selection of step +C size at order nq - 1 if k = 1, at order nq if k = 2, and at order +C nq + 1 if k = 3. +C +C***SEE ALSO SLSODE +C***ROUTINES CALLED (NONE) +C***REVISION HISTORY (YYMMDD) +C 791129 DATE WRITTEN +C 890501 Modified prologue to SLATEC/LDOC format. (FNF) +C 890503 Minor cosmetic changes. (FNF) +C 930809 Renamed to allow single/double precision versions. (ACH) +C***END PROLOGUE SCFODE +C**End + INTEGER METH + INTEGER I, IB, NQ, NQM1, NQP1 + REAL ELCO, TESCO + REAL AGAMQ, FNQ, FNQM1, PC, PINT, RAGQ, + 1 RQFAC, RQ1FAC, TSIGN, XPIN + DIMENSION ELCO(13,12), TESCO(3,12) + DIMENSION PC(12) +C +C***FIRST EXECUTABLE STATEMENT SCFODE + GO TO (100, 200), METH +C + 100 ELCO(1,1) = 1.0E0 + ELCO(2,1) = 1.0E0 + TESCO(1,1) = 0.0E0 + TESCO(2,1) = 2.0E0 + TESCO(1,2) = 1.0E0 + TESCO(3,12) = 0.0E0 + PC(1) = 1.0E0 + RQFAC = 1.0E0 + DO 140 NQ = 2,12 +C----------------------------------------------------------------------- +C The PC array will contain the coefficients of the polynomial +C p(x) = (x+1)*(x+2)*...*(x+nq-1). +C Initially, p(x) = 1. +C----------------------------------------------------------------------- + RQ1FAC = RQFAC + RQFAC = RQFAC/NQ + NQM1 = NQ - 1 + FNQM1 = NQM1 + NQP1 = NQ + 1 +C Form coefficients of p(x)*(x+nq-1). ---------------------------------- + PC(NQ) = 0.0E0 + DO 110 IB = 1,NQM1 + I = NQP1 - IB + 110 PC(I) = PC(I-1) + FNQM1*PC(I) + PC(1) = FNQM1*PC(1) +C Compute integral, -1 to 0, of p(x) and x*p(x). ----------------------- + PINT = PC(1) + XPIN = PC(1)/2.0E0 + TSIGN = 1.0E0 + DO 120 I = 2,NQ + TSIGN = -TSIGN + PINT = PINT + TSIGN*PC(I)/I + 120 XPIN = XPIN + TSIGN*PC(I)/(I+1) +C Store coefficients in ELCO and TESCO. -------------------------------- + ELCO(1,NQ) = PINT*RQ1FAC + ELCO(2,NQ) = 1.0E0 + DO 130 I = 2,NQ + 130 ELCO(I+1,NQ) = RQ1FAC*PC(I)/I + AGAMQ = RQFAC*XPIN + RAGQ = 1.0E0/AGAMQ + TESCO(2,NQ) = RAGQ + IF (NQ .LT. 12) TESCO(1,NQP1) = RAGQ*RQFAC/NQP1 + TESCO(3,NQM1) = RAGQ + 140 CONTINUE + RETURN +C + 200 PC(1) = 1.0E0 + RQ1FAC = 1.0E0 + DO 230 NQ = 1,5 +C----------------------------------------------------------------------- +C The PC array will contain the coefficients of the polynomial +C p(x) = (x+1)*(x+2)*...*(x+nq). +C Initially, p(x) = 1. +C----------------------------------------------------------------------- + FNQ = NQ + NQP1 = NQ + 1 +C Form coefficients of p(x)*(x+nq). ------------------------------------ + PC(NQP1) = 0.0E0 + DO 210 IB = 1,NQ + I = NQ + 2 - IB + 210 PC(I) = PC(I-1) + FNQ*PC(I) + PC(1) = FNQ*PC(1) +C Store coefficients in ELCO and TESCO. -------------------------------- + DO 220 I = 1,NQP1 + 220 ELCO(I,NQ) = PC(I)/PC(2) + ELCO(2,NQ) = 1.0E0 + TESCO(1,NQ) = RQ1FAC + TESCO(2,NQ) = NQP1/ELCO(1,NQ) + TESCO(3,NQ) = (NQ+2)/ELCO(1,NQ) + RQ1FAC = RQ1FAC/FNQ + 230 CONTINUE + RETURN +C----------------------- END OF SUBROUTINE SCFODE ---------------------- + END diff --git a/libcruft/odepack/sewset.f b/libcruft/odepack/sewset.f new file mode 100644 --- /dev/null +++ b/libcruft/odepack/sewset.f @@ -0,0 +1,47 @@ + SUBROUTINE SEWSET (N, ITOL, RTOL, ATOL, YCUR, EWT) +C***BEGIN PROLOGUE SEWSET +C***SUBSIDIARY +C***PURPOSE Set error weight vector. +C***TYPE SINGLE PRECISION (SEWSET-S, DEWSET-D) +C***AUTHOR Hindmarsh, Alan C., (LLNL) +C***DESCRIPTION +C +C This subroutine sets the error weight vector EWT according to +C EWT(i) = RTOL(i)*ABS(YCUR(i)) + ATOL(i), i = 1,...,N, +C with the subscript on RTOL and/or ATOL possibly replaced by 1 above, +C depending on the value of ITOL. +C +C***SEE ALSO SLSODE +C***ROUTINES CALLED (NONE) +C***REVISION HISTORY (YYMMDD) +C 791129 DATE WRITTEN +C 890501 Modified prologue to SLATEC/LDOC format. (FNF) +C 890503 Minor cosmetic changes. (FNF) +C 930809 Renamed to allow single/double precision versions. (ACH) +C***END PROLOGUE SEWSET +C**End + INTEGER N, ITOL + INTEGER I + REAL RTOL, ATOL, YCUR, EWT + DIMENSION RTOL(*), ATOL(*), YCUR(N), EWT(N) +C +C***FIRST EXECUTABLE STATEMENT SEWSET + GO TO (10, 20, 30, 40), ITOL + 10 CONTINUE + DO 15 I = 1,N + 15 EWT(I) = RTOL(1)*ABS(YCUR(I)) + ATOL(1) + RETURN + 20 CONTINUE + DO 25 I = 1,N + 25 EWT(I) = RTOL(1)*ABS(YCUR(I)) + ATOL(I) + RETURN + 30 CONTINUE + DO 35 I = 1,N + 35 EWT(I) = RTOL(I)*ABS(YCUR(I)) + ATOL(1) + RETURN + 40 CONTINUE + DO 45 I = 1,N + 45 EWT(I) = RTOL(I)*ABS(YCUR(I)) + ATOL(I) + RETURN +C----------------------- END OF SUBROUTINE SEWSET ---------------------- + END diff --git a/libcruft/odepack/sintdy.f b/libcruft/odepack/sintdy.f new file mode 100644 --- /dev/null +++ b/libcruft/odepack/sintdy.f @@ -0,0 +1,107 @@ + SUBROUTINE SINTDY (T, K, YH, NYH, DKY, IFLAG) +C***BEGIN PROLOGUE SINTDY +C***SUBSIDIARY +C***PURPOSE Interpolate solution derivatives. +C***TYPE SINGLE PRECISION (SINTDY-S, DINTDY-D) +C***AUTHOR Hindmarsh, Alan C., (LLNL) +C***DESCRIPTION +C +C SINTDY computes interpolated values of the K-th derivative of the +C dependent variable vector y, and stores it in DKY. This routine +C is called within the package with K = 0 and T = TOUT, but may +C also be called by the user for any K up to the current order. +C (See detailed instructions in the usage documentation.) +C +C The computed values in DKY are gotten by interpolation using the +C Nordsieck history array YH. This array corresponds uniquely to a +C vector-valued polynomial of degree NQCUR or less, and DKY is set +C to the K-th derivative of this polynomial at T. +C The formula for DKY is: +C q +C DKY(i) = sum c(j,K) * (T - tn)**(j-K) * h**(-j) * YH(i,j+1) +C j=K +C where c(j,K) = j*(j-1)*...*(j-K+1), q = NQCUR, tn = TCUR, h = HCUR. +C The quantities nq = NQCUR, l = nq+1, N = NEQ, tn, and h are +C communicated by COMMON. The above sum is done in reverse order. +C IFLAG is returned negative if either K or T is out of bounds. +C +C***SEE ALSO SLSODE +C***ROUTINES CALLED XERRWV +C***COMMON BLOCKS SLS001 +C***REVISION HISTORY (YYMMDD) +C 791129 DATE WRITTEN +C 890501 Modified prologue to SLATEC/LDOC format. (FNF) +C 890503 Minor cosmetic changes. (FNF) +C 930809 Renamed to allow single/double precision versions. (ACH) +C 010412 Reduced size of Common block /SLS001/. (ACH) +C 031105 Restored 'own' variables to Common block /SLS001/, to +C enable interrupt/restart feature. (ACH) +C 050427 Corrected roundoff decrement in TP. (ACH) +C***END PROLOGUE SINTDY +C**End + INTEGER K, NYH, IFLAG + REAL T, YH, DKY + DIMENSION YH(NYH,*), DKY(*) + INTEGER IOWND, IOWNS, + 1 ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, + 2 LYH, LEWT, LACOR, LSAVF, LWM, LIWM, METH, MITER, + 3 MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU + REAL ROWNS, + 1 CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND + COMMON /SLS001/ ROWNS(209), + 1 CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND, + 2 IOWND(6), IOWNS(6), + 3 ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, + 4 LYH, LEWT, LACOR, LSAVF, LWM, LIWM, METH, MITER, + 5 MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU + INTEGER I, IC, J, JB, JB2, JJ, JJ1, JP1 + REAL C, R, S, TP + CHARACTER*80 MSG +C +C***FIRST EXECUTABLE STATEMENT SINTDY + IFLAG = 0 + IF (K .LT. 0 .OR. K .GT. NQ) GO TO 80 + TP = TN - HU - 100.0E0*UROUND*SIGN(ABS(TN) + ABS(HU), HU) + IF ((T-TP)*(T-TN) .GT. 0.0E0) GO TO 90 +C + S = (T - TN)/H + IC = 1 + IF (K .EQ. 0) GO TO 15 + JJ1 = L - K + DO 10 JJ = JJ1,NQ + 10 IC = IC*JJ + 15 C = IC + DO 20 I = 1,N + 20 DKY(I) = C*YH(I,L) + IF (K .EQ. NQ) GO TO 55 + JB2 = NQ - K + DO 50 JB = 1,JB2 + J = NQ - JB + JP1 = J + 1 + IC = 1 + IF (K .EQ. 0) GO TO 35 + JJ1 = JP1 - K + DO 30 JJ = JJ1,J + 30 IC = IC*JJ + 35 C = IC + DO 40 I = 1,N + 40 DKY(I) = C*YH(I,JP1) + S*DKY(I) + 50 CONTINUE + IF (K .EQ. 0) RETURN + 55 R = H**(-K) + DO 60 I = 1,N + 60 DKY(I) = R*DKY(I) + RETURN +C + 80 MSG = 'SINTDY- K (=I1) illegal ' + CALL XERRWV (MSG, 30, 51, 0, 1, K, 0, 0, 0.0E0, 0.0E0) + IFLAG = -1 + RETURN + 90 MSG = 'SINTDY- T (=R1) illegal ' + CALL XERRWV (MSG, 30, 52, 0, 0, 0, 0, 1, T, 0.0E0) + MSG=' T not in interval TCUR - HU (= R1) to TCUR (=R2) ' + CALL XERRWV (MSG, 60, 52, 0, 0, 0, 0, 2, TP, TN) + IFLAG = -2 + RETURN +C----------------------- END OF SUBROUTINE SINTDY ---------------------- + END diff --git a/libcruft/odepack/slsode.f b/libcruft/odepack/slsode.f new file mode 100644 --- /dev/null +++ b/libcruft/odepack/slsode.f @@ -0,0 +1,1755 @@ +*DECK SLSODE + SUBROUTINE SLSODE (F, NEQ, Y, T, TOUT, ITOL, RTOL, ATOL, ITASK, + 1 ISTATE, IOPT, RWORK, LRW, IWORK, LIW, JAC, MF) + EXTERNAL F, JAC + INTEGER NEQ, ITOL, ITASK, ISTATE, IOPT, LRW, IWORK, LIW, MF + REAL Y, T, TOUT, RTOL, ATOL, RWORK + DIMENSION NEQ(*), Y(*), RTOL(*), ATOL(*), RWORK(LRW), IWORK(LIW) +C***BEGIN PROLOGUE SLSODE +C***PURPOSE Livermore Solver for Ordinary Differential Equations. +C SLSODE solves the initial-value problem for stiff or +C nonstiff systems of first-order ODE's, +C dy/dt = f(t,y), or, in component form, +C dy(i)/dt = f(i) = f(i,t,y(1),y(2),...,y(N)), i=1,...,N. +C***CATEGORY I1A +C***TYPE SINGLE PRECISION (SLSODE-S, DLSODE-D) +C***KEYWORDS ORDINARY DIFFERENTIAL EQUATIONS, INITIAL VALUE PROBLEM, +C STIFF, NONSTIFF +C***AUTHOR Hindmarsh, Alan C., (LLNL) +C Center for Applied Scientific Computing, L-561 +C Lawrence Livermore National Laboratory +C Livermore, CA 94551. +C***DESCRIPTION +C +C NOTE: The "Usage" and "Arguments" sections treat only a subset of +C available options, in condensed fashion. The options +C covered and the information supplied will support most +C standard uses of SLSODE. +C +C For more sophisticated uses, full details on all options are +C given in the concluding section, headed "Long Description." +C A synopsis of the SLSODE Long Description is provided at the +C beginning of that section; general topics covered are: +C - Elements of the call sequence; optional input and output +C - Optional supplemental routines in the SLSODE package +C - internal COMMON block +C +C *Usage: +C Communication between the user and the SLSODE package, for normal +C situations, is summarized here. This summary describes a subset +C of the available options. See "Long Description" for complete +C details, including optional communication, nonstandard options, +C and instructions for special situations. +C +C A sample program is given in the "Examples" section. +C +C Refer to the argument descriptions for the definitions of the +C quantities that appear in the following sample declarations. +C +C For MF = 10, +C PARAMETER (LRW = 20 + 16*NEQ, LIW = 20) +C For MF = 21 or 22, +C PARAMETER (LRW = 22 + 9*NEQ + NEQ**2, LIW = 20 + NEQ) +C For MF = 24 or 25, +C PARAMETER (LRW = 22 + 10*NEQ + (2*ML+MU)*NEQ, +C * LIW = 20 + NEQ) +C +C EXTERNAL F, JAC +C INTEGER NEQ, ITOL, ITASK, ISTATE, IOPT, LRW, IWORK(LIW), +C * LIW, MF +C REAL Y(NEQ), T, TOUT, RTOL, ATOL(ntol), RWORK(LRW) +C +C CALL SLSODE (F, NEQ, Y, T, TOUT, ITOL, RTOL, ATOL, ITASK, +C * ISTATE, IOPT, RWORK, LRW, IWORK, LIW, JAC, MF) +C +C *Arguments: +C F :EXT Name of subroutine for right-hand-side vector f. +C This name must be declared EXTERNAL in calling +C program. The form of F must be: +C +C SUBROUTINE F (NEQ, T, Y, YDOT) +C INTEGER NEQ +C REAL T, Y(*), YDOT(*) +C +C The inputs are NEQ, T, Y. F is to set +C +C YDOT(i) = f(i,T,Y(1),Y(2),...,Y(NEQ)), +C i = 1, ..., NEQ . +C +C NEQ :IN Number of first-order ODE's. +C +C Y :INOUT Array of values of the y(t) vector, of length NEQ. +C Input: For the first call, Y should contain the +C values of y(t) at t = T. (Y is an input +C variable only if ISTATE = 1.) +C Output: On return, Y will contain the values at the +C new t-value. +C +C T :INOUT Value of the independent variable. On return it +C will be the current value of t (normally TOUT). +C +C TOUT :IN Next point where output is desired (.NE. T). +C +C ITOL :IN 1 or 2 according as ATOL (below) is a scalar or +C an array. +C +C RTOL :IN Relative tolerance parameter (scalar). +C +C ATOL :IN Absolute tolerance parameter (scalar or array). +C If ITOL = 1, ATOL need not be dimensioned. +C If ITOL = 2, ATOL must be dimensioned at least NEQ. +C +C The estimated local error in Y(i) will be controlled +C so as to be roughly less (in magnitude) than +C +C EWT(i) = RTOL*ABS(Y(i)) + ATOL if ITOL = 1, or +C EWT(i) = RTOL*ABS(Y(i)) + ATOL(i) if ITOL = 2. +C +C Thus the local error test passes if, in each +C component, either the absolute error is less than +C ATOL (or ATOL(i)), or the relative error is less +C than RTOL. +C +C Use RTOL = 0.0 for pure absolute error control, and +C use ATOL = 0.0 (or ATOL(i) = 0.0) for pure relative +C error control. Caution: Actual (global) errors may +C exceed these local tolerances, so choose them +C conservatively. +C +C ITASK :IN Flag indicating the task SLSODE is to perform. +C Use ITASK = 1 for normal computation of output +C values of y at t = TOUT. +C +C ISTATE:INOUT Index used for input and output to specify the state +C of the calculation. +C Input: +C 1 This is the first call for a problem. +C 2 This is a subsequent call. +C Output: +C 1 Nothing was done, as TOUT was equal to T. +C 2 SLSODE was successful (otherwise, negative). +C Note that ISTATE need not be modified after a +C successful return. +C -1 Excess work done on this call (perhaps wrong +C MF). +C -2 Excess accuracy requested (tolerances too +C small). +C -3 Illegal input detected (see printed message). +C -4 Repeated error test failures (check all +C inputs). +C -5 Repeated convergence failures (perhaps bad +C Jacobian supplied or wrong choice of MF or +C tolerances). +C -6 Error weight became zero during problem +C (solution component i vanished, and ATOL or +C ATOL(i) = 0.). +C +C IOPT :IN Flag indicating whether optional inputs are used: +C 0 No. +C 1 Yes. (See "Optional inputs" under "Long +C Description," Part 1.) +C +C RWORK :WORK Real work array of length at least: +C 20 + 16*NEQ for MF = 10, +C 22 + 9*NEQ + NEQ**2 for MF = 21 or 22, +C 22 + 10*NEQ + (2*ML + MU)*NEQ for MF = 24 or 25. +C +C LRW :IN Declared length of RWORK (in user's DIMENSION +C statement). +C +C IWORK :WORK Integer work array of length at least: +C 20 for MF = 10, +C 20 + NEQ for MF = 21, 22, 24, or 25. +C +C If MF = 24 or 25, input in IWORK(1),IWORK(2) the +C lower and upper Jacobian half-bandwidths ML,MU. +C +C On return, IWORK contains information that may be +C of interest to the user: +C +C Name Location Meaning +C ----- --------- ----------------------------------------- +C NST IWORK(11) Number of steps taken for the problem so +C far. +C NFE IWORK(12) Number of f evaluations for the problem +C so far. +C NJE IWORK(13) Number of Jacobian evaluations (and of +C matrix LU decompositions) for the problem +C so far. +C NQU IWORK(14) Method order last used (successfully). +C LENRW IWORK(17) Length of RWORK actually required. This +C is defined on normal returns and on an +C illegal input return for insufficient +C storage. +C LENIW IWORK(18) Length of IWORK actually required. This +C is defined on normal returns and on an +C illegal input return for insufficient +C storage. +C +C LIW :IN Declared length of IWORK (in user's DIMENSION +C statement). +C +C JAC :EXT Name of subroutine for Jacobian matrix (MF = +C 21 or 24). If used, this name must be declared +C EXTERNAL in calling program. If not used, pass a +C dummy name. The form of JAC must be: +C +C SUBROUTINE JAC (NEQ, T, Y, ML, MU, PD, NROWPD) +C INTEGER NEQ, ML, MU, NROWPD +C REAL T, Y(*), PD(NROWPD,*) +C +C See item c, under "Description" below for more +C information about JAC. +C +C MF :IN Method flag. Standard values are: +C 10 Nonstiff (Adams) method, no Jacobian used. +C 21 Stiff (BDF) method, user-supplied full Jacobian. +C 22 Stiff method, internally generated full +C Jacobian. +C 24 Stiff method, user-supplied banded Jacobian. +C 25 Stiff method, internally generated banded +C Jacobian. +C +C *Description: +C SLSODE solves the initial value problem for stiff or nonstiff +C systems of first-order ODE's, +C +C dy/dt = f(t,y) , +C +C or, in component form, +C +C dy(i)/dt = f(i) = f(i,t,y(1),y(2),...,y(NEQ)) +C (i = 1, ..., NEQ) . +C +C SLSODE is a package based on the GEAR and GEARB packages, and on +C the October 23, 1978, version of the tentative ODEPACK user +C interface standard, with minor modifications. +C +C The steps in solving such a problem are as follows. +C +C a. First write a subroutine of the form +C +C SUBROUTINE F (NEQ, T, Y, YDOT) +C INTEGER NEQ +C REAL T, Y(*), YDOT(*) +C +C which supplies the vector function f by loading YDOT(i) with +C f(i). +C +C b. Next determine (or guess) whether or not the problem is stiff. +C Stiffness occurs when the Jacobian matrix df/dy has an +C eigenvalue whose real part is negative and large in magnitude +C compared to the reciprocal of the t span of interest. If the +C problem is nonstiff, use method flag MF = 10. If it is stiff, +C there are four standard choices for MF, and SLSODE requires the +C Jacobian matrix in some form. This matrix is regarded either +C as full (MF = 21 or 22), or banded (MF = 24 or 25). In the +C banded case, SLSODE requires two half-bandwidth parameters ML +C and MU. These are, respectively, the widths of the lower and +C upper parts of the band, excluding the main diagonal. Thus the +C band consists of the locations (i,j) with +C +C i - ML <= j <= i + MU , +C +C and the full bandwidth is ML + MU + 1 . +C +C c. If the problem is stiff, you are encouraged to supply the +C Jacobian directly (MF = 21 or 24), but if this is not feasible, +C SLSODE will compute it internally by difference quotients (MF = +C 22 or 25). If you are supplying the Jacobian, write a +C subroutine of the form +C +C SUBROUTINE JAC (NEQ, T, Y, ML, MU, PD, NROWPD) +C INTEGER NEQ, ML, MU, NRWOPD +C REAL T, Y(*), PD(NROWPD,*) +C +C which provides df/dy by loading PD as follows: +C - For a full Jacobian (MF = 21), load PD(i,j) with df(i)/dy(j), +C the partial derivative of f(i) with respect to y(j). (Ignore +C the ML and MU arguments in this case.) +C - For a banded Jacobian (MF = 24), load PD(i-j+MU+1,j) with +C df(i)/dy(j); i.e., load the diagonal lines of df/dy into the +C rows of PD from the top down. +C - In either case, only nonzero elements need be loaded. +C +C d. Write a main program that calls subroutine SLSODE once for each +C point at which answers are desired. This should also provide +C for possible use of logical unit 6 for output of error messages +C by SLSODE. +C +C Before the first call to SLSODE, set ISTATE = 1, set Y and T to +C the initial values, and set TOUT to the first output point. To +C continue the integration after a successful return, simply +C reset TOUT and call SLSODE again. No other parameters need be +C reset. +C +C *Examples: +C The following is a simple example problem, with the coding needed +C for its solution by SLSODE. The problem is from chemical kinetics, +C and consists of the following three rate equations: +C +C dy1/dt = -.04*y1 + 1.E4*y2*y3 +C dy2/dt = .04*y1 - 1.E4*y2*y3 - 3.E7*y2**2 +C dy3/dt = 3.E7*y2**2 +C +C on the interval from t = 0.0 to t = 4.E10, with initial conditions +C y1 = 1.0, y2 = y3 = 0. The problem is stiff. +C +C The following coding solves this problem with SLSODE, using +C MF = 21 and printing results at t = .4, 4., ..., 4.E10. It uses +C ITOL = 2 and ATOL much smaller for y2 than for y1 or y3 because y2 +C has much smaller values. At the end of the run, statistical +C quantities of interest are printed. +C +C EXTERNAL FEX, JEX +C INTEGER IOPT, IOUT, ISTATE, ITASK, ITOL, IWORK(23), LIW, LRW, +C * MF, NEQ +C REAL ATOL(3), RTOL, RWORK(58), T, TOUT, Y(3) +C NEQ = 3 +C Y(1) = 1. +C Y(2) = 0. +C Y(3) = 0. +C T = 0. +C TOUT = .4 +C ITOL = 2 +C RTOL = 1.E-4 +C ATOL(1) = 1.E-6 +C ATOL(2) = 1.E-10 +C ATOL(3) = 1.E-6 +C ITASK = 1 +C ISTATE = 1 +C IOPT = 0 +C LRW = 58 +C LIW = 23 +C MF = 21 +C DO 40 IOUT = 1,12 +C CALL SLSODE (FEX, NEQ, Y, T, TOUT, ITOL, RTOL, ATOL, ITASK, +C * ISTATE, IOPT, RWORK, LRW, IWORK, LIW, JEX, MF) +C WRITE(6,20) T, Y(1), Y(2), Y(3) +C 20 FORMAT(' At t =',E12.4,' y =',3E14.6) +C IF (ISTATE .LT. 0) GO TO 80 +C 40 TOUT = TOUT*10. +C WRITE(6,60) IWORK(11), IWORK(12), IWORK(13) +C 60 FORMAT(/' No. steps =',i4,', No. f-s =',i4,', No. J-s =',i4) +C STOP +C 80 WRITE(6,90) ISTATE +C 90 FORMAT(///' Error halt.. ISTATE =',I3) +C STOP +C END +C +C SUBROUTINE FEX (NEQ, T, Y, YDOT) +C INTEGER NEQ +C REAL T, Y(3), YDOT(3) +C YDOT(1) = -.04*Y(1) + 1.E4*Y(2)*Y(3) +C YDOT(3) = 3.E7*Y(2)*Y(2) +C YDOT(2) = -YDOT(1) - YDOT(3) +C RETURN +C END +C +C SUBROUTINE JEX (NEQ, T, Y, ML, MU, PD, NRPD) +C INTEGER NEQ, ML, MU, NRPD +C REAL T, Y(3), PD(NRPD,3) +C PD(1,1) = -.04 +C PD(1,2) = 1.E4*Y(3) +C PD(1,3) = 1.E4*Y(2) +C PD(2,1) = .04 +C PD(2,3) = -PD(1,3) +C PD(3,2) = 6.E7*Y(2) +C PD(2,2) = -PD(1,2) - PD(3,2) +C RETURN +C END +C +C The output from this program (on a Cray-1 in single precision) +C is as follows. +C +C At t = 4.0000e-01 y = 9.851726e-01 3.386406e-05 1.479357e-02 +C At t = 4.0000e+00 y = 9.055142e-01 2.240418e-05 9.446344e-02 +C At t = 4.0000e+01 y = 7.158050e-01 9.184616e-06 2.841858e-01 +C At t = 4.0000e+02 y = 4.504846e-01 3.222434e-06 5.495122e-01 +C At t = 4.0000e+03 y = 1.831701e-01 8.940379e-07 8.168290e-01 +C At t = 4.0000e+04 y = 3.897016e-02 1.621193e-07 9.610297e-01 +C At t = 4.0000e+05 y = 4.935213e-03 1.983756e-08 9.950648e-01 +C At t = 4.0000e+06 y = 5.159269e-04 2.064759e-09 9.994841e-01 +C At t = 4.0000e+07 y = 5.306413e-05 2.122677e-10 9.999469e-01 +C At t = 4.0000e+08 y = 5.494530e-06 2.197825e-11 9.999945e-01 +C At t = 4.0000e+09 y = 5.129458e-07 2.051784e-12 9.999995e-01 +C At t = 4.0000e+10 y = -7.170603e-08 -2.868241e-13 1.000000e+00 +C +C No. steps = 330, No. f-s = 405, No. J-s = 69 +C +C *Accuracy: +C The accuracy of the solution depends on the choice of tolerances +C RTOL and ATOL. Actual (global) errors may exceed these local +C tolerances, so choose them conservatively. +C +C *Cautions: +C The work arrays should not be altered between calls to SLSODE for +C the same problem, except possibly for the conditional and optional +C inputs. +C +C *Portability: +C Since NEQ is dimensioned inside SLSODE, some compilers may object +C to a call to SLSODE with NEQ a scalar variable. In this event, +C use DIMENSION NEQ(1). Similar remarks apply to RTOL and ATOL. +C +C Note to Cray users: +C For maximum efficiency, use the CFT77 compiler. Appropriate +C compiler optimization directives have been inserted for CFT77. +C +C *Reference: +C Alan C. Hindmarsh, "ODEPACK, A Systematized Collection of ODE +C Solvers," in Scientific Computing, R. S. Stepleman, et al., Eds. +C (North-Holland, Amsterdam, 1983), pp. 55-64. +C +C *Long Description: +C The following complete description of the user interface to +C SLSODE consists of four parts: +C +C 1. The call sequence to subroutine SLSODE, which is a driver +C routine for the solver. This includes descriptions of both +C the call sequence arguments and user-supplied routines. +C Following these descriptions is a description of optional +C inputs available through the call sequence, and then a +C description of optional outputs in the work arrays. +C +C 2. Descriptions of other routines in the SLSODE package that may +C be (optionally) called by the user. These provide the ability +C to alter error message handling, save and restore the internal +C COMMON, and obtain specified derivatives of the solution y(t). +C +C 3. Descriptions of COMMON block to be declared in overlay or +C similar environments, or to be saved when doing an interrupt +C of the problem and continued solution later. +C +C 4. Description of two routines in the SLSODE package, either of +C which the user may replace with his own version, if desired. +C These relate to the measurement of errors. +C +C +C Part 1. Call Sequence +C ---------------------- +C +C Arguments +C --------- +C The call sequence parameters used for input only are +C +C F, NEQ, TOUT, ITOL, RTOL, ATOL, ITASK, IOPT, LRW, LIW, JAC, MF, +C +C and those used for both input and output are +C +C Y, T, ISTATE. +C +C The work arrays RWORK and IWORK are also used for conditional and +C optional inputs and optional outputs. (The term output here +C refers to the return from subroutine SLSODE to the user's calling +C program.) +C +C The legality of input parameters will be thoroughly checked on the +C initial call for the problem, but not checked thereafter unless a +C change in input parameters is flagged by ISTATE = 3 on input. +C +C The descriptions of the call arguments are as follows. +C +C F The name of the user-supplied subroutine defining the ODE +C system. The system must be put in the first-order form +C dy/dt = f(t,y), where f is a vector-valued function of +C the scalar t and the vector y. Subroutine F is to compute +C the function f. It is to have the form +C +C SUBROUTINE F (NEQ, T, Y, YDOT) +C REAL T, Y(*), YDOT(*) +C +C where NEQ, T, and Y are input, and the array YDOT = +C f(T,Y) is output. Y and YDOT are arrays of length NEQ. +C Subroutine F should not alter Y(1),...,Y(NEQ). F must be +C declared EXTERNAL in the calling program. +C +C Subroutine F may access user-defined quantities in +C NEQ(2),... and/or in Y(NEQ(1)+1),..., if NEQ is an array +C (dimensioned in F) and/or Y has length exceeding NEQ(1). +C See the descriptions of NEQ and Y below. +C +C If quantities computed in the F routine are needed +C externally to SLSODE, an extra call to F should be made +C for this purpose, for consistent and accurate results. +C If only the derivative dy/dt is needed, use SINTDY +C instead. +C +C NEQ The size of the ODE system (number of first-order +C ordinary differential equations). Used only for input. +C NEQ may be decreased, but not increased, during the +C problem. If NEQ is decreased (with ISTATE = 3 on input), +C the remaining components of Y should be left undisturbed, +C if these are to be accessed in F and/or JAC. +C +C Normally, NEQ is a scalar, and it is generally referred +C to as a scalar in this user interface description. +C However, NEQ may be an array, with NEQ(1) set to the +C system size. (The SLSODE package accesses only NEQ(1).) +C In either case, this parameter is passed as the NEQ +C argument in all calls to F and JAC. Hence, if it is an +C array, locations NEQ(2),... may be used to store other +C integer data and pass it to F and/or JAC. Subroutines +C F and/or JAC must include NEQ in a DIMENSION statement +C in that case. +C +C Y A real array for the vector of dependent variables, of +C length NEQ or more. Used for both input and output on +C the first call (ISTATE = 1), and only for output on +C other calls. On the first call, Y must contain the +C vector of initial values. On output, Y contains the +C computed solution vector, evaluated at T. If desired, +C the Y array may be used for other purposes between +C calls to the solver. +C +C This array is passed as the Y argument in all calls to F +C and JAC. Hence its length may exceed NEQ, and locations +C Y(NEQ+1),... may be used to store other real data and +C pass it to F and/or JAC. (The SLSODE package accesses +C only Y(1),...,Y(NEQ).) +C +C T The independent variable. On input, T is used only on +C the first call, as the initial point of the integration. +C On output, after each call, T is the value at which a +C computed solution Y is evaluated (usually the same as +C TOUT). On an error return, T is the farthest point +C reached. +C +C TOUT The next value of T at which a computed solution is +C desired. Used only for input. +C +C When starting the problem (ISTATE = 1), TOUT may be equal +C to T for one call, then should not equal T for the next +C call. For the initial T, an input value of TOUT .NE. T +C is used in order to determine the direction of the +C integration (i.e., the algebraic sign of the step sizes) +C and the rough scale of the problem. Integration in +C either direction (forward or backward in T) is permitted. +C +C If ITASK = 2 or 5 (one-step modes), TOUT is ignored +C after the first call (i.e., the first call with +C TOUT .NE. T). Otherwise, TOUT is required on every call. +C +C If ITASK = 1, 3, or 4, the values of TOUT need not be +C monotone, but a value of TOUT which backs up is limited +C to the current internal T interval, whose endpoints are +C TCUR - HU and TCUR. (See "Optional Outputs" below for +C TCUR and HU.) +C +C +C ITOL An indicator for the type of error control. See +C description below under ATOL. Used only for input. +C +C RTOL A relative error tolerance parameter, either a scalar or +C an array of length NEQ. See description below under +C ATOL. Input only. +C +C ATOL An absolute error tolerance parameter, either a scalar or +C an array of length NEQ. Input only. +C +C The input parameters ITOL, RTOL, and ATOL determine the +C error control performed by the solver. The solver will +C control the vector e = (e(i)) of estimated local errors +C in Y, according to an inequality of the form +C +C rms-norm of ( e(i)/EWT(i) ) <= 1, +C +C where +C +C EWT(i) = RTOL(i)*ABS(Y(i)) + ATOL(i), +C +C and the rms-norm (root-mean-square norm) here is +C +C rms-norm(v) = SQRT(sum v(i)**2 / NEQ). +C +C Here EWT = (EWT(i)) is a vector of weights which must +C always be positive, and the values of RTOL and ATOL +C should all be nonnegative. The following table gives the +C types (scalar/array) of RTOL and ATOL, and the +C corresponding form of EWT(i). +C +C ITOL RTOL ATOL EWT(i) +C ---- ------ ------ ----------------------------- +C 1 scalar scalar RTOL*ABS(Y(i)) + ATOL +C 2 scalar array RTOL*ABS(Y(i)) + ATOL(i) +C 3 array scalar RTOL(i)*ABS(Y(i)) + ATOL +C 4 array array RTOL(i)*ABS(Y(i)) + ATOL(i) +C +C When either of these parameters is a scalar, it need not +C be dimensioned in the user's calling program. +C +C If none of the above choices (with ITOL, RTOL, and ATOL +C fixed throughout the problem) is suitable, more general +C error controls can be obtained by substituting +C user-supplied routines for the setting of EWT and/or for +C the norm calculation. See Part 4 below. +C +C If global errors are to be estimated by making a repeated +C run on the same problem with smaller tolerances, then all +C components of RTOL and ATOL (i.e., of EWT) should be +C scaled down uniformly. +C +C ITASK An index specifying the task to be performed. Input +C only. ITASK has the following values and meanings: +C 1 Normal computation of output values of y(t) at +C t = TOUT (by overshooting and interpolating). +C 2 Take one step only and return. +C 3 Stop at the first internal mesh point at or beyond +C t = TOUT and return. +C 4 Normal computation of output values of y(t) at +C t = TOUT but without overshooting t = TCRIT. TCRIT +C must be input as RWORK(1). TCRIT may be equal to or +C beyond TOUT, but not behind it in the direction of +C integration. This option is useful if the problem +C has a singularity at or beyond t = TCRIT. +C 5 Take one step, without passing TCRIT, and return. +C TCRIT must be input as RWORK(1). +C +C Note: If ITASK = 4 or 5 and the solver reaches TCRIT +C (within roundoff), it will return T = TCRIT (exactly) to +C indicate this (unless ITASK = 4 and TOUT comes before +C TCRIT, in which case answers at T = TOUT are returned +C first). +C +C ISTATE An index used for input and output to specify the state +C of the calculation. +C +C On input, the values of ISTATE are as follows: +C 1 This is the first call for the problem +C (initializations will be done). See "Note" below. +C 2 This is not the first call, and the calculation is to +C continue normally, with no change in any input +C parameters except possibly TOUT and ITASK. (If ITOL, +C RTOL, and/or ATOL are changed between calls with +C ISTATE = 2, the new values will be used but not +C tested for legality.) +C 3 This is not the first call, and the calculation is to +C continue normally, but with a change in input +C parameters other than TOUT and ITASK. Changes are +C allowed in NEQ, ITOL, RTOL, ATOL, IOPT, LRW, LIW, MF, +C ML, MU, and any of the optional inputs except H0. +C (See IWORK description for ML and MU.) +C +C Note: A preliminary call with TOUT = T is not counted as +C a first call here, as no initialization or checking of +C input is done. (Such a call is sometimes useful for the +C purpose of outputting the initial conditions.) Thus the +C first call for which TOUT .NE. T requires ISTATE = 1 on +C input. +C +C On output, ISTATE has the following values and meanings: +C 1 Nothing was done, as TOUT was equal to T with +C ISTATE = 1 on input. +C 2 The integration was performed successfully. +C -1 An excessive amount of work (more than MXSTEP steps) +C was done on this call, before completing the +C requested task, but the integration was otherwise +C successful as far as T. (MXSTEP is an optional input +C and is normally 500.) To continue, the user may +C simply reset ISTATE to a value >1 and call again (the +C excess work step counter will be reset to 0). In +C addition, the user may increase MXSTEP to avoid this +C error return; see "Optional Inputs" below. +C -2 Too much accuracy was requested for the precision of +C the machine being used. This was detected before +C completing the requested task, but the integration +C was successful as far as T. To continue, the +C tolerance parameters must be reset, and ISTATE must +C be set to 3. The optional output TOLSF may be used +C for this purpose. (Note: If this condition is +C detected before taking any steps, then an illegal +C input return (ISTATE = -3) occurs instead.) +C -3 Illegal input was detected, before taking any +C integration steps. See written message for details. +C (Note: If the solver detects an infinite loop of +C calls to the solver with illegal input, it will cause +C the run to stop.) +C -4 There were repeated error-test failures on one +C attempted step, before completing the requested task, +C but the integration was successful as far as T. The +C problem may have a singularity, or the input may be +C inappropriate. +C -5 There were repeated convergence-test failures on one +C attempted step, before completing the requested task, +C but the integration was successful as far as T. This +C may be caused by an inaccurate Jacobian matrix, if +C one is being used. +C -6 EWT(i) became zero for some i during the integration. +C Pure relative error control (ATOL(i)=0.0) was +C requested on a variable which has now vanished. The +C integration was successful as far as T. +C +C Note: Since the normal output value of ISTATE is 2, it +C does not need to be reset for normal continuation. Also, +C since a negative input value of ISTATE will be regarded +C as illegal, a negative output value requires the user to +C change it, and possibly other inputs, before calling the +C solver again. +C +C IOPT An integer flag to specify whether any optional inputs +C are being used on this call. Input only. The optional +C inputs are listed under a separate heading below. +C 0 No optional inputs are being used. Default values +C will be used in all cases. +C 1 One or more optional inputs are being used. +C +C RWORK A real working array (single precision). The length of +C RWORK must be at least +C +C 20 + NYH*(MAXORD + 1) + 3*NEQ + LWM +C +C where +C NYH = the initial value of NEQ, +C MAXORD = 12 (if METH = 1) or 5 (if METH = 2) (unless a +C smaller value is given as an optional input), +C LWM = 0 if MITER = 0, +C LWM = NEQ**2 + 2 if MITER = 1 or 2, +C LWM = NEQ + 2 if MITER = 3, and +C LWM = (2*ML + MU + 1)*NEQ + 2 +C if MITER = 4 or 5. +C (See the MF description below for METH and MITER.) +C +C Thus if MAXORD has its default value and NEQ is constant, +C this length is: +C 20 + 16*NEQ for MF = 10, +C 22 + 16*NEQ + NEQ**2 for MF = 11 or 12, +C 22 + 17*NEQ for MF = 13, +C 22 + 17*NEQ + (2*ML + MU)*NEQ for MF = 14 or 15, +C 20 + 9*NEQ for MF = 20, +C 22 + 9*NEQ + NEQ**2 for MF = 21 or 22, +C 22 + 10*NEQ for MF = 23, +C 22 + 10*NEQ + (2*ML + MU)*NEQ for MF = 24 or 25. +C +C The first 20 words of RWORK are reserved for conditional +C and optional inputs and optional outputs. +C +C The following word in RWORK is a conditional input: +C RWORK(1) = TCRIT, the critical value of t which the +C solver is not to overshoot. Required if ITASK +C is 4 or 5, and ignored otherwise. See ITASK. +C +C LRW The length of the array RWORK, as declared by the user. +C (This will be checked by the solver.) +C +C IWORK An integer work array. Its length must be at least +C 20 if MITER = 0 or 3 (MF = 10, 13, 20, 23), or +C 20 + NEQ otherwise (MF = 11, 12, 14, 15, 21, 22, 24, 25). +C (See the MF description below for MITER.) The first few +C words of IWORK are used for conditional and optional +C inputs and optional outputs. +C +C The following two words in IWORK are conditional inputs: +C IWORK(1) = ML These are the lower and upper half- +C IWORK(2) = MU bandwidths, respectively, of the banded +C Jacobian, excluding the main diagonal. +C The band is defined by the matrix locations +C (i,j) with i - ML <= j <= i + MU. ML and MU +C must satisfy 0 <= ML,MU <= NEQ - 1. These are +C required if MITER is 4 or 5, and ignored +C otherwise. ML and MU may in fact be the band +C parameters for a matrix to which df/dy is only +C approximately equal. +C +C LIW The length of the array IWORK, as declared by the user. +C (This will be checked by the solver.) +C +C Note: The work arrays must not be altered between calls to SLSODE +C for the same problem, except possibly for the conditional and +C optional inputs, and except for the last 3*NEQ words of RWORK. +C The latter space is used for internal scratch space, and so is +C available for use by the user outside SLSODE between calls, if +C desired (but not for use by F or JAC). +C +C JAC The name of the user-supplied routine (MITER = 1 or 4) to +C compute the Jacobian matrix, df/dy, as a function of the +C scalar t and the vector y. (See the MF description below +C for MITER.) It is to have the form +C +C SUBROUTINE JAC (NEQ, T, Y, ML, MU, PD, NROWPD) +C REAL T, Y(*), PD(NROWPD,*) +C +C where NEQ, T, Y, ML, MU, and NROWPD are input and the +C array PD is to be loaded with partial derivatives +C (elements of the Jacobian matrix) on output. PD must be +C given a first dimension of NROWPD. T and Y have the same +C meaning as in subroutine F. +C +C In the full matrix case (MITER = 1), ML and MU are +C ignored, and the Jacobian is to be loaded into PD in +C columnwise manner, with df(i)/dy(j) loaded into PD(i,j). +C +C In the band matrix case (MITER = 4), the elements within +C the band are to be loaded into PD in columnwise manner, +C with diagonal lines of df/dy loaded into the rows of PD. +C Thus df(i)/dy(j) is to be loaded into PD(i-j+MU+1,j). ML +C and MU are the half-bandwidth parameters (see IWORK). +C The locations in PD in the two triangular areas which +C correspond to nonexistent matrix elements can be ignored +C or loaded arbitrarily, as they are overwritten by SLSODE. +C +C JAC need not provide df/dy exactly. A crude approximation +C (possibly with a smaller bandwidth) will do. +C +C In either case, PD is preset to zero by the solver, so +C that only the nonzero elements need be loaded by JAC. +C Each call to JAC is preceded by a call to F with the same +C arguments NEQ, T, and Y. Thus to gain some efficiency, +C intermediate quantities shared by both calculations may +C be saved in a user COMMON block by F and not recomputed +C by JAC, if desired. Also, JAC may alter the Y array, if +C desired. JAC must be declared EXTERNAL in the calling +C program. +C +C Subroutine JAC may access user-defined quantities in +C NEQ(2),... and/or in Y(NEQ(1)+1),... if NEQ is an array +C (dimensioned in JAC) and/or Y has length exceeding +C NEQ(1). See the descriptions of NEQ and Y above. +C +C MF The method flag. Used only for input. The legal values +C of MF are 10, 11, 12, 13, 14, 15, 20, 21, 22, 23, 24, +C and 25. MF has decimal digits METH and MITER: +C MF = 10*METH + MITER . +C +C METH indicates the basic linear multistep method: +C 1 Implicit Adams method. +C 2 Method based on backward differentiation formulas +C (BDF's). +C +C MITER indicates the corrector iteration method: +C 0 Functional iteration (no Jacobian matrix is +C involved). +C 1 Chord iteration with a user-supplied full (NEQ by +C NEQ) Jacobian. +C 2 Chord iteration with an internally generated +C (difference quotient) full Jacobian (using NEQ +C extra calls to F per df/dy value). +C 3 Chord iteration with an internally generated +C diagonal Jacobian approximation (using one extra call +C to F per df/dy evaluation). +C 4 Chord iteration with a user-supplied banded Jacobian. +C 5 Chord iteration with an internally generated banded +C Jacobian (using ML + MU + 1 extra calls to F per +C df/dy evaluation). +C +C If MITER = 1 or 4, the user must supply a subroutine JAC +C (the name is arbitrary) as described above under JAC. +C For other values of MITER, a dummy argument can be used. +C +C Optional Inputs +C --------------- +C The following is a list of the optional inputs provided for in the +C call sequence. (See also Part 2.) For each such input variable, +C this table lists its name as used in this documentation, its +C location in the call sequence, its meaning, and the default value. +C The use of any of these inputs requires IOPT = 1, and in that case +C all of these inputs are examined. A value of zero for any of +C these optional inputs will cause the default value to be used. +C Thus to use a subset of the optional inputs, simply preload +C locations 5 to 10 in RWORK and IWORK to 0.0 and 0 respectively, +C and then set those of interest to nonzero values. +C +C Name Location Meaning and default value +C ------ --------- ----------------------------------------------- +C H0 RWORK(5) Step size to be attempted on the first step. +C The default value is determined by the solver. +C HMAX RWORK(6) Maximum absolute step size allowed. The +C default value is infinite. +C HMIN RWORK(7) Minimum absolute step size allowed. The +C default value is 0. (This lower bound is not +C enforced on the final step before reaching +C TCRIT when ITASK = 4 or 5.) +C MAXORD IWORK(5) Maximum order to be allowed. The default value +C is 12 if METH = 1, and 5 if METH = 2. (See the +C MF description above for METH.) If MAXORD +C exceeds the default value, it will be reduced +C to the default value. If MAXORD is changed +C during the problem, it may cause the current +C order to be reduced. +C MXSTEP IWORK(6) Maximum number of (internally defined) steps +C allowed during one call to the solver. The +C default value is 500. +C MXHNIL IWORK(7) Maximum number of messages printed (per +C problem) warning that T + H = T on a step +C (H = step size). This must be positive to +C result in a nondefault value. The default +C value is 10. +C +C Optional Outputs +C ---------------- +C As optional additional output from SLSODE, the variables listed +C below are quantities related to the performance of SLSODE which +C are available to the user. These are communicated by way of the +C work arrays, but also have internal mnemonic names as shown. +C Except where stated otherwise, all of these outputs are defined on +C any successful return from SLSODE, and on any return with ISTATE = +C -1, -2, -4, -5, or -6. On an illegal input return (ISTATE = -3), +C they will be unchanged from their existing values (if any), except +C possibly for TOLSF, LENRW, and LENIW. On any error return, +C outputs relevant to the error will be defined, as noted below. +C +C Name Location Meaning +C ----- --------- ------------------------------------------------ +C HU RWORK(11) Step size in t last used (successfully). +C HCUR RWORK(12) Step size to be attempted on the next step. +C TCUR RWORK(13) Current value of the independent variable which +C the solver has actually reached, i.e., the +C current internal mesh point in t. On output, +C TCUR will always be at least as far as the +C argument T, but may be farther (if interpolation +C was done). +C TOLSF RWORK(14) Tolerance scale factor, greater than 1.0, +C computed when a request for too much accuracy +C was detected (ISTATE = -3 if detected at the +C start of the problem, ISTATE = -2 otherwise). +C If ITOL is left unaltered but RTOL and ATOL are +C uniformly scaled up by a factor of TOLSF for the +C next call, then the solver is deemed likely to +C succeed. (The user may also ignore TOLSF and +C alter the tolerance parameters in any other way +C appropriate.) +C NST IWORK(11) Number of steps taken for the problem so far. +C NFE IWORK(12) Number of F evaluations for the problem so far. +C NJE IWORK(13) Number of Jacobian evaluations (and of matrix LU +C decompositions) for the problem so far. +C NQU IWORK(14) Method order last used (successfully). +C NQCUR IWORK(15) Order to be attempted on the next step. +C IMXER IWORK(16) Index of the component of largest magnitude in +C the weighted local error vector ( e(i)/EWT(i) ), +C on an error return with ISTATE = -4 or -5. +C LENRW IWORK(17) Length of RWORK actually required. This is +C defined on normal returns and on an illegal +C input return for insufficient storage. +C LENIW IWORK(18) Length of IWORK actually required. This is +C defined on normal returns and on an illegal +C input return for insufficient storage. +C +C The following two arrays are segments of the RWORK array which may +C also be of interest to the user as optional outputs. For each +C array, the table below gives its internal name, its base address +C in RWORK, and its description. +C +C Name Base address Description +C ---- ------------ ---------------------------------------------- +C YH 21 The Nordsieck history array, of size NYH by +C (NQCUR + 1), where NYH is the initial value of +C NEQ. For j = 0,1,...,NQCUR, column j + 1 of +C YH contains HCUR**j/factorial(j) times the jth +C derivative of the interpolating polynomial +C currently representing the solution, evaluated +C at t = TCUR. +C ACOR LENRW-NEQ+1 Array of size NEQ used for the accumulated +C corrections on each step, scaled on output to +C represent the estimated local error in Y on +C the last step. This is the vector e in the +C description of the error control. It is +C defined only on successful return from SLSODE. +C +C +C Part 2. Other Callable Routines +C -------------------------------- +C +C The following are optional calls which the user may make to gain +C additional capabilities in conjunction with SLSODE. +C +C Form of call Function +C ------------------------ ---------------------------------------- +C CALL XSETUN(LUN) Set the logical unit number, LUN, for +C output of messages from SLSODE, if the +C default is not desired. The default +C value of LUN is 6. This call may be made +C at any time and will take effect +C immediately. +C CALL XSETF(MFLAG) Set a flag to control the printing of +C messages by SLSODE. MFLAG = 0 means do +C not print. (Danger: this risks losing +C valuable information.) MFLAG = 1 means +C print (the default). This call may be +C made at any time and will take effect +C immediately. +C CALL SSRCOM(RSAV,ISAV,JOB) Saves and restores the contents of the +C internal COMMON blocks used by SLSODE +C (see Part 3 below). RSAV must be a +C real array of length 218 or more, and +C ISAV must be an integer array of length +C 37 or more. JOB = 1 means save COMMON +C into RSAV/ISAV. JOB = 2 means restore +C COMMON from same. SSRCOM is useful if +C one is interrupting a run and restarting +C later, or alternating between two or +C more problems solved with SLSODE. +C CALL SINTDY(,,,,,) Provide derivatives of y, of various +C (see below) orders, at a specified point t, if +C desired. It may be called only after a +C successful return from SLSODE. Detailed +C instructions follow. +C +C Detailed instructions for using SINTDY +C -------------------------------------- +C The form of the CALL is: +C +C CALL SINTDY (T, K, RWORK(21), NYH, DKY, IFLAG) +C +C The input parameters are: +C +C T Value of independent variable where answers are +C desired (normally the same as the T last returned by +C SLSODE). For valid results, T must lie between +C TCUR - HU and TCUR. (See "Optional Outputs" above +C for TCUR and HU.) +C K Integer order of the derivative desired. K must +C satisfy 0 <= K <= NQCUR, where NQCUR is the current +C order (see "Optional Outputs"). The capability +C corresponding to K = 0, i.e., computing y(t), is +C already provided by SLSODE directly. Since +C NQCUR >= 1, the first derivative dy/dt is always +C available with SINTDY. +C RWORK(21) The base address of the history array YH. +C NYH Column length of YH, equal to the initial value of NEQ. +C +C The output parameters are: +C +C DKY Real array of length NEQ containing the computed value +C of the Kth derivative of y(t). +C IFLAG Integer flag, returned as 0 if K and T were legal, +C -1 if K was illegal, and -2 if T was illegal. +C On an error return, a message is also written. +C +C +C Part 3. Common Blocks +C ---------------------- +C +C If SLSODE is to be used in an overlay situation, the user must +C declare, in the primary overlay, the variables in: +C (1) the call sequence to SLSODE, +C (2) the internal COMMON block /SLS001/, of length 255 +C (218 single precision words followed by 37 integer words). +C +C If SLSODE is used on a system in which the contents of internal +C COMMON blocks are not preserved between calls, the user should +C declare the above COMMON block in his main program to insure that +C its contents are preserved. +C +C If the solution of a given problem by SLSODE is to be interrupted +C and then later continued, as when restarting an interrupted run or +C alternating between two or more problems, the user should save, +C following the return from the last SLSODE call prior to the +C interruption, the contents of the call sequence variables and the +C internal COMMON block, and later restore these values before the +C next SLSODE call for that problem. In addition, if XSETUN and/or +C XSETF was called for non-default handling of error messages, then +C these calls must be repeated. To save and restore the COMMON +C block, use subroutine SSRCOM (see Part 2 above). +C +C +C Part 4. Optionally Replaceable Solver Routines +C ----------------------------------------------- +C +C Below are descriptions of two routines in the SLSODE package which +C relate to the measurement of errors. Either routine can be +C replaced by a user-supplied version, if desired. However, since +C such a replacement may have a major impact on performance, it +C should be done only when absolutely necessary, and only with great +C caution. (Note: The means by which the package version of a +C routine is superseded by the user's version may be system- +C dependent.) +C +C SEWSET +C ------ +C The following subroutine is called just before each internal +C integration step, and sets the array of error weights, EWT, as +C described under ITOL/RTOL/ATOL above: +C +C SUBROUTINE SEWSET (NEQ, ITOL, RTOL, ATOL, YCUR, EWT) +C +C where NEQ, ITOL, RTOL, and ATOL are as in the SLSODE call +C sequence, YCUR contains the current dependent variable vector, +C and EWT is the array of weights set by SEWSET. +C +C If the user supplies this subroutine, it must return in EWT(i) +C (i = 1,...,NEQ) a positive quantity suitable for comparing errors +C in Y(i) to. The EWT array returned by SEWSET is passed to the +C SVNORM routine (see below), and also used by SLSODE in the +C computation of the optional output IMXER, the diagonal Jacobian +C approximation, and the increments for difference quotient +C Jacobians. +C +C In the user-supplied version of SEWSET, it may be desirable to use +C the current values of derivatives of y. Derivatives up to order NQ +C are available from the history array YH, described above under +C optional outputs. In SEWSET, YH is identical to the YCUR array, +C extended to NQ + 1 columns with a column length of NYH and scale +C factors of H**j/factorial(j). On the first call for the problem, +C given by NST = 0, NQ is 1 and H is temporarily set to 1.0. +C NYH is the initial value of NEQ. The quantities NQ, H, and NST +C can be obtained by including in SEWSET the statements: +C REAL RLS +C COMMON /SLS001/ RLS(218),ILS(37) +C NQ = ILS(33) +C NST = ILS(34) +C H = RLS(212) +C Thus, for example, the current value of dy/dt can be obtained as +C YCUR(NYH+i)/H (i=1,...,NEQ) (and the division by H is unnecessary +C when NST = 0). +C +C SVNORM +C ------ +C SVNORM is a real function routine which computes the weighted +C root-mean-square norm of a vector v: +C +C d = SVNORM (n, v, w) +C +C where: +C n = the length of the vector, +C v = real array of length n containing the vector, +C w = real array of length n containing weights, +C d = SQRT( (1/n) * sum(v(i)*w(i))**2 ). +C +C SVNORM is called with n = NEQ and with w(i) = 1.0/EWT(i), where +C EWT is as set by subroutine SEWSET. +C +C If the user supplies this function, it should return a nonnegative +C value of SVNORM suitable for use in the error control in SLSODE. +C None of the arguments should be altered by SVNORM. For example, a +C user-supplied SVNORM routine might: +C - Substitute a max-norm of (v(i)*w(i)) for the rms-norm, or +C - Ignore some components of v in the norm, with the effect of +C suppressing the error control on those components of Y. +C --------------------------------------------------------------------- +C***ROUTINES CALLED SEWSET, SINTDY, RUMACH, SSTODE, SVNORM, XERRWV +C***COMMON BLOCKS SLS001 +C***REVISION HISTORY (YYYYMMDD) +C 19791129 DATE WRITTEN +C 19791213 Minor changes to declarations; DELP init. in STODE. +C 19800118 Treat NEQ as array; integer declarations added throughout; +C minor changes to prologue. +C 19800306 Corrected TESCO(1,NQP1) setting in CFODE. +C 19800519 Corrected access of YH on forced order reduction; +C numerous corrections to prologues and other comments. +C 19800617 In main driver, added loading of SQRT(UROUND) in RWORK; +C minor corrections to main prologue. +C 19800923 Added zero initialization of HU and NQU. +C 19801218 Revised XERRWV routine; minor corrections to main prologue. +C 19810401 Minor changes to comments and an error message. +C 19810814 Numerous revisions: replaced EWT by 1/EWT; used flags +C JCUR, ICF, IERPJ, IERSL between STODE and subordinates; +C added tuning parameters CCMAX, MAXCOR, MSBP, MXNCF; +C reorganized returns from STODE; reorganized type decls.; +C fixed message length in XERRWV; changed default LUNIT to 6; +C changed Common lengths; changed comments throughout. +C 19870330 Major update by ACH: corrected comments throughout; +C removed TRET from Common; rewrote EWSET with 4 loops; +C fixed t test in INTDY; added Cray directives in STODE; +C in STODE, fixed DELP init. and logic around PJAC call; +C combined routines to save/restore Common; +C passed LEVEL = 0 in error message calls (except run abort). +C 19890426 Modified prologue to SLATEC/LDOC format. (FNF) +C 19890501 Many improvements to prologue. (FNF) +C 19890503 A few final corrections to prologue. (FNF) +C 19890504 Minor cosmetic changes. (FNF) +C 19890510 Corrected description of Y in Arguments section. (FNF) +C 19890517 Minor corrections to prologue. (FNF) +C 19920514 Updated with prologue edited 891025 by G. Shaw for manual. +C 19920515 Converted source lines to upper case. (FNF) +C 19920603 Revised XERRWV calls using mixed upper-lower case. (ACH) +C 19920616 Revised prologue comment regarding CFT. (ACH) +C 19921116 Revised prologue comments regarding Common. (ACH). +C 19930326 Added comment about non-reentrancy. (FNF) +C 19930723 Changed R1MACH to RUMACH. (FNF) +C 19930801 Removed ILLIN and NTREP from Common (affects driver logic); +C minor changes to prologue and internal comments; +C changed Hollerith strings to quoted strings; +C changed internal comments to mixed case; +C replaced XERRWV with new version using character type; +C changed dummy dimensions from 1 to *. (ACH) +C 19930809 Changed to generic intrinsic names; changed names of +C subprograms and Common blocks to SLSODE etc. (ACH) +C 19930929 Eliminated use of REAL intrinsic; other minor changes. (ACH) +C 20010412 Removed all 'own' variables from Common block /SLS001/ +C (affects declarations in 6 routines). (ACH) +C 20010509 Minor corrections to prologue. (ACH) +C 20031105 Restored 'own' variables to Common block /SLS001/, to +C enable interrupt/restart feature. (ACH) +C 20031112 Added SAVE statements for data-loaded constants. +C +C*** END PROLOGUE SLSODE +C +C*Internal Notes: +C +C Other Routines in the SLSODE Package. +C +C In addition to Subroutine SLSODE, the SLSODE package includes the +C following subroutines and function routines: +C SINTDY computes an interpolated value of the y vector at t = TOUT. +C SSTODE is the core integrator, which does one step of the +C integration and the associated error control. +C SCFODE sets all method coefficients and test constants. +C SPREPJ computes and preprocesses the Jacobian matrix J = df/dy +C and the Newton iteration matrix P = I - h*l0*J. +C SSOLSY manages solution of linear system in chord iteration. +C SEWSET sets the error weight vector EWT before each step. +C SVNORM computes the weighted R.M.S. norm of a vector. +C SSRCOM is a user-callable routine to save and restore +C the contents of the internal Common block. +C DGETRF AND DGETRS ARE ROUTINES FROM LAPACK FOR SOLVING FULL +C SYSTEMS OF LINEAR ALGEBRAIC EQUATIONS. +C DGBTRF AND DGBTRS ARE ROUTINES FROM LAPACK FOR SOLVING BANDED +C LINEAR SYSTEMS. +C RUMACH computes the unit roundoff in a machine-independent manner. +C XERRWV, XSETUN, XSETF, IXSAV, IUMACH handle the printing of all +C error messages and warnings. XERRWV is machine-dependent. +C Note: SVNORM, RUMACH, IXSAV, and IUMACH are function routines. +C All the others are subroutines. +C +C**End +C +C Declare externals. + EXTERNAL SPREPJ, SSOLSY + REAL RUMACH, SVNORM +C +C Declare all other variables. + INTEGER INIT, MXSTEP, MXHNIL, NHNIL, NSLAST, NYH, IOWNS, + 1 ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, + 2 LYH, LEWT, LACOR, LSAVF, LWM, LIWM, METH, MITER, + 3 MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU + INTEGER I, I1, I2, IFLAG, IMXER, KGO, LF0, + 1 LENIW, LENRW, LENWM, ML, MORD, MU, MXHNL0, MXSTP0 + REAL ROWNS, + 1 CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND + REAL ATOLI, AYI, BIG, EWTI, H0, HMAX, HMX, RH, RTOLI, + 1 TCRIT, TDIST, TNEXT, TOL, TOLSF, TP, SIZE, SUM, W0 + DIMENSION MORD(2) + LOGICAL IHIT + CHARACTER*80 MSG + SAVE MORD, MXSTP0, MXHNL0 +C----------------------------------------------------------------------- +C The following internal Common block contains +C (a) variables which are local to any subroutine but whose values must +C be preserved between calls to the routine ("own" variables), and +C (b) variables which are communicated between subroutines. +C The block SLS001 is declared in subroutines SLSODE, SINTDY, SSTODE, +C SPREPJ, and SSOLSY. +C Groups of variables are replaced by dummy arrays in the Common +C declarations in routines where those variables are not used. +C----------------------------------------------------------------------- + COMMON /SLS001/ ROWNS(209), + 1 CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND, + 2 INIT, MXSTEP, MXHNIL, NHNIL, NSLAST, NYH, IOWNS(6), + 3 ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, + 4 LYH, LEWT, LACOR, LSAVF, LWM, LIWM, METH, MITER, + 5 MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU +C + DATA MORD(1),MORD(2)/12,5/, MXSTP0/500/, MXHNL0/10/ +C----------------------------------------------------------------------- +C Block A. +C This code block is executed on every call. +C It tests ISTATE and ITASK for legality and branches appropriately. +C If ISTATE .GT. 1 but the flag INIT shows that initialization has +C not yet been done, an error return occurs. +C If ISTATE = 1 and TOUT = T, return immediately. +C----------------------------------------------------------------------- +C +C***FIRST EXECUTABLE STATEMENT SLSODE + IF (ISTATE .LT. 1 .OR. ISTATE .GT. 3) GO TO 601 + IF (ITASK .LT. 1 .OR. ITASK .GT. 5) GO TO 602 + IF (ISTATE .EQ. 1) GO TO 10 + IF (INIT .EQ. 0) GO TO 603 + IF (ISTATE .EQ. 2) GO TO 200 + GO TO 20 + 10 INIT = 0 + IF (TOUT .EQ. T) RETURN +C----------------------------------------------------------------------- +C Block B. +C The next code block is executed for the initial call (ISTATE = 1), +C or for a continuation call with parameter changes (ISTATE = 3). +C It contains checking of all inputs and various initializations. +C +C First check legality of the non-optional inputs NEQ, ITOL, IOPT, +C MF, ML, and MU. +C----------------------------------------------------------------------- + 20 IF (NEQ(1) .LE. 0) GO TO 604 + IF (ISTATE .EQ. 1) GO TO 25 + IF (NEQ(1) .GT. N) GO TO 605 + 25 N = NEQ(1) + IF (ITOL .LT. 1 .OR. ITOL .GT. 4) GO TO 606 + IF (IOPT .LT. 0 .OR. IOPT .GT. 1) GO TO 607 + METH = MF/10 + MITER = MF - 10*METH + IF (METH .LT. 1 .OR. METH .GT. 2) GO TO 608 + IF (MITER .LT. 0 .OR. MITER .GT. 5) GO TO 608 + IF (MITER .LE. 3) GO TO 30 + ML = IWORK(1) + MU = IWORK(2) + IF (ML .LT. 0 .OR. ML .GE. N) GO TO 609 + IF (MU .LT. 0 .OR. MU .GE. N) GO TO 610 + 30 CONTINUE +C Next process and check the optional inputs. -------------------------- + IF (IOPT .EQ. 1) GO TO 40 + MAXORD = MORD(METH) + MXSTEP = MXSTP0 + MXHNIL = MXHNL0 + IF (ISTATE .EQ. 1) H0 = 0.0E0 + HMXI = 0.0E0 + HMIN = 0.0E0 + GO TO 60 + 40 MAXORD = IWORK(5) + IF (MAXORD .LT. 0) GO TO 611 + IF (MAXORD .EQ. 0) MAXORD = 100 + MAXORD = MIN(MAXORD,MORD(METH)) + MXSTEP = IWORK(6) + IF (MXSTEP .LT. 0) GO TO 612 + IF (MXSTEP .EQ. 0) MXSTEP = MXSTP0 + MXHNIL = IWORK(7) + IF (MXHNIL .LT. 0) GO TO 613 + IF (MXHNIL .EQ. 0) MXHNIL = MXHNL0 + IF (ISTATE .NE. 1) GO TO 50 + H0 = RWORK(5) + IF ((TOUT - T)*H0 .LT. 0.0E0) GO TO 614 + 50 HMAX = RWORK(6) + IF (HMAX .LT. 0.0E0) GO TO 615 + HMXI = 0.0E0 + IF (HMAX .GT. 0.0E0) HMXI = 1.0E0/HMAX + HMIN = RWORK(7) + IF (HMIN .LT. 0.0E0) GO TO 616 +C----------------------------------------------------------------------- +C Set work array pointers and check lengths LRW and LIW. +C Pointers to segments of RWORK and IWORK are named by prefixing L to +C the name of the segment. E.g., the segment YH starts at RWORK(LYH). +C Segments of RWORK (in order) are denoted YH, WM, EWT, SAVF, ACOR. +C----------------------------------------------------------------------- + 60 LYH = 21 + IF (ISTATE .EQ. 1) NYH = N + LWM = LYH + (MAXORD + 1)*NYH + IF (MITER .EQ. 0) LENWM = 0 + IF (MITER .EQ. 1 .OR. MITER .EQ. 2) LENWM = N*N + 2 + IF (MITER .EQ. 3) LENWM = N + 2 + IF (MITER .GE. 4) LENWM = (2*ML + MU + 1)*N + 2 + LEWT = LWM + LENWM + LSAVF = LEWT + N + LACOR = LSAVF + N + LENRW = LACOR + N - 1 + IWORK(17) = LENRW + LIWM = 1 + LENIW = 20 + N + IF (MITER .EQ. 0 .OR. MITER .EQ. 3) LENIW = 20 + IWORK(18) = LENIW + IF (LENRW .GT. LRW) GO TO 617 + IF (LENIW .GT. LIW) GO TO 618 +C Check RTOL and ATOL for legality. ------------------------------------ + RTOLI = RTOL(1) + ATOLI = ATOL(1) + DO 70 I = 1,N + IF (ITOL .GE. 3) RTOLI = RTOL(I) + IF (ITOL .EQ. 2 .OR. ITOL .EQ. 4) ATOLI = ATOL(I) + IF (RTOLI .LT. 0.0E0) GO TO 619 + IF (ATOLI .LT. 0.0E0) GO TO 620 + 70 CONTINUE + IF (ISTATE .EQ. 1) GO TO 100 +C If ISTATE = 3, set flag to signal parameter changes to SSTODE. ------- + JSTART = -1 + IF (NQ .LE. MAXORD) GO TO 90 +C MAXORD was reduced below NQ. Copy YH(*,MAXORD+2) into SAVF. --------- + DO 80 I = 1,N + 80 RWORK(I+LSAVF-1) = RWORK(I+LWM-1) +C Reload WM(1) = RWORK(LWM), since LWM may have changed. --------------- + 90 IF (MITER .GT. 0) RWORK(LWM) = SQRT(UROUND) + IF (N .EQ. NYH) GO TO 200 +C NEQ was reduced. Zero part of YH to avoid undefined references. ----- + I1 = LYH + L*NYH + I2 = LYH + (MAXORD + 1)*NYH - 1 + IF (I1 .GT. I2) GO TO 200 + DO 95 I = I1,I2 + 95 RWORK(I) = 0.0E0 + GO TO 200 +C----------------------------------------------------------------------- +C Block C. +C The next block is for the initial call only (ISTATE = 1). +C It contains all remaining initializations, the initial call to F, +C and the calculation of the initial step size. +C The error weights in EWT are inverted after being loaded. +C----------------------------------------------------------------------- + 100 UROUND = RUMACH() + TN = T + IF (ITASK .NE. 4 .AND. ITASK .NE. 5) GO TO 110 + TCRIT = RWORK(1) + IF ((TCRIT - TOUT)*(TOUT - T) .LT. 0.0E0) GO TO 625 + IF (H0 .NE. 0.0E0 .AND. (T + H0 - TCRIT)*H0 .GT. 0.0E0) + 1 H0 = TCRIT - T + 110 JSTART = 0 + IF (MITER .GT. 0) RWORK(LWM) = SQRT(UROUND) + NHNIL = 0 + NST = 0 + NJE = 0 + NSLAST = 0 + HU = 0.0E0 + NQU = 0 + CCMAX = 0.3E0 + MAXCOR = 3 + MSBP = 20 + MXNCF = 10 +C Initial call to F. (LF0 points to YH(*,2).) ------------------------- + LF0 = LYH + NYH + CALL F (NEQ, T, Y, RWORK(LF0)) + NFE = 1 +C Load the initial value vector in YH. --------------------------------- + DO 115 I = 1,N + 115 RWORK(I+LYH-1) = Y(I) +C Load and invert the EWT array. (H is temporarily set to 1.0.) ------- + NQ = 1 + H = 1.0E0 + CALL SEWSET (N, ITOL, RTOL, ATOL, RWORK(LYH), RWORK(LEWT)) + DO 120 I = 1,N + IF (RWORK(I+LEWT-1) .LE. 0.0E0) GO TO 621 + 120 RWORK(I+LEWT-1) = 1.0E0/RWORK(I+LEWT-1) +C----------------------------------------------------------------------- +C The coding below computes the step size, H0, to be attempted on the +C first step, unless the user has supplied a value for this. +C First check that TOUT - T differs significantly from zero. +C A scalar tolerance quantity TOL is computed, as MAX(RTOL(I)) +C if this is positive, or MAX(ATOL(I)/ABS(Y(I))) otherwise, adjusted +C so as to be between 100*UROUND and 1.0E-3. +C Then the computed value H0 is given by.. +C NEQ +C H0**2 = TOL / ( w0**-2 + (1/NEQ) * SUM ( f(i)/ywt(i) )**2 ) +C 1 +C where w0 = MAX ( ABS(T), ABS(TOUT) ), +C f(i) = i-th component of initial value of f, +C ywt(i) = EWT(i)/TOL (a weight for y(i)). +C The sign of H0 is inferred from the initial values of TOUT and T. +C----------------------------------------------------------------------- + IF (H0 .NE. 0.0E0) GO TO 180 + TDIST = ABS(TOUT - T) + W0 = MAX(ABS(T),ABS(TOUT)) + IF (TDIST .LT. 2.0E0*UROUND*W0) GO TO 622 + TOL = RTOL(1) + IF (ITOL .LE. 2) GO TO 140 + DO 130 I = 1,N + 130 TOL = MAX(TOL,RTOL(I)) + 140 IF (TOL .GT. 0.0E0) GO TO 160 + ATOLI = ATOL(1) + DO 150 I = 1,N + IF (ITOL .EQ. 2 .OR. ITOL .EQ. 4) ATOLI = ATOL(I) + AYI = ABS(Y(I)) + IF (AYI .NE. 0.0E0) TOL = MAX(TOL,ATOLI/AYI) + 150 CONTINUE + 160 TOL = MAX(TOL,100.0E0*UROUND) + TOL = MIN(TOL,0.001E0) + SUM = SVNORM (N, RWORK(LF0), RWORK(LEWT)) + SUM = 1.0E0/(TOL*W0*W0) + TOL*SUM**2 + H0 = 1.0E0/SQRT(SUM) + H0 = MIN(H0,TDIST) + H0 = SIGN(H0,TOUT-T) +C Adjust H0 if necessary to meet HMAX bound. --------------------------- + 180 RH = ABS(H0)*HMXI + IF (RH .GT. 1.0E0) H0 = H0/RH +C Load H with H0 and scale YH(*,2) by H0. ------------------------------ + H = H0 + DO 190 I = 1,N + 190 RWORK(I+LF0-1) = H0*RWORK(I+LF0-1) + GO TO 270 +C----------------------------------------------------------------------- +C Block D. +C The next code block is for continuation calls only (ISTATE = 2 or 3) +C and is to check stop conditions before taking a step. +C----------------------------------------------------------------------- + 200 NSLAST = NST + GO TO (210, 250, 220, 230, 240), ITASK + 210 IF ((TN - TOUT)*H .LT. 0.0E0) GO TO 250 + CALL SINTDY (TOUT, 0, RWORK(LYH), NYH, Y, IFLAG) + IF (IFLAG .NE. 0) GO TO 627 + T = TOUT + GO TO 420 + 220 TP = TN - HU*(1.0E0 + 100.0E0*UROUND) + IF ((TP - TOUT)*H .GT. 0.0E0) GO TO 623 + IF ((TN - TOUT)*H .LT. 0.0E0) GO TO 250 + GO TO 400 + 230 TCRIT = RWORK(1) + IF ((TN - TCRIT)*H .GT. 0.0E0) GO TO 624 + IF ((TCRIT - TOUT)*H .LT. 0.0E0) GO TO 625 + IF ((TN - TOUT)*H .LT. 0.0E0) GO TO 245 + CALL SINTDY (TOUT, 0, RWORK(LYH), NYH, Y, IFLAG) + IF (IFLAG .NE. 0) GO TO 627 + T = TOUT + GO TO 420 + 240 TCRIT = RWORK(1) + IF ((TN - TCRIT)*H .GT. 0.0E0) GO TO 624 + 245 HMX = ABS(TN) + ABS(H) + IHIT = ABS(TN - TCRIT) .LE. 100.0E0*UROUND*HMX + IF (IHIT) GO TO 400 + TNEXT = TN + H*(1.0E0 + 4.0E0*UROUND) + IF ((TNEXT - TCRIT)*H .LE. 0.0E0) GO TO 250 + H = (TCRIT - TN)*(1.0E0 - 4.0E0*UROUND) + IF (ISTATE .EQ. 2) JSTART = -2 +C----------------------------------------------------------------------- +C Block E. +C The next block is normally executed for all calls and contains +C the call to the one-step core integrator SSTODE. +C +C This is a looping point for the integration steps. +C +C First check for too many steps being taken, update EWT (if not at +C start of problem), check for too much accuracy being requested, and +C check for H below the roundoff level in T. +C----------------------------------------------------------------------- + 250 CONTINUE + IF ((NST-NSLAST) .GE. MXSTEP) GO TO 500 + CALL SEWSET (N, ITOL, RTOL, ATOL, RWORK(LYH), RWORK(LEWT)) + DO 260 I = 1,N + IF (RWORK(I+LEWT-1) .LE. 0.0E0) GO TO 510 + 260 RWORK(I+LEWT-1) = 1.0E0/RWORK(I+LEWT-1) + 270 TOLSF = UROUND*SVNORM (N, RWORK(LYH), RWORK(LEWT)) + IF (TOLSF .LE. 1.0E0) GO TO 280 + TOLSF = TOLSF*2.0E0 + IF (NST .EQ. 0) GO TO 626 + GO TO 520 + 280 IF ((TN + H) .NE. TN) GO TO 290 + NHNIL = NHNIL + 1 + IF (NHNIL .GT. MXHNIL) GO TO 290 + MSG = 'SLSODE- Warning..internal T (=R1) and H (=R2) are' + CALL XERRWV (MSG, 50, 101, 0, 0, 0, 0, 0, 0.0E0, 0.0E0) + MSG=' such that in the machine, T + H = T on the next step ' + CALL XERRWV (MSG, 60, 101, 0, 0, 0, 0, 0, 0.0E0, 0.0E0) + MSG = ' (H = step size). Solver will continue anyway' + CALL XERRWV (MSG, 50, 101, 0, 0, 0, 0, 2, TN, H) + IF (NHNIL .LT. MXHNIL) GO TO 290 + MSG = 'SLSODE- Above warning has been issued I1 times. ' + CALL XERRWV (MSG, 50, 102, 0, 0, 0, 0, 0, 0.0E0, 0.0E0) + MSG = ' It will not be issued again for this problem' + CALL XERRWV (MSG, 50, 102, 0, 1, MXHNIL, 0, 0, 0.0E0, 0.0E0) + 290 CONTINUE +C----------------------------------------------------------------------- +C CALL SSTODE(NEQ,Y,YH,NYH,YH,EWT,SAVF,ACOR,WM,IWM,F,JAC,SPREPJ,SSOLSY) +C----------------------------------------------------------------------- + CALL SSTODE (NEQ, Y, RWORK(LYH), NYH, RWORK(LYH), RWORK(LEWT), + 1 RWORK(LSAVF), RWORK(LACOR), RWORK(LWM), IWORK(LIWM), + 2 F, JAC, SPREPJ, SSOLSY) + KGO = 1 - KFLAG + GO TO (300, 530, 540), KGO +C----------------------------------------------------------------------- +C Block F. +C The following block handles the case of a successful return from the +C core integrator (KFLAG = 0). Test for stop conditions. +C----------------------------------------------------------------------- + 300 INIT = 1 + GO TO (310, 400, 330, 340, 350), ITASK +C ITASK = 1. If TOUT has been reached, interpolate. ------------------- + 310 IF ((TN - TOUT)*H .LT. 0.0E0) GO TO 250 + CALL SINTDY (TOUT, 0, RWORK(LYH), NYH, Y, IFLAG) + T = TOUT + GO TO 420 +C ITASK = 3. Jump to exit if TOUT was reached. ------------------------ + 330 IF ((TN - TOUT)*H .GE. 0.0E0) GO TO 400 + GO TO 250 +C ITASK = 4. See if TOUT or TCRIT was reached. Adjust H if necessary. + 340 IF ((TN - TOUT)*H .LT. 0.0E0) GO TO 345 + CALL SINTDY (TOUT, 0, RWORK(LYH), NYH, Y, IFLAG) + T = TOUT + GO TO 420 + 345 HMX = ABS(TN) + ABS(H) + IHIT = ABS(TN - TCRIT) .LE. 100.0E0*UROUND*HMX + IF (IHIT) GO TO 400 + TNEXT = TN + H*(1.0E0 + 4.0E0*UROUND) + IF ((TNEXT - TCRIT)*H .LE. 0.0E0) GO TO 250 + H = (TCRIT - TN)*(1.0E0 - 4.0E0*UROUND) + JSTART = -2 + GO TO 250 +C ITASK = 5. See if TCRIT was reached and jump to exit. --------------- + 350 HMX = ABS(TN) + ABS(H) + IHIT = ABS(TN - TCRIT) .LE. 100.0E0*UROUND*HMX +C----------------------------------------------------------------------- +C Block G. +C The following block handles all successful returns from SLSODE. +C If ITASK .NE. 1, Y is loaded from YH and T is set accordingly. +C ISTATE is set to 2, and the optional outputs are loaded into the +C work arrays before returning. +C----------------------------------------------------------------------- + 400 DO 410 I = 1,N + 410 Y(I) = RWORK(I+LYH-1) + T = TN + IF (ITASK .NE. 4 .AND. ITASK .NE. 5) GO TO 420 + IF (IHIT) T = TCRIT + 420 ISTATE = 2 + RWORK(11) = HU + RWORK(12) = H + RWORK(13) = TN + IWORK(11) = NST + IWORK(12) = NFE + IWORK(13) = NJE + IWORK(14) = NQU + IWORK(15) = NQ + RETURN +C----------------------------------------------------------------------- +C Block H. +C The following block handles all unsuccessful returns other than +C those for illegal input. First the error message routine is called. +C If there was an error test or convergence test failure, IMXER is set. +C Then Y is loaded from YH and T is set to TN. The optional outputs +C are loaded into the work arrays before returning. +C----------------------------------------------------------------------- +C The maximum number of steps was taken before reaching TOUT. ---------- + 500 MSG = 'SLSODE- At current T (=R1), MXSTEP (=I1) steps ' + CALL XERRWV (MSG, 50, 201, 0, 0, 0, 0, 0, 0.0E0, 0.0E0) + MSG = ' taken on this call before reaching TOUT ' + CALL XERRWV (MSG, 50, 201, 0, 1, MXSTEP, 0, 1, TN, 0.0E0) + ISTATE = -1 + GO TO 580 +C EWT(I) .LE. 0.0 for some I (not at start of problem). ---------------- + 510 EWTI = RWORK(LEWT+I-1) + MSG = 'SLSODE- At T (=R1), EWT(I1) has become R2 .LE. 0.' + CALL XERRWV (MSG, 50, 202, 0, 1, I, 0, 2, TN, EWTI) + ISTATE = -6 + GO TO 580 +C Too much accuracy requested for machine precision. ------------------- + 520 MSG = 'SLSODE- At T (=R1), too much accuracy requested ' + CALL XERRWV (MSG, 50, 203, 0, 0, 0, 0, 0, 0.0E0, 0.0E0) + MSG = ' for precision of machine.. see TOLSF (=R2) ' + CALL XERRWV (MSG, 50, 203, 0, 0, 0, 0, 2, TN, TOLSF) + RWORK(14) = TOLSF + ISTATE = -2 + GO TO 580 +C KFLAG = -1. Error test failed repeatedly or with ABS(H) = HMIN. ----- + 530 MSG = 'SLSODE- At T(=R1) and step size H(=R2), the error' + CALL XERRWV (MSG, 50, 204, 0, 0, 0, 0, 0, 0.0E0, 0.0E0) + MSG = ' test failed repeatedly or with ABS(H) = HMIN' + CALL XERRWV (MSG, 50, 204, 0, 0, 0, 0, 2, TN, H) + ISTATE = -4 + GO TO 560 +C KFLAG = -2. Convergence failed repeatedly or with ABS(H) = HMIN. ---- + 540 MSG = 'SLSODE- At T (=R1) and step size H (=R2), the ' + CALL XERRWV (MSG, 50, 205, 0, 0, 0, 0, 0, 0.0E0, 0.0E0) + MSG = ' corrector convergence failed repeatedly ' + CALL XERRWV (MSG, 50, 205, 0, 0, 0, 0, 0, 0.0E0, 0.0E0) + MSG = ' or with ABS(H) = HMIN ' + CALL XERRWV (MSG, 30, 205, 0, 0, 0, 0, 2, TN, H) + ISTATE = -5 +C Compute IMXER if relevant. ------------------------------------------- + 560 BIG = 0.0E0 + IMXER = 1 + DO 570 I = 1,N + SIZE = ABS(RWORK(I+LACOR-1)*RWORK(I+LEWT-1)) + IF (BIG .GE. SIZE) GO TO 570 + BIG = SIZE + IMXER = I + 570 CONTINUE + IWORK(16) = IMXER +C Set Y vector, T, and optional outputs. ------------------------------- + 580 DO 590 I = 1,N + 590 Y(I) = RWORK(I+LYH-1) + T = TN + RWORK(11) = HU + RWORK(12) = H + RWORK(13) = TN + IWORK(11) = NST + IWORK(12) = NFE + IWORK(13) = NJE + IWORK(14) = NQU + IWORK(15) = NQ + RETURN +C----------------------------------------------------------------------- +C Block I. +C The following block handles all error returns due to illegal input +C (ISTATE = -3), as detected before calling the core integrator. +C First the error message routine is called. If the illegal input +C is a negative ISTATE, the run is aborted (apparent infinite loop). +C----------------------------------------------------------------------- + 601 MSG = 'SLSODE- ISTATE (=I1) illegal ' + CALL XERRWV (MSG, 30, 1, 0, 1, ISTATE, 0, 0, 0.0E0, 0.0E0) + IF (ISTATE .LT. 0) GO TO 800 + GO TO 700 + 602 MSG = 'SLSODE- ITASK (=I1) illegal ' + CALL XERRWV (MSG, 30, 2, 0, 1, ITASK, 0, 0, 0.0E0, 0.0E0) + GO TO 700 + 603 MSG = 'SLSODE- ISTATE .GT. 1 but SLSODE not initialized ' + CALL XERRWV (MSG, 50, 3, 0, 0, 0, 0, 0, 0.0E0, 0.0E0) + GO TO 700 + 604 MSG = 'SLSODE- NEQ (=I1) .LT. 1 ' + CALL XERRWV (MSG, 30, 4, 0, 1, NEQ(1), 0, 0, 0.0E0, 0.0E0) + GO TO 700 + 605 MSG = 'SLSODE- ISTATE = 3 and NEQ increased (I1 to I2) ' + CALL XERRWV (MSG, 50, 5, 0, 2, N, NEQ(1), 0, 0.0E0, 0.0E0) + GO TO 700 + 606 MSG = 'SLSODE- ITOL (=I1) illegal ' + CALL XERRWV (MSG, 30, 6, 0, 1, ITOL, 0, 0, 0.0E0, 0.0E0) + GO TO 700 + 607 MSG = 'SLSODE- IOPT (=I1) illegal ' + CALL XERRWV (MSG, 30, 7, 0, 1, IOPT, 0, 0, 0.0E0, 0.0E0) + GO TO 700 + 608 MSG = 'SLSODE- MF (=I1) illegal ' + CALL XERRWV (MSG, 30, 8, 0, 1, MF, 0, 0, 0.0E0, 0.0E0) + GO TO 700 + 609 MSG = 'SLSODE- ML (=I1) illegal.. .LT.0 or .GE.NEQ (=I2)' + CALL XERRWV (MSG, 50, 9, 0, 2, ML, NEQ(1), 0, 0.0E0, 0.0E0) + GO TO 700 + 610 MSG = 'SLSODE- MU (=I1) illegal.. .LT.0 or .GE.NEQ (=I2)' + CALL XERRWV (MSG, 50, 10, 0, 2, MU, NEQ(1), 0, 0.0E0, 0.0E0) + GO TO 700 + 611 MSG = 'SLSODE- MAXORD (=I1) .LT. 0 ' + CALL XERRWV (MSG, 30, 11, 0, 1, MAXORD, 0, 0, 0.0E0, 0.0E0) + GO TO 700 + 612 MSG = 'SLSODE- MXSTEP (=I1) .LT. 0 ' + CALL XERRWV (MSG, 30, 12, 0, 1, MXSTEP, 0, 0, 0.0E0, 0.0E0) + GO TO 700 + 613 MSG = 'SLSODE- MXHNIL (=I1) .LT. 0 ' + CALL XERRWV (MSG, 30, 13, 0, 1, MXHNIL, 0, 0, 0.0E0, 0.0E0) + GO TO 700 + 614 MSG = 'SLSODE- TOUT (=R1) behind T (=R2) ' + CALL XERRWV (MSG, 40, 14, 0, 0, 0, 0, 2, TOUT, T) + MSG = ' Integration direction is given by H0 (=R1) ' + CALL XERRWV (MSG, 50, 14, 0, 0, 0, 0, 1, H0, 0.0E0) + GO TO 700 + 615 MSG = 'SLSODE- HMAX (=R1) .LT. 0.0 ' + CALL XERRWV (MSG, 30, 15, 0, 0, 0, 0, 1, HMAX, 0.0E0) + GO TO 700 + 616 MSG = 'SLSODE- HMIN (=R1) .LT. 0.0 ' + CALL XERRWV (MSG, 30, 16, 0, 0, 0, 0, 1, HMIN, 0.0E0) + GO TO 700 + 617 CONTINUE + MSG='SLSODE- RWORK length needed, LENRW (=I1), exceeds LRW (=I2)' + CALL XERRWV (MSG, 60, 17, 0, 2, LENRW, LRW, 0, 0.0E0, 0.0E0) + GO TO 700 + 618 CONTINUE + MSG='SLSODE- IWORK length needed, LENIW (=I1), exceeds LIW (=I2)' + CALL XERRWV (MSG, 60, 18, 0, 2, LENIW, LIW, 0, 0.0E0, 0.0E0) + GO TO 700 + 619 MSG = 'SLSODE- RTOL(I1) is R1 .LT. 0.0 ' + CALL XERRWV (MSG, 40, 19, 0, 1, I, 0, 1, RTOLI, 0.0E0) + GO TO 700 + 620 MSG = 'SLSODE- ATOL(I1) is R1 .LT. 0.0 ' + CALL XERRWV (MSG, 40, 20, 0, 1, I, 0, 1, ATOLI, 0.0E0) + GO TO 700 + 621 EWTI = RWORK(LEWT+I-1) + MSG = 'SLSODE- EWT(I1) is R1 .LE. 0.0 ' + CALL XERRWV (MSG, 40, 21, 0, 1, I, 0, 1, EWTI, 0.0E0) + GO TO 700 + 622 CONTINUE + MSG='SLSODE- TOUT (=R1) too close to T(=R2) to start integration' + CALL XERRWV (MSG, 60, 22, 0, 0, 0, 0, 2, TOUT, T) + GO TO 700 + 623 CONTINUE + MSG='SLSODE- ITASK = I1 and TOUT (=R1) behind TCUR - HU (= R2) ' + CALL XERRWV (MSG, 60, 23, 0, 1, ITASK, 0, 2, TOUT, TP) + GO TO 700 + 624 CONTINUE + MSG='SLSODE- ITASK = 4 OR 5 and TCRIT (=R1) behind TCUR (=R2) ' + CALL XERRWV (MSG, 60, 24, 0, 0, 0, 0, 2, TCRIT, TN) + GO TO 700 + 625 CONTINUE + MSG='SLSODE- ITASK = 4 or 5 and TCRIT (=R1) behind TOUT (=R2) ' + CALL XERRWV (MSG, 60, 25, 0, 0, 0, 0, 2, TCRIT, TOUT) + GO TO 700 + 626 MSG = 'SLSODE- At start of problem, too much accuracy ' + CALL XERRWV (MSG, 50, 26, 0, 0, 0, 0, 0, 0.0E0, 0.0E0) + MSG=' requested for precision of machine.. See TOLSF (=R1) ' + CALL XERRWV (MSG, 60, 26, 0, 0, 0, 0, 1, TOLSF, 0.0E0) + RWORK(14) = TOLSF + GO TO 700 + 627 MSG = 'SLSODE- Trouble in SINTDY. ITASK = I1, TOUT = R1' + CALL XERRWV (MSG, 50, 27, 0, 1, ITASK, 0, 1, TOUT, 0.0E0) +C + 700 ISTATE = -3 + RETURN +C + 800 MSG = 'SLSODE- Run aborted.. apparent infinite loop ' + CALL XERRWV (MSG, 50, 303, 2, 0, 0, 0, 0, 0.0E0, 0.0E0) + RETURN +C----------------------- END OF SUBROUTINE SLSODE ---------------------- + END diff --git a/libcruft/odepack/sprepj.f b/libcruft/odepack/sprepj.f new file mode 100644 --- /dev/null +++ b/libcruft/odepack/sprepj.f @@ -0,0 +1,193 @@ + SUBROUTINE SPREPJ (NEQ, Y, YH, NYH, EWT, FTEM, SAVF, WM, IWM, + 1 F, JAC) +C***BEGIN PROLOGUE SPREPJ +C***SUBSIDIARY +C***PURPOSE Compute and process Newton iteration matrix. +C***TYPE SINGLE PRECISION (SPREPJ-S, DPREPJ-D) +C***AUTHOR Hindmarsh, Alan C., (LLNL) +C***DESCRIPTION +C +C SPREPJ is called by SSTODE to compute and process the matrix +C P = I - h*el(1)*J , where J is an approximation to the Jacobian. +C Here J is computed by the user-supplied routine JAC if +C MITER = 1 or 4, or by finite differencing if MITER = 2, 3, or 5. +C If MITER = 3, a diagonal approximation to J is used. +C J is stored in WM and replaced by P. If MITER .ne. 3, P is then +C subjected to LU decomposition in preparation for later solution +C of linear systems with P as coefficient matrix. This is done +C by SGETRF if MITER = 1 or 2, and by SGBTRF if MITER = 4 or 5. +C +C In addition to variables described in SSTODE and SLSODE prologues, +C communication with SPREPJ uses the following: +C Y = array containing predicted values on entry. +C FTEM = work array of length N (ACOR in SSTODE). +C SAVF = array containing f evaluated at predicted y. +C WM = real work space for matrices. On output it contains the +C inverse diagonal matrix if MITER = 3 and the LU decomposition +C of P if MITER is 1, 2 , 4, or 5. +C Storage of matrix elements starts at WM(3). +C WM also contains the following matrix-related data: +C WM(1) = SQRT(UROUND), used in numerical Jacobian increments. +C WM(2) = H*EL0, saved for later use if MITER = 3. +C IWM = integer work space containing pivot information, starting at +C IWM(21), if MITER is 1, 2, 4, or 5. IWM also contains band +C parameters ML = IWM(1) and MU = IWM(2) if MITER is 4 or 5. +C EL0 = EL(1) (input). +C IERPJ = output error flag, = 0 if no trouble, .gt. 0 if +C P matrix found to be singular. +C JCUR = output flag = 1 to indicate that the Jacobian matrix +C (or approximation) is now current. +C This routine also uses the COMMON variables EL0, H, TN, UROUND, +C MITER, N, NFE, and NJE. +C +C***SEE ALSO SLSODE +C***ROUTINES CALLED SGBTRF, SGETRF, SVNORM +C***COMMON BLOCKS SLS001 +C***REVISION HISTORY (YYMMDD) +C 791129 DATE WRITTEN +C 890501 Modified prologue to SLATEC/LDOC format. (FNF) +C 890504 Minor cosmetic changes. (FNF) +C 930809 Renamed to allow single/double precision versions. (ACH) +C 010412 Reduced size of Common block /SLS001/. (ACH) +C 031105 Restored 'own' variables to Common block /SLS001/, to +C enable interrupt/restart feature. (ACH) +C***END PROLOGUE SPREPJ +C**End + EXTERNAL F, JAC + INTEGER NEQ, NYH, IWM + REAL Y, YH, EWT, FTEM, SAVF, WM + DIMENSION NEQ(*), Y(*), YH(NYH,*), EWT(*), FTEM(*), SAVF(*), + 1 WM(*), IWM(*) + INTEGER IOWND, IOWNS, + 1 ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, + 2 LYH, LEWT, LACOR, LSAVF, LWM, LIWM, METH, MITER, + 3 MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU + REAL ROWNS, + 1 CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND + COMMON /SLS001/ ROWNS(209), + 1 CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND, + 2 IOWND(6), IOWNS(6), + 3 ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, + 4 LYH, LEWT, LACOR, LSAVF, LWM, LIWM, METH, MITER, + 5 MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU + INTEGER I, I1, I2, IER, II, J, J1, JJ, LENP, + 1 MBA, MBAND, MEB1, MEBAND, ML, ML3, MU, NP1 + REAL CON, DI, FAC, HL0, R, R0, SRUR, YI, YJ, YJJ, + 1 SVNORM +C +C***FIRST EXECUTABLE STATEMENT SPREPJ + NJE = NJE + 1 + IERPJ = 0 + JCUR = 1 + HL0 = H*EL0 + GO TO (100, 200, 300, 400, 500), MITER +C If MITER = 1, call JAC and multiply by scalar. ----------------------- + 100 LENP = N*N + DO 110 I = 1,LENP + 110 WM(I+2) = 0.0E0 + CALL JAC (NEQ, TN, Y, 0, 0, WM(3), N) + CON = -HL0 + DO 120 I = 1,LENP + 120 WM(I+2) = WM(I+2)*CON + GO TO 240 +C If MITER = 2, make N calls to F to approximate J. -------------------- + 200 FAC = SVNORM (N, SAVF, EWT) + R0 = 1000.0E0*ABS(H)*UROUND*N*FAC + IF (R0 .EQ. 0.0E0) R0 = 1.0E0 + SRUR = WM(1) + J1 = 2 + DO 230 J = 1,N + YJ = Y(J) + R = MAX(SRUR*ABS(YJ),R0/EWT(J)) + Y(J) = Y(J) + R + FAC = -HL0/R + CALL F (NEQ, TN, Y, FTEM) + DO 220 I = 1,N + 220 WM(I+J1) = (FTEM(I) - SAVF(I))*FAC + Y(J) = YJ + J1 = J1 + N + 230 CONTINUE + NFE = NFE + N +C Add identity matrix. ------------------------------------------------- + 240 J = 3 + NP1 = N + 1 + DO 250 I = 1,N + WM(J) = WM(J) + 1.0E0 + 250 J = J + NP1 +C Do LU decomposition on P. -------------------------------------------- + CALL SGETRF (N, N, WM(3), N, IWM(21), IER) + IF (IER .NE. 0) IERPJ = 1 + RETURN +C If MITER = 3, construct a diagonal approximation to J and P. --------- + 300 WM(2) = HL0 + R = EL0*0.1E0 + DO 310 I = 1,N + 310 Y(I) = Y(I) + R*(H*SAVF(I) - YH(I,2)) + CALL F (NEQ, TN, Y, WM(3)) + NFE = NFE + 1 + DO 320 I = 1,N + R0 = H*SAVF(I) - YH(I,2) + DI = 0.1E0*R0 - H*(WM(I+2) - SAVF(I)) + WM(I+2) = 1.0E0 + IF (ABS(R0) .LT. UROUND/EWT(I)) GO TO 320 + IF (ABS(DI) .EQ. 0.0E0) GO TO 330 + WM(I+2) = 0.1E0*R0/DI + 320 CONTINUE + RETURN + 330 IERPJ = 1 + RETURN +C If MITER = 4, call JAC and multiply by scalar. ----------------------- + 400 ML = IWM(1) + MU = IWM(2) + ML3 = ML + 3 + MBAND = ML + MU + 1 + MEBAND = MBAND + ML + LENP = MEBAND*N + DO 410 I = 1,LENP + 410 WM(I+2) = 0.0E0 + CALL JAC (NEQ, TN, Y, ML, MU, WM(ML3), MEBAND) + CON = -HL0 + DO 420 I = 1,LENP + 420 WM(I+2) = WM(I+2)*CON + GO TO 570 +C If MITER = 5, make MBAND calls to F to approximate J. ---------------- + 500 ML = IWM(1) + MU = IWM(2) + MBAND = ML + MU + 1 + MBA = MIN(MBAND,N) + MEBAND = MBAND + ML + MEB1 = MEBAND - 1 + SRUR = WM(1) + FAC = SVNORM (N, SAVF, EWT) + R0 = 1000.0E0*ABS(H)*UROUND*N*FAC + IF (R0 .EQ. 0.0E0) R0 = 1.0E0 + DO 560 J = 1,MBA + DO 530 I = J,N,MBAND + YI = Y(I) + R = MAX(SRUR*ABS(YI),R0/EWT(I)) + 530 Y(I) = Y(I) + R + CALL F (NEQ, TN, Y, FTEM) + DO 550 JJ = J,N,MBAND + Y(JJ) = YH(JJ,1) + YJJ = Y(JJ) + R = MAX(SRUR*ABS(YJJ),R0/EWT(JJ)) + FAC = -HL0/R + I1 = MAX(JJ-MU,1) + I2 = MIN(JJ+ML,N) + II = JJ*MEB1 - ML + 2 + DO 540 I = I1,I2 + 540 WM(II+I) = (FTEM(I) - SAVF(I))*FAC + 550 CONTINUE + 560 CONTINUE + NFE = NFE + MBA +C Add identity matrix. ------------------------------------------------- + 570 II = MBAND + 2 + DO 580 I = 1,N + WM(II) = WM(II) + 1.0E0 + 580 II = II + MEBAND +C Do LU decomposition of P. -------------------------------------------- + CALL SGBTRF ( N, N, ML, MU, WM(3), MEBAND, IWM(21), IER) + IF (IER .NE. 0) IERPJ = 1 + RETURN +C----------------------- END OF SUBROUTINE SPREPJ ---------------------- + END diff --git a/libcruft/odepack/ssolsy.f b/libcruft/odepack/ssolsy.f new file mode 100644 --- /dev/null +++ b/libcruft/odepack/ssolsy.f @@ -0,0 +1,91 @@ + SUBROUTINE SSOLSY (WM, IWM, X, TEM) +C***BEGIN PROLOGUE SSOLSY +C***SUBSIDIARY +C***PURPOSE ODEPACK linear system solver. +C***TYPE SINGLE PRECISION (SSOLSY-S, DSOLSY-D) +C***AUTHOR Hindmarsh, Alan C., (LLNL) +C***DESCRIPTION +C +C This routine manages the solution of the linear system arising from +C a chord iteration. It is called if MITER .ne. 0. +C If MITER is 1 or 2, it calls SGETRF to accomplish this. +C If MITER = 3 it updates the coefficient h*EL0 in the diagonal +C matrix, and then computes the solution. +C If MITER is 4 or 5, it calls SGBTRS. +C Communication with SSOLSY uses the following variables: +C WM = real work space containing the inverse diagonal matrix if +C MITER = 3 and the LU decomposition of the matrix otherwise. +C Storage of matrix elements starts at WM(3). +C WM also contains the following matrix-related data: +C WM(1) = SQRT(UROUND) (not used here), +C WM(2) = HL0, the previous value of h*EL0, used if MITER = 3. +C IWM = integer work space containing pivot information, starting at +C IWM(21), if MITER is 1, 2, 4, or 5. IWM also contains band +C parameters ML = IWM(1) and MU = IWM(2) if MITER is 4 or 5. +C X = the right-hand side vector on input, and the solution vector +C on output, of length N. +C TEM = vector of work space of length N, not used in this version. +C IERSL = output flag (in COMMON). IERSL = 0 if no trouble occurred. +C IERSL = 1 if a singular matrix arose with MITER = 3. +C This routine also uses the COMMON variables EL0, H, MITER, and N. +C +C***SEE ALSO SLSODE +C***ROUTINES CALLED SGBTRS, SGETRS +C***COMMON BLOCKS SLS001 +C***REVISION HISTORY (YYMMDD) +C 791129 DATE WRITTEN +C 890501 Modified prologue to SLATEC/LDOC format. (FNF) +C 890503 Minor cosmetic changes. (FNF) +C 930809 Renamed to allow single/double precision versions. (ACH) +C 010412 Reduced size of Common block /SLS001/. (ACH) +C 031105 Restored 'own' variables to Common block /SLS001/, to +C enable interrupt/restart feature. (ACH) +C***END PROLOGUE SSOLSY +C**End + INTEGER IWM + REAL WM, X, TEM + DIMENSION WM(*), IWM(*), X(*), TEM(*) + INTEGER IOWND, IOWNS, + 1 ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, + 2 LYH, LEWT, LACOR, LSAVF, LWM, LIWM, METH, MITER, + 3 MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU + REAL ROWNS, + 1 CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND + COMMON /SLS001/ ROWNS(209), + 1 CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND, + 2 IOWND(6), IOWNS(6), + 3 ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, + 4 LYH, LEWT, LACOR, LSAVF, LWM, LIWM, METH, MITER, + 5 MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU + INTEGER I, MEBAND, ML, MU + REAL DI, HL0, PHL0, R +C +C***FIRST EXECUTABLE STATEMENT SSOLSY + IERSL = 0 + GO TO (100, 100, 300, 400, 400), MITER + 100 CALL SGETRS ( 'N', N, 1, WM(3), N, IWM(21), X, N, INLPCK) + RETURN +C + 300 PHL0 = WM(2) + HL0 = H*EL0 + WM(2) = HL0 + IF (HL0 .EQ. PHL0) GO TO 330 + R = HL0/PHL0 + DO 320 I = 1,N + DI = 1.0E0 - R*(1.0E0 - 1.0E0/WM(I+2)) + IF (ABS(DI) .EQ. 0.0E0) GO TO 390 + 320 WM(I+2) = 1.0E0/DI + 330 DO 340 I = 1,N + 340 X(I) = WM(I+2)*X(I) + RETURN + 390 IERSL = 1 + RETURN +C + 400 ML = IWM(1) + MU = IWM(2) + MEBAND = 2*ML + MU + 1 + CALL SGBTRS ( 'N', N, ML, MU, 1, WM(3), MEBAND, IWM(21), X, N, + * INLPCK) + RETURN +C----------------------- END OF SUBROUTINE SSOLSY ---------------------- + END diff --git a/libcruft/odepack/sstode.f b/libcruft/odepack/sstode.f new file mode 100644 --- /dev/null +++ b/libcruft/odepack/sstode.f @@ -0,0 +1,497 @@ + SUBROUTINE SSTODE (NEQ, Y, YH, NYH, YH1, EWT, SAVF, ACOR, + 1 WM, IWM, F, JAC, PJAC, SLVS) +C***BEGIN PROLOGUE SSTODE +C***SUBSIDIARY +C***PURPOSE Performs one step of an ODEPACK integration. +C***TYPE SINGLE PRECISION (SSTODE-S, DSTODE-D) +C***AUTHOR Hindmarsh, Alan C., (LLNL) +C***DESCRIPTION +C +C SSTODE performs one step of the integration of an initial value +C problem for a system of ordinary differential equations. +C Note: SSTODE is independent of the value of the iteration method +C indicator MITER, when this is .ne. 0, and hence is independent +C of the type of chord method used, or the Jacobian structure. +C Communication with SSTODE is done with the following variables: +C +C NEQ = integer array containing problem size in NEQ(1), and +C passed as the NEQ argument in all calls to F and JAC. +C Y = an array of length .ge. N used as the Y argument in +C all calls to F and JAC. +C YH = an NYH by LMAX array containing the dependent variables +C and their approximate scaled derivatives, where +C LMAX = MAXORD + 1. YH(i,j+1) contains the approximate +C j-th derivative of y(i), scaled by h**j/factorial(j) +C (j = 0,1,...,NQ). on entry for the first step, the first +C two columns of YH must be set from the initial values. +C NYH = a constant integer .ge. N, the first dimension of YH. +C YH1 = a one-dimensional array occupying the same space as YH. +C EWT = an array of length N containing multiplicative weights +C for local error measurements. Local errors in Y(i) are +C compared to 1.0/EWT(i) in various error tests. +C SAVF = an array of working storage, of length N. +C Also used for input of YH(*,MAXORD+2) when JSTART = -1 +C and MAXORD .lt. the current order NQ. +C ACOR = a work array of length N, used for the accumulated +C corrections. On a successful return, ACOR(i) contains +C the estimated one-step local error in Y(i). +C WM,IWM = real and integer work arrays associated with matrix +C operations in chord iteration (MITER .ne. 0). +C PJAC = name of routine to evaluate and preprocess Jacobian matrix +C and P = I - h*el0*JAC, if a chord method is being used. +C SLVS = name of routine to solve linear system in chord iteration. +C CCMAX = maximum relative change in h*el0 before PJAC is called. +C H = the step size to be attempted on the next step. +C H is altered by the error control algorithm during the +C problem. H can be either positive or negative, but its +C sign must remain constant throughout the problem. +C HMIN = the minimum absolute value of the step size h to be used. +C HMXI = inverse of the maximum absolute value of h to be used. +C HMXI = 0.0 is allowed and corresponds to an infinite hmax. +C HMIN and HMXI may be changed at any time, but will not +C take effect until the next change of h is considered. +C TN = the independent variable. TN is updated on each step taken. +C JSTART = an integer used for input only, with the following +C values and meanings: +C 0 perform the first step. +C .gt.0 take a new step continuing from the last. +C -1 take the next step with a new value of H, MAXORD, +C N, METH, MITER, and/or matrix parameters. +C -2 take the next step with a new value of H, +C but with other inputs unchanged. +C On return, JSTART is set to 1 to facilitate continuation. +C KFLAG = a completion code with the following meanings: +C 0 the step was succesful. +C -1 the requested error could not be achieved. +C -2 corrector convergence could not be achieved. +C -3 fatal error in PJAC or SLVS. +C A return with KFLAG = -1 or -2 means either +C abs(H) = HMIN or 10 consecutive failures occurred. +C On a return with KFLAG negative, the values of TN and +C the YH array are as of the beginning of the last +C step, and H is the last step size attempted. +C MAXORD = the maximum order of integration method to be allowed. +C MAXCOR = the maximum number of corrector iterations allowed. +C MSBP = maximum number of steps between PJAC calls (MITER .gt. 0). +C MXNCF = maximum number of convergence failures allowed. +C METH/MITER = the method flags. See description in driver. +C N = the number of first-order differential equations. +C The values of CCMAX, H, HMIN, HMXI, TN, JSTART, KFLAG, MAXORD, +C MAXCOR, MSBP, MXNCF, METH, MITER, and N are communicated via COMMON. +C +C***SEE ALSO SLSODE +C***ROUTINES CALLED SCFODE, SVNORM +C***COMMON BLOCKS SLS001 +C***REVISION HISTORY (YYMMDD) +C 791129 DATE WRITTEN +C 890501 Modified prologue to SLATEC/LDOC format. (FNF) +C 890503 Minor cosmetic changes. (FNF) +C 930809 Renamed to allow single/double precision versions. (ACH) +C 010413 Reduced size of Common block /SLS001/. (ACH) +C 031105 Restored 'own' variables to Common block /SLS001/, to +C enable interrupt/restart feature. (ACH) +C***END PROLOGUE SSTODE +C**End + EXTERNAL F, JAC, PJAC, SLVS + INTEGER NEQ, NYH, IWM + REAL Y, YH, YH1, EWT, SAVF, ACOR, WM + DIMENSION NEQ(*), Y(*), YH(NYH,*), YH1(*), EWT(*), SAVF(*), + 1 ACOR(*), WM(*), IWM(*) + INTEGER IOWND, IALTH, IPUP, LMAX, MEO, NQNYH, NSLP, + 1 ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, + 2 LYH, LEWT, LACOR, LSAVF, LWM, LIWM, METH, MITER, + 3 MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU + INTEGER I, I1, IREDO, IRET, J, JB, M, NCF, NEWQ + REAL CONIT, CRATE, EL, ELCO, HOLD, RMAX, TESCO, + 2 CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND + REAL DCON, DDN, DEL, DELP, DSM, DUP, EXDN, EXSM, EXUP, + 1 R, RH, RHDN, RHSM, RHUP, TOLD, SVNORM + COMMON /SLS001/ CONIT, CRATE, EL(13), ELCO(13,12), + 1 HOLD, RMAX, TESCO(3,12), + 2 CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND, + 3 IOWND(6), IALTH, IPUP, LMAX, MEO, NQNYH, NSLP, + 3 ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, + 4 LYH, LEWT, LACOR, LSAVF, LWM, LIWM, METH, MITER, + 5 MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU +C +C***FIRST EXECUTABLE STATEMENT SSTODE + KFLAG = 0 + TOLD = TN + NCF = 0 + IERPJ = 0 + IERSL = 0 + JCUR = 0 + ICF = 0 + DELP = 0.0E0 + IF (JSTART .GT. 0) GO TO 200 + IF (JSTART .EQ. -1) GO TO 100 + IF (JSTART .EQ. -2) GO TO 160 +C----------------------------------------------------------------------- +C On the first call, the order is set to 1, and other variables are +C initialized. RMAX is the maximum ratio by which H can be increased +C in a single step. It is initially 1.E4 to compensate for the small +C initial H, but then is normally equal to 10. If a failure +C occurs (in corrector convergence or error test), RMAX is set to 2 +C for the next increase. +C----------------------------------------------------------------------- + LMAX = MAXORD + 1 + NQ = 1 + L = 2 + IALTH = 2 + RMAX = 10000.0E0 + RC = 0.0E0 + EL0 = 1.0E0 + CRATE = 0.7E0 + HOLD = H + MEO = METH + NSLP = 0 + IPUP = MITER + IRET = 3 + GO TO 140 +C----------------------------------------------------------------------- +C The following block handles preliminaries needed when JSTART = -1. +C IPUP is set to MITER to force a matrix update. +C If an order increase is about to be considered (IALTH = 1), +C IALTH is reset to 2 to postpone consideration one more step. +C If the caller has changed METH, SCFODE is called to reset +C the coefficients of the method. +C If the caller has changed MAXORD to a value less than the current +C order NQ, NQ is reduced to MAXORD, and a new H chosen accordingly. +C If H is to be changed, YH must be rescaled. +C If H or METH is being changed, IALTH is reset to L = NQ + 1 +C to prevent further changes in H for that many steps. +C----------------------------------------------------------------------- + 100 IPUP = MITER + LMAX = MAXORD + 1 + IF (IALTH .EQ. 1) IALTH = 2 + IF (METH .EQ. MEO) GO TO 110 + CALL SCFODE (METH, ELCO, TESCO) + MEO = METH + IF (NQ .GT. MAXORD) GO TO 120 + IALTH = L + IRET = 1 + GO TO 150 + 110 IF (NQ .LE. MAXORD) GO TO 160 + 120 NQ = MAXORD + L = LMAX + DO 125 I = 1,L + 125 EL(I) = ELCO(I,NQ) + NQNYH = NQ*NYH + RC = RC*EL(1)/EL0 + EL0 = EL(1) + CONIT = 0.5E0/(NQ+2) + DDN = SVNORM (N, SAVF, EWT)/TESCO(1,L) + EXDN = 1.0E0/L + RHDN = 1.0E0/(1.3E0*DDN**EXDN + 0.0000013E0) + RH = MIN(RHDN,1.0E0) + IREDO = 3 + IF (H .EQ. HOLD) GO TO 170 + RH = MIN(RH,ABS(H/HOLD)) + H = HOLD + GO TO 175 +C----------------------------------------------------------------------- +C SCFODE is called to get all the integration coefficients for the +C current METH. Then the EL vector and related constants are reset +C whenever the order NQ is changed, or at the start of the problem. +C----------------------------------------------------------------------- + 140 CALL SCFODE (METH, ELCO, TESCO) + 150 DO 155 I = 1,L + 155 EL(I) = ELCO(I,NQ) + NQNYH = NQ*NYH + RC = RC*EL(1)/EL0 + EL0 = EL(1) + CONIT = 0.5E0/(NQ+2) + GO TO (160, 170, 200), IRET +C----------------------------------------------------------------------- +C If H is being changed, the H ratio RH is checked against +C RMAX, HMIN, and HMXI, and the YH array rescaled. IALTH is set to +C L = NQ + 1 to prevent a change of H for that many steps, unless +C forced by a convergence or error test failure. +C----------------------------------------------------------------------- + 160 IF (H .EQ. HOLD) GO TO 200 + RH = H/HOLD + H = HOLD + IREDO = 3 + GO TO 175 + 170 RH = MAX(RH,HMIN/ABS(H)) + 175 RH = MIN(RH,RMAX) + RH = RH/MAX(1.0E0,ABS(H)*HMXI*RH) + R = 1.0E0 + DO 180 J = 2,L + R = R*RH + DO 180 I = 1,N + 180 YH(I,J) = YH(I,J)*R + H = H*RH + RC = RC*RH + IALTH = L + IF (IREDO .EQ. 0) GO TO 690 +C----------------------------------------------------------------------- +C This section computes the predicted values by effectively +C multiplying the YH array by the Pascal Triangle matrix. +C RC is the ratio of new to old values of the coefficient H*EL(1). +C When RC differs from 1 by more than CCMAX, IPUP is set to MITER +C to force PJAC to be called, if a Jacobian is involved. +C In any case, PJAC is called at least every MSBP steps. +C----------------------------------------------------------------------- + 200 IF (ABS(RC-1.0E0) .GT. CCMAX) IPUP = MITER + IF (NST .GE. NSLP+MSBP) IPUP = MITER + TN = TN + H + I1 = NQNYH + 1 + DO 215 JB = 1,NQ + I1 = I1 - NYH +Cdir$ ivdep + DO 210 I = I1,NQNYH + 210 YH1(I) = YH1(I) + YH1(I+NYH) + 215 CONTINUE +C----------------------------------------------------------------------- +C Up to MAXCOR corrector iterations are taken. A convergence test is +C made on the R.M.S. norm of each correction, weighted by the error +C weight vector EWT. The sum of the corrections is accumulated in the +C vector ACOR(i). The YH array is not altered in the corrector loop. +C----------------------------------------------------------------------- + 220 M = 0 + DO 230 I = 1,N + 230 Y(I) = YH(I,1) + CALL F (NEQ, TN, Y, SAVF) + NFE = NFE + 1 + IF (IPUP .LE. 0) GO TO 250 +C----------------------------------------------------------------------- +C If indicated, the matrix P = I - h*el(1)*J is reevaluated and +C preprocessed before starting the corrector iteration. IPUP is set +C to 0 as an indicator that this has been done. +C----------------------------------------------------------------------- + CALL PJAC (NEQ, Y, YH, NYH, EWT, ACOR, SAVF, WM, IWM, F, JAC) + IPUP = 0 + RC = 1.0E0 + NSLP = NST + CRATE = 0.7E0 + IF (IERPJ .NE. 0) GO TO 430 + 250 DO 260 I = 1,N + 260 ACOR(I) = 0.0E0 + 270 IF (MITER .NE. 0) GO TO 350 +C----------------------------------------------------------------------- +C In the case of functional iteration, update Y directly from +C the result of the last function evaluation. +C----------------------------------------------------------------------- + DO 290 I = 1,N + SAVF(I) = H*SAVF(I) - YH(I,2) + 290 Y(I) = SAVF(I) - ACOR(I) + DEL = SVNORM (N, Y, EWT) + DO 300 I = 1,N + Y(I) = YH(I,1) + EL(1)*SAVF(I) + 300 ACOR(I) = SAVF(I) + GO TO 400 +C----------------------------------------------------------------------- +C In the case of the chord method, compute the corrector error, +C and solve the linear system with that as right-hand side and +C P as coefficient matrix. +C----------------------------------------------------------------------- + 350 DO 360 I = 1,N + 360 Y(I) = H*SAVF(I) - (YH(I,2) + ACOR(I)) + CALL SLVS (WM, IWM, Y, SAVF) + IF (IERSL .LT. 0) GO TO 430 + IF (IERSL .GT. 0) GO TO 410 + DEL = SVNORM (N, Y, EWT) + DO 380 I = 1,N + ACOR(I) = ACOR(I) + Y(I) + 380 Y(I) = YH(I,1) + EL(1)*ACOR(I) +C----------------------------------------------------------------------- +C Test for convergence. If M.gt.0, an estimate of the convergence +C rate constant is stored in CRATE, and this is used in the test. +C----------------------------------------------------------------------- + 400 IF (M .NE. 0) CRATE = MAX(0.2E0*CRATE,DEL/DELP) + DCON = DEL*MIN(1.0E0,1.5E0*CRATE)/(TESCO(2,NQ)*CONIT) + IF (DCON .LE. 1.0E0) GO TO 450 + M = M + 1 + IF (M .EQ. MAXCOR) GO TO 410 + IF (M .GE. 2 .AND. DEL .GT. 2.0E0*DELP) GO TO 410 + DELP = DEL + CALL F (NEQ, TN, Y, SAVF) + NFE = NFE + 1 + GO TO 270 +C----------------------------------------------------------------------- +C The corrector iteration failed to converge. +C If MITER .ne. 0 and the Jacobian is out of date, PJAC is called for +C the next try. Otherwise the YH array is retracted to its values +C before prediction, and H is reduced, if possible. If H cannot be +C reduced or MXNCF failures have occurred, exit with KFLAG = -2. +C----------------------------------------------------------------------- + 410 IF (MITER .EQ. 0 .OR. JCUR .EQ. 1) GO TO 430 + ICF = 1 + IPUP = MITER + GO TO 220 + 430 ICF = 2 + NCF = NCF + 1 + RMAX = 2.0E0 + TN = TOLD + I1 = NQNYH + 1 + DO 445 JB = 1,NQ + I1 = I1 - NYH +Cdir$ ivdep + DO 440 I = I1,NQNYH + 440 YH1(I) = YH1(I) - YH1(I+NYH) + 445 CONTINUE + IF (IERPJ .LT. 0 .OR. IERSL .LT. 0) GO TO 680 + IF (ABS(H) .LE. HMIN*1.00001E0) GO TO 670 + IF (NCF .EQ. MXNCF) GO TO 670 + RH = 0.25E0 + IPUP = MITER + IREDO = 1 + GO TO 170 +C----------------------------------------------------------------------- +C The corrector has converged. JCUR is set to 0 +C to signal that the Jacobian involved may need updating later. +C The local error test is made and control passes to statement 500 +C if it fails. +C----------------------------------------------------------------------- + 450 JCUR = 0 + IF (M .EQ. 0) DSM = DEL/TESCO(2,NQ) + IF (M .GT. 0) DSM = SVNORM (N, ACOR, EWT)/TESCO(2,NQ) + IF (DSM .GT. 1.0E0) GO TO 500 +C----------------------------------------------------------------------- +C After a successful step, update the YH array. +C Consider changing H if IALTH = 1. Otherwise decrease IALTH by 1. +C If IALTH is then 1 and NQ .lt. MAXORD, then ACOR is saved for +C use in a possible order increase on the next step. +C If a change in H is considered, an increase or decrease in order +C by one is considered also. A change in H is made only if it is by a +C factor of at least 1.1. If not, IALTH is set to 3 to prevent +C testing for that many steps. +C----------------------------------------------------------------------- + KFLAG = 0 + IREDO = 0 + NST = NST + 1 + HU = H + NQU = NQ + DO 470 J = 1,L + DO 470 I = 1,N + 470 YH(I,J) = YH(I,J) + EL(J)*ACOR(I) + IALTH = IALTH - 1 + IF (IALTH .EQ. 0) GO TO 520 + IF (IALTH .GT. 1) GO TO 700 + IF (L .EQ. LMAX) GO TO 700 + DO 490 I = 1,N + 490 YH(I,LMAX) = ACOR(I) + GO TO 700 +C----------------------------------------------------------------------- +C The error test failed. KFLAG keeps track of multiple failures. +C Restore TN and the YH array to their previous values, and prepare +C to try the step again. Compute the optimum step size for this or +C one lower order. After 2 or more failures, H is forced to decrease +C by a factor of 0.2 or less. +C----------------------------------------------------------------------- + 500 KFLAG = KFLAG - 1 + TN = TOLD + I1 = NQNYH + 1 + DO 515 JB = 1,NQ + I1 = I1 - NYH +Cdir$ ivdep + DO 510 I = I1,NQNYH + 510 YH1(I) = YH1(I) - YH1(I+NYH) + 515 CONTINUE + RMAX = 2.0E0 + IF (ABS(H) .LE. HMIN*1.00001E0) GO TO 660 + IF (KFLAG .LE. -3) GO TO 640 + IREDO = 2 + RHUP = 0.0E0 + GO TO 540 +C----------------------------------------------------------------------- +C Regardless of the success or failure of the step, factors +C RHDN, RHSM, and RHUP are computed, by which H could be multiplied +C at order NQ - 1, order NQ, or order NQ + 1, respectively. +C In the case of failure, RHUP = 0.0 to avoid an order increase. +C The largest of these is determined and the new order chosen +C accordingly. If the order is to be increased, we compute one +C additional scaled derivative. +C----------------------------------------------------------------------- + 520 RHUP = 0.0E0 + IF (L .EQ. LMAX) GO TO 540 + DO 530 I = 1,N + 530 SAVF(I) = ACOR(I) - YH(I,LMAX) + DUP = SVNORM (N, SAVF, EWT)/TESCO(3,NQ) + EXUP = 1.0E0/(L+1) + RHUP = 1.0E0/(1.4E0*DUP**EXUP + 0.0000014E0) + 540 EXSM = 1.0E0/L + RHSM = 1.0E0/(1.2E0*DSM**EXSM + 0.0000012E0) + RHDN = 0.0E0 + IF (NQ .EQ. 1) GO TO 560 + DDN = SVNORM (N, YH(1,L), EWT)/TESCO(1,NQ) + EXDN = 1.0E0/NQ + RHDN = 1.0E0/(1.3E0*DDN**EXDN + 0.0000013E0) + 560 IF (RHSM .GE. RHUP) GO TO 570 + IF (RHUP .GT. RHDN) GO TO 590 + GO TO 580 + 570 IF (RHSM .LT. RHDN) GO TO 580 + NEWQ = NQ + RH = RHSM + GO TO 620 + 580 NEWQ = NQ - 1 + RH = RHDN + IF (KFLAG .LT. 0 .AND. RH .GT. 1.0E0) RH = 1.0E0 + GO TO 620 + 590 NEWQ = L + RH = RHUP + IF (RH .LT. 1.1E0) GO TO 610 + R = EL(L)/L + DO 600 I = 1,N + 600 YH(I,NEWQ+1) = ACOR(I)*R + GO TO 630 + 610 IALTH = 3 + GO TO 700 + 620 IF ((KFLAG .EQ. 0) .AND. (RH .LT. 1.1E0)) GO TO 610 + IF (KFLAG .LE. -2) RH = MIN(RH,0.2E0) +C----------------------------------------------------------------------- +C If there is a change of order, reset NQ, l, and the coefficients. +C In any case H is reset according to RH and the YH array is rescaled. +C Then exit from 690 if the step was OK, or redo the step otherwise. +C----------------------------------------------------------------------- + IF (NEWQ .EQ. NQ) GO TO 170 + 630 NQ = NEWQ + L = NQ + 1 + IRET = 2 + GO TO 150 +C----------------------------------------------------------------------- +C Control reaches this section if 3 or more failures have occured. +C If 10 failures have occurred, exit with KFLAG = -1. +C It is assumed that the derivatives that have accumulated in the +C YH array have errors of the wrong order. Hence the first +C derivative is recomputed, and the order is set to 1. Then +C H is reduced by a factor of 10, and the step is retried, +C until it succeeds or H reaches HMIN. +C----------------------------------------------------------------------- + 640 IF (KFLAG .EQ. -10) GO TO 660 + RH = 0.1E0 + RH = MAX(HMIN/ABS(H),RH) + H = H*RH + DO 645 I = 1,N + 645 Y(I) = YH(I,1) + CALL F (NEQ, TN, Y, SAVF) + NFE = NFE + 1 + DO 650 I = 1,N + 650 YH(I,2) = H*SAVF(I) + IPUP = MITER + IALTH = 5 + IF (NQ .EQ. 1) GO TO 200 + NQ = 1 + L = 2 + IRET = 3 + GO TO 150 +C----------------------------------------------------------------------- +C All returns are made through this section. H is saved in HOLD +C to allow the caller to change H on the next step. +C----------------------------------------------------------------------- + 660 KFLAG = -1 + GO TO 720 + 670 KFLAG = -2 + GO TO 720 + 680 KFLAG = -3 + GO TO 720 + 690 RMAX = 10.0E0 + 700 R = 1.0E0/TESCO(2,NQU) + DO 710 I = 1,N + 710 ACOR(I) = ACOR(I)*R + 720 HOLD = H + JSTART = 1 + RETURN +C----------------------- END OF SUBROUTINE SSTODE ---------------------- + END diff --git a/libcruft/odepack/svnorm.f b/libcruft/odepack/svnorm.f new file mode 100644 --- /dev/null +++ b/libcruft/odepack/svnorm.f @@ -0,0 +1,34 @@ + REAL FUNCTION SVNORM (N, V, W) +C***BEGIN PROLOGUE SVNORM +C***SUBSIDIARY +C***PURPOSE Weighted root-mean-square vector norm. +C***TYPE SINGLE PRECISION (SVNORM-S, DVNORM-D) +C***AUTHOR Hindmarsh, Alan C., (LLNL) +C***DESCRIPTION +C +C This function routine computes the weighted root-mean-square norm +C of the vector of length N contained in the array V, with weights +C contained in the array W of length N: +C SVNORM = SQRT( (1/N) * SUM( V(i)*W(i) )**2 ) +C +C***SEE ALSO SLSODE +C***ROUTINES CALLED (NONE) +C***REVISION HISTORY (YYMMDD) +C 791129 DATE WRITTEN +C 890501 Modified prologue to SLATEC/LDOC format. (FNF) +C 890503 Minor cosmetic changes. (FNF) +C 930809 Renamed to allow single/double precision versions. (ACH) +C***END PROLOGUE SVNORM +C**End + INTEGER N, I + REAL V, W, SUM + DIMENSION V(N), W(N) +C +C***FIRST EXECUTABLE STATEMENT SVNORM + SUM = 0.0E0 + DO 10 I = 1,N + 10 SUM = SUM + (V(I)*W(I))**2 + SVNORM = SQRT(SUM/N) + RETURN +C----------------------- END OF FUNCTION SVNORM ------------------------ + END diff --git a/libcruft/ordered-qz/Makefile.in b/libcruft/ordered-qz/Makefile.in --- a/libcruft/ordered-qz/Makefile.in +++ b/libcruft/ordered-qz/Makefile.in @@ -26,7 +26,7 @@ EXTERNAL_DISTFILES = $(DISTFILES) -FSRC = dsubsp.f exchqz.f +FSRC = dsubsp.f exchqz.f ssubsp.f sexchqz.f include $(TOPDIR)/Makeconf diff --git a/libcruft/ordered-qz/sexchqz.f b/libcruft/ordered-qz/sexchqz.f new file mode 100644 --- /dev/null +++ b/libcruft/ordered-qz/sexchqz.f @@ -0,0 +1,261 @@ + SUBROUTINE SEXCHQZ(NMAX, N, A, B, Z, L, LS1, LS2, EPS, FAIL) + INTEGER NMAX, N, L, LS1, LS2 + REAL A(NMAX,N), B(NMAX,N), Z(NMAX,N), EPS + LOGICAL FAIL +c modified july 9, 1998 a.s.hodel@eng.auburn.edu: +c calls to AMAX1 changed to call MAX instead. +c calls to giv changed to slartg (LAPACK); required new variable tempr +C* +C* GIVEN THE UPPER TRIANGULAR MATRIX B AND UPPER HESSENBERG MATRIX A +C* WITH CONSECUTIVE LS1XLS1 AND LS2XLS2 DIAGONAL BLOCKS (LS1,LS2.LE.2) +C* STARTING AT ROW/COLUMN L, EXCHQZ PRODUCES EQUIVALENCE TRANSFORMA- +C* TIONS QT AND ZT THAT EXCHANGE THE BLOCKS ALONG WITH THEIR GENERALIZED +C* EIGENVALUES. EXCHQZ REQUIRES THE SUBROUTINES SROT (BLAS) AND GIV. +C* THE PARAMETERS IN THE CALLING SEQUENCE ARE (STARRED PARAMETERS ARE +C* ALTERED BY THE SUBROUTINE): +C* +C* NMAX THE FIRST DIMENSION OF A, B AND Z +C* N THE ORDER OF A, B AND Z +C* *A,*B THE MATRIX PAIR WHOSE BLOCKS ARE TO BE INTERCHANGED +C* *Z UPON RETURN THIS ARRAY IS MULTIPLIED BY THE COLUMN +C* TRANSFORMATION ZT. +C* L THE POSITION OF THE BLOCKS +C* LS1 THE SIZE OF THE FIRST BLOCK +C* LS2 THE SIZE OF THE SECOND BLOCK +C* EPS THE REQUIRED ABSOLUTE ACCURACY OF THE RESULT +C* *FAIL A LOGICAL VARIABLE WHICH IS FALSE ON A NORMAL RETURN, +C* TRUE OTHERWISE. +C* + INTEGER I, J, L1, L2, L3, LI, LJ, LL, IT1, IT2 + REAL U(3,3), D, E, F, G, SA, SB, A11B11, A21B11, + * A12B22, B12B22, + * A22B22, AMMBMM, ANMBMM, AMNBNN, BMNBNN, ANNBNN, TEMPR + LOGICAL ALTB + FAIL = .FALSE. + L1 = L + 1 + LL = LS1 + LS2 + IF (LL.GT.2) GO TO 10 +C*** INTERCHANGE 1X1 AND 1X1 BLOCKS VIA AN EQUIVALENCE +C*** TRANSFORMATION A:=Q*A*Z , B:=Q*B*Z +C*** WHERE Q AND Z ARE GIVENS ROTATIONS + F = MAX(ABS(A(L1,L1)),ABS(B(L1,L1))) + ALTB = .TRUE. + IF (ABS(A(L1,L1)).GE.F) ALTB = .FALSE. + SA = A(L1,L1)/F + SB = B(L1,L1)/F + F = SA*B(L,L) - SB*A(L,L) +C* CONSTRUCT THE COLUMN TRANSFORMATION Z + G = SA*B(L,L1) - SB*A(L,L1) + CALL SLARTG(F, G, D, E,TEMPR) + CALL SROT(L1, A(1,L), 1, A(1,L1), 1, E, -D) + CALL SROT(L1, B(1,L), 1, B(1,L1), 1, E, -D) + CALL SROT(N, Z(1,L), 1, Z(1,L1), 1, E, -D) +C* CONSTRUCT THE ROW TRANSFORMATION Q + IF (ALTB) CALL SLARTG(B(L,L), B(L1,L), D, E,TEMPR) + IF (.NOT.ALTB) CALL SLARTG(A(L,L), A(L1,L), D, E,TEMPR) + CALL SROT(N-L+1, A(L,L), NMAX, A(L1,L), NMAX, D, E) + CALL SROT(N-L+1, B(L,L), NMAX, B(L1,L), NMAX, D, E) + A(L1,L) = 0. + B(L1,L) = 0. + RETURN +C*** INTERCHANGE 1X1 AND 2X2 BLOCKS VIA AN EQUIVALENCE +C*** TRANSFORMATION A:=Q2*Q1*A*Z1*Z2 , B:=Q2*Q1*B*Z1*Z2 +C*** WHERE EACH QI AND ZI IS A GIVENS ROTATION + 10 L2 = L + 2 + IF (LS1.EQ.2) GO TO 60 + G = MAX(ABS(A(L,L)),ABS(B(L,L))) + ALTB = .TRUE. + IF (ABS(A(L,L)).LT.G) GO TO 20 + ALTB = .FALSE. + CALL SLARTG(A(L1,L1), A(L2,L1), D, E,TEMPR) + CALL SROT(N-L, A(L1,L1), NMAX, A(L2,L1), NMAX, D, E) + CALL SROT(N-L, B(L1,L1), NMAX, B(L2,L1), NMAX, D, E) +C** EVALUATE THE PENCIL AT THE EIGENVALUE CORRESPONDING +C** TO THE 1X1 BLOCK + 20 SA = A(L,L)/G + SB = B(L,L)/G + DO 40 J=1,2 + LJ = L + J + DO 30 I=1,3 + LI = L + I - 1 + U(I,J) = SA*B(LI,LJ) - SB*A(LI,LJ) + 30 CONTINUE + 40 CONTINUE + CALL SLARTG(U(3,1), U(3,2), D, E,TEMPR) + CALL SROT(3, U(1,1), 1, U(1,2), 1, E, -D) +C* PERFORM THE ROW TRANSFORMATION Q1 + CALL SLARTG(U(1,1), U(2,1), D, E,TEMPR) + U(2,2) = -U(1,2)*E + U(2,2)*D + CALL SROT(N-L+1, A(L,L), NMAX, A(L1,L), NMAX, D, E) + CALL SROT(N-L+1, B(L,L), NMAX, B(L1,L), NMAX, D, E) +C* PERFORM THE COLUMN TRANSFORMATION Z1 + IF (ALTB) CALL SLARTG(B(L1,L), B(L1,L1), D, E,TEMPR) + IF (.NOT.ALTB) CALL SLARTG(A(L1,L), A(L1,L1), D, E,TEMPR) + CALL SROT(L2, A(1,L), 1, A(1,L1), 1, E, -D) + CALL SROT(L2, B(1,L), 1, B(1,L1), 1, E, -D) + CALL SROT(N, Z(1,L), 1, Z(1,L1), 1, E, -D) +C* PERFORM THE ROW TRANSFORMATION Q2 + CALL SLARTG(U(2,2), U(3,2), D, E,TEMPR) + CALL SROT(N-L+1, A(L1,L), NMAX, A(L2,L), NMAX, D, E) + CALL SROT(N-L+1, B(L1,L), NMAX, B(L2,L), NMAX, D, E) +C* PERFORM THE COLUMN TRANSFORMATION Z2 + IF (ALTB) CALL SLARTG(B(L2,L1), B(L2,L2), D, E,TEMPR) + IF (.NOT.ALTB) CALL SLARTG(A(L2,L1), A(L2,L2), D, E,TEMPR) + CALL SROT(L2, A(1,L1), 1, A(1,L2), 1, E, -D) + CALL SROT(L2, B(1,L1), 1, B(1,L2), 1, E, -D) + CALL SROT(N, Z(1,L1), 1, Z(1,L2), 1, E, -D) + IF (ALTB) GO TO 50 + CALL SLARTG(B(L,L), B(L1,L), D, E,TEMPR) + CALL SROT(N-L+1, A(L,L), NMAX, A(L1,L), NMAX, D, E) + CALL SROT(N-L+1, B(L,L), NMAX, B(L1,L), NMAX, D, E) +C* PUT THE NEGLECTABLE ELEMENTS EQUAL TO ZERO + 50 A(L2,L) = 0. + A(L2,L1) = 0. + B(L1,L) = 0. + B(L2,L) = 0. + B(L2,L1) = 0. + RETURN +C*** INTERCHANGE 2X2 AND 1X1 BLOCKS VIA AN EQUIVALENCE +C*** TRANSFORMATION A:=Q2*Q1*A*Z1*Z2 , B:=Q2*Q1*B*Z1*Z2 +C*** WHERE EACH QI AND ZI IS A GIVENS ROTATION + 60 IF (LS2.EQ.2) GO TO 110 + G = MAX(ABS(A(L2,L2)),ABS(B(L2,L2))) + ALTB = .TRUE. + IF (ABS(A(L2,L2)).LT.G) GO TO 70 + ALTB = .FALSE. + CALL SLARTG(A(L,L), A(L1,L), D, E,TEMPR) + CALL SROT(N-L+1, A(L,L), NMAX, A(L1,L), NMAX, D, E) + CALL SROT(N-L+1, B(L,L), NMAX, B(L1,L), NMAX, D, E) +C** EVALUATE THE PENCIL AT THE EIGENVALUE CORRESPONDING +C** TO THE 1X1 BLOCK + 70 SA = A(L2,L2)/G + SB = B(L2,L2)/G + DO 90 I=1,2 + LI = L + I - 1 + DO 80 J=1,3 + LJ = L + J - 1 + U(I,J) = SA*B(LI,LJ) - SB*A(LI,LJ) + 80 CONTINUE + 90 CONTINUE + CALL SLARTG(U(1,1), U(2,1), D, E,TEMPR) + CALL SROT(3, U(1,1), 3, U(2,1), 3, D, E) +C* PERFORM THE COLUMN TRANSFORMATION Z1 + CALL SLARTG(U(2,2), U(2,3), D, E,TEMPR) + U(1,2) = U(1,2)*E - U(1,3)*D + CALL SROT(L2, A(1,L1), 1, A(1,L2), 1, E, -D) + CALL SROT(L2, B(1,L1), 1, B(1,L2), 1, E, -D) + CALL SROT(N, Z(1,L1), 1, Z(1,L2), 1, E, -D) +C* PERFORM THE ROW TRANSFORMATION Q1 + IF (ALTB) CALL SLARTG(B(L1,L1), B(L2,L1), D, E,TEMPR) + IF (.NOT.ALTB) CALL SLARTG(A(L1,L1), A(L2,L1), D, E,TEMPR) + CALL SROT(N-L+1, A(L1,L), NMAX, A(L2,L), NMAX, D, E) + CALL SROT(N-L+1, B(L1,L), NMAX, B(L2,L), NMAX, D, E) +C* PERFORM THE COLUMN TRANSFORMATION Z2 + CALL SLARTG(U(1,1), U(1,2), D, E,TEMPR) + CALL SROT(L2, A(1,L), 1, A(1,L1), 1, E, -D) + CALL SROT(L2, B(1,L), 1, B(1,L1), 1, E, -D) + CALL SROT(N, Z(1,L), 1, Z(1,L1), 1, E, -D) +C* PERFORM THE ROW TRANSFORMATION Q2 + IF (ALTB) CALL SLARTG(B(L,L), B(L1,L), D, E,TEMPR) + IF (.NOT.ALTB) CALL SLARTG(A(L,L), A(L1,L), D, E,TEMPR) + CALL SROT(N-L+1, A(L,L), NMAX, A(L1,L), NMAX, D, E) + CALL SROT(N-L+1, B(L,L), NMAX, B(L1,L), NMAX, D, E) + IF (ALTB) GO TO 100 + CALL SLARTG(B(L1,L1), B(L2,L1), D, E,TEMPR) + CALL SROT(N-L, A(L1,L1), NMAX, A(L2,L1), NMAX, D, E) + CALL SROT(N-L, B(L1,L1), NMAX, B(L2,L1), NMAX, D, E) +C* PUT THE NEGLECTABLE ELEMENTS EQUAL TO ZERO + 100 A(L1,L) = 0. + A(L2,L) = 0. + B(L1,L) = 0. + B(L2,1) = 0. + B(L2,L1) = 0. + RETURN +C*** INTERCHANGE 2X2 AND 2X2 BLOCKS VIA A SEQUENCE OF +C*** QZ-STEPS REALIZED BY THE EQUIVALENCE TRANSFORMATIONS +C*** A:=Q5*Q4*Q3*Q2*Q1*A*Z1*Z2*Z3*Z4*Z5 +C*** B:=Q5*Q4*Q3*Q2*Q1*B*Z1*Z2*Z3*Z4*Z5 +C*** WHERE EACH QI AND ZI IS A GIVENS ROTATION + 110 L3 = L + 3 +C* COMPUTE IMPLICIT SHIFT + AMMBMM = A(L,L)/B(L,L) + ANMBMM = A(L1,L)/B(L,L) + AMNBNN = A(L,L1)/B(L1,L1) + ANNBNN = A(L1,L1)/B(L1,L1) + BMNBNN = B(L,L1)/B(L1,L1) + DO 130 IT1=1,3 + U(1,1) = 1. + U(2,1) = 1. + U(3,1) = 1. + DO 120 IT2=1,10 +C* PERFORM ROW TRANSFORMATIONS Q1 AND Q2 + CALL SLARTG(U(2,1), U(3,1), D, E,TEMPR) + CALL SROT(N-L+1, A(L1,L), NMAX, A(L2,L), NMAX, D, E) + CALL SROT(N-L, B(L1,L1), NMAX, B(L2,L1), NMAX, D, E) + U(2,1) = D*U(2,1) + E*U(3,1) + CALL SLARTG(U(1,1), U(2,1), D, E,TEMPR) + CALL SROT(N-L+1, A(L,L), NMAX, A(L1,L), NMAX, D, E) + CALL SROT(N-L+1, B(L,L), NMAX, B(L1,L), NMAX, D, E) +C* PERFORM COLUMN TRANSFORMATIONS Z1 AND Z2 + CALL SLARTG(B(L2,L1), B(L2,L2), D, E,TEMPR) + CALL SROT(L3, A(1,L1), 1, A(1,L2), 1, E, -D) + CALL SROT(L2, B(1,L1), 1, B(1,L2), 1, E, -D) + CALL SROT(N, Z(1,L1), 1, Z(1,L2), 1, E, -D) + CALL SLARTG(B(L1,L), B(L1,L1), D, E,TEMPR) + CALL SROT(L3, A(1,L), 1, A(1,L1), 1, E, -D) + CALL SROT(L1, B(1,L), 1, B(1,L1), 1, E, -D) + CALL SROT(N, Z(1,L), 1, Z(1,L1), 1, E, -D) +C* PERFORM TRANSFORMATIONS Q3,Z3,Q4,Z4,Q5 AND Z5 IN +C* ORDER TO REDUCE THE PENCIL TO HESSENBERG FORM + CALL SLARTG(A(L2,L), A(L3,L), D, E,TEMPR) + CALL SROT(N-L+1, A(L2,L), NMAX, A(L3,L), NMAX, D, E) + CALL SROT(N-L1, B(L2,L2), NMAX, B(L3,L2), NMAX, D, E) + CALL SLARTG(B(L3,L2), B(L3,L3), D, E,TEMPR) + CALL SROT(L3, A(1,L2), 1, A(1,L3), 1, E, -D) + CALL SROT(L3, B(1,L2), 1, B(1,L3), 1, E, -D) + CALL SROT(N, Z(1,L2), 1, Z(1,L3), 1, E, -D) + CALL SLARTG(A(L1,L), A(L2,L), D, E,TEMPR) + CALL SROT(N-L+1, A(L1,L), NMAX, A(L2,L), NMAX, D, E) + CALL SROT(N-L, B(L1,L1), NMAX, B(L2,L1), NMAX, D, E) + CALL SLARTG(B(L2,L1), B(L2,L2), D, E,TEMPR) + CALL SROT(L3, A(1,L1), 1, A(1,L2), 1, E, -D) + CALL SROT(L2, B(1,L1), 1, B(1,L2), 1, E, -D) + CALL SROT(N, Z(1,L1), 1, Z(1,L2), 1, E, -D) + CALL SLARTG(A(L2,L1), A(L3,L1), D, E,TEMPR) + CALL SROT(N-L, A(L2,L1), NMAX, A(L3,L1), NMAX, D, E) + CALL SROT(N-L1, B(L2,L2), NMAX, B(L3,L2), NMAX, D, E) + CALL SLARTG(B(L3,L2), B(L3,L3), D, E,TEMPR) + CALL SROT(L3, A(1,L2), 1, A(1,L3), 1, E, -D) + CALL SROT(L3, B(1,L2), 1, B(1,L3), 1, E, -D) + CALL SROT(N, Z(1,L2), 1, Z(1,L3), 1, E, -D) +C* TEST OF CONVERGENCE ON THE ELEMENT SEPARATING THE BLOCKS + IF (ABS(A(L2,L1)).LE.EPS) GO TO 140 +C* COMPUTE A NEW SHIFT IN CASE OF NO CONVERGENCE + A11B11 = A(L,L)/B(L,L) + A12B22 = A(L,L1)/B(L1,L1) + A21B11 = A(L1,L)/B(L,L) + A22B22 = A(L1,L1)/B(L1,L1) + B12B22 = B(L,L1)/B(L1,L1) + U(1,1) = ((AMMBMM-A11B11)*(ANNBNN-A11B11)-AMNBNN* + * ANMBMM+ANMBMM*BMNBNN*A11B11)/A21B11 + A12B22 - A11B11*B12B22 + U(2,1) = (A22B22-A11B11) - A21B11*B12B22 - (AMMBMM-A11B11) - + * (ANNBNN-A11B11) + ANMBMM*BMNBNN + U(3,1) = A(L2,L1)/B(L1,L1) + 120 CONTINUE + 130 CONTINUE + FAIL = .TRUE. + RETURN +C* PUT THE NEGLECTABLE ELEMENTS EQUAL TO ZERO IN +C* CASE OF CONVERGENCE + 140 A(L2,L) = 0. + A(L2,L1) = 0. + A(L3,L) = 0. + A(L3,L1) = 0. + B(L1,L) = 0. + B(L2,L) = 0. + B(L2,L1) = 0. + B(L3,L) = 0. + B(L3,L1) = 0. + B(L3,L2) = 0. + RETURN + END diff --git a/libcruft/ordered-qz/ssubsp.f b/libcruft/ordered-qz/ssubsp.f new file mode 100644 --- /dev/null +++ b/libcruft/ordered-qz/ssubsp.f @@ -0,0 +1,104 @@ + SUBROUTINE SSUBSP(NMAX, N, A, B, Z, FTEST, EPS, NDIM, FAIL, IND) + INTEGER NMAX, N, FTEST, NDIM, IND(N) + LOGICAL FAIL + REAL A(NMAX,N), B(NMAX,N), Z(NMAX,N), EPS +C* +C* GIVEN THE UPPER TRIANGULAR MATRIX B AND UPPER HESSENBERG MATRIX A +C* WITH 1X1 OR 2X2 DIAGONAL BLOCKS, THIS ROUTINE REORDERS THE DIAGONAL +C* BLOCKS ALONG WITH THEIR GENERALIZED EIGENVALUES BY CONSTRUCTING EQUI- +C* VALENCE TRANSFORMATIONS QT AND ZT. THE ROW TRANSFORMATION ZT IS ALSO +C* PERFORMED ON THE GIVEN (INITIAL) TRANSFORMATION Z (RESULTING FROM A +C* POSSIBLE PREVIOUS STEP OR INITIALIZED WITH THE IDENTITY MATRIX). +C* AFTER REORDERING, THE EIGENVALUES INSIDE THE REGION SPECIFIED BY THE +C* FUNCTION FTEST APPEAR AT THE TOP. IF NDIM IS THEIR NUMBER THEN THE +C* NDIM FIRST COLUMNS OF Z SPAN THE REQUESTED SUBSPACE. DSUBSP REQUIRES +C* THE SUBROUTINE EXCHQZ AND THE INTEGER FUNCTION FTEST WHICH HAS TO BE +C* PROVIDED BY THE USER. THE PARAMETERS IN THE CALLING SEQUENCE ARE : +C* (STARRED PARAMETERS ARE ALTERED BY THE SUBROUTINE) +C* +C* NMAX THE FIRST DIMENSION OF A, B AND Z +C* N THE ORDER OF A, B AND Z +C* *A,*B THE MATRIX PAIR WHOSE BLOCKS ARE TO BE REORDERED. +C* *Z UPON RETURN THIS ARRAY IS MULTIPLIED BY THE COLUMN +C* TRANSFORMATION ZT. +C* FTEST(LS,ALPHA,BETA,S,P) AN INTEGER FUNCTION DESCRIBING THE +C* SPECTRUM OF THE DEFLATING SUBSPACE TO BE COMPUTED: +C* WHEN LS=1 FTEST CHECKS IF ALPHA/BETA IS IN THAT SPECTRUM +C* WHEN LS=2 FTEST CHECKS IF THE TWO COMPLEX CONJUGATE +C* ROOTS WITH SUM S AND PRODUCT P ARE IN THAT SPECTRUM +C* IF THE ANSWER IS POSITIVE, FTEST=1, OTHERWISE FTEST=-1 +C* EPS THE REQUIRED ABSOLUTE ACCURACY OF THE RESULT +C* *NDIM AN INTEGER GIVING THE DIMENSION OF THE COMPUTED +C* DEFLATING SUBSPACE +C* *FAIL A LOGICAL VARIABLE WHICH IS FALSE ON A NORMAL RETURN, +C* TRUE OTHERWISE (WHEN SEXCHQZ FAILS) +C* *IND AN INTEGER WORKING ARRAY OF DIMENSION AT LEAST N +C* + INTEGER L, LS, LS1, LS2, L1, LL, NUM, IS, L2I, L2K, I, K, II, + * ISTEP, IFIRST + REAL S, P, D, ALPHA, BETA + FAIL = .TRUE. + NDIM = 0 + NUM = 0 + L = 0 + LS = 1 +C*** CONSTRUCT ARRAY IND(I) WHERE : +C*** IABS(IND(I)) IS THE SIZE OF THE BLOCK I +C*** SIGN(IND(I)) INDICATES THE LOCATION OF ITS EIGENVALUES +C*** (AS DETERMINED BY FTEST). +C*** NUM IS THE NUMBER OF ELEMENTS IN THIS ARRAY + DO 30 LL=1,N + L = L + LS + IF (L.GT.N) GO TO 40 + L1 = L + 1 + IF (L1.GT.N) GO TO 10 + IF (A(L1,L).EQ.0.) GO TO 10 +C* HERE A 2X2 BLOCK IS CHECKED * + LS = 2 + D = B(L,L)*B(L1,L1) + S = (A(L,L)*B(L1,L1)+A(L1,L1)*B(L,L)-A(L1,L)*B(L,L1))/D + P = (A(L,L)*A(L1,L1)-A(L,L1)*A(L1,L))/D + IS = FTEST(LS,ALPHA,BETA,S,P) + GO TO 20 +C* HERE A 1X1 BLOCK IS CHECKED * + 10 LS = 1 + IS = FTEST(LS,A(L,L),B(L,L),S,P) + 20 NUM = NUM + 1 + IF (IS.EQ.1) NDIM = NDIM + LS + IND(NUM) = LS*IS + 30 CONTINUE +C*** REORDER BLOCKS SUCH THAT THOSE WITH POSITIVE VALUE +C*** OF IND(.) APPEAR FIRST. + 40 L2I = 1 + DO 100 I=1,NUM + IF (IND(I).GT.0) GO TO 90 +C* IF A NEGATIVE IND(I) IS ENCOUNTERED, THEN SEARCH FOR THE FIRST +C* POSITIVE IND(K) FOLLOWING ON IT + L2K = L2I + DO 60 K=I,NUM + IF (IND(K).LT.0) GO TO 50 + GO TO 70 + 50 L2K = L2K - IND(K) + 60 CONTINUE +C* IF THERE ARE NO POSITIVE INDICES FOLLOWING ON A NEGATIVE ONE +C* THEN STOP + GO TO 110 +C* IF A POSITIVE IND(K) FOLLOWS ON A NEGATIVE IND(I) THEN +C* INTERCHANGE BLOCK K BEFORE BLOCK I BY PERFORMING K-I SWAPS + 70 ISTEP = K - I + LS2 = IND(K) + L = L2K + DO 80 II=1,ISTEP + IFIRST = K - II + LS1 = -IND(IFIRST) + L = L - LS1 + CALL SEXCHQZ(NMAX, N, A, B, Z, L, LS1, LS2, EPS, FAIL) + IF (FAIL) RETURN + IND(IFIRST+1) = IND(IFIRST) + 80 CONTINUE + IND(I) = LS2 + 90 L2I = L2I + IND(I) + 100 CONTINUE + 110 FAIL = .FALSE. + RETURN + END diff --git a/libcruft/quadpack/Makefile.in b/libcruft/quadpack/Makefile.in --- a/libcruft/quadpack/Makefile.in +++ b/libcruft/quadpack/Makefile.in @@ -27,7 +27,8 @@ EXTERNAL_DISTFILES = $(DISTFILES) FSRC = dqagi.f dqagie.f dqagp.f dqagpe.f dqelg.f dqk15i.f \ - dqk21.f dqpsrt.f xerror.f + dqk21.f dqpsrt.f qagie.f qagi.f qagpe.f qagp.f qelg.f \ + qk15i.f qk21.f qpsrt.f xerror.f include $(TOPDIR)/Makeconf diff --git a/libcruft/quadpack/qagi.f b/libcruft/quadpack/qagi.f new file mode 100644 --- /dev/null +++ b/libcruft/quadpack/qagi.f @@ -0,0 +1,190 @@ + subroutine qagi(f,bound,inf,epsabs,epsrel,result,abserr,neval, + * ier,limit,lenw,last,iwork,work) +c***begin prologue qagi +c***date written 800101 (yymmdd) +c***revision date 830518 (yymmdd) +c***category no. h2a3a1,h2a4a1 +c***keywords automatic integrator, infinite intervals, +c general-purpose, transformation, extrapolation, +c globally adaptive +c***author piessens,robert,appl. math. & progr. div. - k.u.leuven +c de doncker,elise,appl. math. & progr. div. -k.u.leuven +c***purpose the routine calculates an approximation result to a given +c integral i = integral of f over (bound,+infinity) +c or i = integral of f over (-infinity,bound) +c or i = integral of f over (-infinity,+infinity) +c hopefully satisfying following claim for accuracy +c abs(i-result).le.max(epsabs,epsrel*abs(i)). +c***description +c +c integration over infinite intervals +c standard fortran subroutine +c +c parameters +c on entry +c f - subroutine f(x,result) defining the integrand +c function f(x). the actual name for f needs to be +c declared e x t e r n a l in the driver program. +c +c bound - real +c finite bound of integration range +c (has no meaning if interval is doubly-infinite) +c +c inf - integer +c indicating the kind of integration range involved +c inf = 1 corresponds to (bound,+infinity), +c inf = -1 to (-infinity,bound), +c inf = 2 to (-infinity,+infinity). +c +c epsabs - real +c absolute accuracy requested +c epsrel - real +c relative accuracy requested +c if epsabs.le.0 +c and epsrel.lt.max(50*rel.mach.acc.,0.5d-28), +c the routine will end with ier = 6. +c +c +c on return +c result - real +c approximation to the integral +c +c abserr - real +c estimate of the modulus of the absolute error, +c which should equal or exceed abs(i-result) +c +c neval - integer +c number of integrand evaluations +c +c ier - integer +c ier = 0 normal and reliable termination of the +c routine. it is assumed that the requested +c accuracy has been achieved. +c - ier.gt.0 abnormal termination of the routine. the +c estimates for result and error are less +c reliable. it is assumed that the requested +c accuracy has not been achieved. +c error messages +c ier = 1 maximum number of subdivisions allowed +c has been achieved. one can allow more +c subdivisions by increasing the value of +c limit (and taking the according dimension +c adjustments into account). however, if +c this yields no improvement it is advised +c to analyze the integrand in order to +c determine the integration difficulties. if +c the position of a local difficulty can be +c determined (e.g. singularity, +c discontinuity within the interval) one +c will probably gain from splitting up the +c interval at this point and calling the +c integrator on the subranges. if possible, +c an appropriate special-purpose integrator +c should be used, which is designed for +c handling the type of difficulty involved. +c = 2 the occurrence of roundoff error is +c detected, which prevents the requested +c tolerance from being achieved. +c the error may be under-estimated. +c = 3 extremely bad integrand behaviour occurs +c at some points of the integration +c interval. +c = 4 the algorithm does not converge. +c roundoff error is detected in the +c extrapolation table. +c it is assumed that the requested tolerance +c cannot be achieved, and that the returned +c result is the best which can be obtained. +c = 5 the integral is probably divergent, or +c slowly convergent. it must be noted that +c divergence can occur with any other value +c of ier. +c = 6 the input is invalid, because +c (epsabs.le.0 and +c epsrel.lt.max(50*rel.mach.acc.,0.5d-28)) +c or limit.lt.1 or leniw.lt.limit*4. +c result, abserr, neval, last are set to +c zero. exept when limit or leniw is +c invalid, iwork(1), work(limit*2+1) and +c work(limit*3+1) are set to zero, work(1) +c is set to a and work(limit+1) to b. +c +c dimensioning parameters +c limit - integer +c dimensioning parameter for iwork +c limit determines the maximum number of subintervals +c in the partition of the given integration interval +c (a,b), limit.ge.1. +c if limit.lt.1, the routine will end with ier = 6. +c +c lenw - integer +c dimensioning parameter for work +c lenw must be at least limit*4. +c if lenw.lt.limit*4, the routine will end +c with ier = 6. +c +c last - integer +c on return, last equals the number of subintervals +c produced in the subdivision process, which +c determines the number of significant elements +c actually in the work arrays. +c +c work arrays +c iwork - integer +c vector of dimension at least limit, the first +c k elements of which contain pointers +c to the error estimates over the subintervals, +c such that work(limit*3+iwork(1)),... , +c work(limit*3+iwork(k)) form a decreasing +c sequence, with k = last if last.le.(limit/2+2), and +c k = limit+1-last otherwise +c +c work - real +c vector of dimension at least lenw +c on return +c work(1), ..., work(last) contain the left +c end points of the subintervals in the +c partition of (a,b), +c work(limit+1), ..., work(limit+last) contain +c the right end points, +c work(limit*2+1), ...,work(limit*2+last) contain the +c integral approximations over the subintervals, +c work(limit*3+1), ..., work(limit*3) +c contain the error estimates. +c***references (none) +c***routines called qagie,xerror +c***end prologue qagi +c + real abserr, epsabs,epsrel,result,work + integer ier,iwork, lenw,limit,lvl,l1,l2,l3,neval +c + dimension iwork(limit),work(lenw) +c + external f +c +c check validity of limit and lenw. +c +c***first executable statement qagi + ier = 6 + neval = 0 + last = 0 + result = 0.0e+00 + abserr = 0.0e+00 + if(limit.lt.1.or.lenw.lt.limit*4) go to 10 +c +c prepare call for qagie. +c + l1 = limit+1 + l2 = limit+l1 + l3 = limit+l2 +c + call qagie(f,bound,inf,epsabs,epsrel,limit,result,abserr, + * neval,ier,work(1),work(l1),work(l2),work(l3),iwork,last) +c +c call error handler if necessary. +c + lvl = 0 +10 if(ier.eq.6) lvl = 1 + if(ier.ne.0) call xerror('abnormal return from qagi',26,ier,lvl) + return + end diff --git a/libcruft/quadpack/qagie.f b/libcruft/quadpack/qagie.f new file mode 100644 --- /dev/null +++ b/libcruft/quadpack/qagie.f @@ -0,0 +1,460 @@ + subroutine qagie(f,bound,inf,epsabs,epsrel,limit,result,abserr, + * neval,ier,alist,blist,rlist,elist,iord,last) +c***begin prologue qagie +c***date written 800101 (yymmdd) +c***revision date 830518 (yymmdd) +c***category no. h2a3a1,h2a4a1 +c***keywords automatic integrator, infinite intervals, +c general-purpose, transformation, extrapolation, +c globally adaptive +c***author piessens,robert,appl. math & progr. div - k.u.leuven +c de doncker,elise,appl. math & progr. div - k.u.leuven +c***purpose the routine calculates an approximation result to a given +c integral i = integral of f over (bound,+infinity) +c or i = integral of f over (-infinity,bound) +c or i = integral of f over (-infinity,+infinity), +c hopefully satisfying following claim for accuracy +c abs(i-result).le.max(epsabs,epsrel*abs(i)) +c***description +c +c integration over infinite intervals +c standard fortran subroutine +c +c f - subroutine f(x,ierr,result) defining the integrand +c function f(x). the actual name for f needs to be +c declared e x t e r n a l in the driver program. +c +c bound - real +c finite bound of integration range +c (has no meaning if interval is doubly-infinite) +c +c inf - real +c indicating the kind of integration range involved +c inf = 1 corresponds to (bound,+infinity), +c inf = -1 to (-infinity,bound), +c inf = 2 to (-infinity,+infinity). +c +c epsabs - real +c absolute accuracy requested +c epsrel - real +c relative accuracy requested +c if epsabs.le.0 +c and epsrel.lt.max(50*rel.mach.acc.,0.5d-28), +c the routine will end with ier = 6. +c +c limit - integer +c gives an upper bound on the number of subintervals +c in the partition of (a,b), limit.ge.1 +c +c on return +c result - real +c approximation to the integral +c +c abserr - real +c estimate of the modulus of the absolute error, +c which should equal or exceed abs(i-result) +c +c neval - integer +c number of integrand evaluations +c +c ier - integer +c ier = 0 normal and reliable termination of the +c routine. it is assumed that the requested +c accuracy has been achieved. +c - ier.gt.0 abnormal termination of the routine. the +c estimates for result and error are less +c reliable. it is assumed that the requested +c accuracy has not been achieved. +c error messages +c ier = 1 maximum number of subdivisions allowed +c has been achieved. one can allow more +c subdivisions by increasing the value of +c limit (and taking the according dimension +c adjustments into account). however,if +c this yields no improvement it is advised +c to analyze the integrand in order to +c determine the integration difficulties. +c if the position of a local difficulty can +c be determined (e.g. singularity, +c discontinuity within the interval) one +c will probably gain from splitting up the +c interval at this point and calling the +c integrator on the subranges. if possible, +c an appropriate special-purpose integrator +c should be used, which is designed for +c handling the type of difficulty involved. +c = 2 the occurrence of roundoff error is +c detected, which prevents the requested +c tolerance from being achieved. +c the error may be under-estimated. +c = 3 extremely bad integrand behaviour occurs +c at some points of the integration +c interval. +c = 4 the algorithm does not converge. +c roundoff error is detected in the +c extrapolation table. +c it is assumed that the requested tolerance +c cannot be achieved, and that the returned +c result is the best which can be obtained. +c = 5 the integral is probably divergent, or +c slowly convergent. it must be noted that +c divergence can occur with any other value +c of ier. +c = 6 the input is invalid, because +c (epsabs.le.0 and +c epsrel.lt.max(50*rel.mach.acc.,0.5d-28), +c result, abserr, neval, last, rlist(1), +c elist(1) and iord(1) are set to zero. +c alist(1) and blist(1) are set to 0 +c and 1 respectively. +c +c alist - real +c vector of dimension at least limit, the first +c last elements of which are the left +c end points of the subintervals in the partition +c of the transformed integration range (0,1). +c +c blist - real +c vector of dimension at least limit, the first +c last elements of which are the right +c end points of the subintervals in the partition +c of the transformed integration range (0,1). +c +c rlist - real +c vector of dimension at least limit, the first +c last elements of which are the integral +c approximations on the subintervals +c +c elist - real +c vector of dimension at least limit, the first +c last elements of which are the moduli of the +c absolute error estimates on the subintervals +c +c iord - integer +c vector of dimension limit, the first k +c elements of which are pointers to the +c error estimates over the subintervals, +c such that elist(iord(1)), ..., elist(iord(k)) +c form a decreasing sequence, with k = last +c if last.le.(limit/2+2), and k = limit+1-last +c otherwise +c +c last - integer +c number of subintervals actually produced +c in the subdivision process +c +c***references (none) +c***routines called qelg,qk15i,qpsrt,r1mach +c***end prologue qagie +c + real abseps,abserr,alist,area,area1,area12,area2,a1, + * a2,blist,boun,bound,b1,b2,correc,defabs,defab1,defab2, + * dres,r1mach,elist,epmach,epsabs,epsrel,erlarg,erlast, + * errbnd,errmax,error1,error2,erro12,errsum,ertest,oflow,resabs, + * reseps,result,res3la,rlist,rlist2,small,uflow + integer id,ier,ierro,inf,iord,iroff1,iroff2,iroff3,jupbnd,k,ksgn, + * ktmin,last,limit,maxerr,neval,nres,nrmax,numrl2 + logical extrap,noext +c + dimension alist(limit),blist(limit),elist(limit),iord(limit), + * res3la(3),rlist(limit),rlist2(52) +c + external f +c +c the dimension of rlist2 is determined by the value of +c limexp in subroutine qelg. +c +c +c list of major variables +c ----------------------- +c +c alist - list of left end points of all subintervals +c considered up to now +c blist - list of right end points of all subintervals +c considered up to now +c rlist(i) - approximation to the integral over +c (alist(i),blist(i)) +c rlist2 - array of dimension at least (limexp+2), +c containing the part of the epsilon table +c wich is still needed for further computations +c elist(i) - error estimate applying to rlist(i) +c maxerr - pointer to the interval with largest error +c estimate +c errmax - elist(maxerr) +c erlast - error on the interval currently subdivided +c (before that subdivision has taken place) +c area - sum of the integrals over the subintervals +c errsum - sum of the errors over the subintervals +c errbnd - requested accuracy max(epsabs,epsrel* +c abs(result)) +c *****1 - variable for the left subinterval +c *****2 - variable for the right subinterval +c last - index for subdivision +c nres - number of calls to the extrapolation routine +c numrl2 - number of elements currently in rlist2. if an +c appropriate approximation to the compounded +c integral has been obtained, it is put in +c rlist2(numrl2) after numrl2 has been increased +c by one. +c small - length of the smallest interval considered up +c to now, multiplied by 1.5 +c erlarg - sum of the errors over the intervals larger +c than the smallest interval considered up to now +c extrap - logical variable denoting that the routine +c is attempting to perform extrapolation. i.e. +c before subdividing the smallest interval we +c try to decrease the value of erlarg. +c noext - logical variable denoting that extrapolation +c is no longer allowed (true-value) +c +c machine dependent constants +c --------------------------- +c +c epmach is the largest relative spacing. +c uflow is the smallest positive magnitude. +c oflow is the largest positive magnitude. +c + epmach = r1mach(4) +c +c test on validity of parameters +c ----------------------------- +c +c***first executable statement qagie + ier = 0 + neval = 0 + last = 0 + result = 0.0e+00 + abserr = 0.0e+00 + alist(1) = 0.0e+00 + blist(1) = 0.1e+01 + rlist(1) = 0.0e+00 + elist(1) = 0.0e+00 + iord(1) = 0 + if(epsabs.le.0.0e+00.and.epsrel.lt.amax1(0.5e+02*epmach,0.5e-14)) + * ier = 6 + if(ier.eq.6) go to 999 +c +c +c first approximation to the integral +c ----------------------------------- +c +c determine the interval to be mapped onto (0,1). +c if inf = 2 the integral is computed as i = i1+i2, where +c i1 = integral of f over (-infinity,0), +c i2 = integral of f over (0,+infinity). +c + boun = bound + if(inf.eq.2) boun = 0.0e+00 + call qk15i(f,boun,inf,0.0e+00,0.1e+01,result,abserr, + * defabs,resabs,ier) + if (ier.lt.0) return +c +c test on accuracy +c + last = 1 + rlist(1) = result + elist(1) = abserr + iord(1) = 1 + dres = abs(result) + errbnd = amax1(epsabs,epsrel*dres) + if(abserr.le.1.0e+02*epmach*defabs.and.abserr.gt. + * errbnd) ier = 2 + if(limit.eq.1) ier = 1 + if(ier.ne.0.or.(abserr.le.errbnd.and.abserr.ne.resabs).or. + * abserr.eq.0.0e+00) go to 130 +c +c initialization +c -------------- +c + uflow = r1mach(1) + oflow = r1mach(2) + rlist2(1) = result + errmax = abserr + maxerr = 1 + area = result + errsum = abserr + abserr = oflow + nrmax = 1 + nres = 0 + ktmin = 0 + numrl2 = 2 + extrap = .false. + noext = .false. + ierro = 0 + iroff1 = 0 + iroff2 = 0 + iroff3 = 0 + ksgn = -1 + if(dres.ge.(0.1e+01-0.5e+02*epmach)*defabs) ksgn = 1 +c +c main do-loop +c ------------ +c + do 90 last = 2,limit +c +c bisect the subinterval with nrmax-th largest +c error estimate. +c + a1 = alist(maxerr) + b1 = 0.5e+00*(alist(maxerr)+blist(maxerr)) + a2 = b1 + b2 = blist(maxerr) + erlast = errmax + call qk15i(f,boun,inf,a1,b1,area1,error1,resabs,defab1,ier) + if (ier.lt.0) return + call qk15i(f,boun,inf,a2,b2,area2,error2,resabs,defab2,ier) + if (ier.lt.0) return +c +c improve previous approximations to integral +c and error and test for accuracy. +c + area12 = area1+area2 + erro12 = error1+error2 + errsum = errsum+erro12-errmax + area = area+area12-rlist(maxerr) + if(defab1.eq.error1.or.defab2.eq.error2)go to 15 + if(abs(rlist(maxerr)-area12).gt.0.1e-04*abs(area12) + * .or.erro12.lt.0.99e+00*errmax) go to 10 + if(extrap) iroff2 = iroff2+1 + if(.not.extrap) iroff1 = iroff1+1 + 10 if(last.gt.10.and.erro12.gt.errmax) iroff3 = iroff3+1 + 15 rlist(maxerr) = area1 + rlist(last) = area2 + errbnd = amax1(epsabs,epsrel*abs(area)) +c +c test for roundoff error and eventually +c set error flag. +c + if(iroff1+iroff2.ge.10.or.iroff3.ge.20) ier = 2 + if(iroff2.ge.5) ierro = 3 +c +c set error flag in the case that the number of +c subintervals equals limit. +c + if(last.eq.limit) ier = 1 +c +c set error flag in the case of bad integrand behaviour +c at some points of the integration range. +c + if(amax1(abs(a1),abs(b2)).le.(0.1e+01+0.1e+03*epmach)* + * (abs(a2)+0.1e+04*uflow)) ier = 4 +c +c append the newly-created intervals to the list. +c + if(error2.gt.error1) go to 20 + alist(last) = a2 + blist(maxerr) = b1 + blist(last) = b2 + elist(maxerr) = error1 + elist(last) = error2 + go to 30 + 20 alist(maxerr) = a2 + alist(last) = a1 + blist(last) = b1 + rlist(maxerr) = area2 + rlist(last) = area1 + elist(maxerr) = error2 + elist(last) = error1 +c +c call subroutine qpsrt to maintain the descending ordering +c in the list of error estimates and select the +c subinterval with nrmax-th largest error estimate (to be +c bisected next). +c + 30 call qpsrt(limit,last,maxerr,errmax,elist,iord,nrmax) + if(errsum.le.errbnd) go to 115 + if(ier.ne.0) go to 100 + if(last.eq.2) go to 80 + if(noext) go to 90 + erlarg = erlarg-erlast + if(abs(b1-a1).gt.small) erlarg = erlarg+erro12 + if(extrap) go to 40 +c +c test whether the interval to be bisected next is the +c smallest interval. +c + if(abs(blist(maxerr)-alist(maxerr)).gt.small) go to 90 + extrap = .true. + nrmax = 2 + 40 if(ierro.eq.3.or.erlarg.le.ertest) go to 60 +c +c the smallest interval has the largest error. +c before bisecting decrease the sum of the errors +c over the larger intervals (erlarg) and perform +c extrapolation. +c + id = nrmax + jupbnd = last + if(last.gt.(2+limit/2)) jupbnd = limit+3-last + do 50 k = id,jupbnd + maxerr = iord(nrmax) + errmax = elist(maxerr) + if(abs(blist(maxerr)-alist(maxerr)).gt.small) go to 90 + nrmax = nrmax+1 + 50 continue +c +c perform extrapolation. +c + 60 numrl2 = numrl2+1 + rlist2(numrl2) = area + call qelg(numrl2,rlist2,reseps,abseps,res3la,nres) + ktmin = ktmin+1 + if(ktmin.gt.5.and.abserr.lt.0.1e-02*errsum) ier = 5 + if(abseps.ge.abserr) go to 70 + ktmin = 0 + abserr = abseps + result = reseps + correc = erlarg + ertest = amax1(epsabs,epsrel*abs(reseps)) + if(abserr.le.ertest) go to 100 +c +c prepare bisection of the smallest interval. +c + 70 if(numrl2.eq.1) noext = .true. + if(ier.eq.5) go to 100 + maxerr = iord(1) + errmax = elist(maxerr) + nrmax = 1 + extrap = .false. + small = small*0.5e+00 + erlarg = errsum + go to 90 + 80 small = 0.375e+00 + erlarg = errsum + ertest = errbnd + rlist2(2) = area + 90 continue +c +c set final result and error estimate. +c ------------------------------------ +c + 100 if(abserr.eq.oflow) go to 115 + if((ier+ierro).eq.0) go to 110 + if(ierro.eq.3) abserr = abserr+correc + if(ier.eq.0) ier = 3 + if(result.ne.0.0e+00.and.area.ne.0.0e+00)go to 105 + if(abserr.gt.errsum)go to 115 + if(area.eq.0.0e+00) go to 130 + go to 110 + 105 if(abserr/abs(result).gt.errsum/abs(area))go to 115 +c +c test on divergence +c + 110 if(ksgn.eq.(-1).and.amax1(abs(result),abs(area)).le. + * defabs*0.1e-01) go to 130 + if(0.1e-01.gt.(result/area).or.(result/area).gt.0.1e+03. + *or.errsum.gt.abs(area)) ier = 6 + go to 130 +c +c compute global integral sum. +c + 115 result = 0.0e+00 + do 120 k = 1,last + result = result+rlist(k) + 120 continue + abserr = errsum + 130 neval = 30*last-15 + if(inf.eq.2) neval = 2*neval + if(ier.gt.2) ier=ier-1 + 999 return + end diff --git a/libcruft/quadpack/qagp.f b/libcruft/quadpack/qagp.f new file mode 100644 --- /dev/null +++ b/libcruft/quadpack/qagp.f @@ -0,0 +1,223 @@ + subroutine qagp(f,a,b,npts2,points,epsabs,epsrel,result,abserr, + * neval,ier,leniw,lenw,last,iwork,work) +c***begin prologue qagp +c***date written 800101 (yymmdd) +c***revision date 830518 (yymmdd) +c***category no. h2a2a1 +c***keywords automatic integrator, general-purpose, +c singularities at user specified points, +c extrapolation, globally adaptive +c***author piessens,robert,appl. math. & progr. div - k.u.leuven +c de doncker,elise,appl. math. & progr. div. - k.u.leuven +c***purpose the routine calculates an approximation result to a given +c definite integral i = integral of f over (a,b), +c hopefully satisfying following claim for accuracy +c break points of the integration interval, where local +c difficulties of the integrand may occur(e.g. singularities, +c discontinuities), are provided by the user. +c***description +c +c computation of a definite integral +c standard fortran subroutine +c real version +c +c parameters +c on entry +c f - subroutine f(x,ierr,result) defining the integrand +c function f(x). the actual name for f needs to be +c declared e x t e r n a l in the driver program. +c +c a - real +c lower limit of integration +c +c b - real +c upper limit of integration +c +c npts2 - integer +c number equal to two more than the number of +c user-supplied break points within the integration +c range, npts.ge.2. +c if npts2.lt.2, the routine will end with ier = 6. +c +c points - real +c vector of dimension npts2, the first (npts2-2) +c elements of which are the user provided break +c points. if these points do not constitute an +c ascending sequence there will be an automatic +c sorting. +c +c epsabs - real +c absolute accuracy requested +c epsrel - real +c relative accuracy requested +c if epsabs.le.0 +c and epsrel.lt.max(50*rel.mach.acc.,0.5d-28), +c the routine will end with ier = 6. +c +c on return +c result - real +c approximation to the integral +c +c abserr - real +c estimate of the modulus of the absolute error, +c which should equal or exceed abs(i-result) +c +c neval - integer +c number of integrand evaluations +c +c ier - integer +c ier = 0 normal and reliable termination of the +c routine. it is assumed that the requested +c accuracy has been achieved. +c ier.gt.0 abnormal termination of the routine. +c the estimates for integral and error are +c less reliable. it is assumed that the +c requested accuracy has not been achieved. +c error messages +c ier = 1 maximum number of subdivisions allowed +c has been achieved. one can allow more +c subdivisions by increasing the value of +c limit (and taking the according dimension +c adjustments into account). however, if +c this yields no improvement it is advised +c to analyze the integrand in order to +c determine the integration difficulties. if +c the position of a local difficulty can be +c determined (i.e. singularity, +c discontinuity within the interval), it +c should be supplied to the routine as an +c element of the vector points. if necessary +c an appropriate special-purpose integrator +c must be used, which is designed for +c handling the type of difficulty involved. +c = 2 the occurrence of roundoff error is +c detected, which prevents the requested +c tolerance from being achieved. +c the error may be under-estimated. +c = 3 extremely bad integrand behaviour occurs +c at some points of the integration +c interval. +c = 4 the algorithm does not converge. +c roundoff error is detected in the +c extrapolation table. +c it is presumed that the requested +c tolerance cannot be achieved, and that +c the returned result is the best which +c can be obtained. +c = 5 the integral is probably divergent, or +c slowly convergent. it must be noted that +c divergence can occur with any other value +c of ier.gt.0. +c = 6 the input is invalid because +c npts2.lt.2 or +c break points are specified outside +c the integration range or +c (epsabs.le.0 and +c epsrel.lt.max(50*rel.mach.acc.,0.5d-28)) +c result, abserr, neval, last are set to +c zero. exept when leniw or lenw or npts2 is +c invalid, iwork(1), iwork(limit+1), +c work(limit*2+1) and work(limit*3+1) +c are set to zero. +c work(1) is set to a and work(limit+1) +c to b (where limit = (leniw-npts2)/2). +c +c dimensioning parameters +c leniw - integer +c dimensioning parameter for iwork +c leniw determines limit = (leniw-npts2)/2, +c which is the maximum number of subintervals in the +c partition of the given integration interval (a,b), +c leniw.ge.(3*npts2-2). +c if leniw.lt.(3*npts2-2), the routine will end with +c ier = 6. +c +c lenw - integer +c dimensioning parameter for work +c lenw must be at least leniw*2-npts2. +c if lenw.lt.leniw*2-npts2, the routine will end +c with ier = 6. +c +c last - integer +c on return, last equals the number of subintervals +c produced in the subdivision process, which +c determines the number of significant elements +c actually in the work arrays. +c +c work arrays +c iwork - integer +c vector of dimension at least leniw. on return, +c the first k elements of which contain +c pointers to the error estimates over the +c subintervals, such that work(limit*3+iwork(1)),..., +c work(limit*3+iwork(k)) form a decreasing +c sequence, with k = last if last.le.(limit/2+2), and +c k = limit+1-last otherwise +c iwork(limit+1), ...,iwork(limit+last) contain the +c subdivision levels of the subintervals, i.e. +c if (aa,bb) is a subinterval of (p1,p2) +c where p1 as well as p2 is a user-provided +c break point or integration limit, then (aa,bb) has +c level l if abs(bb-aa) = abs(p2-p1)*2**(-l), +c iwork(limit*2+1), ..., iwork(limit*2+npts2) have +c no significance for the user, +c note that limit = (leniw-npts2)/2. +c +c work - real +c vector of dimension at least lenw +c on return +c work(1), ..., work(last) contain the left +c end points of the subintervals in the +c partition of (a,b), +c work(limit+1), ..., work(limit+last) contain +c the right end points, +c work(limit*2+1), ..., work(limit*2+last) contain +c the integral approximations over the subintervals, +c work(limit*3+1), ..., work(limit*3+last) +c contain the corresponding error estimates, +c work(limit*4+1), ..., work(limit*4+npts2) +c contain the integration limits and the +c break points sorted in an ascending sequence. +c note that limit = (leniw-npts2)/2. +c +c***references (none) +c***routines called qagpe,xerror +c***end prologue qagp +c + real a,abserr,b,epsabs,epsrel,points,result,work + integer ier,iwork,leniw,lenw,limit,lvl,l1,l2,l3,neval,npts2 +c + dimension iwork(leniw),points(npts2),work(lenw) +c + external f +c +c check validity of limit and lenw. +c +c***first executable statement qagp + ier = 6 + neval = 0 + last = 0 + result = 0.0e+00 + abserr = 0.0e+00 + if(leniw.lt.(3*npts2-2).or.lenw.lt.(leniw*2-npts2).or.npts2.lt.2) + * go to 10 +c +c prepare call for qagpe. +c + limit = (leniw-npts2)/2 + l1 = limit+1 + l2 = limit+l1 + l3 = limit+l2 + l4 = limit+l3 +c + call qagpe(f,a,b,npts2,points,epsabs,epsrel,limit,result,abserr, + * neval,ier,work(1),work(l1),work(l2),work(l3),work(l4), + * iwork(1),iwork(l1),iwork(l2),last) +c +c call error handler if necessary. +c + lvl = 0 +10 if(ier.eq.6) lvl = 1 + if(ier.ne.0) call xerror('abnormal return from qagp',26,ier,lvl) + return + end diff --git a/libcruft/quadpack/qagpe.f b/libcruft/quadpack/qagpe.f new file mode 100644 --- /dev/null +++ b/libcruft/quadpack/qagpe.f @@ -0,0 +1,560 @@ + subroutine qagpe(f,a,b,npts2,points,epsabs,epsrel,limit,result, + * abserr,neval,ier,alist,blist,rlist,elist,pts,iord,level,ndin, + * last) +c***begin prologue qagpe +c***date written 800101 (yymmdd) +c***revision date 830518 (yymmdd) +c***category no. h2a2a1 +c***keywords automatic integrator, general-purpose, +c singularities at user specified points, +c extrapolation, globally adaptive. +c***author piessens,robert ,appl. math. & progr. div. - k.u.leuven +c de doncker,elise,appl. math. & progr. div. - k.u.leuven +c***purpose the routine calculates an approximation result to a given +c definite integral i = integral of f over (a,b),hopefully +c satisfying following claim for accuracy abs(i-result).le. +c max(epsabs,epsrel*abs(i)). break points of the integration +c interval, where local difficulties of the integrand may +c occur(e.g. singularities,discontinuities),provided by user. +c***description +c +c computation of a definite integral +c standard fortran subroutine +c real version +c +c parameters +c on entry +c f - subroutine f(x,ierr,result) defining the integrand +c function f(x). the actual name for f needs to be +c declared e x t e r n a l in the driver program. +c +c a - real +c lower limit of integration +c +c b - real +c upper limit of integration +c +c npts2 - integer +c number equal to two more than the number of +c user-supplied break points within the integration +c range, npts2.ge.2. +c if npts2.lt.2, the routine will end with ier = 6. +c +c points - real +c vector of dimension npts2, the first (npts2-2) +c elements of which are the user provided break +c points. if these points do not constitute an +c ascending sequence there will be an automatic +c sorting. +c +c epsabs - real +c absolute accuracy requested +c epsrel - real +c relative accuracy requested +c if epsabs.le.0 +c and epsrel.lt.max(50*rel.mach.acc.,0.5d-28), +c the routine will end with ier = 6. +c +c limit - integer +c gives an upper bound on the number of subintervals +c in the partition of (a,b), limit.ge.npts2 +c if limit.lt.npts2, the routine will end with +c ier = 6. +c +c on return +c result - real +c approximation to the integral +c +c abserr - real +c estimate of the modulus of the absolute error, +c which should equal or exceed abs(i-result) +c +c neval - integer +c number of integrand evaluations +c +c ier - integer +c ier = 0 normal and reliable termination of the +c routine. it is assumed that the requested +c accuracy has been achieved. +c ier.gt.0 abnormal termination of the routine. +c the estimates for integral and error are +c less reliable. it is assumed that the +c requested accuracy has not been achieved. +c error messages +c ier = 1 maximum number of subdivisions allowed +c has been achieved. one can allow more +c subdivisions by increasing the value of +c limit (and taking the according dimension +c adjustments into account). however, if +c this yields no improvement it is advised +c to analyze the integrand in order to +c determine the integration difficulties. if +c the position of a local difficulty can be +c determined (i.e. singularity, +c discontinuity within the interval), it +c should be supplied to the routine as an +c element of the vector points. if necessary +c an appropriate special-purpose integrator +c must be used, which is designed for +c handling the type of difficulty involved. +c = 2 the occurrence of roundoff error is +c detected, which prevents the requested +c tolerance from being achieved. +c the error may be under-estimated. +c = 3 extremely bad integrand behaviour occurs +c at some points of the integration +c interval. +c = 4 the algorithm does not converge. +c roundoff error is detected in the +c extrapolation table. it is presumed that +c the requested tolerance cannot be +c achieved, and that the returned result is +c the best which can be obtained. +c = 5 the integral is probably divergent, or +c slowly convergent. it must be noted that +c divergence can occur with any other value +c of ier.gt.0. +c = 6 the input is invalid because +c npts2.lt.2 or +c break points are specified outside +c the integration range or +c (epsabs.le.0 and +c epsrel.lt.max(50*rel.mach.acc.,0.5d-28)) +c or limit.lt.npts2. +c result, abserr, neval, last, rlist(1), +c and elist(1) are set to zero. alist(1) and +c blist(1) are set to a and b respectively. +c +c alist - real +c vector of dimension at least limit, the first +c last elements of which are the left end points +c of the subintervals in the partition of the given +c integration range (a,b) +c +c blist - real +c vector of dimension at least limit, the first +c last elements of which are the right end points +c of the subintervals in the partition of the given +c integration range (a,b) +c +c rlist - real +c vector of dimension at least limit, the first +c last elements of which are the integral +c approximations on the subintervals +c +c elist - real +c vector of dimension at least limit, the first +c last elements of which are the moduli of the +c absolute error estimates on the subintervals +c +c pts - real +c vector of dimension at least npts2, containing the +c integration limits and the break points of the +c interval in ascending sequence. +c +c level - integer +c vector of dimension at least limit, containing the +c subdivision levels of the subinterval, i.e. if +c (aa,bb) is a subinterval of (p1,p2) where p1 as +c well as p2 is a user-provided break point or +c integration limit, then (aa,bb) has level l if +c abs(bb-aa) = abs(p2-p1)*2**(-l). +c +c ndin - integer +c vector of dimension at least npts2, after first +c integration over the intervals (pts(i)),pts(i+1), +c i = 0,1, ..., npts2-2, the error estimates over +c some of the intervals may have been increased +c artificially, in order to put their subdivision +c forward. if this happens for the subinterval +c numbered k, ndin(k) is put to 1, otherwise +c ndin(k) = 0. +c +c iord - integer +c vector of dimension at least limit, the first k +c elements of which are pointers to the +c error estimates over the subintervals, +c such that elist(iord(1)), ..., elist(iord(k)) +c form a decreasing sequence, with k = last +c if last.le.(limit/2+2), and k = limit+1-last +c otherwise +c +c last - integer +c number of subintervals actually produced in the +c subdivisions process +c +c***references (none) +c***routines called qelg,qk21,qpsrt,r1mach +c***end prologue qagpe + real a,abseps,abserr,alist,area,area1,area12,area2,a1, + * a2,b,blist,b1,b2,correc,defabs,defab1,defab2, + * dres,r1mach,elist,epmach,epsabs,epsrel,erlarg,erlast,errbnd, + * errmax,error1,erro12,error2,errsum,ertest,oflow,points,pts, + * resa,resabs,reseps,result,res3la,rlist,rlist2,sign,temp, + * uflow + integer i,id,ier,ierro,ind1,ind2,iord,ip1,iroff1,iroff2, + * iroff3,j,jlow,jupbnd,k,ksgn,ktmin,last,levcur,level,levmax, + * limit,maxerr,ndin,neval,nint,nintp1,npts,npts2,nres, + * nrmax,numrl2 + logical extrap,noext +c +c + dimension alist(limit),blist(limit),elist(limit),iord(limit), + * level(limit),ndin(npts2),points(npts2),pts(npts2),res3la(3), + * rlist(limit),rlist2(52) +c + external f +c +c the dimension of rlist2 is determined by the value of +c limexp in subroutine epsalg (rlist2 should be of dimension +c (limexp+2) at least). +c +c +c list of major variables +c ----------------------- +c +c alist - list of left end points of all subintervals +c considered up to now +c blist - list of right end points of all subintervals +c considered up to now +c rlist(i) - approximation to the integral over +c (alist(i),blist(i)) +c rlist2 - array of dimension at least limexp+2 +c containing the part of the epsilon table which +c is still needed for further computations +c elist(i) - error estimate applying to rlist(i) +c maxerr - pointer to the interval with largest error +c estimate +c errmax - elist(maxerr) +c erlast - error on the interval currently subdivided +c (before that subdivision has taken place) +c area - sum of the integrals over the subintervals +c errsum - sum of the errors over the subintervals +c errbnd - requested accuracy max(epsabs,epsrel* +c abs(result)) +c *****1 - variable for the left subinterval +c *****2 - variable for the right subinterval +c last - index for subdivision +c nres - number of calls to the extrapolation routine +c numrl2 - number of elements in rlist2. if an +c appropriate approximation to the compounded +c integral has been obtained, it is put in +c rlist2(numrl2) after numrl2 has been increased +c by one. +c erlarg - sum of the errors over the intervals larger +c than the smallest interval considered up to now +c extrap - logical variable denoting that the routine +c is attempting to perform extrapolation. i.e. +c before subdividing the smallest interval we +c try to decrease the value of erlarg. +c noext - logical variable denoting that extrapolation is +c no longer allowed (true-value) +c +c machine dependent constants +c --------------------------- +c +c epmach is the largest relative spacing. +c uflow is the smallest positive magnitude. +c oflow is the largest positive magnitude. +c +c***first executable statement qagpe + epmach = r1mach(4) +c +c test on validity of parameters +c ----------------------------- +c + ier = 0 + neval = 0 + last = 0 + result = 0.0e+00 + abserr = 0.0e+00 + alist(1) = a + blist(1) = b + rlist(1) = 0.0e+00 + elist(1) = 0.0e+00 + iord(1) = 0 + level(1) = 0 + npts = npts2-2 + if(npts2.lt.2.or.limit.le.npts.or.(epsabs.le.0.0e+00.and. + * epsrel.lt.amax1(0.5e+02*epmach,0.5e-14))) ier = 6 + if(ier.eq.6) go to 210 +c +c if any break points are provided, sort them into an +c ascending sequence. +c + sign = 1.0e+00 + if(a.gt.b) sign = -1.0e+00 + pts(1) = amin1(a,b) + if(npts.eq.0) go to 15 + do 10 i = 1,npts + pts(i+1) = points(i) + 10 continue + 15 pts(npts+2) = amax1(a,b) + nint = npts+1 + a1 = pts(1) + if(npts.eq.0) go to 40 + nintp1 = nint+1 + do 20 i = 1,nint + ip1 = i+1 + do 20 j = ip1,nintp1 + if(pts(i).le.pts(j)) go to 20 + temp = pts(i) + pts(i) = pts(j) + pts(j) = temp + 20 continue + if(pts(1).ne.amin1(a,b).or.pts(nintp1).ne. + * amax1(a,b)) ier = 6 + if(ier.eq.6) go to 999 +c +c compute first integral and error approximations. +c ------------------------------------------------ +c + 40 resabs = 0.0e+00 + do 50 i = 1,nint + b1 = pts(i+1) + call qk21(f,a1,b1,area1,error1,defabs,resa,ier) + if (ier.lt.0) return + abserr = abserr+error1 + result = result+area1 + ndin(i) = 0 + if(error1.eq.resa.and.error1.ne.0.0e+00) ndin(i) = 1 + resabs = resabs+defabs + level(i) = 0 + elist(i) = error1 + alist(i) = a1 + blist(i) = b1 + rlist(i) = area1 + iord(i) = i + a1 = b1 + 50 continue + errsum = 0.0e+00 + do 55 i = 1,nint + if(ndin(i).eq.1) elist(i) = abserr + errsum = errsum+elist(i) + 55 continue +c +c test on accuracy. +c + last = nint + neval = 21*nint + dres = abs(result) + errbnd = amax1(epsabs,epsrel*dres) + if(abserr.le.0.1e+03*epmach*resabs.and.abserr.gt. + * errbnd) ier = 2 + if(nint.eq.1) go to 80 + do 70 i = 1,npts + jlow = i+1 + ind1 = iord(i) + do 60 j = jlow,nint + ind2 = iord(j) + if(elist(ind1).gt.elist(ind2)) go to 60 + ind1 = ind2 + k = j + 60 continue + if(ind1.eq.iord(i)) go to 70 + iord(k) = iord(i) + iord(i) = ind1 + 70 continue + if(limit.lt.npts2) ier = 1 + 80 if(ier.ne.0.or.abserr.le.errbnd) go to 999 +c +c initialization +c -------------- +c + rlist2(1) = result + maxerr = iord(1) + errmax = elist(maxerr) + area = result + nrmax = 1 + nres = 0 + numrl2 = 1 + ktmin = 0 + extrap = .false. + noext = .false. + erlarg = errsum + ertest = errbnd + levmax = 1 + iroff1 = 0 + iroff2 = 0 + iroff3 = 0 + ierro = 0 + uflow = r1mach(1) + oflow = r1mach(2) + abserr = oflow + ksgn = -1 + if(dres.ge.(0.1e+01-0.5e+02*epmach)*resabs) ksgn = 1 +c +c main do-loop +c ------------ +c + do 160 last = npts2,limit +c +c bisect the subinterval with the nrmax-th largest +c error estimate. +c + levcur = level(maxerr)+1 + a1 = alist(maxerr) + b1 = 0.5e+00*(alist(maxerr)+blist(maxerr)) + a2 = b1 + b2 = blist(maxerr) + erlast = errmax + call qk21(f,a1,b1,area1,error1,resa,defab1,ier) + if (ier.lt.0) return + call qk21(f,a2,b2,area2,error2,resa,defab2,ier) + if (ier.lt.0) return +c +c improve previous approximations to integral +c and error and test for accuracy. +c + neval = neval+42 + area12 = area1+area2 + erro12 = error1+error2 + errsum = errsum+erro12-errmax + area = area+area12-rlist(maxerr) + if(defab1.eq.error1.or.defab2.eq.error2) go to 95 + if(abs(rlist(maxerr)-area12).gt.0.1e-04*abs(area12) + * .or.erro12.lt.0.99e+00*errmax) go to 90 + if(extrap) iroff2 = iroff2+1 + if(.not.extrap) iroff1 = iroff1+1 + 90 if(last.gt.10.and.erro12.gt.errmax) iroff3 = iroff3+1 + 95 level(maxerr) = levcur + level(last) = levcur + rlist(maxerr) = area1 + rlist(last) = area2 + errbnd = amax1(epsabs,epsrel*abs(area)) +c +c test for roundoff error and eventually +c set error flag. +c + if(iroff1+iroff2.ge.10.or.iroff3.ge.20) ier = 2 + if(iroff2.ge.5) ierro = 3 +c +c set error flag in the case that the number of +c subintervals equals limit. +c + if(last.eq.limit) ier = 1 +c +c set error flag in the case of bad integrand behaviour +c at a point of the integration range +c + if(amax1(abs(a1),abs(b2)).le.(0.1e+01+0.1e+03*epmach)* + * (abs(a2)+0.1e+04*uflow)) ier = 4 +c +c append the newly-created intervals to the list. +c + if(error2.gt.error1) go to 100 + alist(last) = a2 + blist(maxerr) = b1 + blist(last) = b2 + elist(maxerr) = error1 + elist(last) = error2 + go to 110 + 100 alist(maxerr) = a2 + alist(last) = a1 + blist(last) = b1 + rlist(maxerr) = area2 + rlist(last) = area1 + elist(maxerr) = error2 + elist(last) = error1 +c +c call subroutine qpsrt to maintain the descending ordering +c in the list of error estimates and select the +c subinterval with nrmax-th largest error estimate (to be +c bisected next). +c + 110 call qpsrt(limit,last,maxerr,errmax,elist,iord,nrmax) +c ***jump out of do-loop + if(errsum.le.errbnd) go to 190 +c ***jump out of do-loop + if(ier.ne.0) go to 170 + if(noext) go to 160 + erlarg = erlarg-erlast + if(levcur+1.le.levmax) erlarg = erlarg+erro12 + if(extrap) go to 120 +c +c test whether the interval to be bisected next is the +c smallest interval. +c + if(level(maxerr)+1.le.levmax) go to 160 + extrap = .true. + nrmax = 2 + 120 if(ierro.eq.3.or.erlarg.le.ertest) go to 140 +c +c the smallest interval has the largest error. +c before bisecting decrease the sum of the errors +c over the larger intervals (erlarg) and perform +c extrapolation. +c + id = nrmax + jupbnd = last + if(last.gt.(2+limit/2)) jupbnd = limit+3-last + do 130 k = id,jupbnd + maxerr = iord(nrmax) + errmax = elist(maxerr) +c ***jump out of do-loop + if(level(maxerr)+1.le.levmax) go to 160 + nrmax = nrmax+1 + 130 continue +c +c perform extrapolation. +c + 140 numrl2 = numrl2+1 + rlist2(numrl2) = area + if(numrl2.le.2) go to 155 + call qelg(numrl2,rlist2,reseps,abseps,res3la,nres) + ktmin = ktmin+1 + if(ktmin.gt.5.and.abserr.lt.0.1e-02*errsum) ier = 5 + if(abseps.ge.abserr) go to 150 + ktmin = 0 + abserr = abseps + result = reseps + correc = erlarg + ertest = amax1(epsabs,epsrel*abs(reseps)) +c ***jump out of do-loop + if(abserr.lt.ertest) go to 170 +c +c prepare bisection of the smallest interval. +c + 150 if(numrl2.eq.1) noext = .true. + if(ier.ge.5) go to 170 + 155 maxerr = iord(1) + errmax = elist(maxerr) + nrmax = 1 + extrap = .false. + levmax = levmax+1 + erlarg = errsum + 160 continue +c +c set the final result. +c --------------------- +c +c + 170 if(abserr.eq.oflow) go to 190 + if((ier+ierro).eq.0) go to 180 + if(ierro.eq.3) abserr = abserr+correc + if(ier.eq.0) ier = 3 + if(result.ne.0.0e+00.and.area.ne.0.0e+00)go to 175 + if(abserr.gt.errsum)go to 190 + if(area.eq.0.0e+00) go to 210 + go to 180 + 175 if(abserr/abs(result).gt.errsum/abs(area))go to 190 +c +c test on divergence. +c + 180 if(ksgn.eq.(-1).and.amax1(abs(result),abs(area)).le. + * resabs*0.1e-01) go to 210 + if(0.1e-01.gt.(result/area).or.(result/area).gt.0.1e+03.or. + * errsum.gt.abs(area)) ier = 6 + go to 210 +c +c compute global integral sum. +c + 190 result = 0.0e+00 + do 200 k = 1,last + result = result+rlist(k) + 200 continue + abserr = errsum + 210 if(ier.gt.2) ier = ier - 1 + result = result*sign + 999 return + end diff --git a/libcruft/quadpack/qelg.f b/libcruft/quadpack/qelg.f new file mode 100644 --- /dev/null +++ b/libcruft/quadpack/qelg.f @@ -0,0 +1,184 @@ + subroutine qelg(n,epstab,result,abserr,res3la,nres) +c***begin prologue qelg +c***refer to qagie,qagoe,qagpe,qagse +c***routines called r1mach +c***revision date 830518 (yymmdd) +c***keywords epsilon algorithm, convergence acceleration, +c extrapolation +c***author piessens,robert,appl. math. & progr. div. - k.u.leuven +c de doncker,elise,appl. math & progr. div. - k.u.leuven +c***purpose the routine determines the limit of a given sequence of +c approximations, by means of the epsilon algorithm of +c p. wynn. an estimate of the absolute error is also given. +c the condensed epsilon table is computed. only those +c elements needed for the computation of the next diagonal +c are preserved. +c***description +c +c epsilon algorithm +c standard fortran subroutine +c real version +c +c parameters +c n - integer +c epstab(n) contains the new element in the +c first column of the epsilon table. +c +c epstab - real +c vector of dimension 52 containing the elements +c of the two lower diagonals of the triangular +c epsilon table. the elements are numbered +c starting at the right-hand corner of the +c triangle. +c +c result - real +c resulting approximation to the integral +c +c abserr - real +c estimate of the absolute error computed from +c result and the 3 previous results +c +c res3la - real +c vector of dimension 3 containing the last 3 +c results +c +c nres - integer +c number of calls to the routine +c (should be zero at first call) +c +c***end prologue qelg +c + real abserr,delta1,delta2,delta3,r1mach, + * epmach,epsinf,epstab,error,err1,err2,err3,e0,e1,e1abs,e2,e3, + * oflow,res,result,res3la,ss,tol1,tol2,tol3 + integer i,ib,ib2,ie,indx,k1,k2,k3,limexp,n,newelm,nres,num + dimension epstab(52),res3la(3) +c +c list of major variables +c ----------------------- +c +c e0 - the 4 elements on which the +c e1 computation of a new element in +c e2 the epsilon table is based +c e3 e0 +c e3 e1 new +c e2 +c newelm - number of elements to be computed in the new +c diagonal +c error - error = abs(e1-e0)+abs(e2-e1)+abs(new-e2) +c result - the element in the new diagonal with least value +c of error +c +c machine dependent constants +c --------------------------- +c +c epmach is the largest relative spacing. +c oflow is the largest positive magnitude. +c limexp is the maximum number of elements the epsilon +c table can contain. if this number is reached, the upper +c diagonal of the epsilon table is deleted. +c +c***first executable statement qelg + epmach = r1mach(4) + oflow = r1mach(2) + nres = nres+1 + abserr = oflow + result = epstab(n) + if(n.lt.3) go to 100 + limexp = 50 + epstab(n+2) = epstab(n) + newelm = (n-1)/2 + epstab(n) = oflow + num = n + k1 = n + do 40 i = 1,newelm + k2 = k1-1 + k3 = k1-2 + res = epstab(k1+2) + e0 = epstab(k3) + e1 = epstab(k2) + e2 = res + e1abs = abs(e1) + delta2 = e2-e1 + err2 = abs(delta2) + tol2 = amax1(abs(e2),e1abs)*epmach + delta3 = e1-e0 + err3 = abs(delta3) + tol3 = amax1(e1abs,abs(e0))*epmach + if(err2.gt.tol2.or.err3.gt.tol3) go to 10 +c +c if e0, e1 and e2 are equal to within machine +c accuracy, convergence is assumed. +c result = e2 +c abserr = abs(e1-e0)+abs(e2-e1) +c + result = res + abserr = err2+err3 +c ***jump out of do-loop + go to 100 + 10 e3 = epstab(k1) + epstab(k1) = e1 + delta1 = e1-e3 + err1 = abs(delta1) + tol1 = amax1(e1abs,abs(e3))*epmach +c +c if two elements are very close to each other, omit +c a part of the table by adjusting the value of n +c + if(err1.le.tol1.or.err2.le.tol2.or.err3.le.tol3) go to 20 + ss = 0.1e+01/delta1+0.1e+01/delta2-0.1e+01/delta3 + epsinf = abs(ss*e1) +c +c test to detect irregular behaviour in the table, and +c eventually omit a part of the table adjusting the value +c of n. +c + if(epsinf.gt.0.1e-03) go to 30 + 20 n = i+i-1 +c ***jump out of do-loop + go to 50 +c +c compute a new element and eventually adjust +c the value of result. +c + 30 res = e1+0.1e+01/ss + epstab(k1) = res + k1 = k1-2 + error = err2+abs(res-e2)+err3 + if(error.gt.abserr) go to 40 + abserr = error + result = res + 40 continue +c +c shift the table. +c + 50 if(n.eq.limexp) n = 2*(limexp/2)-1 + ib = 1 + if((num/2)*2.eq.num) ib = 2 + ie = newelm+1 + do 60 i=1,ie + ib2 = ib+2 + epstab(ib) = epstab(ib2) + ib = ib2 + 60 continue + if(num.eq.n) go to 80 + indx = num-n+1 + do 70 i = 1,n + epstab(i)= epstab(indx) + indx = indx+1 + 70 continue + 80 if(nres.ge.4) go to 90 + res3la(nres) = result + abserr = oflow + go to 100 +c +c compute error estimate +c + 90 abserr = abs(result-res3la(3))+abs(result-res3la(2)) + * +abs(result-res3la(1)) + res3la(1) = res3la(2) + res3la(2) = res3la(3) + res3la(3) = result + 100 abserr = amax1(abserr,0.5e+01*epmach*abs(result)) + return + end diff --git a/libcruft/quadpack/qk15i.f b/libcruft/quadpack/qk15i.f new file mode 100644 --- /dev/null +++ b/libcruft/quadpack/qk15i.f @@ -0,0 +1,202 @@ + subroutine qk15i(f,boun,inf,a,b,result,abserr,resabs,resasc,ierr) +c***begin prologue qk15i +c***date written 800101 (yymmdd) +c***revision date 830518 (yymmdd) +c***category no. h2a3a2,h2a4a2 +c***keywords 15-point transformed gauss-kronrod rules +c***author piessens,robert,appl. math. & progr. div. - k.u.leuven +c de doncker,elise,appl. math. & progr. div. - k.u.leuven +c***purpose the original (infinite integration range is mapped +c onto the interval (0,1) and (a,b) is a part of (0,1). +c it is the purpose to compute +c i = integral of transformed integrand over (a,b), +c j = integral of abs(transformed integrand) over (a,b). +c***description +c +c integration rule +c standard fortran subroutine +c real version +c +c parameters +c on entry +c f - subroutine f(x,ierr,result) defining the integrand +c function f(x). the actual name for f needs to be +c declared e x t e r n a l in the calling program. +c +c boun - real +c finite bound of original integration +c range (set to zero if inf = +2) +c +c inf - integer +c if inf = -1, the original interval is +c (-infinity,bound), +c if inf = +1, the original interval is +c (bound,+infinity), +c if inf = +2, the original interval is +c (-infinity,+infinity) and +c the integral is computed as the sum of two +c integrals, one over (-infinity,0) and one over +c (0,+infinity). +c +c a - real +c lower limit for integration over subrange +c of (0,1) +c +c b - real +c upper limit for integration over subrange +c of (0,1) +c +c on return +c result - real +c approximation to the integral i +c result is computed by applying the 15-point +c kronrod rule(resk) obtained by optimal addition +c of abscissae to the 7-point gauss rule(resg). +c +c abserr - real +c estimate of the modulus of the absolute error, +c which should equal or exceed abs(i-result) +c +c resabs - real +c approximation to the integral j +c +c resasc - real +c approximation to the integral of +c abs((transformed integrand)-i/(b-a)) over (a,b) +c +c***references (none) +c***routines called r1mach +c***end prologue qk15i +c + real a,absc,absc1,absc2,abserr,b,boun,centr, + * dinf,r1mach,epmach,fc,fsum,fval1,fval2,fvalt,fv1, + * fv2,hlgth,resabs,resasc,resg,resk,reskh,result,tabsc1,tabsc2, + * uflow,wg,wgk,xgk + integer inf,j,min0 + external f +c + dimension fv1(7),fv2(7),xgk(8),wgk(8),wg(8) +c +c the abscissae and weights are supplied for the interval +c (-1,1). because of symmetry only the positive abscissae and +c their corresponding weights are given. +c +c xgk - abscissae of the 15-point kronrod rule +c xgk(2), xgk(4), ... abscissae of the 7-point +c gauss rule +c xgk(1), xgk(3), ... abscissae which are optimally +c added to the 7-point gauss rule +c +c wgk - weights of the 15-point kronrod rule +c +c wg - weights of the 7-point gauss rule, corresponding +c to the abscissae xgk(2), xgk(4), ... +c wg(1), wg(3), ... are set to zero. +c + data xgk(1),xgk(2),xgk(3),xgk(4),xgk(5),xgk(6),xgk(7), + * xgk(8)/ + * 0.9914553711208126e+00, 0.9491079123427585e+00, + * 0.8648644233597691e+00, 0.7415311855993944e+00, + * 0.5860872354676911e+00, 0.4058451513773972e+00, + * 0.2077849550078985e+00, 0.0000000000000000e+00/ +c + data wgk(1),wgk(2),wgk(3),wgk(4),wgk(5),wgk(6),wgk(7), + * wgk(8)/ + * 0.2293532201052922e-01, 0.6309209262997855e-01, + * 0.1047900103222502e+00, 0.1406532597155259e+00, + * 0.1690047266392679e+00, 0.1903505780647854e+00, + * 0.2044329400752989e+00, 0.2094821410847278e+00/ +c + data wg(1),wg(2),wg(3),wg(4),wg(5),wg(6),wg(7),wg(8)/ + * 0.0000000000000000e+00, 0.1294849661688697e+00, + * 0.0000000000000000e+00, 0.2797053914892767e+00, + * 0.0000000000000000e+00, 0.3818300505051189e+00, + * 0.0000000000000000e+00, 0.4179591836734694e+00/ +c +c +c list of major variables +c ----------------------- +c +c centr - mid point of the interval +c hlgth - half-length of the interval +c absc* - abscissa +c tabsc* - transformed abscissa +c fval* - function value +c resg - result of the 7-point gauss formula +c resk - result of the 15-point kronrod formula +c reskh - approximation to the mean value of the transformed +c integrand over (a,b), i.e. to i/(b-a) +c +c machine dependent constants +c --------------------------- +c +c epmach is the largest relative spacing. +c uflow is the smallest positive magnitude. +c +c***first executable statement qk15i + epmach = r1mach(4) + uflow = r1mach(1) + dinf = min0(1,inf) +c + centr = 0.5e+00*(a+b) + hlgth = 0.5e+00*(b-a) + tabsc1 = boun+dinf*(0.1e+01-centr)/centr + call f(tabsc1, ierr, fval1) + if (ierr.lt.0) return + if(inf.eq.2) then + call f(-tabsc1, ierr, fval1) + if (ierr.lt.0) return + fval1 = fval1 + fvalt + endif + fc = (fval1/centr)/centr +c +c compute the 15-point kronrod approximation to +c the integral, and estimate the error. +c + resg = wg(8)*fc + resk = wgk(8)*fc + resabs = abs(resk) + do 10 j=1,7 + absc = hlgth*xgk(j) + absc1 = centr-absc + absc2 = centr+absc + tabsc1 = boun+dinf*(0.1e+01-absc1)/absc1 + tabsc2 = boun+dinf*(0.1e+01-absc2)/absc2 + call f(tabsc1, ierr, fval1) + if (ierr.lt.0) return + call f(tabsc2, ierr, fval2) + if (ierr.lt.0) return + if(inf.eq.2) then + call f(-tabsc1,ierr,fvalt) + if (ierr.lt.0) return + fval1 = fval1 + fvalt; + endif + if(inf.eq.2) then + call f(-tabsc2,ierr,fvalt) + if (ierr.lt.0) return + fval2 = fval2 + fvalt; + endif + fval1 = (fval1/absc1)/absc1 + fval2 = (fval2/absc2)/absc2 + fv1(j) = fval1 + fv2(j) = fval2 + fsum = fval1+fval2 + resg = resg+wg(j)*fsum + resk = resk+wgk(j)*fsum + resabs = resabs+wgk(j)*(abs(fval1)+abs(fval2)) + 10 continue + reskh = resk*0.5e+00 + resasc = wgk(8)*abs(fc-reskh) + do 20 j=1,7 + resasc = resasc+wgk(j)*(abs(fv1(j)-reskh)+abs(fv2(j)-reskh)) + 20 continue + result = resk*hlgth + resasc = resasc*hlgth + resabs = resabs*hlgth + abserr = abs((resk-resg)*hlgth) + if(resasc.ne.0.0e+00.and.abserr.ne.0.e0) abserr = resasc* + * amin1(0.1e+01,(0.2e+03*abserr/resasc)**1.5e+00) + if(resabs.gt.uflow/(0.5e+02*epmach)) abserr = amax1 + * ((epmach*0.5e+02)*resabs,abserr) + return + end diff --git a/libcruft/quadpack/qk21.f b/libcruft/quadpack/qk21.f new file mode 100644 --- /dev/null +++ b/libcruft/quadpack/qk21.f @@ -0,0 +1,175 @@ + subroutine qk21(f,a,b,result,abserr,resabs,resasc,ierr) +c***begin prologue qk21 +c***date written 800101 (yymmdd) +c***revision date 830518 (yymmdd) +c***category no. h2a1a2 +c***keywords 21-point gauss-kronrod rules +c***author piessens,robert,appl. math. & progr. div. - k.u.leuven +c de doncker,elise,appl. math. & progr. div. - k.u.leuven +c***purpose to compute i = integral of f over (a,b), with error +c estimate +c j = integral of abs(f) over (a,b) +c***description +c +c integration rules +c standard fortran subroutine +c real version +c +c parameters +c on entry +c f - subroutine f(x,ierr,result) defining the integrand +c function f(x). the actual name for f needs to be +c declared e x t e r n a l in the driver program. +c +c a - real +c lower limit of integration +c +c b - real +c upper limit of integration +c +c on return +c result - real +c approximation to the integral i +c result is computed by applying the 21-point +c kronrod rule (resk) obtained by optimal addition +c of abscissae to the 10-point gauss rule (resg). +c +c abserr - real +c estimate of the modulus of the absolute error, +c which should not exceed abs(i-result) +c +c resabs - real +c approximation to the integral j +c +c resasc - real +c approximation to the integral of abs(f-i/(b-a)) +c over (a,b) +c +c***references (none) +c***routines called r1mach +c***end prologue qk21 +c + real a,absc,abserr,b,centr,dhlgth,epmach,fc,fsum,fval1,fval2, + * fv1,fv2,hlgth,resabs,resg,resk,reskh,result,r1mach,uflow,wg,wgk, + * xgk + integer j,jtw,jtwm1 + external f +c + dimension fv1(10),fv2(10),wg(5),wgk(11),xgk(11) +c +c the abscissae and weights are given for the interval (-1,1). +c because of symmetry only the positive abscissae and their +c corresponding weights are given. +c +c xgk - abscissae of the 21-point kronrod rule +c xgk(2), xgk(4), ... abscissae of the 10-point +c gauss rule +c xgk(1), xgk(3), ... abscissae which are optimally +c added to the 10-point gauss rule +c +c wgk - weights of the 21-point kronrod rule +c +c wg - weights of the 10-point gauss rule +c + data xgk(1),xgk(2),xgk(3),xgk(4),xgk(5),xgk(6),xgk(7), + * xgk(8),xgk(9),xgk(10),xgk(11)/ + * 0.9956571630258081e+00, 0.9739065285171717e+00, + * 0.9301574913557082e+00, 0.8650633666889845e+00, + * 0.7808177265864169e+00, 0.6794095682990244e+00, + * 0.5627571346686047e+00, 0.4333953941292472e+00, + * 0.2943928627014602e+00, 0.1488743389816312e+00, + * 0.0000000000000000e+00/ +c + data wgk(1),wgk(2),wgk(3),wgk(4),wgk(5),wgk(6),wgk(7), + * wgk(8),wgk(9),wgk(10),wgk(11)/ + * 0.1169463886737187e-01, 0.3255816230796473e-01, + * 0.5475589657435200e-01, 0.7503967481091995e-01, + * 0.9312545458369761e-01, 0.1093871588022976e+00, + * 0.1234919762620659e+00, 0.1347092173114733e+00, + * 0.1427759385770601e+00, 0.1477391049013385e+00, + * 0.1494455540029169e+00/ +c + data wg(1),wg(2),wg(3),wg(4),wg(5)/ + * 0.6667134430868814e-01, 0.1494513491505806e+00, + * 0.2190863625159820e+00, 0.2692667193099964e+00, + * 0.2955242247147529e+00/ +c +c +c list of major variables +c ----------------------- +c +c centr - mid point of the interval +c hlgth - half-length of the interval +c absc - abscissa +c fval* - function value +c resg - result of the 10-point gauss formula +c resk - result of the 21-point kronrod formula +c reskh - approximation to the mean value of f over (a,b), +c i.e. to i/(b-a) +c +c +c machine dependent constants +c --------------------------- +c +c epmach is the largest relative spacing. +c uflow is the smallest positive magnitude. +c +c***first executable statement qk21 + epmach = r1mach(4) + uflow = r1mach(1) +c + centr = 0.5e+00*(a+b) + hlgth = 0.5e+00*(b-a) + dhlgth = abs(hlgth) +c +c compute the 21-point kronrod approximation to +c the integral, and estimate the absolute error. +c + resg = 0.0e+00 + call f(centr, ierr, fc) + if (ierr .lt. 0) return + resk = wgk(11)*fc + resabs = abs(resk) + do 10 j=1,5 + jtw = 2*j + absc = hlgth*xgk(jtw) + call f(centr-absc,ierr,fval1) + if (ierr .lt. 0) return + call f(centr+absc,ierr,fval2) + if (ierr .lt. 0) return + fv1(jtw) = fval1 + fv2(jtw) = fval2 + fsum = fval1+fval2 + resg = resg+wg(j)*fsum + resk = resk+wgk(jtw)*fsum + resabs = resabs+wgk(jtw)*(abs(fval1)+abs(fval2)) + 10 continue + do 15 j = 1,5 + jtwm1 = 2*j-1 + absc = hlgth*xgk(jtwm1) + call f(centr-absc,ierr,fval1) + if (ierr .lt. 0) return + call f(centr+absc,ierr,fval2) + if (ierr .lt. 0) return + fv1(jtwm1) = fval1 + fv2(jtwm1) = fval2 + fsum = fval1+fval2 + resk = resk+wgk(jtwm1)*fsum + resabs = resabs+wgk(jtwm1)*(abs(fval1)+abs(fval2)) + 15 continue + reskh = resk*0.5e+00 + resasc = wgk(11)*abs(fc-reskh) + do 20 j=1,10 + resasc = resasc+wgk(j)*(abs(fv1(j)-reskh)+abs(fv2(j)-reskh)) + 20 continue + result = resk*hlgth + resabs = resabs*dhlgth + resasc = resasc*dhlgth + abserr = abs((resk-resg)*hlgth) + if(resasc.ne.0.0e+00.and.abserr.ne.0.0e+00) + * abserr = resasc*amin1(0.1e+01, + * (0.2e+03*abserr/resasc)**1.5e+00) + if(resabs.gt.uflow/(0.5e+02*epmach)) abserr = amax1 + * ((epmach*0.5e+02)*resabs,abserr) + return + end diff --git a/libcruft/quadpack/qpsrt.f b/libcruft/quadpack/qpsrt.f new file mode 100644 --- /dev/null +++ b/libcruft/quadpack/qpsrt.f @@ -0,0 +1,136 @@ + subroutine qpsrt(limit,last,maxerr,ermax,elist,iord,nrmax) +c***begin prologue qpsrt +c***refer to qage,qagie,qagpe,qagse,qawce,qawse,qawoe +c***routines called (none) +c***keywords sequential sorting +c***description +c +c 1. qpsrt +c ordering routine +c standard fortran subroutine +c real version +c +c 2. purpose +c this routine maintains the descending ordering +c in the list of the local error estimates resulting from +c the interval subdivision process. at each call two error +c estimates are inserted using the sequential search +c method, top-down for the largest error estimate +c and bottom-up for the smallest error estimate. +c +c 3. calling sequence +c call qpsrt(limit,last,maxerr,ermax,elist,iord,nrmax) +c +c parameters (meaning at output) +c limit - integer +c maximum number of error estimates the list +c can contain +c +c last - integer +c number of error estimates currently +c in the list +c +c maxerr - integer +c maxerr points to the nrmax-th largest error +c estimate currently in the list +c +c ermax - real +c nrmax-th largest error estimate +c ermax = elist(maxerr) +c +c elist - real +c vector of dimension last containing +c the error estimates +c +c iord - integer +c vector of dimension last, the first k +c elements of which contain pointers +c to the error estimates, such that +c elist(iord(1)),... , elist(iord(k)) +c form a decreasing sequence, with +c k = last if last.le.(limit/2+2), and +c k = limit+1-last otherwise +c +c nrmax - integer +c maxerr = iord(nrmax) +c +c 4. no subroutines or functions needed +c***end prologue qpsrt +c + real elist,ermax,errmax,errmin + integer i,ibeg,ido,iord,isucc,j,jbnd,jupbn,k,last,limit,maxerr, + * nrmax + dimension elist(last),iord(last) +c +c check whether the list contains more than +c two error estimates. +c +c***first executable statement qpsrt + if(last.gt.2) go to 10 + iord(1) = 1 + iord(2) = 2 + go to 90 +c +c this part of the routine is only executed +c if, due to a difficult integrand, subdivision +c increased the error estimate. in the normal case +c the insert procedure should start after the +c nrmax-th largest error estimate. +c + 10 errmax = elist(maxerr) + if(nrmax.eq.1) go to 30 + ido = nrmax-1 + do 20 i = 1,ido + isucc = iord(nrmax-1) +c ***jump out of do-loop + if(errmax.le.elist(isucc)) go to 30 + iord(nrmax) = isucc + nrmax = nrmax-1 + 20 continue +c +c compute the number of elements in the list to +c be maintained in descending order. this number +c depends on the number of subdivisions still +c allowed. +c + 30 jupbn = last + if(last.gt.(limit/2+2)) jupbn = limit+3-last + errmin = elist(last) +c +c insert errmax by traversing the list top-down, +c starting comparison from the element elist(iord(nrmax+1)). +c + jbnd = jupbn-1 + ibeg = nrmax+1 + if(ibeg.gt.jbnd) go to 50 + do 40 i=ibeg,jbnd + isucc = iord(i) +c ***jump out of do-loop + if(errmax.ge.elist(isucc)) go to 60 + iord(i-1) = isucc + 40 continue + 50 iord(jbnd) = maxerr + iord(jupbn) = last + go to 90 +c +c insert errmin by traversing the list bottom-up. +c + 60 iord(i-1) = maxerr + k = jbnd + do 70 j=i,jbnd + isucc = iord(k) +c ***jump out of do-loop + if(errmin.lt.elist(isucc)) go to 80 + iord(k+1) = isucc + k = k-1 + 70 continue + iord(i) = last + go to 90 + 80 iord(k+1) = last +c +c set maxerr and ermax. +c + 90 maxerr = iord(nrmax) + ermax = elist(maxerr) + return + end diff --git a/liboctave/ChangeLog b/liboctave/ChangeLog --- a/liboctave/ChangeLog +++ b/liboctave/ChangeLog @@ -1,3 +1,48 @@ +2008-05-21 David Bateman + + * CmplxGEBAL.cc (ComplexGEPBALANCE), dbleGEPBAL.cc (GEPBALANCE), + fCmplxGEPBAL.cc (FloatComplexGEPBALANCE), floatGEPBAL.cc + (FloatGEPBALANCE): New class for generalized eigenvalue balancing. + * CmplxGEBAL.h (ComplexGEPBALANCE), dbleGEPBAL.h (GEPBALANCE), + fCmplxGEPBAL.h (FloatComplexGEPBALANCE), floatGEPBAL.h + (FloatGEPBALANCE): Declare them. + * Makefile.in (MATRIX_INC): Include them here. + (MATRIX_SRC): and here. + + * floatAEPBAL.cc (FloatAEPBALANCE), fCmplxAEPBAL.cc + (FloatComplexAEPBALANCE): New classes for single precision + Algebraic eignvalue balancing. + * floatAEPBAL.h (FloatAEPBALANCE), fCmplxAEPBAL.h + (FloatComplexAEPBALANCE): Declare them. + * Makefile.in (MATRIX_INC): Include them here. + (MATRIX_SRC): and here. + + * floatHESS.cc (FloatHESS), fCmplxHESS.cc (FloatComplexHESS): New + classes for single precision Hessenberg decomposition. + * floatHESS.h (FloatHESS), fCmplxHESS.h (FloatComplexHESS): + Declare them. + * Makefile.in (MATRIX_INC): Include them here. + (MATRIX_SRC): and here. + + * floatQR.cc (FloatQR), fCmplxQR.cc (FloatComplexQR): New + classes for single precision QR decomposition. + * floatQR.h (FloatQR), fCmplxQR.h (FloatComplexQR): + Declare them. + * Makefile.in (MATRIX_INC): Include them here. + (MATRIX_SRC): and here. + + * floatQRP.cc (FloatQRP), fCmplxQRP.cc (FloatComplexQRP): New + classes for single precision permuted QR decomposition. + * floatQRP.h (FloatQRP), fCmplxQRP.h (FloatComplexQRP): + Declare them. + * Makefile.in (MATRIX_INC): Include them here. + (MATRIX_SRC): and here. + + * mx-defs (FloatAEPBALANCE, FloatComplexAEPBALANCE, + ComplexGEPBALANCE, FloatGEPBALANCE,FloatComplexGEPBALANCE, + FloatHESS, FloatComplexHESS, FloatQR, FloatComplexQR, QRP, + ComplexQRP, FloatQRP, FloatComplexQRP): Declare classes. + 2008-05-20 David Bateman * Array.cc (Array Array::transpose () const): Modify for tiled