
      SUBROUTINE clcvec(phacur, phasig, phader, nvpar, alpha, beta,
     &                  ier, ier2)

      INTEGER nvpar
      DOUBLE PRECISION alpha(nvpar, nvpar), beta(nvpar)
      REAL phacur(*), phasig(*), phader(*)

      INTEGER ier, ier2

c This is wrap-up for the the routines that calculate the alpha and beta
c arrays. Beta is the minus half times the vector of first derivatives of the 
c statistic wrt to the fit parameters and alpha half times the matrix of 
c second derivatives. Note that to avoid numerically calculating the second 
c derivatives analytic calculations are used to express the derivatives in 
c terms of the derivatives of the model (or (y_obs-y_mod)/sigma in the case 
c of chi-squared). The terms involving second derivatives of the model are 
c assumed to be small.

c	arguments:
c	phacur	r	 i: vector of T=(y_obs-y_mod)/sigma at current parameter 
c	phasig	r	 i: vector of sigma at current parameter 
c	phader	r	 i: vector of derivatives of T 
c	alpha	r*8	 r: array of derivatives
c	beta	r*8	 r: vector required by crfitx
c	ier	i	 r: error flag (see below)
c	ier2	i	 r: error info flag: (see below)
c	error conditions:
c	ier=	ier2=
c	0	-	normal return
c	-1	ivpar	the indicated variable parameter shows no variation 
c                       of the model when calculating the derivative with 
c                       respect to this parameter 
c       -2              failed to grab memory

      INCLUDE '../../inc/xspec.inc'

c Pointers for local dynamic arrays

      INTEGER idc1, idc2

c Other local variables

      DOUBLE PRECISION dsum

      INTEGER nbsave, ivpar, jvpar, ipha, iphaoff, jphaoff

      CHARACTER wrtstr*255

      DOUBLE PRECISION dlprior, d2lprior
      INTEGER dgdpnt, dgndst, dgnbne
      LOGICAL cgmerr 
      CHARACTER xgstat*11
      EXTERNAL xgstat, dgndst, dgnbne, dgdpnt, cgmerr
      EXTERNAL dlprior, d2lprior

      SAVE idc1, idc2, nbsave

      DATA idc1, idc2, nbsave/-1,-1,-1/

c Grab the memory for summation arrays

      IF ( dgnbne(dgndst()) .NE. nbsave ) THEN
         nbsave = dgnbne(dgndst())
         CALL udmget(nbsave, 7, idc1, ier2)
         CALL udmget(nbsave, 7, idc2, ier2)
         IF ( ier2 .NE. 0 ) THEN
            CALL xwrite('Memory allocation failed in CLCVEC', 2)
            ier = -2
            RETURN
         ENDIF
      ENDIF

c Do the case of chi-squared

      IF ( xgstat() .EQ. 'Chi-Squared') THEN

          CALL AB_CHI2(phacur, MEMD(idc1), MEMD(idc2))

c Do the case of C-statistic. 

      ELSEIF ( xgstat() .EQ. 'C-statistic' ) THEN

          IF(cgmerr()) call xwrite(
     &   'Warning: model error ignored used in C-statistics',5) 

          CALL AB_CSTAT(MEMR(dgdpnt('src')), MEMR(dgdpnt('bkg')),
     &                  MEMR(dgdpnt('mod')), MEMR(dgdpnt('reg')),
     &                  MEMR(dgdpnt('brg')), MEMR(dgdpnt('are')),
     &                  MEMR(dgdpnt('bre')), MEMD(idc1), MEMD(idc2))

c Do the case of L-statistic

      ELSEIF ( xgstat() .EQ. 'L-statistic' ) THEN

          IF(cgmerr()) call xwrite(
     &   'Warning: model error ignored used in L-statistics',5) 

          CALL AB_LSTAT(MEMR(dgdpnt('src')), MEMR(dgdpnt('bkg')),
     &                  MEMR(dgdpnt('mod')), MEMR(dgdpnt('reg')),
     &                  MEMR(dgdpnt('brg')), MEMR(dgdpnt('are')),
     &                  MEMR(dgdpnt('bre')), MEMD(idc1), MEMD(idc2))

      END IF

c If the statistic is either C or L then we reset phader so it is the
c derivative of M not of (O-M)/sigma.

      IF ( xgstat() .EQ. 'C-statistic' .OR. 
     &     xgstat() .EQ. 'L-statistic') THEN

          DO ivpar = 1, nvpar
             iphaoff = (ivpar-1)*nbsave
             DO ipha = 1, nbsave
                phader(ipha+iphaoff) = - phasig(ipha) 
     &                                 * phader(ipha+iphaoff)
             ENDDO
          ENDDO

       ENDIF

c Now loop over the variable parameters loading the alpha and beta vectors

      DO ivpar = 1, nvpar

         dsum = 0.D0
         iphaoff = (ivpar-1)*nbsave

         DO ipha = 1, nbsave
            dsum = dsum + MEMD(idc1+ipha-1)*phader(ipha+iphaoff)
         ENDDO

         beta(ivpar) = dsum

         DO jvpar = ivpar, nvpar

            dsum = 0.D0
            jphaoff = (jvpar-1)*nbsave

            DO ipha = 1, nbsave
               dsum = dsum + MEMD(idc2+ipha-1)*phader(ipha+iphaoff)
     &                                        *phader(ipha+jphaoff)
            ENDDO

            alpha(ivpar, jvpar) = dsum - d2lprior(ivpar, jvpar)
            alpha(jvpar, ivpar) = dsum - d2lprior(jvpar, ivpar)

         ENDDO


c  if there is no variation in the model for this parameter then return
c  with an error 4.

         IF ( alpha(ivpar,ivpar) .EQ. 0. ) THEN
            ier = -1
            ier2 = ivpar
            WRITE(wrtstr, '(a,i8)') 
     &  'CLCVEC: No variation in the model for variable parameter ',
     &  ivpar
            CALL xwrite(wrtstr,20)
            RETURN
         ENDIF

      ENDDO

      RETURN
      END 



c============================================================

      SUBROUTINE AB_CSTAT(phaobs, phabkg, phamod, region, brgion, 
     &                    areasc, breasc, dc1, dc2)

      IMPLICIT NONE

      DOUBLE PRECISION dc1(*), dc2(*)
      REAL phaobs(*), phamod(*), phabkg(*), region(*), brgion(*)
      REAL areasc(*), breasc(*)

c  calculate the summation arrays used in the alpha matrix and beta vector.

c       arguments:
c       phaobs  r        i: observed rate in the ith combined pha channel.
c       phabkg  r        i: background rate in the ith combined pha channel.
c       phamod  r        i: the current models' expected rate of the ith pha
c                           channel.
c       region  r        i: source backscal array
c       brgion  r        i: background backscal array
c       dc1     r*8      r: array used in first derivative summation
c       dc2     r*8      r: array used in second derivative summation

      DOUBLE PRECISION dconv, dbconv, dtconv, dbfact, dfact
      DOUBLE PRECISION dmod, dobs, dbobs
      DOUBLE PRECISION da, db, dc, dd, dq
      DOUBLE PRECISION df, dg, dh
      INTEGER ipha, idset, isign
      LOGICAL qbkgf

      INTEGER dgndst, dgnbne, dgnbnb
      REAL dgtime, dgbtme
      EXTERNAL dgndst, dgnbne, dgnbnb, dgbtme, dgtime

c Initialize the summation arrays
 
      DO ipha = 1, dgnbne(dgndst())
         dc1(ipha) = 0.d0
         dc2(ipha) = 0.d0
      ENDDO

c loop around the pha bins

      idset = 1
      dfact = DBLE(dgtime(idset))
      dbfact = DBLE(dgbtme(idset))
      qbkgf = ( dgbtme(idset) .NE. 0. )

      DO ipha = 1, dgnbne(dgndst())

c if this is the first bin or we are moving onto another dataset
c then set the dataset stuff

         IF ( ipha .GT. dgnbne(idset) ) THEN

            idset = idset + 1
            dfact = DBLE(dgtime(idset))
            dbfact = DBLE(dgbtme(idset)) 
            qbkgf = ( dgbtme(idset) .NE. 0. )

         ENDIF

         dconv = dfact * DBLE(areasc(ipha))
         dobs = dconv*DBLE(phaobs(ipha))

         dbconv = 0.0
         dbobs = 0.0
         IF ( qbkgf ) THEN
            IF ( region(ipha) .NE. 0. ) THEN
               dbconv = dbfact*DBLE(breasc(ipha))
     &                     *DBLE(brgion(ipha))/DBLE(region(ipha))
            ELSE
               dbconv = dbfact
            ENDIF
            dbobs = dbconv*DBLE(phabkg(ipha))
         ENDIF

         dtconv = dconv + dbconv

c Put a floor under the model of 1.e-5 counts/bin

         dmod = MAX(DBLE(phamod(ipha)), 1.D-5/dconv)

c First do case of no background spectrum

         IF ( .NOT. qbkgf ) THEN

            dc1(ipha) = dobs/dmod - dconv
            dc2(ipha) = dobs/dmod**2

c Now have background spectrum: special case of no data counts

         ELSEIF ( dobs .EQ. 0.0d0 ) THEN

            dc1(ipha) = -dconv
            dc2(ipha) = 0.0

c If there are no background counts...

         ELSEIF ( dbobs .EQ. 0.0d0 ) THEN

            IF ( dmod .LE. dobs/dtconv ) THEN
               dc1(ipha) = dbconv
               dc2(ipha) = 0.0
            ELSE
               dc1(ipha) = (dobs/dmod)-dconv
               dc2(ipha) = dobs/dmod**2
            ENDIF

c else if there are both data and background counts...

         ELSE

            da = dtconv
            db = dtconv*dmod - dobs - dbobs
            dc = -dbobs*dmod
            dd = sqrt(db**2 - 4*da*dc)
            isign = 1
            IF ( db .LT. 0.0d0 ) isign = -1
            dq = -0.5*(db + isign*dd)
            df = dq/da
            IF ( df .LT. 0.0d0 ) THEN
               df = dc/dq
               dg = (dtconv*dmod - dobs - dbobs - dd)/(2*dd)
               dh = 2*dtconv*(dobs/dd)*(dbobs/dd)/dd
            ELSE
               dg = (-dtconv*dmod + dobs - dbobs - dd)/(2*dd)
               dh = -2*dtconv*(dobs/dd)*(dbobs/dd)/dd
            ENDIF

cc            dobs1 = dobs/dtconv
cc            dbobs1 = dbobs/dtconv
cc            da1 =  SQRT( (dmod-dobs1-dbobs1)**2
cc     &                   +4*dbobs1*dmod )
cc            df = (dobs1 + dbobs1 - dmod + da1)/2.
cc            dg = (dmod - dobs1 + dbobs1 - da1)/2./da1
cc            dh = 2*(dobs1/da1)*(dbobs1/da1)/da1

            IF ( (dmod+df) .NE. 0.d0 .AND. df .NE. 0.d0 ) THEN

               dc1(ipha) = dobs*(1+dg)/(dmod+df) 
     &                        + dbobs*dg/df - dtconv*dg - dconv
               dc2(ipha) = dtconv*dh
     &                - dobs*(dh-(1+dg)**2/(dmod+df))/(dmod+df)
     &                - dbobs*(dh-dg**2/df)/df

            ENDIF

         ENDIF

      ENDDO

      RETURN
      END

c============================================================

      SUBROUTINE AB_LSTAT(phaobs, phabkg, phamod, region, brgion, 
     &                    areasc, breasc, dc1, dc2)

      DOUBLE PRECISION dc1(*), dc2(*)
      REAL phaobs(*), phamod(*), phabkg(*), region(*), brgion(*)
      REAL areasc(*), breasc(*)

c  calculate the summation arrays used in the alpha matrix and beta vector.

c       arguments:
c       phaobs  r        i: observed rate in the ith combined pha channel.
c       phabkg  r        i: background rate in the ith combined pha channel.
c       phamod  r        i: the current models' expected rate of the ith pha
c                           channel.
c       region  r        i: source backscal values
c       brgion  r        i: background backscal values
c       areasc  r        i: source areascal values
c       breasc  r        i: background areascal values
c       dc1     r*8      r: array used in first derivative summation
c       dc2     r*8      r: array used in second derivative summation

      DOUBLE PRECISION dconv, dbconv, dtconv, dfact, dbfact
      DOUBLE PRECISION dmod, dobs, dbobs
      DOUBLE PRECISION df, dg, dh, dt1, dt2
      INTEGER ipha, idset, nobs, nbobs
      LOGICAL qbkgf

      DOUBLE PRECISION lorsum
      INTEGER dgndst, dgnbne, dgnbnb
      REAL dgtime, dgbtme
      EXTERNAL dgndst, dgnbne, dgnbnb, dgbtme
      EXTERNAL dgtime, lorsum

c initialize the work arrays
 
      DO ipha = 1, dgnbne(dgndst())
         dc1(ipha) = 0.d0
         dc2(ipha) = 0.d0
      ENDDO

c loop around the pha bins

      idset = 1
      dfact = DBLE(dgtime(idset))
      dbfact = DBLE(dgbtme(idset))
      qbkgf = ( dgbtme(idset) .NE. 0. )

      DO ipha = 1, dgnbne(dgndst())

c if this is the first bin or we are moving onto another dataset
c then set the dataset stuff

         IF ( ipha .GT. dgnbne(idset) ) THEN

            idset = idset + 1
            dfact = DBLE(dgtime(idset))
            dbfact = DBLE(dgbtme(idset))
            qbkgf = ( dgbtme(idset) .NE. 0. )

         ENDIF

         dconv = DBLE(areasc(ipha)) * dfact
         dobs = DBLE(phaobs(ipha))
         dbobs = DBLE(phabkg(ipha))
         dmod = DBLE(phamod(ipha))

c If there is not a background file then this defaults to the C-statistic

         IF ( .NOT.qbkgf ) THEN

            IF ( dmod .NE. 0.d0 ) THEN
               dc1(ipha) = dconv*(dobs/dmod-1.d0)
               dc2(ipha) = dconv*dobs/dmod**2
            ENDIF

c If there is a background file...

         ELSE

            IF ( region(ipha) .NE. 0. ) THEN
               dbconv = dbfact*DBLE(breasc(ipha))
     &                        *DBLE(brgion(ipha))/DBLE(region(ipha))
            ELSE
               dbconv = dbfact
            ENDIF
            dtconv = dconv + dbconv

            dt1 = LOG(dtconv)
            dt2 = 2 * dt1

            nobs = NINT(dobs*dconv)
            nbobs = NINT(dbobs*dbconv)

c we use df for the log of the sum over dmod^j, dg for j dmod^(j-1) and 
c dh for j(j-1) dmod^(j-2).

            df = lorsum(dtconv*dmod, nobs, nbobs, 0)
            dg = lorsum(dtconv*dmod, nobs, nbobs, 1) + dt1
            dh = lorsum(dtconv*dmod, nobs, nbobs, 2) + dt2

c Now pull all the terms together and attempt to avoid numerical overflows

            dc1(ipha) = EXP(dg-df) - dconv
            dc2(ipha) = EXP(2*(dg-df)) - EXP(dh-df)

         ENDIF

      ENDDO

      RETURN
      END


c==============================================================

      SUBROUTINE AB_CHI2(phacur, dc1, dc2)

      DOUBLE PRECISION dc1(*), dc2(*)
      REAL phacur(*)

c  calculate the summation arrays used in the alpha matrix and beta vector.
c  For chi^2 these are particularly simple - being -phacur and 1 respectively.

c       arguments:
c       phacur  r        i: vector of T=(y_obs-y_mod)/sigma at current parameter
c       dc1     r*8      r: array used in first derivative summation
c       dc2     r*8      r: array used in second derivative summation


      INTEGER ipha

      INTEGER dgndst, dgnbne
      EXTERNAL dgndst, dgnbne

c Loop around the pha bins

      DO ipha = 1, dgnbne(dgndst())

         dc1(ipha) = -phacur(ipha)
         dc2(ipha) = 1.d0

      ENDDO

      RETURN
      END





