      program transform
c
c find standard stars, transform, output file
c requires COLLATEd file with accurate astrometry
c plus a file of standard stars in a specific format.
c This program is quite convoluted because I'm trying
c to automate it as much as possible.
c written 01-April-1997 aah
c
      character*80 file1,file2
c
      print *,'TRANSFORM Version 1.0'
      print *,' '
      print *,'Enter standards filename: '
      read (5,'(a)') file1
      open (unit=2,file=file1,status='old')
      call getstds
      print *,'Enter mean coefficients filename: '
      read (5,'(a)') file2
c
c loop over input files
c
100   continue
      print *,'Enter input filename, xxx ends: '
      read (5,'(a)') file1
      if (file1.ne.'xxx') then
        open (unit=1,file=file1,status='old')
        print *,'Enter output filename: '
        read (5,'(a)') file1
        open (unit=3,file=file1,status='new')
        open (unit=22,file=file2,status='old')
        call getstars
        call calctrans
        call writestars
        goto 100
      endif
      stop
      end

      subroutine getstds
c
c read standards file
c note: maximum of 2000 standard stars allowed
c format is one line header, followed by
c name, gsc#, ra, dec, b, v, r, i
c where ra,dec are J2000 in degrees
c look at sample file to see exact columnar spacing.
c Note: for now, I'm deleting any star that is
c fainter than V=13.
c
      parameter (MAXSTD=2000)
      real*8 ra(MAXSTD),dec(MAXSTD)
      real*4 vstd(MAXSTD),vistd(MAXSTD),a,b,c,d
      integer i,nstd,indx(MAXSTD,2)
      common /blka/ ra,dec,vstd,vistd,indx,nstd
c
      read (2,*)
      i=1
100   continue
      read (2,900,end=200) ra(i),dec(i),a,b,c,d
900   format (20x,2f11.5,2x,4f7.3)
      if (a.gt.13.0) goto 100
      vstd(i) = b
      vistd(i) = b-d
      i=i+1
      if (i.gt.MAXSTD) goto 200
      goto 100
200   continue
      nstd = i-1
      write (6,901) nstd
901   format (i5,' Standards were read.')
      close(2)
      return
      end

      subroutine getstars
c
c read raw collated file, find matches with standards
c matches are 15arcsec radius error box
c can have 2 separate V-I solutions, so save v,vi1,vi2.
c
      parameter (MAXSTD=2000)
      real*8 ra(MAXSTD),dec(MAXSTD),rax,decx
      real*8 hjd1,hjd2,hjd3,err,minerr
      real*4 vstd(MAXSTD),vistd(MAXSTD),dra,ddec
      real*4 fwhmx1,fwhmx2,fwhmx3,fwhmy1,fwhmy2,fwhmy3
      real*4 x1,x2,x3,y1,y2,y3,dmag1,dmag2,dmag3
      real*4 mag1,mag2,mag3,v1(MAXSTD),vi1(MAXSTD),vi2(MAXSTD)
      real*4 v2(MAXSTD),vivi1(MAXSTD),vivi2(MAXSTD)
      integer i,nstd,n1,n2,indx(MAXSTD,2)
      common /blka/ ra,dec,vstd,vistd,indx,nstd
      common /blkb/ v1,v2,vi1,vi2,vivi1,vivi2,n1,n2
c
      minerr = (15./3600.)**2
      n1 = 1
      n2 = 1
c
c loop over stars in collated list
c
100   continue
        read (1,901,end=200) rax,decx,dra,ddec,
     $    hjd1,fwhmx1,fwhmy1,mag1,dmag1,
     $    hjd2,fwhmx2,fwhmy2,mag2,dmag2,
     $    hjd3,fwhmx3,fwhmy3,mag3,dmag3
901     format(4f9.4,f11.4,4f7.3/
     $    5x,f11.4,4f7.3/
     $    5x,f11.4,4f7.3)
c
c brute force check against standards
c for transformation, need V (mag1) + I (mag2 or mag3).  If
c this object does not have V & I, pass it over.
c
        if (mag1.gt.99.0) goto 100
        if (mag2.gt.99.0.and.mag3.gt.99.0) goto 100
c
c now check vs. standard star list to see if have coordinate match
c vx = vstd - vins
c vix = (V-I)std
c vivix = (V-I)std - (V-I)ins
c
        do i=1,nstd
          err = (ra(i)-rax)**2 + (dec(i)-decx)**2
          if (err.lt.minerr) then
            if (mag2.lt.99.0) then
              v1(n1) = vstd(i) - mag1
              vivi1(n1) = vistd(i) - (mag1-mag2)
              vi1(n1) = vistd(i)
              indx(i,1) = i
              n1 = n1 + 1
            endif
            if (mag3.lt.99.0) then
              v2(n2) = vstd(i) - mag1
              vivi2(n2) = vistd(i) - (mag1-mag3)
              vi2(n2) = vistd(i)
              indx(i,2) = i
              n2 = n2 + 1
            endif
            goto 100
          endif
        enddo
        goto 100
200   continue
      n1 = n1-1
      n2 = n2-1
      write (6,904) n1,n2
904   format (i5,' Stars with I1 and ',i5,
     $  ' Stars with I2 were read.')
      return
      end

      subroutine calctrans
c
c calculate the transformation coefficients
c this is the heart of the program.  I usually include
c interactive graphics here so that you can delete
c discrepant points, but we need to be as automated as
c possible for TASS.  Therefore, I just iterate once after
c removing the worst points.
c
      parameter (MAXSTD=2000)
      real*4 v1(MAXSTD),vi1(MAXSTD),vi2(MAXSTD)
      real*4 vivi1(MAXSTD),vivi2(MAXSTD),v2(MAXSTD)
      real*4 a1,a2,a3,a4,b1,b2,b3,b4,s1,s2,s3,s4
      integer n1,n2,n3,n4
      common /blkb/ v1,v2,vi1,vi2,vivi1,vivi2,n1,n2
      common /blkc/ a1,a2,a3,a4,b1,b2,b3,b4
c
      read(22,902) a3,b3,a1,b1
      read(22,902) a4,b4,a2,b2
902   format (4f7.3)
      close(22)
c
      print *,'Zerocalc(0), Fullcalc(1), or use Means(2)? '
      read (5,*) iflag
      if (iflag.eq.1) then
c
c perform full transformation calculation w/one iteration
c
        if (n1.ge.2) then
          call dofulltran(v1,vi1,vivi1,n1,a3,b3,a1,b1)
          call sigma(1,s3,s1)
          call dofulltran(v1,vi1,vivi1,n1,a3,b3,a1,b1)
        endif
        n3 = n1
        call sigma(1,s3,s1)
        if (n2.ge.2) then
          call dofulltran(v2,vi2,vivi2,n2,a4,b4,a2,b2)
          call sigma(2,s4,s2)
          call dofulltran(v2,vi2,vivi2,n2,a4,b4,a2,b2)
        endif
        n4 = n2
        call sigma(2,s4,s2)
        write (3,900) a3,b3,a1,b1,s3,s1,n3
        write (3,901) a4,b4,a2,b2,s4,s2,n4
900     format (' Full transform using I1: ',6f8.3,i5)
901     format (' Full transform using I2: ',6f8.3,i5)
      else
        if (iflag.eq.0) then
c
c just calculate zero points w/one iteration
c
          if (n1.ge.1) then
            call dozerotran(v1,vi1,vivi1,n1,a3,b3,a1,b1)
            call sigma(1,s3,s1)
            call dozerotran(v1,vi1,vivi1,n1,a3,b3,a1,b1)
          endif
          n3 = n1
          call sigma(1,s3,s1)
          if (n2.ge.1) then
            call dozerotran(v2,vi2,vivi2,n2,a4,b4,a2,b2)
            call sigma(2,s4,s2)
            call dozerotran(v2,vi2,vivi2,n2,a4,b4,a2,b2)
          endif
          n4 = n2
          call sigma(2,s4,s2)
          write (3,903) a3,b3,a1,b1,s3,s1,n3
          write (3,904) a4,b4,a2,b2,s4,s2,n4
903       format (' Zero transform using I1: ',6f8.3,i5)
904       format (' Zero transform using I2: ',6f8.3,i5)
        else
          write (3,905) a3,b3,a1,b1,s3,s1,n1
          write (3,906) a4,b4,a2,b2,s4,s2,n2
905       format (' Mean transform using I1: ',6f8.3,i5)
906       format (' Mean transform using I2: ',6f8.3,i5)
        endif
      endif
      return
      end

      subroutine dofulltran (x,y,z,n,a,b,c,d)
c
c main part of linear transformation routine
c
      real*4 x(n),y(n),z(n)
      real*4 a,b,c,d
      integer n
c
      if (n.gt.1) then
c transform for v as function of (v-i)
        call lin (y,x,n,a,b)
c transform for (v-i) as function of (v-i)
        call lin (y,z,n,c,d)
        c = 1./(1.-c)
        d = c*d
      else
        a = 1.0
        c = 1.0
        b = 0.
        d = 0.
      endif
      return
      end

      subroutine dozerotran (x,y,z,n,a,b,c,d)
c
c main part of zero transformation routine
c this uses mean slope and just determines intercepts b,d
c
      real*8 sum1,sum2
      real*4 x(n),y(n),z(n)
      real*4 a,b,c,d
      integer n
c
      if (n.gt.1) then
        sum1 = 0.
        sum2 = 0.
        c = 1. - (1./c)
        do i=1,n
          sum2 = sum2 + (x(i)-a*y(i))
          sum1 = sum1 + (z(i)-c*y(i))
        enddo
        d = sum1 / float(n)
        b = sum2 / float(n)
        c = 1./(1.-c)
        d = c*d
      else
        a = 1.0
        c = 1.0
        b = 0.
        d = 0.
      endif
      return
      end

      subroutine sigma (m,s1,s2)
c
c calculate rms deviation for standards with this fit
c
      parameter (MAXSTD=2000,XINDEF=9.999)
      real*8 ra(MAXSTD),dec(MAXSTD),sum1,sum2
      real*4 vstd(MAXSTD),vistd(MAXSTD),s1,s2
      real*4 v1(MAXSTD),vi1(MAXSTD),vi2(MAXSTD)
      real*4 v2(MAXSTD),vivi1(MAXSTD),vivi2(MAXSTD)
      real*4 a1,a2,a3,a4,b1,b2,b3,b4,xx,yy,x1,xi1
      real*4 dx(MAXSTD)
      integer i,nstd,n1,n2,m,indx(MAXSTD,2)
      common /blka/ ra,dec,vstd,vistd,indx,nstd
      common /blkb/ v1,v2,vi1,vi2,vivi1,vivi2,n1,n2
      common /blkc/ a1,a2,a3,a4,b1,b2,b3,b4
c
      sum1 = 0.0
      sum2 = 0.0
c check whether we are working with camera0-1 or camera1-2
      if (m.eq.1) then
c if more than 1 point in fit, then calculate deviations
        if (n1.gt.1) then
c loop over total number of standards used
          do i=1,n1
            j = indx(i,m)
            xx = vistd(j) - vivi1(i)
            yy = vstd(j) - v1(i)
            xi1 = a1*(xx)+b1
            x1 = yy + a3*xi1 + b3
            dx(i) = abs(vstd(j)-x1)
c sum all errors
            sum1 = sum1 + dx(i)
            sum2 = sum2 + abs(vistd(j)-xi1)
          enddo
c find mean errors
          s1 = sum1 / float(n1)
          s2 = sum2 / float(n1)
c and remove the 2(max) most discrepant points for next iteration
          call remove(dx,v1,vi1,vivi1,indx(1,1),n1)
        else
          s1 = XINDEF
          s2 = XINDEF
        endif
c using camera1-2
      else
c if more than 1 point in fit, then calculate deviations
        if (n2.gt.1) then
c loop over total number of standards used
          do i=1,n2
            j = indx(i,m)
            xx = vistd(j) - vivi2(i)
            yy = vstd(j) - v2(i)
            xi1 = a2*(xx)+b2
            x1 = yy + a4*xi1 + b4
            dx(i) = abs(vstd(j)-x1)
c sum all errors
            sum1 = sum1 + dx(i)
            sum2 = sum2 + abs(vistd(j)-xi1)
           enddo
c find mean errors
          s1 = sum1 / float(n2)
          s2 = sum2 / float(n2)
c and remove the 1 or 2 most discrepant points for next iteration
          call remove(dx,v2,vi2,vivi2,indx(1,2),n2)
        else
          s1 = XINDEF
          s2 = XINDEF
        endif
      endif
      return
      end

      subroutine remove (dx,v,vi,vivi,indx,n)
c
c remove discrepant points from standards
c up to two points are removed.
c This is convoluted logic.  I'm sure there is a better way
c to remove discrepant points from arrays.
c
      parameter (MAXSTD=2000)
      real*4 dx(*),v(*),vi(*),vivi(*)
      integer indx(*),id(MAXSTD),idx(MAXSTD),n
c
c first, check to see if sufficient points to make remove effective
c
      if (n.ge.5) then
c
c sort dx
c
        do i=1,n
          id(i) = i
        enddo
        call sort (n,dx,id)
c
c rearrange data arrays according to sort
c note: reuse dx since no longer needed
c
        do i=1,n
          dx(i) = v(id(i))
        enddo
        do i=1,n
          v(i) = dx(i)
          dx(i) = vi(id(i))
        enddo
        do i=1,n
          vi(i) = dx(i)
          dx(i) = vivi(id(i))
        enddo
        do i=1,n
          vivi(i) = dx(i)
          idx(i) = indx(id(i))
        enddo
        do i=1,n
          indx(i) = idx(i)
        enddo
c this drops last two values
        n = n - 2
      endif
      return
      end

      subroutine writestars
c
c this routine calculates V & I and then writes updated array to file
c
      parameter (XINDEF=99.999)
      real*8 rax,decx,hjd1,hjd2,hjd3
      real*4 dra,ddec
      real*4 fwhmx1,fwhmx2,fwhmx3,fwhmy1,fwhmy2,fwhmy3
      real*4 x1,x2,x3,y1,y2,y3,dmag1,dmag2,dmag3
      real*4 mag1,mag2,mag3,xx,v1,v2,vi1,vi2
      real*4 a1,a2,a3,a4,b1,b2,b3,b4
      common /blkc/ a1,a2,a3,a4,b1,b2,b3,b4
c
c rewind input file and loop over number of entries
c
      rewind(1)
100   continue
        read (1,901,end=200) rax,decx,dra,ddec,
     $    hjd1,fwhmx1,fwhmy1,mag1,dmag1,
     $    hjd2,fwhmx2,fwhmy2,mag2,dmag2,
     $    hjd3,fwhmx3,fwhmy3,mag3,dmag3
901     format(4f9.4,f11.4,4f7.3/
     $    5x,f11.4,4f7.3/
     $    5x,f11.4,4f7.3)
        if (mag1.gt.99.0) then
          vi1 = mag2
          vi2 = mag3
          xx = mag1
        else
          if (mag2.gt.99.0) then
            vi1 = XINDEF
            v1 = XINDEF
          else
            vi1 = a1*(mag1-mag2)+b1
            v1 = mag1 + a3*vi1 + b3
            vi1 = v1 - vi1
          endif
          if (mag3.gt.99.0) then
            vi2 = XINDEF
            v2 = XINDEF
          else
            vi2 = a2*(mag1-mag3)+b2
            v2 = mag1 + a4*vi2 + b4
            vi2 = v2 - vi2
          endif
          if (v1.eq.XINDEF) xx = v2
          if (v2.eq.XINDEF) xx = v1
          if (v1.ne.XINDEF.and.v2.ne.XINDEF) xx=(v1+v2)/2.
        endif
        write (3,901) rax,decx,dra,ddec,
     $    hjd1,fwhmx1,fwhmy1,xx,dmag1,
     $    hjd2,fwhmx2,fwhmy2,vi1,dmag2,
     $    hjd3,fwhmx3,fwhmy3,vi2,dmag3
      goto 100
200   continue
      close(1)
      close(3)
      return
      end

	subroutine lin (x,y,m,a,b)
c
c  *** Linear least squares routine from Nielson ***
c  Simple solution with no weighting factors
c
c  Inputs:
c		x,y   data arrays
c		m     number of points in arrays
c  Outputs:
c		a,b   where y=ax+b
c
c  *** written by A. Henden 1973 ***
c
	dimension x(m),y(m)
	double precision a1,a2,a3,c1,c2,det
c  initialize summing parameters
	a2=0.
	a3=0.
	c1=0.
	c2=0.
	a1=m
c  loop to set up matrix coefficients
	do 10 i=1,m
	a2=a2+x(i)
	a3=a3+x(i)*x(i)
	c1=c1+y(i)
	c2=c2+y(i)*x(i)
10	continue
c  solve matrix - simple since only 2x2
	det=1./(a1*a3-a2*a2)
	b=-(a2*c2-c1*a3)*det
	a=(a1*c2-c1*a2)*det
	return
	end

      SUBROUTINE SORT (n,x,index)
c
c heapsort of array x with corresponding index array index
c from numerical recipies
c
      DIMENSION x(n),index(n)
      k = n/2+1
      ir = n
10    continue
      IF (k.gt.1) THEN
        k = k-1
        xx = x(k)
        ii = index(k)
      ELSE
        xx = x(ir)
        ii = index(ir)
        x(ir) = x(1)
        index(ir) = index(1)
        ir = ir-1
        IF (ir.eq.1) THEN
          x(1) = xx
          index(1) = ii
          RETURN
        ENDIF
      ENDIF
      i = k
      j = k+k
20    IF (j.le.ir) THEN
        IF (j.lt.ir) THEN
          IF (x(j).lt.x(j+1)) j = j+1
        ENDIF
        IF (xx.lt.x(j)) THEN
          x(i) = x(j)
          index(i) = index(j)
          i = j
          j = j+j
        ELSE
          j = ir+1
        ENDIF
      GOTO 20
      ENDIF
      x(i) = xx
      index(i) = ii
      GOTO 10
      END
