C @(#)psf.for	19.1 (ES0-DMD) 02/25/03 13:23:50
C===========================================================================
C Copyright (C) 1995 European Southern Observatory (ESO)
C
C This program is free software; you can redistribute it and/or 
C modify it under the terms of the GNU General Public License as 
C published by the Free Software Foundation; either version 2 of 
C the License, or (at your option) any later version.
C
C This program is distributed in the hope that it will be useful,
C but WITHOUT ANY WARRANTY; without even the implied warranty of
C MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
C GNU General Public License for more details.
C
C You should have received a copy of the GNU General Public 
C License along with this program; if not, write to the Free 
C Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, 
C MA 02139, USA.
C
C Corresponding concerning ESO-MIDAS should be addressed as follows:
C	Internet e-mail: midas@eso.org
C	Postal address: European Southern Observatory
C			Data Management Division 
C			Karl-Schwarzschild-Strasse 2
C			D 85748 Garching bei Muenchen 
C			GERMANY
C===========================================================================
C
      SUBROUTINE  GETPSF (PIC, NCOL, NROW, PAR, PSF, OPT, NOPT)
      IMPLICIT NONE
C
C=======================================================================
C
C This subroutine generates a point-spread function from one or the
C average of several stars.
C
C                OFFICIAL DAO VERSION:  1991 May 10
C
C The subroutine reads in a subarray around the first desired
C point-spread function star, fits a gaussian profile to the core of
C the image, and generates a look-up table of the residuals of the
C actual image data from the gaussian fit.  If desired, it will then
C fit this PSF to another star to determine its precise centroid,
C scale the same Gaussian to the new star's core, and add the
C differences between the actual data and the scaled Gaussian to the
C look-up table.  This can go on star after star after star.
C The parameters of the Gaussian approximation and the table of
C corrections from the approximation to the true PSF are stored in
C a disk file.
C
C Arguments
C
C PSFRAD (INPUT) is the radius, in pixels, of the circular area within
C        which we ultimately wish to define the PSF.  Because of the
C        need to perform numerical interpolation, we will actually
C        generate and store a look-up table occupying a larger area.
C        The look-up table will be square, even though the corners will
C        be unused.
C
C FITRAD (INPUT) is the fitting radius, which will be used in defining
C        what is meant by a "neighbor" of the PSF star.
C
C Both of these arguments are user-definable parameters, whose values
C may be altered by a DEFAULT.OPT file, or by the OPTIONS command.
C
C=======================================================================
C
C Modifications as of 1991 May 10.
C ===================================
C
C
C I'm going to try to rig this thing so it can reduce the weights of
C (that is, "ignore") discordant pixels in the calculation of the
C look-up tables of corrections.  To accomplish this, I'm going to
C change the way PSF operates.  Instead of reading in a subsection
C for each PSF star one at a time, it will read in the whole image
C and work in memory.
C
      INTEGER MAXBOX, MAXPSF, MAXSTR, MAXN, MAXPAR, MAXEXP, NCOL, NROW
      INTEGER NOPT
      PARAMETER  (MAXPAR=6, MAXPSF=145, MAXEXP=6,
     .     MAXBOX=69, MAXSTR=60000, MAXN=200)
C MAXSTR increased from 9999 to 60000, because now larger images are
C allowed which will also result in more stars 5/99 PN     
C
C Parameters
C
C MAXBOX is the square subarray that will hold the largest final PSF.
C        If the maximum PSF radius permitted is R, then MAXBOX is the
C        odd integer 2*INT(R)+1.  However, because we will be dealing
C        with two levels of interpolation:  (1) interpolating the raw
C        picture data to arrive at a PSF whose centroid coincides with
C        the central pixel of the look-up table; and (2) interpolating
C        within the PSF itself to evaluate it for comparison with the
C        raw picture data for the program stars, PSF will have to
C        operate on a square array which is larger by 7 pixels in X
C        and Y than MAXBOX.  Hence, the dimensions below are all
C        MAXBOX + 7.
C
C MAXPSF is the dimension of the largest lookup table that will ever
C        need to be generated.  Recall that the corrections from the
C        Gaussian approximation of the PSF to the true PSF will be
C        stored in a table with a half-pixel grid size.
C        MAXPSF must then equal
C
C                       2*[ 2*INT(R) + 1 ] + 7.
C
C MAXSTR is the largest number of stars permitted in a data file.
C
C MAXN is the maximum permitted number of PSF stars.
C
C MAXPAR is the maximum number of parameters which may be used to
C        describe the analytic part of the PSF, *** IN ADDITION TO
C        the central intensity, and the x and y centroids.
C
C MAXEXP is the maximum number of terms in the expansion of the
C        look-up table (1 for constant, 3 for linear, 6 for quadratic).
C
      CHARACTER LINE*80, LABEL*8
      CHARACTER*30 COOFIL, MAGFIL, PSFFIL, FITFIL, GRPFIL, SWITCH
      CHARACTER EXTEND*30, CASE*30, FLAG(MAXN)*1, ANSWER*1
      REAL CON(MAXPSF,MAXPSF), CORNER(MAXPSF*MAXPSF/4)
      REAL PIC(NCOL,NROW)
      REAL PAR(MAXPAR)
      REAL C(MAXEXP,MAXEXP), V(MAXEXP), TERM(MAXEXP)
      REAL PSF(MAXEXP,MAXPSF,MAXPSF)
      REAL XCEN(MAXSTR), YCEN(MAXSTR), APMAG(MAXSTR), SKY(MAXSTR)
      REAL HPSF(MAXN), OPT(NOPT)
      REAL HJNK(MAXN), XJNK(MAXN), YJNK(MAXN)
      REAL PROFIL, BICUBC, PCTILE, SQRT
      INTEGER ID(MAXSTR), NTAB(-1:2), NPARAM
      LOGICAL IN(MAXPSF,MAXPSF), EDGE(MAXPSF,MAXPSF)
C
      DOUBLE PRECISION SUM, VOL
      REAL LOBAD, HIBAD, THRESH, AP1, PHPADU, READNS, FRAD, RONOIS,
     .     FWHM, WATCH, FITRAD, RADSQ, PSFRAD, PSFMAG, FMAX, DATUM, RSQ,
     .     DFDX, DFDY, SIG, DX, DY, RDX, RDY, XMID, YMID, DP, OLD, W,
     .     WT, RADIUS, SCALE, SUMSQ, SUMN
      INTEGER I, J, K, L, N, NIN, LX, LY, MX, MY, NTOT, NSTAR, ISTAR, NL
      INTEGER IEXPAND, IFRAC, IPSTYP, NPSF, NPAR, ISTAT, EDGESQ,
     .     NEXP, MIDDLE, MIDSQ, IDX, JDY, JDYSQ, IX, JY, ITER, NPASS
      LOGICAL STAROK
C
      COMMON /FILNAM/ COOFIL, MAGFIL, PSFFIL, FITFIL, GRPFIL
      COMMON /PEAK/ PHPADU, RONOIS
C
      DATA NTAB / 0, 1, 3, 6 /
C
C-----------------------------------------------------------------------
C
C SECTION 1
C
C Set up the necessary variables, open the necessary files, read in the
C relevant data for all stars.
C
      FWHM = OPT(5)
      WATCH = OPT(11)
      FITRAD = OPT(12)
      RADSQ = FITRAD**2
      PSFRAD = OPT(13)
      IEXPAND = NINT(OPT(14))
      IFRAC = NINT(OPT(15))
      NPASS = NINT(OPT(17))
C
C If in the final analysis we want to be able to determine a value for
C the point-spread function anywhere within a radius of R pixels, and
C we want the lookup table to have a one-half pixel grid spacing in
C each coordinate.  To go from 0 to R with half-pixel steps, we
C need 2*R points, not including the central ("0") one.  Outside this
C we will need an additional pixel, just to make sure we will be able to
C do the interpolations at the outermost radii.  Then, to get a
C square box centered on (0,0) we will need 2*(2*R+1)+1 pixels.
C
      NPSF = 2*(NINT(2.*PSFRAD)+1)+1
      PSFRAD = (REAL(NPSF-1)/2. - 1.)/2.
      MIDDLE = (NPSF+1)/2
C
C Ascertain the name of the input (aperture, usually) photometry file,
C and read in the relevant data for all stars.
C
      CALL TBLANK
  920 CALL GETNAM ('File with aperture results:', MAGFIL)
      IF ((MAGFIL .EQ. 'END OF FILE') .OR.
     .     (MAGFIL .EQ. 'GIVE UP')) THEN
         MAGFIL = ' '
         RETURN
      END IF
      CALL INFILE (2, MAGFIL, ISTAT)
      IF (ISTAT .NE. 0) THEN
         CALL STUPID ('Error opening input file '//MAGFIL)
         MAGFIL = 'GIVE UP'
         GO TO 920
      END IF
      CALL RDHEAD (2, NL, I, I, LOBAD, HIBAD, THRESH, AP1,
     .     PHPADU, READNS, DX)
      RONOIS = READNS**2
C
      I = 0
 1010 I = I+1
      IF (I .GT. MAXSTR) GO TO 1100
 1020 CALL RDSTAR (2, NL, ID(I), XCEN(I), YCEN(I), APMAG(I), SKY(I))
      IF (ID(I) .LT. 0) GO TO 1100             ! End-of-file encountered
      IF (ID(I) .EQ. 0) GO TO 1020             ! Blank line encountered
      GO TO 1010
C
 1100 NTOT = I-1
      CALL CLFILE (2)
      PSFFIL = SWITCH(MAGFIL, CASE('.lst'))
      CALL GETNAM ('File with PSF stars:', PSFFIL)
      IF ((PSFFIL .EQ. 'END OF FILE') .OR.
     .     (PSFFIL .EQ. 'GIVE UP')) THEN
         PSFFIL = ' '
         RETURN
      END IF
      CALL INFILE (2, PSFFIL, ISTAT)
      IF (ISTAT .NE. 0) THEN
         CALL STUPID ('Error opening input file '//PSFFIL)
         PSFFIL = 'GIVE UP'
         GO TO 1120
      END IF
      NL = -1
      CALL RDHEAD (2, NL, I, I, LOBAD, HIBAD, THRESH, AP1,
     .     PHPADU, READNS, FRAD)
      PSFFIL = SWITCH(PSFFIL, CASE('.psf'))
 1120 CALL GETNAM ('File for the PSF:', PSFFIL)
      IF ((PSFFIL .EQ. 'END OF FILE') .OR.
     .     (PSFFIL .EQ. 'GIVE UP')) THEN
         PSFFIL = ' '
         RETURN
      END IF
      PSFFIL = EXTEND(PSFFIL, CASE('psf'))
      CALL OUTFIL (3, PSFFIL, ISTAT)
      IF (ISTAT .NE. 0) THEN
         CALL STUPID ('Error opening output file '//PSFFIL)
         PSFFIL = 'GIVE UP'
         GO TO 1120
      END IF
      CALL TBLANK
C
C Read in the entire image.
C
      LX = 1
      LY = 1
      MX = NCOL
      MY = NROW
      CALL RDARAY ('DATA', LX, LY, MX, MY, NCOL, PIC, ISTAT)
C
C-----------------------------------------------------------------------
C
C SECTIONS 2
C
C Learn the name of each PSF star and find it in the star list.  Display
C a subarray around it if desired, and check it for invalid pixels.
C
      NSTAR = 0
      N = NPARAM(1, FWHM, LABEL, PAR, MAXPAR)
C
C NSTAR will point at the last PSF star in the stack after the PSF
C stars have been brought to the top.
C
 2000 CONTINUE
      CALL RDSTAR (2, NL, I, DX, DY, RDX, RDY)
      IF (I .EQ. 0) GO TO 2000
      IF (I .LT. 0) THEN
         CALL CLFILE (2)
         GO TO 3000
      END IF
C
      DO 2010 ISTAR=NSTAR+1,NTOT
      IF (ID(ISTAR) .EQ. I) GO TO 2020
 2010 CONTINUE
      WRITE (LINE, 701) I, ': Star not found.'
  701 FORMAT (I5, A)
      CALL STUPID (LINE)
      GO TO 2000
C
 2020 CONTINUE
      IF ( ( INT(XCEN(ISTAR)-FITRAD) .LT. 0 ) .OR.
     .     ( INT(XCEN(ISTAR)+FITRAD) .GT. NCOL ) .OR.
     .     ( INT(YCEN(ISTAR)-FITRAD) .LT. 0 ) .OR.
     .     ( INT(YCEN(ISTAR)+FITRAD) .GT. NROW ) ) THEN
         WRITE (LINE,701) ID(ISTAR), ': Too near edge of frame.'
         CALL STUPID (LINE)
         GO TO 2000
      END IF
      IF (NSTAR .EQ. 0) THEN
C
C This assigns the aperture magnitude of the first PSF star to the
C constant PSFMAG.  If the star-list file contains an aperture
C magnitude, use that one rather than the one in the input
C photometry file, which may have accumulated some drift over the
C course of several iterations.
C
         IF ((RDX .GT. 0.5) .AND. (RDX .LT. 50.)) THEN
            PSFMAG = RDX
         ELSE
            PSFMAG = APMAG(ISTAR)
         END IF
      END IF
C
C Define the subarray containing the star and search it for "bad"
C pixels.  This will include a two-pixel border around the PSF box
C itself, to guarantee valid interpolations to within the PSF box.
C
      LX = MAX0( 1, INT(XCEN(ISTAR)-PSFRAD)-1 )
      LY = MAX0( 1, INT(YCEN(ISTAR)-PSFRAD)-1 )
      MX = MIN0(NCOL, INT(XCEN(ISTAR)+PSFRAD)+2 )
      MY = MIN0(NROW, INT(YCEN(ISTAR)+PSFRAD)+2 )
C
      FMAX=-32768.
      STAROK=.TRUE.
C
      DO J=LY,MY
         DO I=LX,MX
            DATUM = PIC(I,J)
            IF ((DATUM .LT. LOBAD) .OR. (DATUM .GT. HIBAD)) THEN
               RSQ = (I-XCEN(ISTAR))**2 + (J-YCEN(ISTAR))**2
               IF (RSQ .LE. RADSQ) THEN
                 WRITE (LINE,627) ID(ISTAR)
 627             FORMAT (1X, I5, ' is not a good star.')
                 CALL STUPID (LINE(1:26))
                 GO TO 2000
               END IF
C
               IF (STAROK) THEN
                 STAROK = .FALSE.
                 IF (WATCH .GT. -0.5) THEN
                   CALL TBLANK
                   WRITE (6,628) ID(ISTAR), DATUM, 7, I, J
 628               FORMAT (1X, I5, ' has a bad pixel:',  F9.1,
     .                  ' at position', A1, 2I5)
                 ELSE
                   WRITE (6,629) ID(ISTAR)
 629               FORMAT (1X, I5, ' has bad pixels.')
                 END IF
               ELSE
                 IF (WATCH .GT. -0.5)
     .                WRITE (6,628) ID(ISTAR), DATUM, 0, I, J
               END IF
C
C Replace the defective pixel with an average of surrounding
C pixels.
C
               DATUM = 0.
               SUMN = 0.
               DO L=MAX0(1,J-1),MIN0(NROW,J+1)
                  DO K=MAX0(1,I-1),MIN0(NCOL,I+1)
                     IF ((PIC(K,L) .GE. LOBAD) .AND.
     .                   (PIC(K,L) .LE. HIBAD)) THEN
                        DATUM = DATUM + PIC(K,L)
                        SUMN = SUMN+1.
                     END IF
                  END DO
               END DO
               IF (SUMN .LT. 1.5) THEN
                  WRITE (LINE,627) ID(ISTAR)
                  CALL STUPID (LINE(1:26))
                  GO TO 2000
               ELSE
                  PIC(I,J) = DATUM/SUMN
               END IF
            ELSE
               IF (DATUM .GT. FMAX) FMAX=DATUM
            END IF
         END DO
      END DO
C
      IF ((WATCH .GT. -0.5) .AND. (.NOT. STAROK)) THEN
         CALL TBLANK
         CALL GETYN ('Try this one anyway?', ANSWER)
         IF (ANSWER .EQ. 'E') THEN
            CALL CLFILE (2)
            CALL CLFILE (3)
            RETURN
         END IF
         IF (ANSWER .NE. 'Y') GO TO 2000
      END IF
C
      IF (WATCH .GT. 0.5) THEN
         CALL SHOW (PIC(LX,LY), FMAX, SKY(ISTAR),
     .        MX-LX+1, MY-LY+1, NCOL)
         WRITE (6,622) ID(ISTAR), XCEN(ISTAR), YCEN(ISTAR),
     .        APMAG(ISTAR), NINT(FMAX)
  622    FORMAT (1X, I5, 2F9.2, F9.3, 2X, 'Brightest pixel:', I7)
         CALL GETYN ('Use this one?', ANSWER)
         IF (ANSWER .EQ. 'E') THEN
            CALL CLFILE (2)
            CALL CLFILE (3)
            RETURN
         END IF
         IF (ANSWER .EQ. 'N') GO TO 2000
      END IF
C
C Switch this star (at position ISTAR) with the one at position NSTAR+1
C (which is the highest star in the stack not already a PSF star).
C Estimate the height of the best-fitting profile of type 1 (probably
C a Gaussian) on the basis of the central pixel.
C
      NSTAR = NSTAR+1
      CALL SWAPP (ID, XCEN, YCEN, APMAG, SKY, ISTAR, NSTAR)
      HPSF(NSTAR) = (FMAX-SKY(NSTAR))/
     .     PROFIL(1, 0., 0., PAR, DFDX, DFDY, TERM, 0)
      IF (NSTAR .LE. MAXN) GO TO 2000
C
 3000 CONTINUE
      NEXP = NTAB(IEXPAND) + 2*IFRAC
      IF (NSTAR .LT. NEXP) THEN
         CALL STUPID (
     .   'There aren''t enough PSF stars for a PSF this variable.')
         WRITE (6,*) 'Please change something.'
         CALL TBLANK
         RETURN
      END IF
      CALL TBLANK
      CALL OVRWRT ('    Chi     Parameters...', 1)
C
C If OPT(16) (Analytic model PSF) is negative, then try all PSF types
C from 1 to | OPT(16) |, inclusive.
C
      K = NINT(OPT(16))
      J = MAX0(1,K)
      K = IABS(K)
      OLD = 1.E38
      IPSTYP = 0
      DO 3050 I=J,K
C
         DO L=1,NSTAR
            HJNK(L) = HPSF(L)
            XJNK(L) = XCEN(L)
            YJNK(L) = YCEN(L)
         END DO
C
         N = NPARAM(I, FWHM, LABEL, PAR, MAXPAR)
         CALL  FITANA  (PIC, NCOL, NROW, HJNK, XJNK, YJNK, SKY,
     .       NSTAR, LOBAD, HIBAD, FITRAD, WATCH, I, PAR, N, SIG)
C
C SIG is the root-mean-square scatter about the best-fitting analytic
C function averaged over the central disk of radius FITRAD, expressed
C as a fraction of the peak amplitude of the analytic model.
C
         IF (PAR(1) .LT. 0.) GO TO 3050
C
C If this latest fit is better than any previous one, store the
C parameters of the stars and the model for later reference.
C
         IF (SIG .LT. OLD) THEN
            IPSTYP = I
            NPAR = N
            WRITE (LINE,201) (PAR(L), L=1,NPAR)
  201       FORMAT (1X, 1P, 6E13.5)
            DO L=1,NSTAR
               HPSF(L) = HJNK(L)
               XCEN(L) = XJNK(L)
               YCEN(L) = YJNK(L)
            END DO
            OLD = SIG
         END IF
 3050 CONTINUE
      IF (IPSTYP .LE. 0) RETURN
      CALL TBLANK
      READ (LINE,*) (PAR(L), L=1,NPAR)
C
C This last bit ensures that the subsequent computations will be
C performed with the parameters rounded off exactly the same as they
C appear in the output .PSF file.
C
C Write PSF file header.
C
      XMID = REAL(NCOL-1)/2.
      YMID = REAL(NROW-1)/2.
      WRITE (3,202) LABEL, NPSF, NPAR, NTAB(IEXPAND), 5*IFRAC,
     .     PSFMAG, HPSF(1), XMID, YMID
  202 FORMAT (1X, A8, 4I5, F9.3, F15.3, 2F9.1)
      WRITE (3,203) LINE
  203 FORMAT (A)
C
C=======================================================================
C
C At this point, we have values for the parameters of the best-fitting
C analytic function.  Now we may want to generate the look-up table of
C corrections from the best-fitting analytic function to the actual
C data.  This will be generated within a square box of size NPSF x NPSF
C with half-pixel spacing, centered on the centroid of the star.
C
C First, subtract the analytic function from all the PSF stars in the
C original image.
C
      DP = 0.
      DO ISTAR=1,NSTAR
         LX = MAX0( 1, INT(XCEN(ISTAR)-PSFRAD)-1 )
         LY = MAX0( 1, INT(YCEN(ISTAR)-PSFRAD)-1 )
         MX = MIN0(NCOL, INT(XCEN(ISTAR)+PSFRAD)+2 )
         MY = MIN0(NROW, INT(YCEN(ISTAR)+PSFRAD)+2 )
         RDX = 0.0
         RDY = 0.0
         DO 3350 J=LY,MY
            DY = REAL(J) - YCEN(ISTAR)
            W = DY**2
            DO I=LX,MX
               DX = REAL(I) - XCEN(ISTAR)
               PIC(I,J) = PIC(I,J) - HPSF(ISTAR) *
     .              PROFIL(IPSTYP, DX, DY, PAR, DFDX, DFDY, TERM, 0)
               IF (DX**2 + W .LT. RADSQ) THEN
                  RDX = RDX + (PIC(I,J)-SKY(ISTAR))**2
                  RDY = RDY + 1.
               END IF
            END DO
 3350    CONTINUE
         DP = DP + RDY                      ! Total number of pixels
         RDX = SQRT(RDX/RDY)                ! Scatter inside fit radius
         PSF(ISTAR,1,1) = RDX/(HPSF(ISTAR)*
     .        PROFIL(IPSTYP, 0., 0., PAR, DFDX, DFDY, TERM, 0))
      END DO
C
      DP = SQRT(DP/(DP-REAL(NEXP+3*NSTAR))) ! Degrees of freedom
      DO ISTAR=1,NSTAR
         PSF(ISTAR,1,1) = DP * PSF(ISTAR,1,1)
         FLAG(ISTAR) = ' '
         IF (SIG .GT. 0.) THEN
            RDX = PSF(ISTAR,1,1)/SIG
            IF (RDX .GE. 3.) THEN
               FLAG(ISTAR) = '*'
            ELSE IF (RDX .GE. 2.) THEN
               FLAG(ISTAR) = '?'
            END IF
         END IF
      END DO
      K = (NSTAR-1)/5 + 1                   ! Number of lines
      WRITE (6,68)
   68 FORMAT (/' Profile errors:'/)
      DO I=1,K
         WRITE (6,69) (ID(ISTAR), PSF(ISTAR,1,1),
     .        FLAG(ISTAR), ISTAR=I,NSTAR,K)
   69    FORMAT (5(1X, I5, F7.3, 1X, A1, 1X))
      END DO
      CALL TBLANK
CD     CALL COPPIC (CASE('junk'), ISTAT)
CD     LX = 1
CD     LY = 1
CD     MX = NCOL
CD     MY = NROW
CD     CALL WRARAY ('copy', LX, LY, MX, MY, NCOL, PIC, ISTAT)
CD     CALL CLPIC ('COPY')
      IF (IEXPAND+IFRAC .LT. 0) GO TO 2900
      SCALE = HPSF(1)
      DO ISTAR=NSTAR,1,-1
         HPSF(ISTAR) = HPSF(ISTAR)/HPSF(1)
      END DO
C
C=======================================================================
C
C Now compute look-up tables.
C
      MIDSQ = MIDDLE**2
C
C MIDDLE is the center of the look-up table, which will correspond to
C the centroid of the analytic PSF.  MIDSQ is the square of the
C radius of the PSF table, plus a pixel's worth of slack just to
C make sure you'll always have a 4x4 array suitable for interpolation.
C
      NIN = 0
      EDGESQ = (MIDDLE-2)**2
      DO J=1,NPSF
         JDY = J-MIDDLE
         JDYSQ = JDY**2
         DY = REAL(JDY)/2.
         DO I=1,NPSF
            DO K=1,NEXP
               PSF(K,I,J) = 0.0
            END DO
C
            IDX = I-MIDDLE
            IF (IDX**2 + JDYSQ .LE. MIDSQ) THEN
               IN(I,J) = .TRUE.
               NIN = NIN + 1
               IF (IDX**2 + JDYSQ .GE. EDGESQ) THEN
                  EDGE(I,J) = .TRUE.
               ELSE
                  EDGE(I,J) = .FALSE.
               END IF
            ELSE
               IN(I,J) = .FALSE.
               EDGE(I,J) = .FALSE.
            END IF
         END DO
      END DO
C
      TERM(1) = 1.
      DO 4950 JY=1,NPSF
         RDY = REAL(JY-MIDDLE)/2.
C
         DO 4940 IX=1,NPSF
            IF (.NOT. IN(IX,JY)) GO TO 4940
C
C Don't waste time with pixels outside a radius = (MIDDLE-1).
C
            RDX = REAL(IX-MIDDLE)/2.
            DO 4935 ITER=0,NPASS
C
C Initialize accumulators.
C
            SUMSQ = 0.
            SUMN = 0.
            DO L=1,NEXP
               V(L) = 0.
               DO K=1,NEXP
                  C(K,L) = 0.
               END DO
            END DO
C
C Now, for this point in the set of lookup table(s) [(IX,JY), where
C (MIDDLE,MIDDLE) corresponds to the centroid of the PSF], consult
C each of the PSF stars to determine the value(s) to put into the
C table(s).
C
            DO 4900 ISTAR = 1,NSTAR
C
C What pixels in the original image constitute a 4x4 box surrounding
C this (IX,JY) in the PSF, as referred to this star's centroid?
C
               DX = XCEN(ISTAR) + RDX
               DY = YCEN(ISTAR) + RDY
               I = INT(DX)
               J = INT(DY)
C
C The 4x4 box is given by  I-1 <= x <= I+2, J-1 <= y <= J+2.
C
               IF ((I .LT. 2) .OR. (J .LT. 2) .OR.
     .              (I+2 .GT. NCOL) .OR.
     .              (J+2 .GT. NROW)) GO TO 4900           ! Next star
               DX = DX - I
               DY = DY - J
C
C The point which corresponds PRECISELY to the offset (RDX,RDY)
C from the star's centroid, lies a distance (DX,DY) from pixel
C (I,J).
C
C Use bicubic interpolation to evaluate the residual PSF amplitude
C at this point.  Scale the residual up to match the first PSF star.
C
               DP = BICUBC(PIC(I-1,J-1), NCOL, DX, DY, DFDX, DFDY)
     .              - SKY(ISTAR)
               DP = DP/HPSF(ISTAR)
               SUMSQ = SUMSQ + ABS(DP)
               SUMN = SUMN + 1.
               IF (IEXPAND .GE. 1) THEN
                  TERM(2) = (XCEN(ISTAR)-1.)/XMID-1.
                  TERM(3) = (YCEN(ISTAR)-1.)/YMID-1.
                  IF (IEXPAND .GE. 2) THEN
                     TERM(4) = 1.5*TERM(2)**2-0.5
                     TERM(5) = TERM(2)*TERM(3)
                     TERM(6) = 1.5*TERM(3)**2-0.5
                  END IF
               END IF
C
C               IF (IFRAC .GE. 1) THEN
C
C INSERT CODE HERE
C
               IF (ITER .GT. 0) THEN
                  OLD = 0.
                  DO K=1,NEXP
                     OLD = OLD + PSF(K,IX,JY) * TERM(K)
                  END DO
C
                  IF (ITER .LT. MAX0(3,NPASS/2)) THEN
                     W = HPSF(ISTAR)/(1. + (ABS(DP - OLD)/SIG))
                  ELSE
                     W = HPSF(ISTAR)/(1. + ((DP - OLD)/SIG)**2)
                  END IF
               ELSE
                  W = HPSF(ISTAR)
               END IF
C
               DO K=1,NEXP
                  WT = W*TERM(K)
                  V(K) = V(K) + WT*DP
                  DO L=1,NEXP
                     C(K,L) = C(K,L) + WT*TERM(L)
                  END DO
               END DO
 4900       CONTINUE
C
            CALL INVERS (C, MAXEXP, NEXP, ISTAT)
            CALL VMUL (C, MAXEXP, NEXP, V, PSF(1,IX,JY))
            SIG = 1.2533*SUMSQ/SQRT(SUMN*(SUMN - NEXP))
 4935       CONTINUE
 4940    CONTINUE
 4950 CONTINUE
      IF (NEXP .LT. 2) GO TO 2800
C
C At this point, we must be sure that any higher order terms
C in the PSF [i.e. those that go as powers of (XCEN-XMID) and
C (YCEN-YMID)] contain zero volume, so that the total volume
C of the PSF is independent of position.  This will be done
C by looking at the total flux contained in the look-up
C tables of index 2 and higher.  The analytic function
C will be scaled to the same total flux and subtracted from
C each of the higher lookup tables and added into the
C lookup table of index 1.  I scale the analytic function
C instead of simply transferring the net flux from the
C higher tables to table 1, because it is poor fits of
C the analytic profile to the image data which has caused
C the net flux in the lookup tables to depend upon position.
C
C Compute the brightness weighted average value of each of
C the terms in the polynomial expansion.
C
      DO K=1,NEXP
         TERM(K) = 0.
      END DO
C
      DO ISTAR=NSTAR,1,-1
         DX = (XCEN(ISTAR)-1.)/XMID-1.
         DY = (YCEN(ISTAR)-1.)/YMID-1.
         TERM(1) = TERM(1) + HPSF(ISTAR)
         TERM(2) = TERM(2) + HPSF(ISTAR)*DX
         TERM(3) = TERM(3) + HPSF(ISTAR)*DY
         IF (IEXPAND .GE. 2) THEN
            TERM(4) = TERM(4) + HPSF(ISTAR)*(1.5*DX**2-0.5)
            TERM(5) = TERM(5) + HPSF(ISTAR)*(DX*DY)
            TERM(6) = TERM(6) + HPSF(ISTAR)*(1.5*DY**2-0.5)
         END IF
C
C            IF (IFRAC .GE. 1) THEN
C
C INSERT CODE HERE
C
      END DO
C
      DO K=NEXP,1,-1
         TERM(K) = TERM(K)/TERM(1)
      END DO
C
C Okey doke.  Now if there is any net volume contained in any of the
C higher order (variable) terms of the PSF, we will remove it in two
C steps.  First of all, there is the possibility that there were some
C errors in the sky estimates which was correlated with position.
C We will remove this by determining the median value of PSF(K,I,J)
C in the outermost ring of the PSF, at the PSF RADIUS.  This
C value will be subtracted from PSF(K,I,J); it will also be added into
C the constant part of the PSF --- evaluated at a location corresponding
C to the mean value of the polynomial term --- to keep the PSF for the
C mean polynomial unchanged.  That way, if there is on average some
C systematic error in sky estimate, at least it will be constant over
C the area of the frame.  (This, of course, is potentially dangerous for
C a globular cluster or similar object centered within the frame.  I
C have to think about this some more.)
C
CD     CALL COPPIC (CASE('stuff'), ISTAT)
CD     DO K=1,NCOL
CD        CORNER(K) = -32768
CD     END DO
CD     LX = 1
CD     MX = NCOL
CD     MY = 1
CD     DO K=1,NROW
CD        LY = K
CD        CALL WRARAY ('COPY', LX, LY, MX, MY, NCOL, CORNER, ISTAT)
CD     END DO
C
CD     DO K=1,NEXP
CD        L = MOD(K-1,6)
CD        L = L*NPSF + L
CD        LY = (K-1)/6
CD        LY = LY*NPSF + LY
CD        MX = 1
CD        MY = 1
CD        DO J=1,NPSF
CD           LY = LY + 1
CD           DO I=1,NPSF
CD              LX = L + I
CD              CALL WRARAY ('COPY', LX, LY, MX, MY, MAXPSF,
CD    .              PSF(K,I,J), ISTAT)
CD           END DO
CD        END DO
CD     END DO
C
      DO K=2,NEXP
CD        L = 0
CD        DO J=1,NPSF
CD           DO I=1,NPSF
CD              IF (.NOT. IN(I,J)) THEN
CD                 L = L+1
CD                 CORNER(L) = PSF(K,I,J)
CD              END IF
CD           END DO
CD        END DO
CD        WRITE (6,*) K, ' CORNER =', PCTILE(CORNER, L, (L+1)/2), L
C
         L = 0
         DO J=1,NPSF
            DO I=1,NPSF
               IF (EDGE(I,J)) THEN
                  L = L+1
                  CORNER(L) = PSF(K,I,J)
               END IF
            END DO
         END DO
         DX = PCTILE(CORNER, L, (L+1)/2)
CD        WRITE (6,*) K, L, '     DX =', DX, TERM(K)
         DY = TERM(K) * DX
C
CD        L = 0
         DO J=1,NPSF
            DO I=1,NPSF
               IF (IN(I,J)) THEN
                  PSF(K,I,J) = PSF(K,I,J) - DX
                  PSF(1,I,J) = PSF(1,I,J) + DY
CD              ELSE
CD                 PSF(K,I,J) = PSF(K,I,J) - DX
CD                 PSF(1,I,J) = PSF(1,I,J) + DY
CD                 L = L+1
CD                 CORNER(L) = PSF(K,I,J)
               END IF
            END DO
         END DO
CD        WRITE (6,*) K, ' CORNER =', PCTILE(CORNER, L, (L+1)/2), L
CD        L = 0
CD        DO J=1,NPSF
CD           DO I=1,NPSF
CD              IF (EDGE(I,J)) THEN
CD                 L = L+1
CD                 CORNER(L) = PSF(K,I,J)
CD              END IF
CD           END DO
CD        END DO
CD        WRITE (6,*) K, '   EDGE =', PCTILE(CORNER, L, (L+1)/2), L
CD        WRITE (6,*)
      END DO
C
CD     DO K=1,NEXP
CD        L = MOD(K-1,6)
CD        L = L*NPSF + L
CD        LY = (K-1)/6 + ((NEXP-1)/6 + 1)
CD        LY = LY*NPSF + LY
CD        MX = 1
CD        MY = 1
CD        DO J=1,NPSF
CD           LY = LY + 1
CD           DO I=1,NPSF
CD              LX = L + I
CD              CALL WRARAY ('COPY', LX, LY, MX, MY, MAXPSF,
CD    .              PSF(K,I,J), ISTAT)
CD           END DO
CD        END DO
CD     END DO
C
C Now for each of the higher PSF's, determine the mean volume inside
C the PSF RADIUS.  Scale the constant part of the PSF as needed and
C subtract from the variable part and add back in to the constant part.
C
C Tabulate the constant part of the PSF and compute its net volume.
C
      DO J=1,NPSF
         DY = REAL(J-MIDDLE)/2.
         DO I=1,NPSF
            IF (IN(I,J)) THEN
               DX = REAL(I-MIDDLE)/2.
               CON(I,J) = SCALE *
     .              PROFIL(IPSTYP, DX, DY, PAR, DFDX, DFDY, V, 0)
C    .              + PSF(1,I,J)
            END IF
         END DO
      END DO
C
C Ensure that that profile which will be added to or subtracted from
C the various subtables has a median value of zero around its rim.
C
      L = 0
      DO J=1,NPSF
         DO I=1,NPSF
            IF (EDGE(I,J)) THEN
               L = L+1
               CORNER(L) = CON(I,J)
            END IF
         END DO
      END DO
      DX = PCTILE(CORNER, L, (L+1)/2)
CD     WRITE (6,*) 1, L, '     DX =', DX
C
      VOL = 0.0D0
      DO J=1,NPSF
         DO I=1,NPSF
            IF (IN(I,J)) THEN
               CON(I,J) = CON(I,J) - DX
               VOL = VOL + DBLE(CON(I,J))
            END IF
         END DO
      END DO
CD     LY = 3*((NEXP-1)/6+1)
CD     LY = LY*NPSF + LY
CD     MX = 1
CD     MY = 1
CD     DO J=1,NPSF
CD        LY = LY + 1
CD        DO I=1,NPSF
CD           LX = I
CD           CALL WRARAY ('COPY', LX, LY, MX, MY, MAXPSF,
CD    .              CON(I,J), ISTAT)
CD        END DO
CD     END DO
C
CD     WRITE (6,*) 'VOL =', SNGL(VOL)
C
C Now determine the net volume of each of the higher-order PSF
C tables, and force it to zero by subtracting a scaled copy of
C the constant PSF.  Scale the part that has been subtracted off
C by the mean polynomial term and add it in to the constant
C part of the PSF, so that at the centroid of the PSF stars'
C positions, the PSF remains unchanged.
C
      DO K=2,NEXP
         SUM = 0.0D0
         DO J=1,NPSF
            DO I=1,NPSF
               IF (IN(I,J)) SUM = SUM + DBLE(PSF(K,I,J))
            END DO
         END DO
C
CD        WRITE (6,*) K, '  SUM =', SUM
         DX = SNGL(SUM/VOL)
         DY = TERM(K)*DX
CD        SUM = 0.0D0
         DO J=1,NPSF
            DO I=1,NPSF
               IF (IN(I,J)) THEN
                  PSF(K,I,J) = PSF(K,I,J) - DX * CON(I,J)
                  PSF(1,I,J) = PSF(1,I,J) + DY * CON(I,J)
CD                 SUM = SUM + PSF(K,I,J)
               END IF
            END DO
         END DO
CD        WRITE (6,*) K, '  SUM =', SUM
CD        WRITE (6,*)
      END DO
C
CD     DO K=1,NEXP
CD        L = MOD(K-1,6)
CD        L = L*NPSF + L
CD        LY = (K-1)/6 + 2*((NEXP-1)/6+1)
CD        LY = LY*NPSF + LY
CD        MX = 1
CD        MY = 1
CD        DO J=1,NPSF
CD           LY = LY + 1
CD           DO I=1,NPSF
CD              LX = L + I
CD              CALL WRARAY ('COPY', LX, LY, MX, MY, MAXPSF,
CD    .              PSF(K,I,J), ISTAT)
CD           END DO
CD        END DO
CD     END DO
C
CD     CALL CLPIC ('COPY')
C
C!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
C
 2800 CONTINUE
      DO K=1,NEXP
         WRITE (3,204) ((PSF(K,I,J), I=1,NPSF), J=1,NPSF)
  204    FORMAT (1X, 1P, 6E13.6)
      END DO
C
 2900 CALL CLFILE (3)
C
C Now generate the file of neighbors.
C
      MAGFIL = SWITCH(PSFFIL, CASE('.nei'))
      CALL TBLANK
      WRITE (6,*) 'File with PSF stars'' neighbors = ', MAGFIL
 2920 CALL OUTFIL (3, MAGFIL, ISTAT)
      IF (ISTAT .NE. 0) THEN
         CALL STUPID ('Error opening output file '//MAGFIL)
         MAGFIL = 'GIVE UP'
         CALL GETNAM ('Name for neighbor-star file:', MAGFIL)
         IF ((MAGFIL .EQ. 'END OF FILE') .OR.
     .        (MAGFIL .EQ. 'GIVE UP')) THEN
            MAGFIL = ' '
            RETURN
         ELSE
            MAGFIL = EXTEND(MAGFIL, CASE('nei'))
            GO TO 2920
         END IF
      END IF
C
C First, write out the PSF stars.
C
      CALL WRHEAD (3, 3, NCOL, NROW, 7, LOBAD, HIBAD, THRESH, AP1,
     .     PHPADU, READNS, RADIUS)
      DO I=1,NSTAR
         WRITE (3,280) ID(I), XCEN(I), YCEN(I), APMAG(I), SKY(I)
 280     FORMAT (1X, I5, 4F9.3)
      END DO
C
C Now look for all stars within a radius equal to
C 1.5*PSFRAD+2.*FITRAD+1 of any of the PSF stars.
C
      RSQ = (1.5*PSFRAD+2.*FITRAD+1.)**2
      L = NSTAR+1
C
C L will point at the first irrelevant star.
C
      DO I=1,NSTAR
         J = L
 5020    IF ((XCEN(J)-XCEN(I))**2 + (YCEN(J)-YCEN(I))**2 .LE. RSQ) THEN
            CALL SWAPP (ID, XCEN, YCEN, APMAG, SKY, J, L)
            WRITE (3,280) ID(L), XCEN(L), YCEN(L), APMAG(L), SKY(L)
            L = L+1
         END IF
         IF (J .LT. NTOT) THEN
            J = J+1
            GO TO 5020
         END IF
      END DO
C
C Now all stars in the stack between positions NSTAR+1 and L-1,
C inclusive, lie within the specified radius of the PSF stars and have
C been written out.  Finally, look for any stars within a radius
C equal to 2*FITRAD+1 of any of THESE stars, and of each other.
C
      RSQ = (2.*FITRAD+1)**2
      I = NSTAR+1
 5110 J = L
 5120 IF ((XCEN(J)-XCEN(I))**2 + (YCEN(J)-YCEN(I))**2 .LE. RSQ) THEN
         CALL SWAPP (ID, XCEN, YCEN, APMAG, SKY, J, L)
         WRITE (3,280) ID(L), XCEN(L), YCEN(L), APMAG(L), SKY(L)
         L = L+1
      END IF
      IF (J .LT. NTOT) THEN
         J = J+1
         GO TO 5120
      END IF
C
      I = I+1
      IF (I .LT. L) GO TO 5110
      CALL CLFILE (3)
      RETURN
      END!
C
C#######################################################################
C
      SUBROUTINE  FITANA  (PIC, NCOL, NROW, H, XCEN, YCEN, SKY, NSTAR,
     .     LOBAD, HIBAD, FITRAD, WATCH, IPSTYP, PAR, NPAR, CHI)
C
C This subroutine fits the ANALYTIC profile to the selected stars.
C
C  OFFICIAL DAO VERSION:    1991 May 10
C
      IMPLICIT NONE
      INTEGER MAXPAR, MAXBOX, MAXN, NCOL, NROW
      PARAMETER  (MAXPAR=6, MAXBOX=69, MAXN=200)
      CHARACTER*80 LINE
      REAL PIC(NCOL,NROW)
      REAL H(*), XCEN(*), YCEN(*), SKY(*), CLAMP(MAXPAR), OLD(MAXPAR)
      REAL C(MAXPAR,MAXPAR), V(MAXPAR), PAR(MAXPAR), T(MAXPAR),
     .     Z(MAXPAR)
      REAL XCLAMP(MAXN), YCLAMP(MAXN), XOLD(MAXN), YOLD(MAXN)
      REAL ABS, PROFIL, SQRT
C
      REAL DHN, DHD, DXN, DXD, DYN, DYD, DX, DY, DYSQ
      REAL LOBAD, PEAK, DP, PROD, DHDXC, DHDYC, P, WT
      REAL RSQ, SUMWT, OLDCHI, CHI, WATCH, FITRAD, HIBAD
      INTEGER I, J, K, L, LX, LY, MX, MY, ISTAT
      INTEGER ISTAR, MPAR, NITER, NPAR, IPSTYP, NSTAR
      LOGICAL FULL
C
C-----------------------------------------------------------------------
C
      FULL = .FALSE.
      DO I=1,NPAR
         Z(I) = 0.
         OLD(I) = 0.
         CLAMP(I) = 0.5
      END DO
      CLAMP(1) = 2.
      CLAMP(2) = 2.
      NITER = 0
      OLDCHI = 0.
      DO I=1,NSTAR
         XOLD(I) = 0.
         YOLD(I) = 0.
         XCLAMP(I) = 1.
         YCLAMP(I) = 1.
      END DO
C
      MPAR = 2
C
C-----------------------------------------------------------------------
C
C SECTION 1
C
C Now we will fit an integrated analytic function to the central part
C of the stellar profile.  For each star we will solve for three
C parameters: (1) H, the central height of the model profile (above
C sky); (2) XCEN, C the centroid of the star in x; and (3) YCEN,
C likewise for y.  In addition, from ALL STARS CONSIDERED TOGETHER
C we will determine any other parameters, PAR(i), required to describe
C the profile.  We will use a circle of radius FITRAD centered on the
C position of each PSF star. NOTE THAT we do not fit the data to an
C actual analytic profile, but rather the function is numerically
C integrated over the area of each pixel, and the observed data are fit
C to these integrals.
C
 1000 NITER = NITER+1
      IF (NITER .GT. 300) THEN
         CALL STUPID ('Failed to converge.')
         PAR(1) = -1.
         RETURN
      END IF
C
C Initialize the big accumulators.
C
      DO I=1,NPAR
         V(I)=0.0                        ! Zero the vector of residuals
         DO J=1,NPAR
            C(J,I)=0.0                   ! Zero the normal matrix
         END DO
      END DO
      CHI = 0.0
      SUMWT = 0.0
C
C Using the analytic model PSF defined by the current set of parameters,
C compute corrections to the brightnesses and centroids of all the PSF
C stars.  MEANWHILE, accumulate the corrections to the model parameters.
C
      RSQ = FITRAD**2
      DO 1400 ISTAR=1,NSTAR
      LX = INT(XCEN(ISTAR)-FITRAD) + 1
      LY = INT(YCEN(ISTAR)-FITRAD) + 1
      MX = INT(XCEN(ISTAR)+FITRAD)
      MY = INT(YCEN(ISTAR)+FITRAD)
C
      DHN = 0.0D0
      DHD = 0.0D0
      DXN = 0.0D0
      DXD = 0.0D0
      DYN = 0.0D0
      DYD = 0.0D0
      DO J=LY,MY
         DY = REAL(J) - YCEN(ISTAR)
         DYSQ = DY**2
         DO I=LX,MX
            DX = REAL(I) - XCEN(ISTAR)
            WT = (DX**2+DYSQ)/RSQ
            IF (WT .LT. 1.) THEN
               P = PROFIL(IPSTYP, DX, DY, PAR, DHDXC, DHDYC, T, 0)
               DP = PIC(I,J) - H(ISTAR)*P - SKY(ISTAR)
               DHDXC = H(ISTAR)*DHDXC
               DHDYC = H(ISTAR)*DHDYC
C              WT = 1. - WT**2            ! Weight as function of radius
               WT = 5./(5.+WT/(1.-WT))
               PROD = WT*P
               DHN = DHN + PROD*DP
               DHD = DHD + PROD*P
               PROD = WT*DHDXC
               DXN = DXN + PROD*DP
               DXD = DXD + PROD*DHDXC
               PROD = WT*DHDYC
               DYN = DYN + PROD*DP
               DYD = DYD + PROD*DHDYC
            END IF
         END DO
      END DO
C
      H(ISTAR) = H(ISTAR) + DHN/DHD
C
      DXN = DXN/DXD
      IF (XOLD(ISTAR)*DXN .LT. 0.) XCLAMP(ISTAR) = 0.5*XCLAMP(ISTAR)
      XOLD(ISTAR) = DXN
      XCEN(ISTAR) = XCEN(ISTAR)+DXN/(1.+ABS(DXN)/XCLAMP(ISTAR))
C
      DYN = DYN/DYD
      IF (YOLD(ISTAR)*DYN .LT. 0.) YCLAMP(ISTAR) = 0.5*YCLAMP(ISTAR)
      YOLD(ISTAR) = DYN
      YCEN(ISTAR) = YCEN(ISTAR)+DYN/(1.+ABS(DYN)/YCLAMP(ISTAR))
C
      PEAK = H(ISTAR) * PROFIL(IPSTYP,0.,0., PAR, DHDXC, DHDYC, T, 0)
      DO J=LY,MY
         DY = REAL(J)-YCEN(ISTAR)
         DYSQ = DY**2
         DO I=LX,MX
            DX = REAL(I)-XCEN(ISTAR)
            WT = (DX**2+DYSQ)/RSQ
            IF (WT .LT. 1.) THEN
               P = PROFIL(IPSTYP, DX, DY, PAR, DHDXC, DHDYC, T, 1)
               DP = PIC(I,J) - H(ISTAR)*P - SKY(ISTAR)
               DO K=1,MPAR
                  T(K) = H(ISTAR)*T(K)
               END DO
               CHI = CHI + (DP/PEAK)**2
               SUMWT = SUMWT + 1.
C              WT = 1. - WT**2            ! Weight as function of radius
               WT = 5./(5.+WT/(1.-WT))
               DO K=1,MPAR
                  V(K) = V(K) + WT*DP*T(K)
                  DO L=1,MPAR
                     C(L,K) = C(L,K) + WT*T(L)*T(K)
                  END DO
               END DO
            END IF
         END DO
      END DO
 1400 CONTINUE
C
C Correct the fitting parameters.
C
      CALL INVERS (C, MAXPAR, MPAR, ISTAT)
      CALL VMUL (C, MAXPAR, MPAR, V, Z)
      DO I=1,MPAR
         IF (Z(I)*OLD(I) .LT. 0.) THEN
            CLAMP(I) = 0.5*CLAMP(I)
         ELSE
            CLAMP(I) = 1.1*CLAMP(I)
         END IF
         OLD(I) = Z(I)
         Z(I) = CLAMP(I)*Z(I)
      END DO
      Z(1) = AMAX1(-0.1*PAR(1), AMIN1(0.1*PAR(1), Z(1)))
      Z(2) = AMAX1(-0.1*PAR(2), AMIN1(0.1*PAR(2), Z(2)))
      DO I=1,MPAR
         PAR(I) = PAR(I)+Z(I)
      END DO
C
      SUMWT = SUMWT - REAL(MPAR + 3*NSTAR)
      IF (SUMWT .GT. 0) THEN
         CHI = SQRT(CHI/SUMWT)
      ELSE
         CHI = 9.9999
      END IF
C
      WRITE (LINE,661) CHI, (PAR(I), I=1,MPAR)
  661 FORMAT (1X, F7.4, 6F10.5)
      I=10*MPAR+13
      IF (WATCH .GT. -1.5) CALL OVRWRT (LINE(1:I), 2)
      IF (MPAR .EQ. NPAR) THEN
         IF (ABS(OLDCHI/CHI-1.) .LT. 1.E-5) THEN
            CALL OVRWRT (LINE(1:I), 3)
            RETURN
         END IF
      ELSE
         IF (ABS(OLDCHI/CHI-1.) .LT. 1.E-3) THEN
            MPAR = MPAR+1
            OLDCHI = 0.
            GO TO 1000
         END IF
      END IF
C
      OLDCHI = CHI
      GO TO 1000
      END!
C
C#######################################################################
C
C Exchange two stars in the star list.
C
C   OFFICIAL DAO VERSION:       1991 May 10
C
      SUBROUTINE SWAPP (ID, X, Y, A, S, I, J)
      IMPLICIT NONE
      REAL X(*), Y(*), A(*), S(*)
      INTEGER ID(*)
C
      REAL HOLD
      INTEGER I, J, IHOLD
C
      IHOLD = ID(I)
      ID(I) = ID(J)
      ID(J) = IHOLD
      HOLD = X(I)
      X(I) = X(J)
      X(J) = HOLD
      HOLD = Y(I)
      Y(I) = Y(J)
      Y(J) = HOLD
      HOLD = A(I)
      A(I) = A(J)
      A(J) = HOLD
      HOLD = S(I)
      S(I) = S(J)
      S(J) = HOLD
      RETURN
      END!
