C---+----1----+----2----+----3----+----4----+----5----+----6----+----7--
      SUBROUTINE ZTREND(
     &  IERROR,N,M,NUM,T,TMIN,TMAX,
     &  M1,M2,M3,M4,M5,M6,
     &  QBO,SOLAR,EXTRA1,EXTRA2,
     &  ALPHA,BETA,GAMMA,DELTA,EPS1,EPS2,
     &  VAR_ALPHA,VAR_BETA,VAR_GAMMA,VAR_DELTA,VAR_EPS1,VAR_EPS2,
     &  ALPHA_FIT,BETA_FIT,GAMMA_FIT,DELTA_FIT,EPS1_FIT,EPS2_FIT,
     &  RESIDUAL_FIT,VAR_FACTOR,
     &  F,WK,A,AINV,S,C,COV,CS)
C
C PROCEDURE: Performs multiple linear regression trend analysis of
C an arbitrary time series.  OPTIONAL: error analysis for regression
C coefficients (uses standard multivariate noise model).
C
C _/_/_/_/_/_/_/_/_/_/ S H O R T   T U T O R I A L _/_/_/_/_/_/_/_/_/_/
C Form of general regression trend model used in this procedure
C (t=time index):
C
C            T(t)=ALPHA(t)
C                    +BETA(t)*t
C                        +GAMMA(t)*QBO(t)
C                            +DELTA(t)*SOLAR(t)
C                                +EPS1(t)*EXTRA1(t)
C                                    +EPS2(t)*EXTRA2(t)
C                                        +RESIDUAL_FIT(t),
C
C where ALPHA represents the 12-month seasonal fit, BETA is the 
C 12-month seasonal trend coefficient, RESIDUAL_FIT(t) represents the 
C error time series, and GAMMA, DELTA, EPS1, and EPS2 are 12-month 
C coefficients corresponding to the ozone driving quantities QBO 
C (quasi-biennial oscillation), SOLAR (solar-UV proxy), and proxies
C EXTRA1 and EXTRA2 (for example, these latter two might be ENSO, 
C vorticity, geopotential heights, or temperature), respectively.
C The general model above assumes simple linear relationships 
C between T(t) and surrogates which is hopefully valid as a
C first approximation.  Note that for total ozone trends based on 
C chemical species such as involving Chlorine, the trend term 
C BETA(t)*t could be replaced (ignored by setting m2=0 in the 
C procedure call), with EPS1(t)*EXTRA1(t) where EXTRA1(t) is 
C the chemical proxy time series.
C
C This procedure assumes the following form for the coefficients
C ALPHA, BETA, GAMMA,...) in effort to approximate realistic
C seasonal dependence of sensitivity between T(t) and surrogate
C [The expansion shown below is for ALPHA(t) - similar expansions
C for BETA(t), GAMMA(t), DELTA(t), EPS1(t), and EPS2(t)]:
C
C ALPHA(t) = A0                                           <== Constant
C  +A1*cos(1*2*PI*t*dt/365.25)+A2*sin(1*2*PI*t*dt/365.25  <== 12-month
C  +A3*cos(2*2*PI*t*dt/365.25)+A4*sin(2*2*PI*t*dt/365.25) <== 6-month
C  +A5*cos(3*2*PI*t*dt/365.25)+A6*sin(3*2*pi*t*dt/365.25) <== 4-month
C  +          .                      .                  .
C  +          .                      .                  .
C  +          .                      .                  .
C
C where A0, A1, A2,... are constants, and t (t=1,2,...,n) is the
C time index (NO UNITS).
C
C Trend models often use a particular harmonic expansion to
C represent the seasonalility of the action between T(t) and a
C particular surrogate.  Shown below are two EXAMPLES of such
C chosen harmonic expansions for total ozone trend analyses [T(t)
C is a total ozone time series]:
C
C   1) Stolarski, Bloomfield, McPeters [1991] model:
C
C     ALPHA(t): A0, A1, A2, A3, A4, A5, A6, A7, A8 (const+12,6,4,3mo)
C     BETA(t) : A0, A1, A2, A3, A4 (const+12mo+6mo)
C     GAMMA(t): A0, A1, A2 (const+12mo)
C     DELTA(t): A0, A1, A2 (  "    "  )
C              (no proxies other than QBO and SOLAR)
C
C   2) Randel and Cobb [1994] zonally asymmetric model:
C
C     ALPHA(t): A0, A1, A2, A3, A4, A5, A6 (const+12,6,4mo)
C     BETA(t) : A0, A1, A2, A3, A4, A5, A6 (       "      )
C     GAMMA(t): A0, A1, A2, A3, A4, A5, A6 (       "      )
C     DELTA(t): A0, A1, A2, A3, A4, A5, A6 (       "      )
C     EPS1(t):  A0, A1, A2, A3, A4, A5, A6 (       "      )
C      (no proxies other than QBO, SOLAR, and an "EXTRA" proxy ENSO)
C
C _/_/_/_/_/_/ P A R A M E T E R   I N F O R M A T I O N _/_/_/_/_/_/_/
C
C INPUT: (1st three lines of parameter list - all MUST be declared
C         prior to calling ZTREND.F)
C
C       IERROR <== If preset to 1, standard error analysis is
C                  performed for regression coefficients.  Any
C                  other value SKIPS it
C       N <== Length (dimension) of array "T" to be modelled
C       M <== Total number of regression constants in the model
C             (this is EQUIVALENT to M1+M2+M3+...+M6 (see below)
C       NUM <== Number of time series measurements PER YEAR. NUM is
C               used to introduce seasonal dependence of the 
C               coefficients ALPHA(t), BETA(t), ..., EPS2(t)
C       T <== The arbitrary time series for which regression trend
C             analysis is performed
C       TMIN,TMAX = Values of input series T that are less than
C          TMIN or greater than TMAX will NOT be included in the
C          regression (these are the flagging values)
C       M1, M2, M3, M4, M5, M6 <== Number (1,3,5,7,...) of constants 
C                                  to include in seasonal, trend, qbo,
C                                  solar, extra1, and extra2 proxy
C                                  coefficients, respectively. These
C                                  must all be ODD numbers if not
C                                  ZERO. When you set any of M1,
C                                  M2,...,M6 to ZERO, this will
C                                  IGNORE the respective surrogate
C                                  during regression
C       QBO <== Quasi-biennial oscillation time series proxy
C       SOLAR <== Solar time series proxy
C       EXTRA1 <== An extra time series proxy (e.g., ENSO)
C       EXTRA2 <== Another extra time series proxy (e.g., vorticity)
C
C OUTPUT (lines 4-8 in parameter list)
C
C       ALPHA <== Seasonal coefficient (see tutorial above)
C       BETA  <== Seasonal trend coefficient in units
C                 reciprocal to sampling interval.  Example: If T(t)
C                 is total ozone in Dobson units and the number of
C                 samples per year "NUM" is 52, then trends (i.e.,
C                 BETA(t)) will be in Dobson units per week
C       GAMMA <== Seasonal qbo coefficient
C       DELTA <== Seasonal solar coefficient
C       EPS1 <== Seasonal coefficient for 1st extra proxy
C       EPS2 <== Seasonal coefficient for 2n2 extra proxy
C
C       VAR_ALPHA, VAR_BETA, VAR_GAMMA, <== Seasonal variances
C       VAR_DELTA, VAR_EPS1, VAR_EPS2   <== of the coefficients
C
C       ALPHA_FIT    <== Seasonal fit (same length "N" as array "T(t)")
C       BETA_FIT     <== Trend fit                     "
C       GAMMA_FIT    <== QBO fit                       "
C       DELTA_FIT    <== Solar fit                     "
C       EPS1_FIT     <== 1st extra proxy fit           "
C       EPS2_FIT     <== 2nd extra proxy fit           "
C       RESIDUAL_FIT <== Residual fit                  "
C       VAR_FACTOR   <== Seasonal variability factor for coefficient
C                        variance series.  This seasonal variability
C                        IS INVOKED AUTOMATICALLY in this program
C                        as follows:
C
C                        VAR_ALPHA(*)=VAR_ALPHA(*)*VAR_FACTOR(*)
C                        VAR_BETA(*)=VAR_BETA(*)*VAR_FACTOR(*)
C                        VAR_GAMMA(*)=VAR_GAMMA(*)*VAR_FACTOR(*)
C                        VAR_DELTA(*)=VAR_DELTA(*)*VAR_FACTOR(*)
C                        VAR_EPS1(*)=VAR_EPS1(*)*VAR_FACTOR(*)
C                        VAR_EPS2(*)=VAR_EPS2(*)*VAR_FACTOR(*)
C
C
C       F,WK,A,AINV,S,C,COV,CS <== Internal arrays to this procedure
C                                  (see "zregr.f" for meaning)
C
C IMPORTANT NOTES:
C
C  1) The time series length N must be greater than M, otherwise
C     you are solving for more constants in the regression than
C     the number of time series values.  Also, the multivariate
C     statistical analysis in this procedure is valid only if N>M.
C
C  2) EACH of M1, M2, ..., M6 must be LESS THAN the number of data
C     samples per year NUM.  Otherwise the linear system becomes
C     singular.
C
C  3) The above linear model can be written as Y = XB + e, where
C     Y is the time series vector (T(t) above) being modeled, 
C     X is a matrix of data values, and B is the coefficient
C     vector to be derived.  Solving for B via least squares
C     yields (prime denotes transpose):
C
C                                  -1
C                          B = (X'X) X'Y
C
C  4) This procedure uses a standard multivariate statistical
C     model that yields
C                                                2      -1
C        covariance matrix for B = cov[B] = sigma * (X'X)
C
C                              2
C     where data variance sigma is estimated from the vector
C     dot product e*e divided by N-M.
C
C  This routine also internally invokes a more realistic
C  seasonality of variances for the time-dependent regression
C  coefficients (i.e., VAR_ALPHA, VAR_BETA, ...)  by modulating
C  their values by the annual climatology of e*e/(N-M) (see plot
C  below):
C
C    Annual    |
C  Climatology |
C      of      |         *
C     e*e      |
C    -----     |
C    N - M     |             *
C              |     *
C              |
C              | *                                           *
C              |                 *                       *
C              |
C              |                     *               *
C              |                         *       *
C              |                             *
C             -+---+---+---+---+---+---+---+---+---+---+---+---+
C                J   F   M   A   M   J   J   A   S   O   N   D
C  For example,
C
C            VAR_ALPHA(*)=VAR_ALPHA(*)*VAR_FACTOR(*)
C
C  where VAR_FACTOR is equivalent to the above annual climatology
C  function for e*e/(N-M) divided by it's annual mean.
C
C  Physical reason for using this modulation approach:
C
C  Values for e*e/(N-M) are generally highly seasonally-dependent.
C  For example, taking annual samplings such as sampling only
C  January monthly means will produce different estimates of
C  e*e/(N-M) as opposed to annual sampling using July monthly means.
C  Several papers in the past on ozone trends have used annual
C  sampling.  A caveat with this approach is that annual sampling
C  produces aliasing effects where all variabilities with periods
C  shorter than two years (Nyquist folding period) will not be
C  detected properly.
C
C  The modulation factor VAR_FACTOR provides an extra step that
C  goes beyond standard multivariate statistics.  After calling
C  "ztrend.pro" if you want you can once again regain the original
C  multivariate coefficient variances by dividing by VAR_FACTOR:
C
C             VAR_ALPHA(*)=VAR_ALPHA(*)/VAR_FACTOR(*)
C             VAR_BETA(*)=VAR_BETA(*)/VAR_FACTOR(*)
C             VAR_GAMMA(*)=VAR_GAMMA(*)/VAR_FACTOR(*)
C             VAR_DELTA(*)=VAR_DELTA(*)/VAR_FACTOR(*)
C             VAR_EPS1(*)=VAR_EPS1(*)/VAR_FACTOR(*)
C             VAR_EPS2(*)=VAR_EPS2(*)/VAR_FACTOR(*)
C
C Address questions/comments to:
C   Dr. Jerry Ziemke
C   NASA/Goddard Space Flight Center            PH: (301) 614-6034
C   Code 614                                   FAX: (301) 614-5903
C   Greenbelt, MD  20771
C   (Affil: GESTAR, Morgan St. Univ., Baltimore, MD)
C   e-mail: jerald.r.ziemke@nasa.gov

      PARAMETER(ICHECK=0,IPRINT=0)
      REAL T(N),F(N,M),WK(N,2*N),A(M,M),AINV(M,M),S(M),C(M),
     & COV(M,M),QBO(N),SOLAR(N),EXTRA1(N),EXTRA2(N),CS(52,N)
      REAL ALPHA(NUM),BETA(NUM),GAMMA(NUM),DELTA(NUM),EPS1(NUM),
     & EPS2(NUM)
      REAL VAR_ALPHA(NUM),VAR_BETA(NUM),VAR_GAMMA(NUM),VAR_DELTA(NUM),
     & VAR_EPS1(NUM),VAR_EPS2(NUM)
      REAL ALPHA_FIT(N),BETA_FIT(N),GAMMA_FIT(N),DELTA_FIT(N),
     & EPS1_FIT(N),EPS2_FIT(N),RESIDUAL_FIT(N),VAR_FACTOR(NUM)

      DT=365.25/NUM
      W1=2.0*3.14159265*DT/365.25
      DO I=1,N
        CS(1,I)=1.0
        DO J=1,25
          CS(2*J,I)=COS(J*W1*I)
          CS(2*J+1,I)=SIN(J*W1*I)
        ENDDO
      ENDDO

      IC=0
      IF (M1.GT.0) THEN
        DO J=1,M1
          IC=IC+1
          DO I=1,N
            F(I,IC)=CS(J,I)
          ENDDO
        ENDDO
      ENDIF
      IF (M2.GT.0) THEN
        DO J=1,M2
          IC=IC+1
          DO I=1,N
            F(I,IC)=I*CS(J,I)
          ENDDO
        ENDDO
      ENDIF
      IF (M3.GT.0) THEN
        DO J=1,M3
          IC=IC+1
          DO I=1,N
            F(I,IC)=QBO(I)*CS(J,I)
          ENDDO
        ENDDO
      ENDIF
      IF (M4.GT.0) THEN
        DO J=1,M4
          IC=IC+1
          DO I=1,N
            F(I,IC)=SOLAR(I)*CS(J,I)
          ENDDO
        ENDDO
      ENDIF
      IF (M5.GT.0) THEN
        DO J=1,M5
          IC=IC+1
          DO I=1,N
            F(I,IC)=EXTRA1(I)*CS(J,I)
          ENDDO
        ENDDO
      ENDIF
      IF (M6.GT.0) THEN
        DO J=1,M6
          IC=IC+1
          DO I=1,N
            F(I,IC)=EXTRA2(I)*CS(J,I)
          ENDDO
        ENDDO
      ENDIF
      !_/_/_/_ BEGIN _/_/_/_/_/zregr.f ROUTINE_/_/_/_ BEGIN _/_/_/_/_/
      NGOOD=0
      DO I=1,N
        IF ((T(I).GT.TMIN).AND.(T(I).LT.TMAX)) NGOOD=NGOOD+1
      ENDDO
      DO J=1,M
        S(J)=0.
        DO I=1,N
          IF ((T(I).GT.TMIN).AND.(T(I).LT.TMAX)) THEN
            S(J)=S(J)+T(I)*F(I,J)         ! <== S=F'T
          ENDIF
        ENDDO
      ENDDO
      !Construct matrix A:
      DO K=1,M
        DO J=1,M
          A(J,K)=0.
          DO I=1,N
            IF ((T(I).GT.TMIN).AND.(T(I).LT.TMAX)) THEN
              A(J,K)=A(J,K)+F(I,J)*F(I,K) ! <== A=F'F
            ENDIF
          ENDDO
        ENDDO
      ENDDO
      DO I=1,M
        DO J=1,M
          WK(I,J)=A(I,J)
        ENDDO
      ENDDO
      DO I=1,M
        DO J=M+1,2*M
          IF (M+I.EQ.J) THEN
            WK(I,J)=1.0
          ELSE
            WK(I,J)=0.0
          ENDIF
        ENDDO
      ENDDO
      DO K=1,M
        DO I=1,M
          IF (I.NE.K) THEN
            IF (WK(K,K).EQ.0.0) THEN
              L=1
 30           IF (WK(L,K).EQ.0.0) THEN
                L=L+1
                GOTO 30
              ENDIF
              DO J=K,2*M
                WK(K,J)=WK(K,J)+WK(L,J)
              ENDDO
            ENDIF
            U=-WK(I,K)/WK(K,K)
            DO J=K+1,2*M
              WK(I,J)=WK(I,J)+U*WK(K,J)
            ENDDO
          ENDIF
        ENDDO
      ENDDO
      DO J=1,M
        DO I=1,M
          AINV(I,J)=WK(I,J+M)/WK(I,I)
        ENDDO
      ENDDO
      IF (IPRINT.EQ.1) THEN
        DO J=1,M
          WRITE(*,'(1X,A7,I3,A19)')'Column ',J,' of inverse matrix:'
          DO I=1,M
            WRITE(*,*) A(I,J)
          ENDDO
        ENDDO
      ENDIF
      IF (ICHECK.EQ.1) THEN
        WRITE(*,*)'-----------------------------------------------'
        WRITE(*,*)'Simple error check by multiplying A by AINV:'
        WRITE(*,*)'(this should ideally yield the identity matrix)'
        DO J=1,M
          WRITE(*,'(1X,A7,I3,A27)')
     &      'Column ',J,' of product matrix A*AINV:'
          DO I=1,M
            SUM=0.
            DO K=1,M
              SUM=SUM+A(I,K)*AINV(K,J)
            ENDDO
            WRITE(*,*) SUM
          ENDDO
        ENDDO
      ENDIF
      !Coefficient vector solution:
      DO I=1,M
        C(I)=0.
        DO J=1,M
          C(I)=C(I)+AINV(I,J)*S(J)
        ENDDO
      ENDDO
      IF (IERROR.EQ.1) THEN
        DO I=1,N
          IF ((T(I).GT.TMIN).AND.(T(I).LT.TMAX)) THEN
            SUM=0
            DO J=1,M
              SUM=SUM+C(J)*F(I,J)
            ENDDO
            RESIDUAL_FIT(I)=T(I)-SUM
          ENDIF
        ENDDO
        SUM=0
        DO I=1,N
          IF ((T(I).GT.TMIN).AND.(T(I).LT.TMAX))
     &      SUM=SUM+RESIDUAL_FIT(I)**2
        ENDDO
        SIGSQR=SUM/(NGOOD-M)
        DO K=1,M
          DO J=1,M
            COV(J,K)=SIGSQR*AINV(J,K)
          ENDDO
        ENDDO
      ENDIF
      !_/_/_/_/_ END _/_/_/_/_/zregr.f ROUTINE_/_/_/_/_ END _/_/_/_/_/
      !Individual seasonal coeffs (ALPHA, BETA,...)
      DO I=1,NUM
        IF (M1.GT.0) THEN
          SUM=0.
          DO J=1,M1
            SUM=SUM+C(J)*CS(J,I)
          ENDDO
          ALPHA(I)=SUM
        ENDIF
        IF (M2.GT.0) THEN
          SUM=0.
          DO J=1,M2
            SUM=SUM+C(J+M1)*CS(J,I)
          ENDDO
          BETA(I)=SUM
        ENDIF
        IF (M3.GT.0) THEN
          SUM=0.
          DO J=1,M3
            SUM=SUM+C(J+M1+M2)*CS(J,I)
          ENDDO
          GAMMA(I)=SUM
        ENDIF
        IF (M4.GT.0) THEN
          SUM=0.
          DO J=1,M4
            SUM=SUM+C(J+M1+M2+M3)*CS(J,I)
          ENDDO
          DELTA(I)=SUM
        ENDIF
        IF (M5.GT.0) THEN
          SUM=0.
          DO J=1,M5
            SUM=SUM+C(J+M1+M2+M3+M4)*CS(J,I)
          ENDDO
          EPS1(I)=SUM
        ENDIF
        IF (M6.GT.0) THEN
          SUM=0.
          DO J=1,M6
            SUM=SUM+C(J+M1+M2+M3+M4+M5)*CS(J,I)
          ENDDO
          EPS2(I)=SUM
        ENDIF
      ENDDO
      IF (IERROR.EQ.1) THEN
        !Seasonal factor (VAR_FACTOR) for coeff variances
        DO I=1,NUM
          SUM=0.
          SUMCT=0.
          DO IYEAR=1,N/NUM
            MM=I+NUM*(IYEAR-1)
            IF ((T(MM).GT.TMIN).AND.(T(MM).LT.TMAX)) THEN
              SUM=SUM+RESIDUAL_FIT(MM)**2
              SUMCT=SUMCT+1.
            ENDIF
          ENDDO
          IF (SUMCT.GT.0.) VAR_FACTOR(I)=SUM/SUMCT
          IF (SUMCT.EQ.0.) VAR_FACTOR(I)=0.
        ENDDO
        SUM=0.
        DO I=1,NUM
          SUM=SUM+VAR_FACTOR(I)
        ENDDO
        SUM=SUM/NUM
        IF (SUM.GT.0.) THEN
          DO I=1,NUM
            VAR_FACTOR(I)=VAR_FACTOR(I)/SUM
          ENDDO
        ENDIF
        IF (M1.GT.0) THEN
          DO I=1,NUM
            SUM=0.
            DO K=1,M1
              DO J=1,M1
                SUM=SUM+COV(J,K)*CS(J,I)*CS(K,I)
              ENDDO
            ENDDO
            VAR_ALPHA(I)=SUM*VAR_FACTOR(I)
          ENDDO
        ENDIF
        IF (M2.GT.0) THEN
          DO I=1,NUM
            SUM=0.
            DO K=1,M2
              DO J=1,M2
                SUM=SUM+COV(J+M1,K+M1)*CS(J,I)*CS(K,I)
              ENDDO
            ENDDO
            VAR_BETA(I)=SUM*VAR_FACTOR(I)
          ENDDO
        ENDIF
        IF (M3.GT.0) THEN
          DO I=1,NUM
            SUM=0.
            DO K=1,M3
              DO J=1,M3
                SUM=SUM+COV(J+M1+M2,K+M1+M2)*CS(J,I)*CS(K,I)
              ENDDO
            ENDDO
            VAR_GAMMA(I)=SUM*VAR_FACTOR(I)
          ENDDO
        ENDIF
        IF (M4.GT.0) THEN
          DO I=1,NUM
            SUM=0.
            DO K=1,M4
              DO J=1,M4
                SUM=SUM+COV(J+M1+M2+M3,K+M1+M2+M3)
     &              *CS(J,I)*CS(K,I)
              ENDDO
            ENDDO
            VAR_DELTA(I)=SUM*VAR_FACTOR(I)
          ENDDO
        ENDIF
        IF (M5.GT.0) THEN
          DO I=1,NUM
            SUM=0.
            DO K=1,M5
              DO J=1,M5
                SUM=SUM+COV(J+M1+M2+M3+M4,K+M1+M2+M3+M4)
     &              *CS(J,I)*CS(K,I)
              ENDDO
            ENDDO
            VAR_EPS1(I)=SUM*VAR_FACTOR(I)
          ENDDO
        ENDIF
        IF (M6.GT.0) THEN
          DO I=1,NUM
            SUM=0.
            DO K=1,M6
              DO J=1,M6
                SUM=SUM+COV(J+M1+M2+M3+M4+M5,K+M1+M2+M3+M4+M5)
     &              *CS(J,I)*CS(K,I)
              ENDDO
            ENDDO
            VAR_EPS2(I)=SUM*VAR_FACTOR(I)
          ENDDO
        ENDIF
      ENDIF
      !Individual time series fits:
      DO I=1,N
        II=MOD(I-1,NUM)+1
        ALPHA_FIT(I)=ALPHA(II)
        BETA_FIT(I)=BETA(II)*I
        GAMMA_FIT(I)=GAMMA(II)*QBO(I)
        DELTA_FIT(I)=DELTA(II)*SOLAR(I)
        EPS1_FIT(I)=EPS1(II)*EXTRA1(I)
        EPS2_FIT(I)=EPS2(II)*EXTRA2(I)
      ENDDO

      RETURN
      END
