#include "nrutil.h"
#include "bezalel01.h"
#include "fitsio.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*A library of image processing routines written by Ari Heinze,
named after the ancient Hebrew artisan Bezalel, who was given skill
by God to carry out the artwork and engineering for the Tabernacle, in
the hopes that I will be similarly blessed in the writing of this
code for exploring the Creator's world.*/

/*readim01.  Reads a FITS file into a C matrix using utilities
from cfitsio.  These utilities accept a matrix whose first pixel
is [0][0], and which has the vertical, y coordinate as the first
index.  Oddly, however, the vector naxes which gives the cfitsio
routines the dimensions of the images, has the x size as the first
value and the y size as the second.  The convention of bezalel01
is that the x axis is the first and the y axis is the second, under
all circumstances.  The conversion from cfitsio to bezalel
convention is handled in this function, and writeim01
handles the reverse conversion.*/

int readim01(int nx,int ny,char* imname,float **image)
{
  fitsfile *fptr;
  int status,  nfound, anynull,ii,jj;
  long naxes[2];
  long npixels;
  long fpixel[2];
  char filename[80]; 
  float nullval,**image2;

  printf("readim01 preparing to read image called %s.\n",imname);

  image2 = matrix(0,ny-1,0,nx-1);

  status = 0;

  /*Obtain FITS file pointer*/
  if(fits_open_file(&fptr,imname,READONLY, &status))
    {
       fits_report_error(stderr, status); /* print error report */

       exit( status );    /* terminate the program, returning error status */
    }

  /*Reads the number and length of the axes*/
  if(fits_read_keys_lng(fptr, "NAXIS", 1, 2, naxes, &nfound, &status))
    {
       fits_report_error(stderr, status); /* print error report */

       exit( status );    /* terminate the program, returning error status */
    }

  npixels = naxes[0]*naxes[1];

  if(nx!=naxes[0]||ny!=naxes[1])
    {
      printf("ERROR: readim01 AXIS MISMATCH.  ABORTING!\n");
      return(0);
    }

  nullval = 0;
  fpixel[0] = 1;
  fpixel[1] = 1;


  /*Read actual data into c matrix image2.*/
  if(fits_read_pix(fptr, TFLOAT, fpixel, npixels, &nullval, image2[0], &anynull, &status))
    {
         fits_report_error(stderr, status); /* print error report */

	 exit( status );    /* terminate the program, returning error status */
    }
  fits_close_file(fptr,&status);

  for(ii=1;ii<=nx;ii++)
    {
      for(jj=1;jj<=ny;jj++)
	{
	  image[ii][jj] = image2[jj-1][ii-1];
	}
    }

  free_matrix(image2,0,naxes[1]-1,0,naxes[0]-1);

  return(1);
}

/*Read layer ilayer of a fits data cube into a 
  c matrix*/
int readim02(int nx,int ny,char* imname,float **image,int ilayer)
{
  fitsfile *fptr;
  int status,  nfound, anynull,ii,jj;
  long naxes[2];
  long npixels;
  long fpixel[3];
  char filename[80]; 
  float nullval,**image2;

  printf("readim01 preparing to read image called %s.\n",imname);

  image2 = matrix(0,ny-1,0,nx-1);

  status = 0;

  /*Obtain FITS file pointer*/
  if(fits_open_file(&fptr,imname,READONLY, &status))
    {
       fits_report_error(stderr, status); /* print error report */

       exit( status );    /* terminate the program, returning error status */
    }

  naxes[0] = nx;
  naxes[1] = ny;

  npixels = naxes[0]*naxes[1];

  nullval = 0;
  fpixel[0] = 1;
  fpixel[1] = 1;
  fpixel[2] = ilayer;


  /*Read actual data into c matrix image2.*/
  if(fits_read_pix(fptr, TFLOAT, fpixel, npixels, &nullval, image2[0], &anynull, &status))
    {
         fits_report_error(stderr, status); /* print error report */

	 exit( status );    /* terminate the program, returning error status */
    }
  fits_close_file(fptr,&status);

  for(ii=1;ii<=nx;ii++)
    {
      for(jj=1;jj<=ny;jj++)
	{
	  image[ii][jj] = image2[jj-1][ii-1];
	}
    }

  free_matrix(image2,0,naxes[1]-1,0,naxes[0]-1);
  fflush(stdout);
  printf("Readim finished OK\n");
  fflush(stdout);

  return(1);
}



/*writeim01.  Writes a C matrix into a FITS file using utilities
from cfitsio.  These utilities accept a matrix whose first pixel
is [0][0], and which has the vertical, y coordinate as the first
index.  Oddly, however, the vector naxes which gives the cfitsio
routines the dimensions of the images, has the x size as the first
value and the y size as the second.  The convention of bezalel01
is that the x axis is the first and the y axis is the second, under
all circumstances.  The conversion from bezalel to cfitsio
convention is handled in this function, and readim01
handles the reverse conversion.*/
int writeim01(int nx,int ny,char* imname,float **image)
{
  fitsfile *fptr;
  int status,ii,jj;
  long naxes[2],naxis;
  long npixels;
  long fpixel;
  long bitpix;
  char filename[80]; 
  float **image2;

  image2 = matrix(0,ny-1,0,nx-1);

  for(ii=1;ii<=nx;ii++)
    {
      for(jj=1;jj<=ny;jj++)
	{
	  image2[jj-1][ii-1] = image[ii][jj];
	}
    }

  naxis = 2;  /*2-dimensional image*/
  naxes[0] = nx;
  naxes[1] =  ny;
  npixels = naxes[0]*naxes[1];
  bitpix = FLOAT_IMG; /* Floating point pixels */

  /*Delete any existing file of this name*/
  remove(imname);

  status = 0;

  /*Create new FITS file*/
  if(fits_create_file(&fptr,imname,&status))
    {
      fits_report_error(stderr, status); /* print error report */
      
      exit( status );    /* terminate the program, returning error status */
    }
  
  /*Create image header for new FITS file*/
  if(fits_create_img(fptr,bitpix,naxis,naxes,&status))
    {
      fits_report_error(stderr, status); /* print error report */
      
      exit( status );    /* terminate the program, returning error status */
    }
  
  /* First pixel is 1 */
  fpixel = 1;
  
  /*Write actual data to FITS file*/
  if(fits_write_img(fptr,TFLOAT,fpixel,npixels,image2[0],&status))
    {
      fits_report_error(stderr, status); /* print error report */
      
      exit( status );    /* terminate the program, returning error status */
    }

  /*Close FITS file*/
  if(fits_close_file(fptr,&status))
    {
      fits_report_error(stderr, status); /* print error report */
      
      exit( status );    /* terminate the program, returning error status */
    }

  free_matrix(image2,0,ny-1,0,nx-1);
  return(1);
}


/*writeim02. Like writeim01 but has the special property that
it writes a UT header keyword of the form WED APR 12 hh:mm:ss 2006.
Note that the UT is the only variable here.  The keyword
will be written as WED APR 12 2006 no matter what the real
date is.  The ut is converted from floating point to
integer form internally.  It is written with initial
zeros; i.e. 05:04:09, not 5:4:9, for compatability
with headread02 (which is this functions reason for being).*/
int writeim02(int nx,int ny,char* imname,float **image,float ut)
{
  fitsfile *fptr;
  int status,ii,jj,uthr,utmin,utsec;
  long naxes[2],naxis;
  long npixels;
  long fpixel;
  long bitpix;
  char filename[80],utstr[80]; 
  float **image2;
  int tensplace,onesplace;

  image2 = matrix(0,ny-1,0,nx-1);

  for(ii=1;ii<=nx;ii++)
    {
      for(jj=1;jj<=ny;jj++)
	{
	  image2[jj-1][ii-1] = image[ii][jj];
	}
    }

  naxis = 2;  /*2-dimensional image*/
  naxes[0] = nx;
  naxes[1] =  ny;
  npixels = naxes[0]*naxes[1];
  bitpix = FLOAT_IMG; /* Floating point pixels */

  /*Delete any existing file of this name*/
  remove(imname);

  status = 0;

  /*Create new FITS file*/
  if(fits_create_file(&fptr,imname,&status))
    {
      fits_report_error(stderr, status); /* print error report */
      
      exit( status );    /* terminate the program, returning error status */
    }
  
  /*Create image header for new FITS file*/
  if(fits_create_img(fptr,bitpix,naxis,naxes,&status))
    {
      fits_report_error(stderr, status); /* print error report */
      
      exit( status );    /* terminate the program, returning error status */
    }
  
  /*Get integer UT values*/
  uthr = ut;
  utmin = 1.0*(ut*60.0 - (float)uthr*60.0);
  utsec = 1.0*(ut*3600.0 - (float)uthr*3600.0 - (float)utmin*60.0);
  /*WED APR 12 hh:mm:ss 2006*/
  utstr[0] = 'W';
  utstr[1] = 'E';
  utstr[2] = 'D';
  utstr[3] = ' ';
  utstr[4] = 'A';
  utstr[5] = 'P';
  utstr[6] = 'R';
  utstr[7] = ' ';
  utstr[8] = '1';
  utstr[9] = '2';
  utstr[10] = ' ';
  tensplace = uthr/10;
  onesplace = uthr - tensplace*10;
  utstr[11] = '0'+tensplace;
  utstr[12] = '0'+onesplace;
  utstr[13] = ':';
  tensplace = utmin/10;
  onesplace = utmin - tensplace*10;
  utstr[14] = '0'+tensplace;
  utstr[15] = '0'+onesplace;
  utstr[16] = ':';
  tensplace = utsec/10;
  onesplace = utsec - tensplace*10;
  utstr[17] = '0'+tensplace;
  utstr[18] = '0'+onesplace;
  utstr[19] = ' ';
  utstr[20] = '2';
  utstr[21] = '0';
  utstr[22] = '0';
  utstr[23] = '6';
  utstr[24] = '\0';
  printf("ut = %f\tutstr = %s\n",ut,utstr);

  if(fits_update_key(fptr, TSTRING, "UT", utstr,"Universal time", &status))
    {
      fits_report_error(stderr, status); /* print error report */
      
      exit( status );    /* terminate the program, returning error status */
    }


  /* First pixel is 1 */
  fpixel = 1;
  
  /*Write actual data to FITS file*/
  if(fits_write_img(fptr,TFLOAT,fpixel,npixels,image2[0],&status))
    {
      fits_report_error(stderr, status); /* print error report */
      
      exit( status );    /* terminate the program, returning error status */
    }

  /*Close FITS file*/
  if(fits_close_file(fptr,&status))
    {
      fits_report_error(stderr, status); /* print error report */
      
      exit( status );    /* terminate the program, returning error status */
    }

  free_matrix(image2,0,ny-1,0,nx-1);
  return(1);
}


/*writeim03.  Like writeim03, but will (I hope) copy
  the whole header.*/
int writeim03(int nx,int ny,char* imname1, char* imname2,float **image)
{
  fitsfile *fptr1;
  fitsfile *fptr2;
  int status,ii,jj;
  long naxes[2],naxis;
  long npixels;
  long fpixel;
  long bitpix;
  char filename[80]; 
  float **image2;

  image2 = matrix(0,ny-1,0,nx-1);

  for(ii=1;ii<=nx;ii++)
    {
      for(jj=1;jj<=ny;jj++)
	{
	  image2[jj-1][ii-1] = image[ii][jj];
	}
    }

  naxis = 2;  /*2-dimensional image*/
  naxes[0] = nx;
  naxes[1] =  ny;
  npixels = naxes[0]*naxes[1];
  bitpix = FLOAT_IMG; /* Floating point pixels */

  /*Delete any existing file of this name*/
  remove(imname2);

  status = 0;

 /*Obtain FITS file pointer to old image*/
  if(fits_open_file(&fptr1,imname1,READONLY, &status))
    {
       fits_report_error(stderr, status); /* print error report */

       exit( status );    /* terminate the program, returning error status */
    }


  /*Create new FITS file*/
  if(fits_create_file(&fptr2,imname2,&status))
    {
      fits_report_error(stderr, status); /* print error report */
      
      exit( status );    /* terminate the program, returning error status */
    }
  
  /*Copy old header into new FITS file*/
  if(fits_copy_header(fptr1,fptr2,&status))
    {
      fits_report_error(stderr, status); /* print error report */
      
      exit( status );    /* terminate the program, returning error status */
    }

  /*Close old FITS file*/
  if(fits_close_file(fptr1,&status))
    {
      fits_report_error(stderr, status); /* print error report */
      
      exit( status );    /* terminate the program, returning error status */
    }
  
  /* First pixel is 1 */
  fpixel = 1;
  
  /*Write actual data to FITS file*/
  if(fits_write_img(fptr2,TFLOAT,fpixel,npixels,image2[0],&status))
    {
      fits_report_error(stderr, status); /* print error report */
      
      exit( status );    /* terminate the program, returning error status */
    }

  /*Close new FITS file*/
  if(fits_close_file(fptr2,&status))
    {
      fits_report_error(stderr, status); /* print error report */
      
      exit( status );    /* terminate the program, returning error status */
    }

  free_matrix(image2,0,ny-1,0,nx-1);
  return(1);
}



/*putguass.  Puts a guassian of specified location, amplitude,
and sigma into an image.  The guassian parameters must be given
in the vector gaussvec, with the ordering x,y,sigma,amp.*/

int putgauss01(int nx,int ny,float **image,float *gaussvec)
{
  int i,j;
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image[i][j]+=gaussvec[4]*exp(-(pow(1.0*i-gaussvec[1],2.0)+pow(1.0*j-gaussvec[2],2.0))/(2.0*pow(gaussvec[3],2.0)));
	}
    }
  return(1);
}

/*statsim01.  Calculates the number of pixels, the mean pixel
value, the rms pixel variation, and the min and max pixel values
for an image.  Attempts to determine the dimensions of the image,
and outputs NSIZETRYS guesses at them.  Outputs the positions of 
the highest and lowest pixels given the assumption that the 
image is as square as possible.  The vector statsims must
have length 4, as it will hold the mean, rms, min, and max
pixel values in that order.  The vector sizeims must have length
(IMSIZETRYS+2)*2+1, as it will hold the number of pixels,
IMSIZETRYS guesses at the x and y dimensions of the image, and
the positions of the lowest and highest pixel assuming the first
(squarest) guess at the image dimensions is correct.*/

int statsim01(char *imname,float *statsims,int *sizeims)
{
  FILE *fp1;
  float pixval,fx,fy,minpix,maxpix,rms,mean;
  int npix,nx,ny,c,tryct,i,nmin,nmax;
  npix = 0;
  fp1 = fopen(imname,"r");
  while(c!=EOF)
    {
      c = getc(fp1);
      if(c=='\n')
	{
	  npix+=1;
	}
    }
  fclose(fp1);
  sizeims[1] = npix;
  fx = pow((1.0*npix),0.5);
  nx = 1.0*(fx-2.0);
  tryct = 1;
  while(tryct<=IMSIZETRYS&&ny>=1)
    {
      fy = (1.0*npix)/(1.0*nx);
      ny = 1.0*(fy+INTCOR);
      if(ny*nx==npix)
	{
	  sizeims[tryct*2] = nx;
	  sizeims[tryct*2+1] = ny;
	  tryct+=1;
	}
      nx+=1;
    }
  fp1 = fopen(imname,"r");
  fscanf(fp1,"%f",&mean);
  minpix = maxpix = mean;
  nmin = nmax = 1;
  for(i=2;i<=npix;i++)
    {
      fscanf(fp1,"%f",&pixval);
      mean+=pixval;
      if(pixval<minpix)
	{
	  minpix = pixval;
	  nmin = i;
	}
      if(pixval>maxpix)
	{
	  maxpix = pixval;
	  nmax = i;
	}
    }
  fclose(fp1);
  mean/=(1.0*npix);
  sizeims[(IMSIZETRYS+1)*2+1]=nmin/sizeims[2] + 1.0;
  sizeims[(IMSIZETRYS+1)*2]=nmin-(sizeims[(IMSIZETRYS+1)*2+1] - 1)*sizeims[2];
  sizeims[(IMSIZETRYS+2)*2+1]=nmax/sizeims[2] + 1.0;
  sizeims[(IMSIZETRYS+2)*2]=nmax-(sizeims[(IMSIZETRYS+2)*2+1] - 1)*sizeims[2];

  fp1 = fopen(imname,"r");
  for(i=1;i<=npix;i++)
    {
      fscanf(fp1,"%f",&pixval);
      rms+=pow(pixval-mean,2.0);
    }
  fclose(fp1);
  rms=pow(rms/(1.0*npix-1.0),0.5);
  statsims[1] = mean;
  statsims[2] = rms;
  statsims[3] = minpix;
  statsims[4] = maxpix;
  return(1);
}


/*statsim02.  Similar in purpose to statsim01, statsim02 is
a simpler, faster version that accepts a ready-made image matrix.  
It outputs the mean, rms, min, and max in the vector statsims 
of length 4, and the number of pixels, and location of minimum
and maximum pixels in the vector sizeims of length 5.  statsim02
also differs from statsim01 in that it requires the specification
of a box over which the statistics should be taken.  In normal
use as an image statistics program this box will be the whole
image, but it can be a smaller box equally well.  The box is
specified in the integer vector boxvec of length 4, with
entries xlow, xhigh, ylow, yhigh.*/


int statsim02(float **image,int nx,int ny,int *boxvec,float *statsims,int *sizeims)
{
  int i,j;
  float mean,rms,min,max;
  if(boxvec[2]<boxvec[1]||boxvec[4]<boxvec[3]||boxvec[1]<1||boxvec[2]>nx||boxvec[3]<1||boxvec[4]>ny)
    {
      printf("ERROR: statsim02 CALLED WITH INVALID STATISTICS BOX\n");
      printf("ABORTING\n");
      return(0);
    }
  mean = 0.0;
  min = max = image[1][1];
  sizeims[1] = (boxvec[2]-boxvec[1]+1)*(boxvec[4]-boxvec[3]+1);
  sizeims[2] = sizeims[3] = sizeims[4] = sizeims[5] = 1;
  for(i=boxvec[1];i<=boxvec[2];i++)
    {
      for(j=boxvec[3];j<=boxvec[4];j++)
	{
	  mean+=image[i][j];
	  if(image[i][j]<min)
	    {
	      min = image[i][j];
	      sizeims[2] = i;
	      sizeims[3] = j;
	    }
	  if(image[i][j]>max)
	    {
	      max = image[i][j];
	      sizeims[4] = i;
	      sizeims[5] = j;
	    }
	}
    }
  mean/=(1.0*sizeims[1]);
  rms = 0.0;
  for(i=boxvec[1];i<=boxvec[2];i++)
    {
      for(j=boxvec[3];j<=boxvec[4];j++)
	{
	  rms+=pow(mean-image[i][j],2.0);
	}
    }
  rms=pow(rms/(1.0*sizeims[1]-1.0),0.5);
  statsims[1] = mean;
  statsims[2] = rms;
  statsims[3] = min;
  statsims[4] = max;
  return(1);
}


/*statsim03.  Similar in purpose to statsim02, statsim03 is
a stripped down version that accepts a ready-made image matrix.  
It outputs the mean and rms calculated using a sigma-clip
that is given as a parameter. statsim03 is for use in programs
where simple data is needed over and over again, where a sigma clip
might be needed, and where no one cares what or where the highest
and lowest pixels in the image were.  statsim03 requires the 
specification of a box over which the statistics should be taken.  
The box is specified in the integer vector boxvec of length 4, 
with entries xlow, xhigh, ylow, yhigh.*/

int statsim03(float **image,int nx,int ny,int *boxvec,float *rms,float *mean,float sigclip)
{
  int i,j,npix;
  float mean1,rms1,mean2,rms2,min,max;
  if(boxvec[2]<boxvec[1]||boxvec[4]<boxvec[3]||boxvec[1]<1||boxvec[2]>nx||boxvec[3]<1||boxvec[4]>ny)
    {
      printf("ERROR: statsim03 CALLED WITH INVALID STATISTICS BOX\n");
      printf("xl=%d xh=%d yl=%d yh=%d nx=%d ny=%d\n",boxvec[1],boxvec[2],boxvec[3],boxvec[4],nx,ny);
      printf("ABORTING\n");
      return(0);
    }
  mean1 = 0.0;
  npix = (boxvec[2]-boxvec[1]+1)*(boxvec[4]-boxvec[3]+1);
  for(i=boxvec[1];i<=boxvec[2];i++)
    {
      for(j=boxvec[3];j<=boxvec[4];j++)
	{
	  mean1+=image[i][j];
	}
    }
  mean1/=(1.0*npix);
  rms1 = 0.0;
  for(i=boxvec[1];i<=boxvec[2];i++)
    {
      for(j=boxvec[3];j<=boxvec[4];j++)
	{
	  rms1+=pow(mean1-image[i][j],2.0);
	}
    }
  rms1=pow(rms1/(1.0*npix-1.0),0.5);
  npix = 0;
  mean2 = 0.0;
  for(i=boxvec[1];i<=boxvec[2];i++)
    {
      for(j=boxvec[3];j<=boxvec[4];j++)
	{
	  if(pow(pow(mean1-image[i][j],2.0),0.5)<sigclip*rms1)
	    {
	      npix+=1;
	      mean2+=image[i][j];
	    }
	}
    }
  mean2/=(1.0*npix);
  npix = 0;
  rms2 = 0.0;
  for(i=boxvec[1];i<=boxvec[2];i++)
    {
      for(j=boxvec[3];j<=boxvec[4];j++)
	{
	  if(pow(pow(mean1-image[i][j],2.0),0.5)<sigclip*rms1)
	    {
	      npix+=1;
	      rms2+=pow(mean2-image[i][j],2.0);
	    }
	}
    }
  rms2 = pow(rms2/(1.0*npix-1.0),0.5);
  *rms=rms2;
  *mean = mean2;
  return(1);
}

/*statsim03c: exactly like statsim03, except uses a pseudo-creeping mean combine
  rather than a sigma clip.*/
int statsim03c(float **image,int nx,int ny,int *boxvec,float *rms,float *mean,float rlev)
{
  int i,j,npix,pct;
  float mean1,rms1,mean2,rms2,min,max,meanerror;
  float *pixvec;

  if(boxvec[2]<boxvec[1]||boxvec[4]<boxvec[3]||boxvec[1]<1||boxvec[2]>nx||boxvec[3]<1||boxvec[4]>ny)
    {
      printf("ERROR: statsim03 CALLED WITH INVALID STATISTICS BOX\n");
      printf("xl=%d xh=%d yl=%d yh=%d nx=%d ny=%d\n",boxvec[1],boxvec[2],boxvec[3],boxvec[4],nx,ny);
      printf("ABORTING\n");
      return(0);
    }
  npix = (1+boxvec[2]-boxvec[1])*(1+boxvec[4]-boxvec[3]);
  pixvec = vector(1,npix);

  pct = 0;
  for(i=boxvec[1];i<=boxvec[2];i++)
    {
      for(j=boxvec[3];j<=boxvec[4];j++)
	{
	  pct+=1;
	  pixvec[pct]=image[i][j];
	}
    }
  pseudocreep01(pixvec,npix,rlev,mean,&meanerror,rms);

  free_vector(pixvec,1,npix);
  return(1);
}



/*statsim04: exacly like statsim01 except that it uses a sigma clip*/

int statsim04(char *imname,float *statsims,int *sizeims,float sigclip)
{
  FILE *fp1;
  float pixval,fx,fy,minpix,maxpix,rms,mean;
  int npix,nx,ny,c,tryct,i,nmin,nmax;
  npix = 0;
  float rms2,mean2,norm;
  fp1 = fopen(imname,"r");
  while(c!=EOF)
    {
      c = getc(fp1);
      if(c=='\n')
	{
	  npix+=1;
	}
    }
  fclose(fp1);
  sizeims[1] = npix;
  fx = pow((1.0*npix),0.5);
  nx = 1.0*(fx-2.0);
  tryct = 1;
  while(tryct<=IMSIZETRYS&&ny>=1)
    {
      fy = (1.0*npix)/(1.0*nx);
      ny = 1.0*(fy+INTCOR);
      if(ny*nx==npix)
	{
	  sizeims[tryct*2] = nx;
	  sizeims[tryct*2+1] = ny;
	  tryct+=1;
	}
      nx+=1;
    }
  fp1 = fopen(imname,"r");
  fscanf(fp1,"%f",&mean);
  minpix = maxpix = mean;
  nmin = nmax = 1;
  for(i=2;i<=npix;i++)
    {
      fscanf(fp1,"%f",&pixval);
      mean+=pixval;
      if(pixval<minpix)
	{
	  minpix = pixval;
	  nmin = i;
	}
      if(pixval>maxpix)
	{
	  maxpix = pixval;
	  nmax = i;
	}
    }
  fclose(fp1);
  mean/=(1.0*npix);
  sizeims[(IMSIZETRYS+1)*2+1]=nmin/sizeims[2] + 1.0;
  sizeims[(IMSIZETRYS+1)*2]=nmin-(sizeims[(IMSIZETRYS+1)*2+1] - 1)*sizeims[2];
  sizeims[(IMSIZETRYS+2)*2+1]=nmax/sizeims[2] + 1.0;
  sizeims[(IMSIZETRYS+2)*2]=nmax-(sizeims[(IMSIZETRYS+2)*2+1] - 1)*sizeims[2];

  fp1 = fopen(imname,"r");
  for(i=1;i<=npix;i++)
    {
      fscanf(fp1,"%f",&pixval);
      rms+=pow(pixval-mean,2.0);
    }
  fclose(fp1);
  rms=pow(rms/(1.0*npix-1.0),0.5);

  mean2=rms2=norm=0.0;
  fp1 = fopen(imname,"r");
  for(i=1;i<=npix;i++)
    {
      fscanf(fp1,"%f",&pixval);
      if(pow(pow(pixval-mean,2.0),0.5)<sigclip*rms)
	{
	  mean2+=pixval;
	  norm+=1.0;
	}
    }
  fclose(fp1);
  mean2/=norm;
  rms2=norm=0.0;
  fp1 = fopen(imname,"r");
  for(i=1;i<=npix;i++)
    {
      fscanf(fp1,"%f",&pixval);
      if(pow(pow(pixval-mean,2.0),0.5)<sigclip*rms)
	{
	  rms2+=pow(mean2-pixval,2.0);
	  norm+=1.0;
	}
    }
  fclose(fp1);
  rms2 = pow(rms2/(norm-1.0),0.5);

  statsims[1] = mean2;
  statsims[2] = rms2;
  statsims[3] = minpix;
  statsims[4] = maxpix;
  return(1);
}


/*submean01: a simple program to subtract from an image
the mean pixel value within a specified box, as calculated
by statsim03.*/
int submean01(float **image,float sigclip,int nx,int ny,int *boxvec)
{

  int i,j;
  float norm,rms;
  statsim03(image,nx,ny,boxvec,&rms,&norm,sigclip);

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image[i][j]-=norm;
	}
    }
  return(1);
}

/*submean01c: Exactly like submean01, but uses a pseudo-creeping
mean combine rather than a sigma clip in calculating the mean*/
int submean01c(float **image,float rlev,int nx,int ny,int *boxvec)
{

  int i,j;
  float norm,rms;
  statsim03c(image,nx,ny,boxvec,&rms,&norm,rlev);

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image[i][j]-=norm;
	}
    }
  return(1);
}

/*streaksmooth01: a program to average all columns in a horizontal
band spanning the image, and output an image in which every pixel in
each column is set to the averaged value in the band.*/
int streaksmooth01(float **image1,float **image2,float sigclip,int nx,int ny,int yl,int yh)
{

  int *boxvec,i,j;
  float meanval,rms;

  boxvec = ivector(1,4);
  for(i=1;i<=nx;i++)
    {
      boxvec[1] = boxvec[2] = i;
      boxvec[3] = yl;
      boxvec[4] = yh;
      statsim03(image1,nx,ny,boxvec,&rms,&meanval,sigclip);
      for(j=1;j<=ny;j++)
	{
	  image2[i][j] = meanval;
	}
    }
  free_ivector(boxvec,1,4);
  return(1);
}

/*streaksmooth01c: exactly like streaksmooth01, but uses a pseudo-creeping
  mean combine instead of a sigma clip for the column means*/
int streaksmooth01c(float **image1,float **image2,float rlev,int nx,int ny,int yl,int yh)
{

  int *boxvec,i,j;
  float meanval,rms;

  boxvec = ivector(1,4);
  for(i=1;i<=nx;i++)
    {
      boxvec[1] = boxvec[2] = i;
      boxvec[3] = yl;
      boxvec[4] = yh;
      statsim03c(image1,nx,ny,boxvec,&rms,&meanval,rlev);
      for(j=1;j<=ny;j++)
	{
	  image2[i][j] = meanval;
	}
    }
  free_ivector(boxvec,1,4);
  return(1);
}


/*imzero: a very simple program to zero an image matrix.*/
int imzero(float **image,int nx,int ny)
{
  int i,j;
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image[i][j] = 0.0;
	}
    }
  return(1);
}

/*mathimc01: a very simple program to add a constant to an image.
Note that image1 and image2 can be the same without problems*/
int mathimc01(float **image1,float **image2,int nx,int ny,float x)
{
  int i,j;
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image2[i][j]=image1[i][j]+x;
	}
    }
  return(1);
}

/*mathimc02: a very simple program to subtract a constant from an image.
Note that image1 and image2 can be the same without problems*/
int mathimc02(float **image1,float **image2,int nx,int ny,float x)
{
  int i,j;
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image2[i][j]=image1[i][j]-x;
	}
    }
  return(1);
}

/*mathimc03: a very simple program to multiply an image by a constant.
Note that image1 and image2 can be the same without problems*/
int mathimc03(float **image1,float **image2,int nx,int ny,float x)
{
  int i,j;
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image2[i][j]=image1[i][j]*x;
	}
    }
  return(1);
}

/*mathimc04: a very simple program to divide an image by a constant.
Note that image1 and image2 can be the same without problems*/
int mathimc04(float **image1,float **image2,int nx,int ny,float x)
{
  int i,j;
  if(x==0.0)
    {
      printf("ERROR: mathimc04 CALLED WITH ZERO DIVIDE!\n");
      printf("ABORTING\n");
      return(1);
    }
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image2[i][j]=image1[i][j]/x;
	}
    }
  return(1);
}

/*mathimtim01: a very simple program to add an image to an image.
Note that image1 and image2 can be the same without problems*/
int mathimtim01(float **image1,float **image2,int nx,int ny,float **image3)
{
  int i,j;
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image2[i][j]=image1[i][j]+image3[i][j];
	}
    }
  return(1);
}

/*mathimtim02: a very simple program to subtract an image from an image.
Note that image1 and image2 can be the same without problems*/
int mathimtim02(float **image1,float **image2,int nx,int ny,float **image3)
{
  int i,j;
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image2[i][j]=image1[i][j]-image3[i][j];
	}
    }
  return(1);
}

/*mathimtim03: a very simple program to multiply an image by a constant.
Note that image1 and image2 can be the same without problems*/
int mathimtim03(float **image1,float **image2,int nx,int ny,float **image3)
{
  int i,j;
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image2[i][j]=image1[i][j]*image3[i][j];
	}
    }
  return(1);
}

/*mathimtim04: a very simple program to divide an image by an image.
Note that image1 and image2 can be the same without problems.
Note that a zero divide does not produce an error, but that zeros
in the denominator image are replaced with the constant RBADPIX,
which should probably be 1.0.  In the usual case of flatfielding,
zeros should be removed from the flatfield before mathimtim04 is called.*/
int mathimtim04(float **image1,float **image2,int nx,int ny,float **image3)
{
  int i,j;
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  if(image3[i][j]!=0.0)
	    {
	      image2[i][j]=image1[i][j]/image3[i][j];
	    }
	  else{
	    image2[i][j] = image1[i][j]/RBADPIX;
	    printf("WARNING: mathimtim04 FINDS A ZERO DIVIDE\n");
	  }
	}
    }
  return(1);
}

/*imagemath01: Perform a mathematical operation on two images*/
int imagemath01(int nx, int ny,float **inimage01,char moperator,float **inimage02,float **outimage)
{
    if(moperator == '+')
    {
	mathimtim01(inimage01,outimage,nx,ny,inimage02);
    }
    else if(moperator == '-')
    {
	mathimtim02(inimage01,outimage,nx,ny,inimage02);
    }
    else if(moperator == '*')
    {
	mathimtim03(inimage01,outimage,nx,ny,inimage02);
    }
    else if(moperator == '/')
    {
	mathimtim04(inimage01,outimage,nx,ny,inimage02);
    }
    else
    {
	printf("IMAGE MATH ERROR: OPERAND NOT +,-,*,or/\n");
	printf("ABORTING!\n");
	return(0);
    }
    return(1);
}

/*imagemath02: Perform a mathematical operation on an image and a constant*/
int imagemath02(int nx, int ny,float **inimage,char moperator,float x,float **outimage)
{
    if(moperator == '+')
    {
	mathimc01(inimage,outimage,nx,ny,x);
    }
    else if(moperator == '-')
    {
	mathimc01(inimage,outimage,nx,ny,x);
    }
    else if(moperator == '*')
    {
	mathimc01(inimage,outimage,nx,ny,x);
    }
    else if(moperator == '/')
    {
	mathimc01(inimage,outimage,nx,ny,x);
    }
    else
    {
	printf("IMAGE MATH ERROR: OPERAND NOT +,-,*,or/\n");
	printf("ABORTING!\n");
	return(0);
    }
    return(1);
}


/*mmask01: given an image, makes a crude unsharp mask of it
  using a block of specified input half-size.*/
int mmask01(float **image1,float **image2,int nx,int ny,int bsize)
{
  int i,j,k,ibot,jbot,itop,jtop;
  float sum,*linvec;

  linvec = vector(1,ny);

  for(i=1;i<=nx;i++)
    {
      ibot = i-bsize;
      itop = i+bsize;
      if(ibot<1)
	{
	  ibot = 1;
	}
      if(itop>nx)
	{
	  itop = nx;
	}
      for(j=1;j<=ny;j++)
	{
	  linvec[j] = 0.0;
	  for(k=ibot;k<=itop;k++)
	    {
	      if(k>=1&&k<=nx)
		{
		  linvec[j]+=image1[k][j];
		}
	    }
	}
      sum = 0.0;
      for(j=1;j<=1+bsize;j++)
	{
	  sum+=linvec[j];
	}
      for(j=1;j<=ny;j++)
	{
	  jbot = j-bsize;
	  jtop = j+bsize;
	  if(jbot<1)
	    {
	      jbot = 1;
	    }
	  if(jtop>ny)
	    {
	      jtop = ny;
	    }
	  image2[i][j] = sum/((1.0*itop-1.0*ibot+1.0)*(1.0*jtop-1.0*jbot+1.0));
	  if(jtop<2*bsize+1)
	    {
	      sum+=linvec[jtop+1];
	    }
	  else if(jbot>ny-2*bsize)
	    {
	      sum-=linvec[jbot];
	    }
	  else if(jbot<=ny-2*bsize&&jtop>=1+2*bsize)
	    {
	      sum+=(linvec[jtop+1]-linvec[jbot]);
	    }
	  else{
	    printf("ERROR: IMPOSSIBLE CASE IN mmask01!\n");
	    printf("ABORTING.\n");
	  }
	}
    }

  free_vector(linvec,1,ny);
  return(1);
}

/*mmaskjunk01: Exactly like mmask01, but slower and more transparent
to code.  Its sole purpose is as a reality check on mmask01.
The reality check is successfully passed.*/
int mmaskjunk01(float **image1,float **image2,int nx,int ny,int bsize)
{
  int i,j,k,l;
  float mean,norm;

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  norm = mean = 0.0;
	  for(k=i-bsize;k<=i+bsize;k++)
	    {
	      for(l=j-bsize;l<=j+bsize;l++)
		{
		  if(k>=1&&k<=nx&&l>=1&&l<=ny)
		    {
		      norm+=1.0;
		      mean+=image1[k][l];
		    }
		}
	    }
	  image2[i][j] = mean/norm;
	}
    }
  return(1);
}

/*mmask02: given an image, makes an unsharp mask of it
  using a radial gaussian kernal of specified size in
  a box of specified half-size.  Much slower than mmask01,
  this program also does a much cleaner job.  It is the
  one to use when detailed analyses of the blurred image
  are to be performed, or for unsharp masking of final
  science images.*/
int mmask02(float **image1,float **image2,int nx,int ny,int bsize,float sigma)
{
  float **boxim,norm;
  int i,j,k,l;
  boxim = matrix(1,2*bsize+1,1,2*bsize+1);
  norm = 0.0;
  for(k=1;k<=2*bsize+1;k++)
    {
      for(l=1;l<=2*bsize+1;l++)
	{
	  boxim[k][l] = exp(-(pow(1.0*k-(1.0*bsize+1.0),2.0)+pow(1.0*l-(1.0*bsize+1.0),2.0))/(2.0*pow(sigma,2.0)));
	}
    }
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  norm = 0.0;
	  for(k=i-bsize;k<=i+bsize;k++)
	    {
	      for(l=j-bsize;l<=j+bsize;l++)
		{
		  if(k>=1&&k<=nx&&l>=1&&l<=ny)
		    {
		      norm+=boxim[k-i+bsize+1][l-j+bsize+1];
		    }
		}
	    }
	  image2[i][j] = 0.0;
	  for(k=i-bsize;k<=i+bsize;k++)
	    {
	      for(l=j-bsize;l<=j+bsize;l++)
		{
		  if(k>=1&&k<=nx&&l>=1&&l<=ny)
		    {
		      image2[i][j]+=boxim[k-i+bsize+1][l-j+bsize+1]*image1[k][l]/norm;
		    }
		}
	    }
	}
    }
  free_matrix(boxim,1,2*bsize+1,1,2*bsize+1);
  return(1);
}


/*mmask03: given an image, makes an unsharp mask of it
  using a radial gaussian kernal of specified size in
  a box of specified half-size.  It differes from mmask02
  in that it performs a 3-iteration sigma clip at specified
  rejection on the raw values in the box before averaging
  them with th gaussian kernal.  It also differs in that
  it actually doesn't take an input box, but defines its
  own box such that the sided are 5 pixels beyond the radius
  at which the gaussian kernal drops to KERNLOW = 0.01 of
  its central value.  mmask03 considers zero a valid data
  value.*/
int mmask03(float **image1,float **image2,int nx,int ny,float sigma,float sigclip)
{
  float *imvec,*gaussvec,norm,radlim,rad;
  int i,j,k,l,bhw,veclen,sgct,sgct2;
  float *imvec2,*gaussvec2,mean1,rms1;

  radlim = pow(-log(KERNLOW)*2,0.5)*sigma;
  bhw = radlim+5;

  veclen = (2*bhw+1)*(2*bhw+1);

  imvec = vector(1,veclen);
  gaussvec = vector(1,veclen);
  imvec2 = vector(1,veclen);
  gaussvec2 = vector(1,veclen);

  for(i=1;i<=nx;i++)
    {
      printf("mmask03 processing column %d\n",i);
      for(j=1;j<=ny;j++)
	{
	  sgct = 0;
	  for(k=i-bhw;k<=i+bhw;k++)
	    {
	      for(l=j-bhw;l<=j+bhw;l++)
		{
		  if(k>=1&&k<=nx&&l>=1&&l<=ny)
		    {
		      rad = pow(pow(1.0*k-1.0*i,2.0)+pow(1.0*l-1.0*j,2.0),0.5);
		      if(rad<=radlim)
			{
			  sgct+=1;
			  imvec[sgct] = image1[k][l];
			  gaussvec[sgct] = exp(-0.5*pow(rad/sigma,2.0));
			}
		    }
		}
	    }
	  if(sgct>1)
	    {
	      meanrms01(imvec,sgct,&mean1,&rms1);
	      sgct2 = 0;
	      for(k=1;k<=sgct;k++)
		{
		  if(fabs(imvec[k]-mean1)<sigclip*rms1)
		    {
		      sgct2+=1;
		      imvec2[sgct2] = imvec[k];
		      gaussvec2[sgct2] = gaussvec[k];
		    }
		}
	      if(sgct2>1)
		{
		  meanrms01(imvec2,sgct2,&mean1,&rms1);
		  sgct = 0;
		  for(k=1;k<=sgct2;k++)
		    {
		      if(fabs(imvec2[k]-mean1)<sigclip*rms1)
			{
			  sgct+=1;
			  imvec[sgct] = imvec2[k];
			  gaussvec[sgct] = gaussvec2[k];
			}
		    }
		  if(sgct>1)
		    {
		      meanrms01(imvec,sgct,&mean1,&rms1);
		      sgct2 = 0;
		      for(k=1;k<=sgct;k++)
			{
			  if(fabs(imvec[k]-mean1)<sigclip*rms1)
			    {
			      sgct2+=1;
			      imvec2[sgct2] = imvec[k];
			      gaussvec2[sgct2] = gaussvec[k];
			    }
			}
		      if(sgct2>1)
			{
			  norm = mean1 = 0.0;
			  for(k=1;k<=sgct2;k++)
			    {
			      mean1+=imvec2[k]*gaussvec2[k];
			      norm+=gaussvec2[k];
			    }
			  mean1/=norm;
			  image2[i][j] = mean1;
			}
		      else
			{
			  /*sgct2 is not greater than 1*/
			  /*however, sgct must be greater than 1*/
			  /*or we wouldn't be here.  Thus:*/
			  norm = mean1 = 0.0;
			  for(k=1;k<=sgct;k++)
			    {
			      mean1+=imvec[k]*gaussvec[k];
			      norm+=gaussvec[k];
			    }
			  mean1/=norm;
			  image2[i][j] = mean1;
			}
		    }
		  else
		    {
		      /*sgct is not greater than 1*/
		      /*However, sgct2 must be, or we wouldn't*/
		      /*be here.  Thus:*/
		      norm = mean1 = 0.0;
		      for(k=1;k<=sgct2;k++)
			{
			  mean1+=imvec2[k]*gaussvec2[k];
			  norm+=gaussvec2[k];
			}
		      mean1/=norm;
		      image2[i][j] = mean1;
		    }
		}
	      else
		{
		  /*sgct2 is not greater than 1, but sgct is*/
		  norm = mean1 = 0.0;
		  for(k=1;k<=sgct;k++)
		    {
		      mean1+=imvec[k]*gaussvec[k];
		      norm+=gaussvec[k];
		    }
		  mean1/=norm;
		  image2[i][j] = mean1;
		}
	    }
	  else
	    {
	      /*From the beginning sgct is not greater than 1*/
	      /*We conservatively set the mask image value to zero*/
	      image2[i][j] = 0.0;
	    }
	}
    }

	    
  free_vector(imvec,1,veclen);
  free_vector(gaussvec,1,veclen);
  free_vector(imvec2,1,veclen);
  free_vector(gaussvec2,1,veclen);

  return(1);
}


/*mmask04: like mmask03 but does not consider zero
  a valid data value.*/
int mmask04(float **image1,float **image2,int nx,int ny,float sigma,float sigclip)
{
  float *imvec,*gaussvec,norm,radlim,rad;
  int i,j,k,l,bhw,veclen,sgct,sgct2;
  float *imvec2,*gaussvec2,mean1,rms1;

  radlim = pow(-log(KERNLOW)*2,0.5)*sigma;
  bhw = radlim+5;

  veclen = (2*bhw+1)*(2*bhw+1);

  imvec = vector(1,veclen);
  gaussvec = vector(1,veclen);
  imvec2 = vector(1,veclen);
  gaussvec2 = vector(1,veclen);

  for(i=1;i<=nx;i++)
    {
      printf("mmask04 processing column %d\n",i);
      for(j=1;j<=ny;j++)
	{
	  if(image1[i][j]!=0.0)
	    {
	  sgct = 0;
	  for(k=i-bhw;k<=i+bhw;k++)
	    {
	      for(l=j-bhw;l<=j+bhw;l++)
		{
		  if(k>=1&&k<=nx&&l>=1&&l<=ny)
		    {
		      rad = pow(pow(1.0*k-1.0*i,2.0)+pow(1.0*l-1.0*j,2.0),0.5);
		      if(rad<=radlim&&image1[k][l]!=0.0)
			{
			  sgct+=1;
			  imvec[sgct] = image1[k][l];
			  gaussvec[sgct] = exp(-0.5*pow(rad/sigma,2.0));
			}
		    }
		}
	    }
	  if(sgct>1)
	    {
	      meanrms01(imvec,sgct,&mean1,&rms1);
	      sgct2 = 0;
	      for(k=1;k<=sgct;k++)
		{
		  if(fabs(imvec[k]-mean1)<sigclip*rms1)
		    {
		      sgct2+=1;
		      imvec2[sgct2] = imvec[k];
		      gaussvec2[sgct2] = gaussvec[k];
		    }
		}
	      if(sgct2>1)
		{
		  meanrms01(imvec2,sgct2,&mean1,&rms1);
		  sgct = 0;
		  for(k=1;k<=sgct2;k++)
		    {
		      if(fabs(imvec2[k]-mean1)<sigclip*rms1)
			{
			  sgct+=1;
			  imvec[sgct] = imvec2[k];
			  gaussvec[sgct] = gaussvec2[k];
			}
		    }
		  if(sgct>1)
		    {
		      meanrms01(imvec,sgct,&mean1,&rms1);
		      sgct2 = 0;
		      for(k=1;k<=sgct;k++)
			{
			  if(fabs(imvec[k]-mean1)<sigclip*rms1)
			    {
			      sgct2+=1;
			      imvec2[sgct2] = imvec[k];
			      gaussvec2[sgct2] = gaussvec[k];
			    }
			}
		      if(sgct2>1)
			{
			  norm = mean1 = 0.0;
			  for(k=1;k<=sgct2;k++)
			    {
			      mean1+=imvec2[k]*gaussvec2[k];
			      norm+=gaussvec2[k];
			    }
			  mean1/=norm;
			  image2[i][j] = mean1;
			}
		      else
			{
			  /*sgct2 is not greater than 1*/
			  /*however, sgct must be greater than 1*/
			  /*or we wouldn't be here.  Thus:*/
			  norm = mean1 = 0.0;
			  for(k=1;k<=sgct;k++)
			    {
			      mean1+=imvec[k]*gaussvec[k];
			      norm+=gaussvec[k];
			    }
			  mean1/=norm;
			  image2[i][j] = mean1;
			}
		    }
		  else
		    {
		      /*sgct is not greater than 1*/
		      /*However, sgct2 must be, or we wouldn't*/
		      /*be here.  Thus:*/
		      norm = mean1 = 0.0;
		      for(k=1;k<=sgct2;k++)
			{
			  mean1+=imvec2[k]*gaussvec2[k];
			  norm+=gaussvec2[k];
			}
		      mean1/=norm;
		      image2[i][j] = mean1;
		    }
		}
	      else
		{
		  /*sgct2 is not greater than 1, but sgct is*/
		  norm = mean1 = 0.0;
		  for(k=1;k<=sgct;k++)
		    {
		      mean1+=imvec[k]*gaussvec[k];
		      norm+=gaussvec[k];
		    }
		  mean1/=norm;
		  image2[i][j] = mean1;
		}
	    }
	  else
	    {
	      /*From the beginning sgct is not greater than 1*/
	      /*We conservatively set the mask image value to zero*/
	      image2[i][j] = 0.0;
	    }
	    }
	  else
	    {
	      image2[i][j] = 0.0;
	    }
	}
    }

	    
  free_vector(imvec,1,veclen);
  free_vector(gaussvec,1,veclen);
  free_vector(imvec2,1,veclen);
  free_vector(gaussvec2,1,veclen);

  return(1);
}

/*mmask04uc: like mmask04 but can be set specifically
to not consider numbers above and below specified
thresholds as valid data values..*/
int mmask04uc(float **image1,float **image2,int nx,int ny,float sigma,float sigclip,float lothresh,float hithresh)
{
  float *imvec,*gaussvec,norm,radlim,rad;
  int i,j,k,l,bhw,veclen,sgct,sgct2;
  float *imvec2,*gaussvec2,mean1,rms1;

  radlim = pow(-log(KERNLOW)*2,0.5)*sigma;
  bhw = radlim+5;

  veclen = (2*bhw+1)*(2*bhw+1);

  imvec = vector(1,veclen);
  gaussvec = vector(1,veclen);
  imvec2 = vector(1,veclen);
  gaussvec2 = vector(1,veclen);

  for(i=1;i<=nx;i++)
    {
      printf("mmask04 processing column %d\n",i);
      for(j=1;j<=ny;j++)
	{
	  if(image1[i][j]>=lothresh&&image1[i][j]<=hithresh)
	    {
	  sgct = 0;
	  for(k=i-bhw;k<=i+bhw;k++)
	    {
	      for(l=j-bhw;l<=j+bhw;l++)
		{
		  if(k>=1&&k<=nx&&l>=1&&l<=ny)
		    {
		      rad = pow(pow(1.0*k-1.0*i,2.0)+pow(1.0*l-1.0*j,2.0),0.5);
		      if(rad<=radlim&&image1[k][l]>=lothresh&&image1[k][l]<=hithresh)
			{
			  sgct+=1;
			  imvec[sgct] = image1[k][l];
			  gaussvec[sgct] = exp(-0.5*pow(rad/sigma,2.0));
			}
		    }
		}
	    }
	  if(sgct>1)
	    {
	      meanrms01(imvec,sgct,&mean1,&rms1);
	      sgct2 = 0;
	      for(k=1;k<=sgct;k++)
		{
		  if(fabs(imvec[k]-mean1)<sigclip*rms1)
		    {
		      sgct2+=1;
		      imvec2[sgct2] = imvec[k];
		      gaussvec2[sgct2] = gaussvec[k];
		    }
		}
	      if(sgct2>1)
		{
		  meanrms01(imvec2,sgct2,&mean1,&rms1);
		  sgct = 0;
		  for(k=1;k<=sgct2;k++)
		    {
		      if(fabs(imvec2[k]-mean1)<sigclip*rms1)
			{
			  sgct+=1;
			  imvec[sgct] = imvec2[k];
			  gaussvec[sgct] = gaussvec2[k];
			}
		    }
		  if(sgct>1)
		    {
		      meanrms01(imvec,sgct,&mean1,&rms1);
		      sgct2 = 0;
		      for(k=1;k<=sgct;k++)
			{
			  if(fabs(imvec[k]-mean1)<sigclip*rms1)
			    {
			      sgct2+=1;
			      imvec2[sgct2] = imvec[k];
			      gaussvec2[sgct2] = gaussvec[k];
			    }
			}
		      if(sgct2>1)
			{
			  norm = mean1 = 0.0;
			  for(k=1;k<=sgct2;k++)
			    {
			      mean1+=imvec2[k]*gaussvec2[k];
			      norm+=gaussvec2[k];
			    }
			  mean1/=norm;
			  image2[i][j] = mean1;
			}
		      else
			{
			  /*sgct2 is not greater than 1*/
			  /*however, sgct must be greater than 1*/
			  /*or we wouldn't be here.  Thus:*/
			  norm = mean1 = 0.0;
			  for(k=1;k<=sgct;k++)
			    {
			      mean1+=imvec[k]*gaussvec[k];
			      norm+=gaussvec[k];
			    }
			  mean1/=norm;
			  image2[i][j] = mean1;
			}
		    }
		  else
		    {
		      /*sgct is not greater than 1*/
		      /*However, sgct2 must be, or we wouldn't*/
		      /*be here.  Thus:*/
		      norm = mean1 = 0.0;
		      for(k=1;k<=sgct2;k++)
			{
			  mean1+=imvec2[k]*gaussvec2[k];
			  norm+=gaussvec2[k];
			}
		      mean1/=norm;
		      image2[i][j] = mean1;
		    }
		}
	      else
		{
		  /*sgct2 is not greater than 1, but sgct is*/
		  norm = mean1 = 0.0;
		  for(k=1;k<=sgct;k++)
		    {
		      mean1+=imvec[k]*gaussvec[k];
		      norm+=gaussvec[k];
		    }
		  mean1/=norm;
		  image2[i][j] = mean1;
		}
	    }
	  else
	    {
	      /*From the beginning sgct is not greater than 1*/
	      /*We set the mask image value to the value in the original image*/
	      image2[i][j] = image1[i][j];
	    }
	    }
	  else
	    {
	      image2[i][j] = image1[i][j];
	    }
	}
    }

	    
  free_vector(imvec,1,veclen);
  free_vector(gaussvec,1,veclen);
  free_vector(imvec2,1,veclen);
  free_vector(gaussvec2,1,veclen);

  return(1);
}


/*mmask05: given an image, makes an unsharp mask of it
  using a radial gaussian kernal of specified size in
  a box of specified half-size.  It differes from mmask02
  in that it performs creeping mean rejection on the
  image pixels in the box before convolving with the kernal.  
  It also differs in that
  it actually doesn't take an input box, but defines its
  own box such that the sided are 5 pixels beyond the radius
  at which the gaussian kernal drops to KERNLOW = 0.01 of
  its central value.  mmask05 considers zero a valid data
  value.*/
int mmask05(float **image1,float **image2,int nx,int ny,float sigma,float rlev)
{
  float *imvec,*gaussvec,norm,radlim,rad;
  int i,j,k,l,bhw,veclen,sgct,sgct2;
  float *imvec2,*gaussvec2,mean1,mean2,errn,emax;
  int nrej,rejnum,wp;

  radlim = pow(-log(KERNLOW)*2,0.5)*sigma;
  bhw = radlim+5;

  veclen = (2*bhw+1)*(2*bhw+1);

  imvec = vector(1,veclen);
  gaussvec = vector(1,veclen);

  if(rlev<0.0)
    {
      printf("Bad rejection level in mmask05.  ABORTING\n");
      return(0);
    }
  if(rlev>0.5)
    {
      printf("Rejection level in mmask05 set to 0.5.  Was %f, which is not allowed\n",rlev);
      rlev = 0.5;
    }

  for(i=1;i<=nx;i++)
    {
      printf("mmask05 processing column %d\n",i);
      for(j=1;j<=ny;j++)
	{
	  sgct = 0;
	  for(k=i-bhw;k<=i+bhw;k++)
	    {
	      for(l=j-bhw;l<=j+bhw;l++)
		{
		  if(k>=1&&k<=nx&&l>=1&&l<=ny)
		    {
		      rad = pow(pow(1.0*k-1.0*i,2.0)+pow(1.0*l-1.0*j,2.0),0.5);
		      if(rad<=radlim)
			{
			  sgct+=1;
			  imvec[sgct] = image1[k][l];
			  gaussvec[sgct] = exp(-0.5*pow(rad/sigma,2.0));
			}
		    }
		}
	    }
	  if(sgct>1)
	    {
	      rejnum = 1.0*rlev*(1.0*sgct);
	      for(nrej=0;nrej<rejnum;nrej++)
		{
		  /*Get current mean*/
		  mean1 = norm = 0.0;
		  for(k=1;k<=sgct-nrej;k++)
		    {
		      norm += 1.0;
		      mean1+=imvec[k];
		    }
		  mean1/=norm;

		  /*identify the worst point*/
		  emax = fabs(mean1-imvec[1]);
		  wp = 1;
		  for(k=2;k<=sgct-nrej;k++)
		    {
		      errn = fabs(mean1-imvec[k]);
		      if(errn > emax)
			{
			  emax = errn;
			  wp = k;
			}
		    }
		  /*overwrite the worst point with the good point
                    that is about to be rejected.*/
		  imvec[wp] = imvec[sgct-nrej];
		  gaussvec[wp] = gaussvec[sgct-nrej];
		}
	      mean1 = norm = 0.0;
	      for(k=1;k<=sgct-rejnum;k++)
		{
		  mean1+=imvec[k]*gaussvec[k];
		  norm+=gaussvec[k];
		}
	      image2[i][j] = mean1/norm;
	    }
	  else
	    {
	      /*We conservatively set the mask image value to zero*/
	      image2[i][j] = 0.0;
	    }
	}
    }

  return(1);
}


/*mmask06: like mmask05 but does not consider zero a valid data value*/
int mmask06(float **image1,float **image2,int nx,int ny,float sigma,float rlev)
{
  float *imvec,*gaussvec,norm,radlim,rad;
  int i,j,k,l,bhw,veclen,sgct,sgct2;
  float *imvec2,*gaussvec2,mean1,mean2,errn,emax;
  int nrej,rejnum,wp;

  radlim = pow(-log(KERNLOW)*2,0.5)*sigma;
  bhw = radlim+5;

  veclen = (2*bhw+1)*(2*bhw+1);

  imvec = vector(1,veclen);
  gaussvec = vector(1,veclen);

  if(rlev<0.0)
    {
      printf("Bad rejection level in mmask06.  ABORTING\n");
      return(0);
    }
  if(rlev>0.5)
    {
      printf("Rejection level in mmask06 set to 0.5.  Was %f, which is not allowed\n",rlev);
      rlev = 0.5;
    }

  for(i=1;i<=nx;i++)
    {
      printf("mmask06 processing column %d\n",i);
      for(j=1;j<=ny;j++)
	{
	  if(image1[i][j]!=0.0)
	    {
	  sgct = 0;
	  for(k=i-bhw;k<=i+bhw;k++)
	    {
	      for(l=j-bhw;l<=j+bhw;l++)
		{
		  if(k>=1&&k<=nx&&l>=1&&l<=ny)
		    {
		      rad = pow(pow(1.0*k-1.0*i,2.0)+pow(1.0*l-1.0*j,2.0),0.5);
		      if(rad<=radlim&&image1[k][l]!=0.0)
			{
			  sgct+=1;
			  imvec[sgct] = image1[k][l];
			  gaussvec[sgct] = exp(-0.5*pow(rad/sigma,2.0));
			}
		    }
		}
	    }
	  if(sgct>1)
	    {
	      rejnum = 1.0*rlev*(1.0*sgct);
	      for(nrej=0;nrej<rejnum;nrej++)
		{
		  /*Get current mean*/
		  mean1 = norm = 0.0;
		  for(k=1;k<=sgct-nrej;k++)
		    {
		      norm += 1.0;
		      mean1+=imvec[k];
		    }
		  mean1/=norm;

		  /*identify the worst point*/
		  emax = fabs(mean1-imvec[1]);
		  wp = 1;
		  for(k=2;k<=sgct-nrej;k++)
		    {
		      errn = fabs(mean1-imvec[k]);
		      if(errn > emax)
			{
			  emax = errn;
			  wp = k;
			}
		    }
		  /*overwrite the worst point with the good point
                    that is about to be rejected.*/
		  imvec[wp] = imvec[sgct-nrej];
		  gaussvec[wp] = gaussvec[sgct-nrej];
		}
	      mean1 = norm = 0.0;
	      for(k=1;k<=sgct-rejnum;k++)
		{
		  mean1+=imvec[k]*gaussvec[k];
		  norm+=gaussvec[k];
		}
	      image2[i][j] = mean1/norm;
	    }
	  else
	    {
	      /*We conservatively set the mask image value to zero*/
	      image2[i][j] = 0.0;
	    }
	    }
	  else
	    {
	      image2[i][j] = 0.0;
	    }
	}
    }

  return(1);
}




/*afp01: For each pixel, finds the mean and rms in a 5x5 square
centered on that pixel, neglecting the pixel itself.  Also finds 
the mean in a 3x3 square centered on the pixel, neglecting the
pixel itself.  If the pixel differs from the 3x3 mean by more
than sigclip times the 5x5 rms, the pixel is replaced with the
3x3 mean.  The number of pixels fixed is returned in numfix.
This is a crude, transparent method.  There may be a faster
way, but it isn't more than 2x faster and I'm not going to
code it right now.*/
int afp01(float **image,int nx,int ny,float sigclip,int *numfix)
{
  int i,j,k,l;
  float mean3,mean5,rms,norm3,norm5;

  *numfix = 0;

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  mean3 = norm3 = 0.0;
	  for(k=i-1;k<=i+1;k++)
	    {
	      for(l=j-1;l<=j+1;l++)
		{
		  if(k>=1&&k<=nx&&l>=1&&l<=nx)
		    {
		      if(k==i&&l==j)
			{
			  ;
			}
		      else{
			mean3+=image[k][l];
			norm3+=1.0;
		      }
		    }
		}
	    }
	  mean3/=norm3;
	  mean5 = norm5 = 0.0;
	  for(k=i-2;k<=i+2;k++)
	    {
	      for(l=j-2;l<=j+2;l++)
		{
		  if(k>=1&&k<=nx&&l>=1&&l<=nx)
		    {
		      if(k==i&&l==j)
			{
			  ;
			}
		      else{
			mean5+=image[k][l];
			norm5+=1.0;
		      }
		    }
		}
	    }
	  mean5/=norm5;
	  rms = 0.0;
	  for(k=i-2;k<=i+2;k++)
	    {
	      for(l=j-2;l<=j+2;l++)
		{
		  if(k>=1&&k<=nx&&l>=1&&l<=nx)
		    {
		      if(k==i&&l==j)
			{
			  ;
			}
		      else{
			rms+=pow(image[k][l]-mean5,2.0);
		      }
		    }
		}
	    }
	  rms = pow(rms/(norm5-1.0),0.5);
	  if(pow(pow(image[i][j]-mean3,2.0),0.5)>sigclip*rms)
	    {
	      image[i][j] = mean3;
	      *numfix+=1;
	    }
	}
    }

  return(1);
}

/*afp02: Exactly like afp01 except that the identification of
bad pixels is performed on an image that has been unsharp masked
using mmask01.*/
int afp02(float **image,int nx,int ny,float sigclip,int *numfix,int bsize)
{
  int i,j,k,l;
  float mean3,mean5,meanr,rms,norm3,norm5;
  float **image2;
  image2 = matrix(1,nx,1,ny);

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image2[i][j] = image[i][j];
	}
    }

  unsharp01(image2,nx,ny,bsize);

  *numfix = 0;

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  meanr = mean3 = norm3 = 0.0;
	  for(k=i-1;k<=i+1;k++)
	    {
	      for(l=j-1;l<=j+1;l++)
		{
		  if(k>=1&&k<=nx&&l>=1&&l<=nx)
		    {
		      if(k==i&&l==j)
			{
			  ;
			}
		      else{
			mean3+=image2[k][l];
			meanr+=image[k][l];
			norm3+=1.0;
		      }
		    }
		}
	    }
	  mean3/=norm3;
	  meanr/=norm3;
	  mean5 = norm5 = 0.0;
	  for(k=i-2;k<=i+2;k++)
	    {
	      for(l=j-2;l<=j+2;l++)
		{
		  if(k>=1&&k<=nx&&l>=1&&l<=nx)
		    {
		      if(k==i&&l==j)
			{
			  ;
			}
		      else{
			mean5+=image2[k][l];
			norm5+=1.0;
		      }
		    }
		}
	    }
	  mean5/=norm5;
	  rms = 0.0;
	  for(k=i-2;k<=i+2;k++)
	    {
	      for(l=j-2;l<=j+2;l++)
		{
		  if(k>=1&&k<=nx&&l>=1&&l<=nx)
		    {
		      if(k==i&&l==j)
			{
			  ;
			}
		      else{
			rms+=pow(image2[k][l]-mean5,2.0);
		      }
		    }
		}
	    }
	  rms = pow(rms/(norm5-1.0),0.5);
	  if(pow(pow(image2[i][j]-mean3,2.0),0.5)>sigclip*rms)
	    {
	      image[i][j] = meanr;
	      *numfix+=1;
	    }
	}
    }
  free_matrix(image2,1,nx,1,ny);
  return(1);
}


/*ifixpix01: A program, in imitation of the IRAF fixpix task
to remove specified bad pixel regions in an image.  It reads
a file, bpfile, of five columns, the xl, xh,yl, yh specification
of the bad pixel region, and the direction of interpolation:
1 = interpolation in x, 2 = interpolation in y.*/
int ifixpix01(float **image,int nx,int ny,char *bpfile)
{
  int i,j,k,**bp,nlines,c;
  FILE *fp1;
  nlines = 0;
  fp1 = fopen(bpfile,"r");
  c = 0;
  while(c!=EOF)
    {
      c = getc(fp1);
      if(c=='\n')
	{
	  nlines+=1;
	}
    }
  fclose(fp1);
  bp = imatrix(1,nlines,1,5);
  fp1 = fopen(bpfile,"r");
  for(i=1;i<=nlines;i++)
    {
      for(j=1;j<=5;j++)
	{
	  fscanf(fp1,"%d",bp[i]+j);
	}
    }
  fclose(fp1);
  for(k=1;k<=nlines;k++)
    {
      if(bp[k][2]<bp[k][1]||bp[k][4]<bp[k][3]||bp[k][5]<1||bp[k][5]>2)
	{
	  printf("ERROR: BAD ENTRY IN BAD PIXEL FILE!\n");
	  printf("line %d: %d %d %d %d %d\n",k,bp[k][1],bp[k][2],bp[k][3],bp[k][4],bp[k][5]);
	  printf("ifixpix01 ABORTING\n");
	  return(0);
	}
      if(bp[k][5]==1)
	{
	  if(bp[k][1]<=1&&bp[k][2]<nx)
	    {
	      for(i=bp[k][1];i<=bp[k][2];i++)
		{
		  for(j=bp[k][3];j<=bp[k][4];j++)
		    {
		      if(j>=1&&j<=ny&&i>=1&&i<=nx)
			{
			  image[i][j] = image[bp[k][2]+1][j];
			}
		    }
		}
	    }
	  else if(bp[k][1]<=1&&bp[k][2]>=nx)
	    {
	      printf("WARNING: ifixpix01 CALLED WITH OUT-OF-IMAGE INTERPOLATION\n");
	      printf("REGION %d PIXEL VALUES BEING SET TO %f\n",k,IFPERRVAL);
	      for(i=bp[k][1];i<=bp[k][2];i++)
		{
		  for(j=bp[k][3];j<=bp[k][4];j++)
		    {
		      if(j>=1&&j<=ny&&i>=1&&i<=nx)
			{
			  image[i][j] = IFPERRVAL;
			}
		    }
		}
	    }
	  else if(bp[k][1]>1&&bp[k][2]>=nx)
	    {
	      for(i=bp[k][1];i<=bp[k][2];i++)
		{
		  for(j=bp[k][3];j<=bp[k][4];j++)
		    {
		      if(j>=1&&j<=ny&&i>=1&&i<=nx)
			{
			  image[i][j] = image[bp[k][1]-1][j];
			}
		    }
		}
	    }
	  else if(bp[k][1]>1&&bp[k][2]<nx)
	    {
	      for(i=bp[k][1];i<=bp[k][2];i++)
		{
		  for(j=bp[k][3];j<=bp[k][4];j++)
		    {
		      if(j>=1&&j<=ny&&i>=1&&i<=nx)
			{
			  image[i][j] = image[bp[k][1]-1][j]+(image[bp[k][2]+1][j]-image[bp[k][1]-1][j])*(1.0*i-(1.0*bp[k][1]-1.0))/(1.0*bp[k][2] - 1.0*bp[k][1]+2.0);
			}
		    }
		}
	    }
	  else{
	    printf("ERROR: ifixpix01 FINDS IMPOSSIBLE X INTERPOLATION CASE\n");
	    printf("ABORTING!\n");
	    return(0);
	  }
	}
      if(bp[k][5]==2)
	{
	  if(bp[k][3]<=1&&bp[k][4]<ny)
	    {
	      for(i=bp[k][1];i<=bp[k][2];i++)
		{
		  for(j=bp[k][3];j<=bp[k][4];j++)
		    {
		      if(j>=1&&j<=ny&&i>=1&&i<=nx)
			{
			  image[i][j] = image[i][bp[k][4]+1];
			}
		    }
		}
	    }
	  else if(bp[k][3]<=1&&bp[k][4]>=ny)
	    {
	      printf("WARNING: ifixpix01 CALLED WITH OUT-OF-IMAGE INTERPOLATION\n");
	      printf("REGION %d PIXEL VALUES BEING SET TO %f\n",k,IFPERRVAL);
	      for(i=bp[k][1];i<=bp[k][2];i++)
		{
		  for(j=bp[k][3];j<=bp[k][4];j++)
		    {
		      if(j>=1&&j<=ny&&i>=1&&i<=nx)
			{
			  image[i][j] = IFPERRVAL;
			}
		    }
		}
	    }
	  else if(bp[k][3]>1&&bp[k][4]>=ny)
	    {
	      for(i=bp[k][1];i<=bp[k][2];i++)
		{
		  for(j=bp[k][3];j<=bp[k][4];j++)
		    {
		      if(j>=1&&j<=ny&&i>=1&&i<=nx)
			{
			  image[i][j] = image[i][bp[k][3]-1];
			}
		    }
		}
	    }
	  else if(bp[k][3]>1&&bp[k][4]<ny)
	    {
	      for(i=bp[k][1];i<=bp[k][2];i++)
		{
		  for(j=bp[k][3];j<=bp[k][4];j++)
		    {
		      if(j>=1&&j<=ny&&i>=1&&i<=nx)
			{
			  image[i][j] = image[i][bp[k][3]-1]+(image[i][bp[k][4]+1]-image[i][bp[k][3]-1])*(1.0*j-(1.0*bp[k][3]-1.0))/(1.0*bp[k][4] - 1.0*bp[k][3]+2.0);
			}
		    }
		}
	    }
	  else{
	    printf("ERROR: ifixpix01 FINDS IMPOSSIBLE Y INTERPOLATION CASE\n");
	    printf("ABORTING!\n");
	    return(0);
	  }
	}
      /*Interp appears correct & complete*/
    }

  free_imatrix(bp,1,nlines,1,5);
  return(1);
}


/*ifixpix02: Exactly like ifixpix01 except that it mirror
images the bad pixel file left-to-right if mirrorpar is
1 and top to bottom if mirrorpar is 2.  For all other
values of mirrorpar it operates exactly as ifixpix01.*/
int ifixpix02(float **image,int nx,int ny,char *bpfile,int mirrorpar)
{
  int i,j,k,**bp,nlines,c,bphold;
  FILE *fp1;
  nlines = 0;
  fp1 = fopen(bpfile,"r");
  c = 0;
  while(c!=EOF)
    {
      c = getc(fp1);
      if(c=='\n')
	{
	  nlines+=1;
	}
    }
  fclose(fp1);
  bp = imatrix(1,nlines,1,5);
  fp1 = fopen(bpfile,"r");
  for(i=1;i<=nlines;i++)
    {
      for(j=1;j<=5;j++)
	{
	  fscanf(fp1,"%d",bp[i]+j);
	}
    }
  fclose(fp1);

  if(mirrorpar==1)
    {
      for(i=1;i<=nlines;i++)
	{
	  bphold = nx+1-bp[i][2];
	  bp[i][2] = nx+1-bp[i][1];
	  bp[i][1] = bphold;
	}
    }
  else if(mirrorpar==2)
    {
      for(i=1;i<=nlines;i++)
	{
	  bphold = ny+1-bp[i][4];
	  bp[i][4] = ny+1-bp[i][3];
	  bp[i][3] = bphold;
	}
    }

  for(k=1;k<=nlines;k++)
    {
      if(bp[k][2]<bp[k][1]||bp[k][4]<bp[k][3]||bp[k][5]<1||bp[k][5]>2)
	{
	  printf("ERROR: BAD ENTRY IN BAD PIXEL FILE!\n");
	  printf("line %d: %d %d %d %d %d\n",k,bp[k][1],bp[k][2],bp[k][3],bp[k][4],bp[k][5]);
	  printf("ifixpix01 ABORTING\n");
	  return(0);
	}
      if(bp[k][5]==1)
	{
	  if(bp[k][1]<=1&&bp[k][2]<nx)
	    {
	      for(i=bp[k][1];i<=bp[k][2];i++)
		{
		  for(j=bp[k][3];j<=bp[k][4];j++)
		    {
		      if(j>=1&&j<=ny&&i>=1&&i<=nx)
			{
			  image[i][j] = image[bp[k][2]+1][j];
			}
		    }
		}
	    }
	  else if(bp[k][1]<=1&&bp[k][2]>=nx)
	    {
	      printf("WARNING: ifixpix01 CALLED WITH OUT-OF-IMAGE INTERPOLATION\n");
	      printf("REGION %d PIXEL VALUES BEING SET TO %f\n",k,IFPERRVAL);
	      for(i=bp[k][1];i<=bp[k][2];i++)
		{
		  for(j=bp[k][3];j<=bp[k][4];j++)
		    {
		      if(j>=1&&j<=ny&&i>=1&&i<=nx)
			{
			  image[i][j] = IFPERRVAL;
			}
		    }
		}
	    }
	  else if(bp[k][1]>1&&bp[k][2]>=nx)
	    {
	      for(i=bp[k][1];i<=bp[k][2];i++)
		{
		  for(j=bp[k][3];j<=bp[k][4];j++)
		    {
		      if(j>=1&&j<=ny&&i>=1&&i<=nx)
			{
			  image[i][j] = image[bp[k][1]-1][j];
			}
		    }
		}
	    }
	  else if(bp[k][1]>1&&bp[k][2]<nx)
	    {
	      for(i=bp[k][1];i<=bp[k][2];i++)
		{
		  for(j=bp[k][3];j<=bp[k][4];j++)
		    {
		      if(j>=1&&j<=ny&&i>=1&&i<=nx)
			{
			  image[i][j] = image[bp[k][1]-1][j]+(image[bp[k][2]+1][j]-image[bp[k][1]-1][j])*(1.0*i-(1.0*bp[k][1]-1.0))/(1.0*bp[k][2] - 1.0*bp[k][1]+2.0);
			}
		    }
		}
	    }
	  else{
	    printf("ERROR: ifixpix01 FINDS IMPOSSIBLE X INTERPOLATION CASE\n");
	    printf("ABORTING!\n");
	    return(0);
	  }
	}
      if(bp[k][5]==2)
	{
	  if(bp[k][3]<=1&&bp[k][4]<ny)
	    {
	      for(i=bp[k][1];i<=bp[k][2];i++)
		{
		  for(j=bp[k][3];j<=bp[k][4];j++)
		    {
		      if(j>=1&&j<=ny&&i>=1&&i<=nx)
			{
			  image[i][j] = image[i][bp[k][4]+1];
			}
		    }
		}
	    }
	  else if(bp[k][3]<=1&&bp[k][4]>=ny)
	    {
	      printf("WARNING: ifixpix01 CALLED WITH OUT-OF-IMAGE INTERPOLATION\n");
	      printf("REGION %d PIXEL VALUES BEING SET TO %f\n",k,IFPERRVAL);
	      for(i=bp[k][1];i<=bp[k][2];i++)
		{
		  for(j=bp[k][3];j<=bp[k][4];j++)
		    {
		      if(j>=1&&j<=ny&&i>=1&&i<=nx)
			{
			  image[i][j] = IFPERRVAL;
			}
		    }
		}
	    }
	  else if(bp[k][3]>1&&bp[k][4]>=ny)
	    {
	      for(i=bp[k][1];i<=bp[k][2];i++)
		{
		  for(j=bp[k][3];j<=bp[k][4];j++)
		    {
		      if(j>=1&&j<=ny&&i>=1&&i<=nx)
			{
			  image[i][j] = image[i][bp[k][3]-1];
			}
		    }
		}
	    }
	  else if(bp[k][3]>1&&bp[k][4]<ny)
	    {
	      for(i=bp[k][1];i<=bp[k][2];i++)
		{
		  for(j=bp[k][3];j<=bp[k][4];j++)
		    {
		      if(j>=1&&j<=ny&&i>=1&&i<=nx)
			{
			  image[i][j] = image[i][bp[k][3]-1]+(image[i][bp[k][4]+1]-image[i][bp[k][3]-1])*(1.0*j-(1.0*bp[k][3]-1.0))/(1.0*bp[k][4] - 1.0*bp[k][3]+2.0);
			}
		    }
		}
	    }
	  else{
	    printf("ERROR: ifixpix01 FINDS IMPOSSIBLE Y INTERPOLATION CASE\n");
	    printf("ABORTING!\n");
	    return(0);
	  }
	}
      /*Interp appears correct & complete*/
    }

  free_imatrix(bp,1,nlines,1,5);
  return(1);
}



/*unsharp01.  Uses mmask01 to perform a crude
unsharp masking of an image using a block
of specified input size.*/
int unsharp01(float **image1,int nx,int ny,int bsize)
{
  float **image2;
  int i,j;
  image2 = matrix(1,nx,1,ny);
  mmask01(image1,image2,nx,ny,bsize);
  mathimtim02(image1,image1,nx,ny,image2);
  free_matrix(image2,1,nx,1,ny);
}

/*unsharp02.  Uses mmask02 to perform clean
unsharp masking of an image using a gaussian
of given sigma in a box of given input size.
Much slower than unsharp01, but also much
better for precision analysis or unsharp
masking of final science images..*/
int unsharp02(float **image1,int nx,int ny,int bsize,float sigma)
{
  float **image2;
  int i,j;
  image2 = matrix(1,nx,1,ny);
  mmask02(image1,image2,nx,ny,bsize,sigma);
  mathimtim02(image1,image1,nx,ny,image2);
  free_matrix(image2,1,nx,1,ny);
}


/*unsharp03.  Uses mmask02,03,04,05,or 06
depending on the input value mchoose being
2,3,4,5,or 6.  Aborts if it's some other
number.  In the case of mmask02, sets box
size to be the point were the gaussian
drops to KERNLOW = 0.01.  The parameter
trimpar is sigclip if mmask03 or 04 is
being used, and rlev if mmask05 or 06
is being used*/
int unsharp03(float **image1,int nx,int ny,float sigma,float trimpar,int mchoose)
{
  int bsize;
  float fbsize,**image2;
  image2 = matrix(1,nx,1,ny);

  if(mchoose<2||mchoose>6)
    {
      printf("ERROR: Bad mask type choice value.  unsharp03 ABORTING\n");
      return(0);
    }
  else if(mchoose==2)
    {
      fbsize = pow(-log(KERNLOW)*2.0,0.5)*sigma;
      bsize = fbsize+0.5;
      mmask02(image1,image2,nx,ny,bsize,sigma);
      mathimtim02(image1,image1,nx,ny,image2);
    }
  else if(mchoose==3)
    {
      mmask03(image1,image2,nx,ny,sigma,trimpar);
      mathimtim02(image1,image1,nx,ny,image2);
    }
  else if(mchoose==4)
    {
      mmask04(image1,image2,nx,ny,sigma,trimpar);
      mathimtim02(image1,image1,nx,ny,image2);
    }
  else if(mchoose==5)
    {
      mmask05(image1,image2,nx,ny,sigma,trimpar);
      mathimtim02(image1,image1,nx,ny,image2);
    }
  else if(mchoose==6)
    {
      mmask06(image1,image2,nx,ny,sigma,trimpar);
      mathimtim02(image1,image1,nx,ny,image2);
    }

  free_matrix(image2,1,nx,1,ny);
  return(1);

}

/*bottomsub01.  Subtracts from every pixel
in a column the average of the bottom two
pixels in that column.*/
int bottomsub01(float **image,int nx,int ny)
{
  float avg;
  int i,j;
  for(i=1;i<=nx;i++)
    {
      avg = (image[i][1]+image[i][2])/2.0;
      for(j=1;j<=ny;j++)
	{
	  image[i][j]-=avg;
	}
    }
  return(1);
}


/*Celestial to horizontal*/
int ctoh01(float ha,float dec,float lat,float *alt,float *az)
{
  float colat;
  float x,y,z;
  float xp,yp,zp;

  colat = PI/2.0 - lat;

  z = sin(dec);
  x = sin(-ha)*cos(dec);
  y = -cos(ha)*cos(dec);

  zp = z*cos(colat) - y*sin(colat);
  yp = y*cos(colat) + z*sin(colat);
  xp = x;

  *alt = asin(zp);
  if(x==0.0)
    {
      if(yp>=0.0)
	{
	  *az = 0.0;
	}
      else{
	*az = PI;
      }
    }
  else if(xp > 0.0)
    {
      *az = PI/2.0 - atan(yp/xp);
    }
  else{
    *az = 3.0*PI/2.0 - atan(yp/xp);
  }
  return(1);
}


/*Horizontal to celestial*/
int htoc01(float alt,float az,float lat,float *ha,float *dec,float *pa)
{
  float colat;
  float x,y,z;
  float xp,yp,zp;
  float dxp,dyp,dzp,dx,dy,dz,du,hatheta;
  float ddec,dha;

  colat = PI/2.0 - lat;
  z = sin(alt);
  x = sin(az)*cos(alt);
  y = cos(az)*cos(alt);

  zp = z*cos(colat) + y*sin(colat);
  yp = y*cos(colat) - z*sin(colat);
  xp = x;

  *dec = asin(zp);

  if(xp == 0.0)
    {
      if(yp<=0.0)
	{
	  *ha = 0.0;
	}
      else{
	*ha = PI;
      }
    }
  else if(xp > 0.0)
    {
      *ha = -PI/2.0 - atan(yp/xp);
    }
  else{
    *ha = PI/2.0 - atan(yp/xp);
  }

  hatheta = atan(yp/xp);

  ddec = (1.0/cos(*dec))*(cos(alt)*cos(colat)-cos(az)*sin(alt)*sin(colat));

  dx = -sin(az)*sin(alt);
  dy = -cos(az)*sin(alt);
  dz = cos(alt);
  dxp = dx;
  dyp = dy*cos(colat)-dz*sin(colat);

  du = (xp*dyp-yp*dxp)/pow(xp,2.0);

  dha = -pow(cos(hatheta),2.0)*du;

  dha*=cos(*dec);

  printf("%f\t%f\t%f\n",ddec,dha,ddec*ddec+dha*dha);

  if(dha==0.0)
    {
      if(ddec>=0.0)
	{
	  *pa = 0.0;
	}
      else{
	*pa = PI;
      }
    }
  else if(dha < 0.0)
    {
      *pa = PI/2.0 + atan(ddec/dha);
    }
  else{
    *pa = 3.0*PI/2.0 + atan(ddec/dha);
  }
  return(1);
}

/*precess01: Given J2000.0 RA and DEC in radians, and the 
integer number of days it has been since 00:00 UT on 
Jan 1, 2000.  If precesscon is 1, precesses RA and DEC 
to the epoch of date using formulae from the 2007 
Astronomical Almanac, and outputs these values in radians.
If precesscon is -1, deprecesses the input ra and dec
from the epoch of data to J2000.0.*/
int precess01(float dec1,float ra1,int ndays,float *dec2,float *ra2,int precesscon)
{
  double tds,zetaa,thetaa,zaa,ra3,dec3,ra4,dec4,cosra,sinra;

  /*time since standard epoch*/
  tds = (double)ndays/36525.0;

  /*cubic approximation to precession*/
  zetaa = ZET0 + ZET1*tds + ZET2*pow(tds,2.0) + ZET3*pow(tds,3.0) + ZET4*pow(tds,4.0) + ZET5*pow(tds,5.0);
  zaa = Z0 + Z1*tds + Z2*pow(tds,2.0) + Z3*pow(tds,3.0) + Z4*pow(tds,4.0) + Z5*pow(tds,5.0);
  thetaa = THET1*tds + THET2*pow(tds,2.0) + THET3*pow(tds,3.0) + THET4*pow(tds,4.0) + THET5*pow(tds,5.0);

  /*transformation from arcseconds to radians*/
  zetaa*=(PI/648000.0);
  zaa*=(PI/648000.0);
  thetaa*=(PI/648000.0);

  /*Make double-precision variable for old dec and ra*/
  ra3 = ra1;
  dec3 = dec1;

  /*if declination was obviously meant to be the pole, but
    it has gotten a little off by roundoff error, collapse
    it to the pole.*/
  if(fabs(dec1-PI/2.0)<SMALLANG)
    {
      dec3 = PI/2.0;
    }

  if(precesscon>=0)
    {
      /*Precess given J2000.0 coords to epoch of date*/

      /*get new declination*/
      if(dec3!=PI/2.0)
	{
	  printf("precess01 has normal declination case\n");
	  dec4 = asin(cos(ra3+zetaa)*sin(thetaa)*cos(dec3) + cos(thetaa)*sin(dec3));
	}
      else
	{
	  printf("precess01 has polar declination case\n");
	  dec4 = asin(cos(thetaa));
	}
      /*if declination was obviously meant to be the pole, but
        it has gotten a little off by roundoff error, collapse
        it to the pole.*/
      if(fabs(dec4-PI/2.0)<SMALLANG)
	{
	  dec4 = PI/2.0;
	}
      /*get new right ascension*/
      if(dec3!=PI/2.0&&dec4!=PI/2.0)
	{
	  printf("precess01 has normal right ascension case\n");
	  cosra = (cos(ra3+zetaa)*cos(thetaa)*cos(dec3) - sin(thetaa)*sin(dec3))/cos(dec4);
	  sinra = (sin(ra3+zetaa)*cos(dec3))/cos(dec4);
	  if(sinra>=0.0)
	    {
	      ra4 = acos(cosra)+zaa;
	    }
	  else{
	    ra4 = 2.0*PI - acos(cosra)+zaa;
	  }
	}
      else if(dec3==PI/2.0&&dec4!=PI/2.0)
	{	  
	  printf("precess01 has polar input right ascension case\n");
	  ra4 = PI + zaa;
	}
      else if(dec4==PI/2.0)
	{
	  printf("precess01 has polar output right ascension case\n");
	  ra4 = 0.0;
	}
      else
	{
	  printf("IMPOSSIBLE CASE ERROR IN precess01\n");
	}
    }
  else
    {
      /*Deprecess given epoch of date coords to J2000.0*/

      /*get new declination*/
      if(dec3!=PI/2.0)
	{
	  printf("precess01 has normal declination case\n");
	  dec4 = asin(-cos(ra3-zaa)*sin(thetaa)*cos(dec3) + cos(thetaa)*sin(dec3));
	  printf("ra3 = %f\tzaa = %f\tdec3 = %f\tPI/2.0-dec3 = %f\tthetaa = %f\n",ra3,zaa,dec3,PI/2.0-dec3,thetaa);
	}
      else
	{
	  printf("precess01 has polar declination case\n");
	  dec4 = asin(cos(thetaa));
	}
      /*if declination was obviously meant to be the pole, but
        it has gotten a little off by roundoff error, collapse
        it to the pole.*/
      if(fabs(dec4-PI/2.0)<SMALLANG)
	{
	  dec4 = PI/2.0;
	}
      /*get new right ascension*/
      if(dec3!=PI/2.0&&dec4!=PI/2.0)
	{
	  printf("precess01 has normal right ascension case\n");
	  cosra = (cos(ra3-zaa)*cos(thetaa)*cos(dec3) + sin(thetaa)*sin(dec3))/cos(dec4);
	  sinra = (sin(ra3-zaa)*cos(dec3))/cos(dec4);
	  if(sinra>=0.0)
	    {
	      ra4 = acos(cosra)-zetaa;
	    }
	  else{
	    ra4 = 2.0*PI - acos(cosra)-zetaa;
	  }
	}
      else if(dec3==PI/2.0&&dec4!=PI/2.0)
	{
	  printf("precess01 has polar input right ascension case\n");
	  ra4 = 2.0*PI-zetaa; /*Note this could be wrong*/
                              /*There might be two solutions*/   
	}
      else if(dec4==PI/2.0)
	{
	  printf("precess01 has polar output right ascension case\n");
	  ra4 = 0.0;
	}
      else
	{
	  printf("IMPOSSIBLE CASE ERROR IN precess01\n");
	}
    }
  *ra2 = ra4;
  *dec2 = dec4;
  return(1);
}

/*aapget01:  Given a vector to
hold the output quantities, the
lattitude and longitude of a site, the declination
and right ascension of an object, the Greenwhich mean
sidereal time at 00:00 UT on the date of the 
observations, the equation of the equinoxes at
00:00 UT on the day of the observations and on
the subsequent day, the
number of days between 00:00 UT Jan 1, 2000 and the
day of the observations.  Calculates the new
right ascension and declination for the object based
on the number of days since Jan 1 2000 and
the precession formulae given in the Astronomical
Almanac.  Calculates the local 
apparent sidereal time using the UT, longitude, GAST, 
and equation of the equinoxes.  Calculates the hour 
angle of the object at the time of the observations.
Calculates the altitude, azimuth, and postion angle
of the object at the time of the observations.
Outputs these quantities in the supplied vector.
Right ascension is expected in decimal hours; dec,
lat, and lon in decimal degrees, gast in decimal hours,
eq1 and eq2 in decimal seconds, and ndays in decimal days
(although ndays is always an integer).
The output is the LST in decimal hours, the HA in
decimal hours, and then ALT, AZ, and PA in decimal degrees*/
int aapget01(float *inquan,float *outquan)
{
  float ut,ra1,dec1,lat,lon,gmst,eq1,eq2,ndays;
  float ra2,dec2,ha,zetaa,zaa,thetaa,tds,cosra,sinra;
  float lst,alt,az,pa;

  ra1 = inquan[1];
  dec1 = inquan[2];
  lat = inquan[3];
  lon = inquan[4];
  gmst = inquan[5];
  eq1 = inquan[6];
  eq2 = inquan[7];
  ndays = inquan[8];
  ut = inquan[9];

  /*Find New Celestial Coordinates*/

  /*transform ra, dec to radians*/
  ra1*=(PI/12.0);
  dec1*=(PI/180.0);

  /*get new declination and right ascension*/
  precess01(dec1,ra1,ndays,&dec2,&ra2,1);
  printf("delta RA = %f arcsec\tdelta DEC = %f arcsec\n",(ra2-ra1)*648000.0/PI*cos(dec2),(dec2-dec1)*648000.0/PI);

  /*New celestial coordinates have now been found*/
  /*Find LST at Time of Observation*/
  /*correct for longitude*/
  printf("aapget01: GSMT = %f",gmst);
  lst = gmst + lon/15.0;
  printf("\t%f",lst);
  /*correct for UT*/
  lst+=ut*DAYRATE;
  printf("\t%f",lst);
  /*correct for equation of equinoxes*/
  lst+=(eq1+(eq2-eq1)*(ut/24.0))/3600.0;
  printf("\t%f\n",lst);
  /*correct for out-of-range values*/
  while(lst>=24.0)
    {
      lst-=24.0;
    }
  while(lst<0.0)
    {
      lst+=24.0;
    }
  printf("At the time of the observation the LST was %f\n",lst);
  /*LST at time of observation has been found*/

  outquan[1] = lst;
  /*Find Altitude, Azimuth, and Position Angle*/  
  /*get ha*/
  ha = lst*PI/12.0 - ra2;
  if(ha>PI)
    {
      ha = 2.0*PI-ha;
    }
  else if(ha<=-PI)
    {
      ha = 2.0*PI+ha;
    }
  /*translate lat to radians*/
  lat*=(PI/180.0);
  printf("HA = %f\tDEC = %f\t",ha*(12.0/PI),dec2*(180.0/PI));
  outquan[2] = ha*(12.0/PI);
  ctoh01(ha,dec2,lat,&alt,&az);
  printf("ALT = %f\tAZ = %f\n",alt*(180.0/PI),az*(180.0/PI));
  outquan[3] = alt*(180.0/PI);
  outquan[4] = az*(180.0/PI);
  htoc01(alt,az,lat,&ha,&dec1,&pa);
  printf("HA = %f\tDEC = %f\tPA = %f\n",ha*(12.0/PI),dec1*(180.0/PI),pa*(180.0/PI));
  outquan[5] = pa*(180.0/PI);
  return(1);
}

/*headread01: given the input of an IRAF header file, looks
for a keyword UT.  If UT is found, reads it expecting it to
have the form = ' WED JUN 22 04:48:14 2005.  Thus, after the
= ' sequence, it looks for two strings, an integer, and then
3 integers seperated by colons.  It transforms the three
integers into a decimal UT value and outputs this.  If
it doesn't find UT as a keyword, it prints an error
and returns a value of zero.*/
float headread01(char *imname)
{
  FILE *fp1;
  char strtest[80],day[80],month[80],hold[80];
  int c,lnum,i,mday,uth,utm,uts,utfound;
  float ut;

  strcpy(hold,"UT");
  /*printf("%s\n",hold);*/

  fp1 = fopen(imname,"r");
  lnum = 0;
  while(c!=EOF)
    {
      c = getc(fp1);
      if(c=='\n')
	{
	  lnum+=1;
	}
    }
  fclose(fp1);
  fp1 = fopen(imname,"r");
  utfound = 0.0;
  for(i=1;i<=lnum;i++)
    {
      c = 0;
      fscanf(fp1,"%s",strtest);
      /*printf("%s\n",strtest);*/
      if(strcmp(hold,strtest)==0)
	{
	  utfound = 1;
	  c = getc(fp1);
	  while(c!='=')
	    {
	      c = getc(fp1);
	    }
	  c = getc(fp1);
	  c = getc(fp1);
	  fscanf(fp1,"%s",day);
	  /*printf("%s\n",day);*/
	  fscanf(fp1,"%s",month);
	  /*printf("%s\n",month);*/
	  fscanf(fp1,"%d",&mday);
	  /*printf("%d\n",mday);*/
	  fscanf(fp1,"%d:%d:%d",&uth,&utm,&uts);
	  printf("UT is %d:%d:%d\n",uth,utm,uts);
	  ut = 1.0*uth+1.0*utm/60.0 + 1.0*uts/3600.0;
	  return(ut);
	}
      else{
	while(c!='\n')
	  {
	    c = getc(fp1);
	  }
      }
    }
  printf("ERROR: headread01 DOES NOT FIND UT KEYWORD IN HEADER FILE!\n");
  printf("ABORTING WITH UT SET TO ZERO\n");
  return(0.0);
}

/*headread02: given the input of a FITS file, looks
for a keyword UT.  If UT is found, reads it expecting it to
have the form = ' WED JUN 22 04:48:14 2005.  Thus, after the
= ' sequence, it looks for two strings, an integer, and then
3 integers seperated by colons.  It transforms the three
integers into a decimal UT value and outputs this.  If
it doesn't find UT as a keyword, it prints an error
and returns a value of zero.*/
float headread02(char* imname)
{
  fitsfile *fptr;
  int status,  nfound, anynull,ii,jj;
  long naxes[2];
  long npixels;
  long fpixel[2];
  float nullval,**image2;
  char utval[800];
  int nowpos,colpos,uth,utm,uts,utfound,c;
  float ut;

  printf("headread02 here OK\n");
  fflush(stdout);

  status = 0;

  /*Obtain FITS file pointer*/
  if(fits_open_file(&fptr,imname,READONLY, &status))
    {
       fits_report_error(stderr, status); /* print error report */
      printf("headread02 error on fits open\n");
      fflush(stdout);
       exit( status );    /* terminate the program, returning error status */
    }

  printf("Opened fits file in headread OK\n");
  fflush(stdout);
  if(fits_read_card(fptr,"UT",utval,&status))
    {
       fits_report_error(stderr, status); /* print error report */
      printf("headread02 error on fits read\n");
      fflush(stdout);
       exit( status );    /* terminate the program, returning error status */
    }

  /*find the first colon in the long string*/
  utfound = nowpos = 0;
  c = 'A';
  while(utfound == 0&&c!='\0')
    {
      c = utval[nowpos];
      if(c==':')
	{
	  utfound = 1;
	  colpos = nowpos;
	}
      nowpos+=1;
    }

  if(c!='\0')
    {
      uth = (utval[colpos-2]-'0')*10 + (utval[colpos-1]-'0');
      utm = (utval[colpos+1]-'0')*10 + (utval[colpos+2]-'0');
      uts = (utval[colpos+4]-'0')*10 + (utval[colpos+5]-'0');
      printf("headread02 finds UT = %d:%d:%d\n",uth,utm,uts);
      ut = 1.0*uth + 1.0*utm/60.0 +1.0*uts/3600.0;
      fits_close_file(fptr,&status);
      return(ut);
    }

  printf("ERROR: headread02 DOES NOT FIND UT KEYWORD IN HEADER FILE!\n");
  printf("ABORTING WITH UT SET TO ZERO\n");

  fits_close_file(fptr,&status);
  return(0.0);
}



/*centroid01: given an image matrix, an integer guess
at a stellar centroid, and three centroding box half-sizes,
performs three-iteration box centroiding and outputs the
x, y coordinates of the result.  Does not subtract a
sky background.*/
int centroid01(float **image,int nx,int ny,int *incoords,int *boxs,float *outcoords)
{
  int i,j,cx,cy,safeins;
  float norm,fx,fy;

  cx = incoords[1];
  cy = incoords[2];

  norm = fx = fy = 0.0;
  safeins = 1;
  for(i=cx-boxs[1];i<=cx+boxs[1];i++)
    {
      for(j=cy-boxs[1];j<=cy+boxs[1];j++)
	{
	  if(i>=1&&i<=nx&&j>=1&&j<=ny)
	    {
	      norm+=image[i][j];
	      fx+=(1.0*i)*image[i][j];
	      fy+=(1.0*j)*image[i][j];
	    }
	  else{
	    safeins = 0;
	  }
	}
    }
  if(safeins!=1)
    {
      printf("WARNING: centroid01 FINDS PART OF CENTROID BOX OUTSIDE IMAGE!\n");
      printf("PROCESSING WILL PROCEED BUT CENTROID COULD BE WRONG\n");
    }
  fx/=norm;
  fy/=norm;
  cx = fx+0.5;
  cy = fy+0.5;
  norm = fx = fy = 0.0;
  safeins = 1;
  for(i=cx-boxs[2];i<=cx+boxs[2];i++)
    {
      for(j=cy-boxs[2];j<=cy+boxs[2];j++)
	{
	  if(i>=1&&i<=nx&&j>=1&&j<=ny)
	    {
	      norm+=image[i][j];
	      fx+=(1.0*i)*image[i][j];
	      fy+=(1.0*j)*image[i][j];
	    }
	  else{
	    safeins = 0;
	  }
	}
    }
  if(safeins!=1)
    {
      printf("WARNING: centroid01 FINDS PART OF CENTROID BOX OUTSIDE IMAGE!\n");
      printf("PROCESSING WILL PROCEED BUT CENTROID COULD BE WRONG\n");
    }
  fx/=norm;
  fy/=norm;
  cx = fx+0.5;
  cy = fy+0.5;
  norm = fx = fy = 0.0;
  safeins = 1;
  for(i=cx-boxs[3];i<=cx+boxs[3];i++)
    {
      for(j=cy-boxs[3];j<=cy+boxs[3];j++)
	{
	  if(i>=1&&i<=nx&&j>=1&&j<=ny)
	    {
	      norm+=image[i][j];
	      fx+=(1.0*i)*image[i][j];
	      fy+=(1.0*j)*image[i][j];
	    }
	  else{
	    safeins = 0;
	  }
	}
    }
  if(safeins!=1)
    {
      printf("WARNING: centroid01 FINDS PART OF CENTROID BOX OUTSIDE IMAGE!\n");
      printf("PROCESSING WILL PROCEED BUT CENTROID COULD BE WRONG\n");
    }
  fx/=norm;
  fy/=norm;
  outcoords[1]=fx;
  outcoords[2] = fy;
  return(1);
}


/*centroid02: Exactly like centroid01, but subtracts a sky
background using a box given in sbvec*/
int centroid02(float **image,int nx,int ny,int *incoords,int *boxs,float *outcoords,int *sbvec)
{
  int i,j,cx,cy,safeins;
  float norm,fx,fy,**image2;

  image2 = matrix(1,nx,1,ny);
  imcopy01(image,image2,nx,ny);
  submean01(image2,CANSCLIP,nx,ny,sbvec);
  cx = incoords[1];
  cy = incoords[2];

  norm = fx = fy = 0.0;
  safeins = 1;
  for(i=cx-boxs[1];i<=cx+boxs[1];i++)
    {
      for(j=cy-boxs[1];j<=cy+boxs[1];j++)
	{
	  if(i>=1&&i<=nx&&j>=1&&j<=ny)
	    {
	      norm+=image2[i][j];
	      fx+=(1.0*i)*image2[i][j];
	      fy+=(1.0*j)*image2[i][j];
	    }
	  else{
	    safeins = 0;
	  }
	}
    }
  if(safeins!=1)
    {
      printf("WARNING: centroid02 FINDS PART OF CENTROID BOX OUTSIDE IMAGE!\n");
      printf("PROCESSING WILL PROCEED BUT CENTROID COULD BE WRONG\n");
    }
  fx/=norm;
  fy/=norm;
  cx = fx+0.5;
  cy = fy+0.5;
  norm = fx = fy = 0.0;
  safeins = 1;
  for(i=cx-boxs[2];i<=cx+boxs[2];i++)
    {
      for(j=cy-boxs[2];j<=cy+boxs[2];j++)
	{
	  if(i>=1&&i<=nx&&j>=1&&j<=ny)
	    {
	      norm+=image2[i][j];
	      fx+=(1.0*i)*image2[i][j];
	      fy+=(1.0*j)*image2[i][j];
	    }
	  else{
	    safeins = 0;
	  }
	}
    }
  if(safeins!=1)
    {
      printf("WARNING: centroid02 FINDS PART OF CENTROID BOX OUTSIDE IMAGE!\n");
      printf("PROCESSING WILL PROCEED BUT CENTROID COULD BE WRONG\n");
    }
  fx/=norm;
  fy/=norm;
  cx = fx+0.5;
  cy = fy+0.5;
  norm = fx = fy = 0.0;
  safeins = 1;
  for(i=cx-boxs[3];i<=cx+boxs[3];i++)
    {
      for(j=cy-boxs[3];j<=cy+boxs[3];j++)
	{
	  if(i>=1&&i<=nx&&j>=1&&j<=ny)
	    {
	      norm+=image2[i][j];
	      fx+=(1.0*i)*image2[i][j];
	      fy+=(1.0*j)*image2[i][j];
	    }
	  else{
	    safeins = 0;
	  }
	}
    }
  if(safeins!=1)
    {
      printf("WARNING: centroid02 FINDS PART OF CENTROID BOX OUTSIDE IMAGE!\n");
      printf("PROCESSING WILL PROCEED BUT CENTROID COULD BE WRONG\n");
    }
  fx/=norm;
  fy/=norm;
  outcoords[1]=fx;
  outcoords[2] = fy;
  free_matrix(image2,1,nx,1,ny);
  return(1);
}

/*centroid02c: Exactly like centroid02, but uses pseudocreep01 to get the mean
of the sky subtraction box*/
int centroid02c(float **image,int nx,int ny,int *incoords,int *boxs,float *outcoords,int *sbvec)
{
  int i,j,cx,cy,safeins;
  float norm,fx,fy,**image2;

  image2 = matrix(1,nx,1,ny);
  imcopy01(image,image2,nx,ny);
  submean01c(image2,CANRLEV,nx,ny,sbvec);
  cx = incoords[1];
  cy = incoords[2];

  norm = fx = fy = 0.0;
  safeins = 1;
  for(i=cx-boxs[1];i<=cx+boxs[1];i++)
    {
      for(j=cy-boxs[1];j<=cy+boxs[1];j++)
	{
	  if(i>=1&&i<=nx&&j>=1&&j<=ny)
	    {
	      norm+=image2[i][j];
	      fx+=(1.0*i)*image2[i][j];
	      fy+=(1.0*j)*image2[i][j];
	    }
	  else{
	    safeins = 0;
	  }
	}
    }
  if(safeins!=1)
    {
      printf("WARNING: centroid02 FINDS PART OF CENTROID BOX OUTSIDE IMAGE!\n");
      printf("PROCESSING WILL PROCEED BUT CENTROID COULD BE WRONG\n");
    }
  fx/=norm;
  fy/=norm;
  cx = fx+0.5;
  cy = fy+0.5;
  norm = fx = fy = 0.0;
  safeins = 1;
  for(i=cx-boxs[2];i<=cx+boxs[2];i++)
    {
      for(j=cy-boxs[2];j<=cy+boxs[2];j++)
	{
	  if(i>=1&&i<=nx&&j>=1&&j<=ny)
	    {
	      norm+=image2[i][j];
	      fx+=(1.0*i)*image2[i][j];
	      fy+=(1.0*j)*image2[i][j];
	    }
	  else{
	    safeins = 0;
	  }
	}
    }
  if(safeins!=1)
    {
      printf("WARNING: centroid02 FINDS PART OF CENTROID BOX OUTSIDE IMAGE!\n");
      printf("PROCESSING WILL PROCEED BUT CENTROID COULD BE WRONG\n");
    }
  fx/=norm;
  fy/=norm;
  cx = fx+0.5;
  cy = fy+0.5;
  norm = fx = fy = 0.0;
  safeins = 1;
  for(i=cx-boxs[3];i<=cx+boxs[3];i++)
    {
      for(j=cy-boxs[3];j<=cy+boxs[3];j++)
	{
	  if(i>=1&&i<=nx&&j>=1&&j<=ny)
	    {
	      norm+=image2[i][j];
	      fx+=(1.0*i)*image2[i][j];
	      fy+=(1.0*j)*image2[i][j];
	    }
	  else{
	    safeins = 0;
	  }
	}
    }
  if(safeins!=1)
    {
      printf("WARNING: centroid02 FINDS PART OF CENTROID BOX OUTSIDE IMAGE!\n");
      printf("PROCESSING WILL PROCEED BUT CENTROID COULD BE WRONG\n");
    }
  fx/=norm;
  fy/=norm;
  outcoords[1]=fx;
  outcoords[2] = fy;
  free_matrix(image2,1,nx,1,ny);
  return(1);
}


/*centroid03: Like centroid01, but uses radial centroiding
rather than a centroid box, and uses an unlimited number
of iterations.*/
int centroid03(float **image,int nx,int ny,int *incoords,float *rads,float *outcoords,int itnum)
{
  int i,j,k,safeins;
  float norm,fx,fy,fx2,fy2;
  int bhw,xl,xh,yl,yh;

  fx2 = 1.0*incoords[1];
  fy2 = 1.0*incoords[2];


  for(k=1;k<=itnum;k++)
    {
      norm = fx = fy = 0.0;
      bhw = rads[k]+5.0;
      xl = fx2 - 1.0*bhw;
      xh = fx2 + 1.0*bhw;
      yl = fy2 - 1.0*bhw;
      yh = fy2 + 1.0*bhw;
      for(i=xl;i<=xh;i++)
	{
	  for(j=yl;j<=yh;j++)
	    {
	      if(pow(pow(1.0*i-fx2,2.0)+pow(1.0*j-fy2,2.0),0.5)<=rads[k])
		{
		  norm+=image[i][j];
		  fx+=(1.0*i)*image[i][j];
		  fy+=(1.0*j)*image[i][j];
		}
	    }
	}
      fx/=norm;
      fy/=norm;
      fx2 = fx;
      fy2 = fy;
    }
  outcoords[1] = fx;
  outcoords[2] = fy;
  printf("Shift by centroid03: %f, %f\n",fx-1.0*incoords[1],fy-1.0*incoords[2]);
  return(1);
}

/*centroid04: Like centroid03, but uses a sky subtraction box.*/
int centroid04(float **image,int nx,int ny,int *incoords,float *rads,float *outcoords,int itnum,int *sbvec)
{
  int i,j,k,safeins;
  float norm,fx,fy,fx2,fy2,**image2;
  int bhw,xl,xh,yl,yh;

  image2 = matrix(1,nx,1,ny);
  imcopy01(image,image2,nx,ny);
  submean01(image2,CANSCLIP,nx,ny,sbvec);

  fx2 = 1.0*incoords[1];
  fy2 = 1.0*incoords[2];

  for(k=1;k<=itnum;k++)
    {
      norm = fx = fy = 0.0;
      bhw = rads[k]+5.0;
      xl = fx2 - 1.0*bhw;
      xh = fx2 + 1.0*bhw;
      yl = fy2 - 1.0*bhw;
      yh = fy2 + 1.0*bhw;
      for(i=xl;i<=xh;i++)
	{
	  for(j=yl;j<=yh;j++)
	    {
	      if(pow(pow(1.0*i-fx2,2.0)+pow(1.0*j-fy2,2.0),0.5)<=rads[k])
		{
		  norm+=image2[i][j];
		  fx+=(1.0*i)*image2[i][j];
		  fy+=(1.0*j)*image2[i][j];
		}
	    }
	}
      fx/=norm;
      fy/=norm;
      fx2 = fx;
      fy2 = fy;
    }
  outcoords[1] = fx;
  outcoords[2] = fy;
  printf("Shift by centroid03: %f, %f\n",fx-1.0*incoords[1],fy-1.0*incoords[2]);
  free_matrix(image2,1,nx,1,ny);
  return(1);
}

/*centroid04c: Like centroid04, but uses pseudocreep01 to average
the sky subtraction box.*/
int centroid04c(float **image,int nx,int ny,int *incoords,float *rads,float *outcoords,int itnum,int *sbvec)
{
  int i,j,k,safeins;
  float norm,fx,fy,fx2,fy2,**image2;
  int bhw,xl,xh,yl,yh;

  image2 = matrix(1,nx,1,ny);
  imcopy01(image,image2,nx,ny);
  submean01c(image2,CANRLEV,nx,ny,sbvec);

  fx2 = 1.0*incoords[1];
  fy2 = 1.0*incoords[2];

  for(k=1;k<=itnum;k++)
    {
      norm = fx = fy = 0.0;
      bhw = rads[k]+5.0;
      xl = fx2 - 1.0*bhw;
      xh = fx2 + 1.0*bhw;
      yl = fy2 - 1.0*bhw;
      yh = fy2 + 1.0*bhw;
      for(i=xl;i<=xh;i++)
	{
	  for(j=yl;j<=yh;j++)
	    {
	      if(pow(pow(1.0*i-fx2,2.0)+pow(1.0*j-fy2,2.0),0.5)<=rads[k])
		{
		  norm+=image2[i][j];
		  fx+=(1.0*i)*image2[i][j];
		  fy+=(1.0*j)*image2[i][j];
		}
	    }
	}
      fx/=norm;
      fy/=norm;
      fx2 = fx;
      fy2 = fy;
    }
  outcoords[1] = fx;
  outcoords[2] = fy;
  printf("Shift by centroid03: %f, %f\n",fx-1.0*incoords[1],fy-1.0*incoords[2]);
  free_matrix(image2,1,nx,1,ny);
  return(1);
}


/*centroid05: Like centroid03, but requires an input sky subtraction image,
and performs special sky subtraction before centroiding, so it can be used
with Clio data on faint stars.  Pretty specialized for infrared nodding data,
but, who knows, could be useful for some weird optical application too.*/
int centroid05(float **image1,float **image2,int nx,int ny,int *incoords,float *rads,float *outcoords,int itnum,int *sbox)
{
  int i,j,k,safeins,bhw;
  float norm,fx,fy,fx2,fy2;
  float **image3,**image4;
  int xl,xh,yl,yh;

  image3 = matrix(1,nx,1,ny);
  image4 = matrix(1,nx,1,ny);

  fx2 = 1.0*incoords[1];
  fy2 = 1.0*incoords[2];

  imcopy01(image1,image3,nx,ny);
  imcopy01(image2,image4,nx,ny);

  specialsub01(image3,nx,ny,sbox,image4);

  for(k=1;k<=itnum;k++)
    {
      norm = fx = fy = 0.0;
      bhw = rads[k]+5.0;
      xl = fx2 - 1.0*bhw;
      xh = fx2 + 1.0*bhw;
      yl = fy2 - 1.0*bhw;
      yh = fy2 + 1.0*bhw;
      for(i=xl;i<=xh;i++)
	{
	  for(j=yl;j<=yh;j++)
	    {
	      if(pow(pow(1.0*i-fx2,2.0)+pow(1.0*j-fy2,2.0),0.5)<=rads[k])
		{
		  norm+=image3[i][j];
		  fx+=(1.0*i)*image3[i][j];
		  fy+=(1.0*j)*image3[i][j];
		}
	    }
	}
      fx/=norm;
      fy/=norm;
      fx2 = fx;
      fy2 = fy;
    }
  outcoords[1] = fx;
  outcoords[2] = fy;
  printf("Shift by centroid03: %f, %f\n",fx-1.0*incoords[1],fy-1.0*incoords[2]);

  free_matrix(image3,1,nx,1,ny);
  free_matrix(image4,1,nx,1,ny);
  return(1);
}


/*centroid05c: Like centroid05, but uses the version of specialsub01
that uses psuedocreep01 rather than straight sigma-clip to scale the
images*/
int centroid05c(float **image1,float **image2,int nx,int ny,int *incoords,float *rads,float *outcoords,int itnum,int *sbox)
{
  int i,j,k,safeins,bhw,bedgerr;
  float norm,fx,fy,fx2,fy2;
  float **image3,**image4;
  int xl,xh,yl,yh;

  image3 = matrix(1,nx,1,ny);
  image4 = matrix(1,nx,1,ny);

  fx2 = 1.0*incoords[1];
  fy2 = 1.0*incoords[2];

  imcopy01(image1,image3,nx,ny);
  imcopy01(image2,image4,nx,ny);

  specialsub01c(image3,nx,ny,sbox,image4);

  for(k=1;k<=itnum;k++)
    {
      bedgerr = 0;
      norm = fx = fy = 0.0;
      bhw = rads[k]+5.0;
      xl = fx2 - 1.0*bhw;
      xh = fx2 + 1.0*bhw;
      yl = fy2 - 1.0*bhw;
      yh = fy2 + 1.0*bhw;
      for(i=xl;i<=xh;i++)
	{
	  for(j=yl;j<=yh;j++)
	    {
	      if(pow(pow(1.0*i-fx2,2.0)+pow(1.0*j-fy2,2.0),0.5)<=rads[k])
		{
		  if(i>=1&&i<=nx&&j>=1&&j<=ny)
		    {
		      norm+=image3[i][j];
		      fx+=(1.0*i)*image3[i][j];
		      fy+=(1.0*j)*image3[i][j];
		    }
		  else
		    {
		      bedgerr = 1;
		    }
		}
	    }
	}
      fx/=norm;
      fy/=norm;
      fx2 = fx;
      fy2 = fy;
      if(bedgerr==1)
	{
	  printf("WARNING: centroid05c found part of the centroiding aperture\n");
	  printf("was off the image on iteration %d.  \nProcessing will continue but the result could be inaccurate\n",k);
	}
    }

  outcoords[1] = fx;
  outcoords[2] = fy;
  printf("Shift by centroid05c: %f, %f\n",fx-1.0*incoords[1],fy-1.0*incoords[2]);
  free_matrix(image3,1,nx,1,ny);
  free_matrix(image4,1,nx,1,ny);
  return(1);
}


/*rcentroid01: Carries out itnum centroiding
iterations with a circular centering region of different
radius for each iteration.  The radii are stored in the
vector rads, which is of length itnum.  If skysubyes is
set to one, sky subtraction is performed based on the
sky value from an annulus between anrad1 and anrad2.
If creepmeanyes is set to one, the averaging of the
sky vector is performed using pseudocreep01 and an
rejection factor of 0.5.  Otherwise a single-iteration
5.0 sigma clip is performed on the sky subtraction region.*/
int rcentroid01(float **image,int nx,int ny,int *incoords,float *rads,float *outcoords,int itnum,float *skyrads,int skysubyes,int creepmeanyes)
{
  int i,j,k,sgct,bhw,badrad;
  float norm,skyval,data1,xcen,ycen,prad;

  outcoords[1] = 1.0*incoords[1];
  outcoords[2] = 1.0*incoords[2];

  for(k=1;k<=itnum;k++)
    {
      /*If skysubyes is 1, calculate the sky background*/
      if(skysubyes==1)
	{
	  if(creepmeanyes==1)
	    {
	      skyfind02(image,nx,ny,skyrads,&skyval,&data1,outcoords);
	    }
	  else
	    {
	      skyfind03(image,nx,ny,skyrads,&skyval,&data1,outcoords);
	    }
	}
      else
	{
	  skyval = 0.0;
	}
      bhw = rads[k]+5.0;
      xcen = ycen = norm = 0.0;
      badrad = 0;
      for(i=outcoords[1]-bhw;i<=outcoords[1]+bhw;i++)
	{
	  for(j=outcoords[2]-bhw;j<=outcoords[2]+bhw;j++)
	    {
	      prad = pow(pow(1.0*i-outcoords[1],2.0)+pow(1.0*j-outcoords[2],2.0),0.5);
	      if(prad<=rads[k])
		{
		  if(i>=1&&i<=nx&&j>=1&&j<=ny)
		    {
		      norm+=(image[i][j]-skyval);
		      xcen+=(image[i][j]-skyval)*(1.0*i);
		      ycen+=(image[i][j]-skyval)*(1.0*j);
		    }
		  else
		    {
		      badrad = 1;
		    }
		}
	    }
	}
      outcoords[1] = xcen/norm;
      outcoords[2] = ycen/norm;
      if(badrad==1)
	{
	  printf("WARNING: rcentroid01 found the centroiding\n");
	  printf("region was partly off the image on interation %d\n",k);
	  printf("the program will return normally but this may indicate\n");
	  printf("something has gone wrong\n");
	}
    }

  return(1);
}

/*rphotcen01: Performs the same centroiding procedure as
rcentroid01, but also sums the flux within a photometric
aperture of radius aprad, and returns this in photsum*/
int rphotcen01(float **image,int nx,int ny,int *incoords,float *rads,float *outcoords,int itnum,float *skyrads,int skysubyes,int creepmeanyes,float aprad,float *photsum)
{
  int i,j,k,sgct,bhw,badrad;
  float norm,skyval,data1,xcen,ycen,prad;

  outcoords[1] = 1.0*incoords[1];
  outcoords[2] = 1.0*incoords[2];

  for(k=1;k<=itnum;k++)
    {
      /*If skysubyes is 1, calculate the sky background*/
      if(skysubyes==1)
	{
	  if(creepmeanyes==1)
	    {
	      skyfind02(image,nx,ny,skyrads,&skyval,&data1,outcoords);
	    }
	  else
	    {
	      skyfind03(image,nx,ny,skyrads,&skyval,&data1,outcoords);
	    }
	}
      else
	{
	  skyval = 0.0;
	}
      bhw = rads[k]+5.0;
      xcen = ycen = norm = 0.0;
      badrad = 0;
      for(i=outcoords[1]-bhw;i<=outcoords[1]+bhw;i++)
	{
	  for(j=outcoords[2]-bhw;j<=outcoords[2]+bhw;j++)
	    {
	      prad = pow(pow(1.0*i-outcoords[1],2.0)+pow(1.0*j-outcoords[2],2.0),0.5);
	      if(prad<=rads[k])
		{
		  if(i>=1&&i<=nx&&j>=1&&j<=ny)
		    {
		      norm+=(image[i][j]-skyval);
		      xcen+=(image[i][j]-skyval)*(1.0*i);
		      ycen+=(image[i][j]-skyval)*(1.0*j);
		    }
		  else
		    {
		      badrad = 1;
		    }
		}
	    }
	}
      outcoords[1] = xcen/norm;
      outcoords[2] = ycen/norm;
      if(badrad==1)
	{
	  printf("WARNING: rphotcen01 found the centroiding\n");
	  printf("region was partly off the image on interation %d\n",k);
	  printf("the program will return normally but this may indicate\n");
	  printf("something has gone wrong\n");
	}
    }

  bhw = aprad+5.0;
  badrad = 0;
  norm = 0.0;
  for(i=outcoords[1]-bhw;i<=outcoords[1]+bhw;i++)
    {
      for(j=outcoords[2]-bhw;j<=outcoords[2]+bhw;j++)
	{
	  prad = pow(pow(1.0*i-outcoords[1],2.0)+pow(1.0*j-outcoords[2],2.0),0.5);
	  if(prad<=aprad)
	    {
	      if(i>=1&&i<=nx&&j>=1&&j<=ny)
		{
		  norm+=(image[i][j]-skyval);
		}
	      else 
		{
		  badrad = 1;
		}
	    }
	}
    }
  *photsum = norm;
  if(badrad==1)
    {
      printf("WARNING: rphotcen01 found the photometric\n");
      printf("aperture was partly off the image.\n");
      printf("The program will return normally but this may indicate\n");
      printf("something has gone wrong, and the photometric value\n");
      printf("may be bad\n");
    }

  return(1);
}



/*rphot01: carries out aperture photometry about
a given center, with no centroiding.  If
skysubyes is one, carries out sky subtraction.
If creepmeanyes is one, uses creeping mean
averaging in the sky subtraction.  Otherwise,
uses a sigle iteration 5.0 sigma clip.*/
int rphot01(float **image,int nx,int ny,float *cen,float *skyrads,int skysubyes,int creepmeanyes,float aprad,float *photsum)
{
  int i,j,k,sgct,bhw,badrad;
  float norm,skyval,data1,prad;

  /*If skysubyes is 1, calculate the sky background*/
  if(skysubyes==1)
    {
      if(creepmeanyes==1)
	{
	  skyfind02(image,nx,ny,skyrads,&skyval,&data1,cen);
	}
      else
	{
	  skyfind03(image,nx,ny,skyrads,&skyval,&data1,cen);
	}
    }
  else
    {
      skyval = 0.0;
    }

  bhw = aprad+5.0;
  badrad = 0;
  norm = 0.0;
  for(i=cen[1]-bhw;i<=cen[1]+bhw;i++)
    {
      for(j=cen[2]-bhw;j<=cen[2]+bhw;j++)
	{
	  prad = pow(pow(1.0*i-cen[1],2.0)+pow(1.0*j-cen[2],2.0),0.5);
	  if(prad<=aprad)
	    {
	      if(i>=1&&i<=nx&&j>=1&&j<=ny)
		{
		  norm+=(image[i][j]-skyval);
		}
	      else 
		{
		  badrad = 1;
		}
	    }
	}
    }
  *photsum = norm;
  if(badrad==1)
    {
      printf("WARNING: rphot01 found the photometric\n");
      printf("aperture was partly off the image.\n");
      printf("The program will return normally but this may indicate\n");
      printf("something has gone wrong, and the photometric value\n");
      printf("may be bad\n");
    }

  return(1);
}


/*specialsub01: A simple program that takes an image and subtracts another from
it.  The first image is changed and the second is not, but in the actual subtraction
a copy of the second image is scaled to match the first within a given box, and
the scaled copy is used in the subtraction, so that the mean of the resultant
image is zero with that box*/
int specialsub01(float **image1,int nx,int ny,int *sbox,float **image2)
{
  int i,j;
  float **image3,mean1,mean2,rms;

  image3 = matrix(1,nx,1,ny);
  imcopy01(image2,image3,nx,ny);
  statsim03(image1,nx,ny,sbox,&rms,&mean1,CANSCLIP);
  statsim03(image3,nx,ny,sbox,&rms,&mean2,CANSCLIP);
  mathimc03(image3,image3,nx,ny,mean1/mean2);
  mathimtim02(image1,image1,nx,ny,image3);

  free_matrix(image3,1,nx,1,ny);
  return(1);
}



/*specialsub01c: exactly like specialsub01, but uses a pseudo-creeping mean
  combine rather than a sigma clip for box means*/
int specialsub01c(float **image1,int nx,int ny,int *sbox,float **image2)
{
  int i,j;
  float **image3,mean1,mean2,rms;

  image3 = matrix(1,nx,1,ny);
  imcopy01(image2,image3,nx,ny);
  statsim03c(image1,nx,ny,sbox,&rms,&mean1,CANRLEV);
  statsim03c(image3,nx,ny,sbox,&rms,&mean2,CANRLEV);
  mathimc03(image3,image3,nx,ny,mean1/mean2);
  mathimtim02(image1,image1,nx,ny,image3);

  free_matrix(image3,1,nx,1,ny);
  return(1);
}


/*imcopy01: a very simple program that simply copies one image to another*/
int imcopy01(float **image1,float **image2,int nx,int ny)
{
  int i,j;
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image2[i][j] = image1[i][j];
	}
    }
  return(1);
}

/*zeropad01: given an image matrix, nx, ny, an integer vector of length
4 giving the zero pad thickness on the left side, right side, bottom,
and top, and a new image matrix WITH APPROPRIATE DIMENSIONS SET BY THE
CALLING PROGRAM, puts a zero-padded version of the old image matrix into
the new one*/
int zeropad01(float **image1,int nx,int ny,int *zpvec,float **image2)
{
  int i,j;
  imzero(image2,nx+zpvec[1]+zpvec[2],ny+zpvec[3]+zpvec[4]);
  for(i=zpvec[1]+1;i<=zpvec[1]+nx;i++)
    {
      for(j=zpvec[3]+1;j<=zpvec[3]+ny;j++)
	{
	  image2[i][j] = image1[i-zpvec[1]][j-zpvec[3]];
	}
    }
  return(1);
}



/*zerotrim01: given an image matrix, nx, ny, an integer vector of length
8 giving the zero trim on the left side, right side, bottom, and top
of the image, and the corner cut for the lower left, lower right,
upper left, and upper right corners, zero trims the image.
A corner cut of x means that all pixels satisfying 
ydist + xdist less than  x are set to zero, where ydist and xdist are
the y and x distances from the corner.*/
int zerotrim01(float **image,int nx,int ny, int *ztvec)
{
  int i,j;
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  if(i<=ztvec[1]||i>=nx-ztvec[2]+1||j<=ztvec[3]||j>=ny-ztvec[4]+1)
	    {
	      image[i][j] = 0.0;
	    }
	  if((i+j)<=ztvec[5]||(nx-i+1+j)<=ztvec[6]||(ny-j+1+i)<=ztvec[7]||(nx-i+1+ny-j+1)<=ztvec[8])
	    {
	      image[i][j] = 0.0;
	    }
	}
    }
  return(1);
}

/*zerotrim02: like zerotrim01, but instead of integer corner
cuts it allows a floating point circular cut using cvec,
with three entries, the first two of which are
the center and the third of which is the radius*/
int zerotrim02(float **image,int nx,int ny, int *ztvec,float *cvec)
{
  int i,j;
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  if(i<=ztvec[1]||i>=nx-ztvec[2]+1||j<=ztvec[3]||j>=ny-ztvec[4]+1)
	    {
	      image[i][j] = 0.0;
	    }
	  if(pow(pow(1.0*i-cvec[1],2.0)+pow(1.0*j-cvec[2],2.0),0.5)>=cvec[3])
	    {
	      image[i][j] = 0.0;
	    }
	}
    }
  return(1);
}

/*zerotrim03: like zerotrim02 in its cutting geometry,
but attempts to remove edge glow by subtracting an averaged
border vector in a manner similar to colfudge02.*/
int zerotrim03(float **image,int nx,int ny, int *ztvec,float *cvec,int border,int avstep)
{
  int i,j,k;
  float **image1,**image2,**image3,**avgbox,**subvecs;
  int blocknum,avstart,avend,halfblock,*circlegood,ipx,ipy;
  float data1,data2,rad,theta,px,py,xb,yb,xe,ye;

  avgbox = matrix(1,border,1,avstep);
  image1 = matrix(1,nx,1,ny);
  image2 = matrix(1,nx,1,ny);
  image3 = matrix(1,nx,1,ny);

  halfblock = avstep/2;
  imzero(image1,nx,ny);
  imzero(image2,nx,ny);
  imzero(image3,nx,ny);

  /*Horizontal Borders Along Top and Bottom*/

  /*x ranges from ztvec[1]+1 up to nx-ztvec[2]*/
  blocknum = (nx-ztvec[2]-ztvec[1])/avstep + 1;
  /*bottom*/
  subvecs = matrix(1,blocknum,1,border);
  for(k=1;k<=blocknum;k++)
    {
      printf("k = %d\n",k);
      fflush(stdout);
      avstart = ztvec[1] + (k-1)*avstep + 1;
      avend = ztvec[1] + k*avstep;
      if(avend>nx-ztvec[2])
	{
	  avend = nx-ztvec[2];
	}
      for(j=ztvec[3]+1;j<=ztvec[3]+border;j++)
	{
	  for(i=avstart;i<=avend;i++)
	    {
	      avgbox[j-ztvec[3]][i-avstart+1] = image[i][j];
	    }
	  creepvec01(avgbox[j-ztvec[3]],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	  subvecs[k][j-ztvec[3]] = data1;
	}
    }
  for(i=ztvec[1]+1;i<=ztvec[1]+halfblock;i++)
    {
      for(j=ztvec[3]+1;j<=ztvec[3]+border;j++)
	{
	  image1[i][j] = subvecs[1][j-ztvec[3]];
	}
    }
  for(k=1;k<=blocknum-1;k++)
    {
      for(i=ztvec[1]+(k-1)*avstep+halfblock+1;i<=ztvec[1]+k*avstep+halfblock;i++)
	{
	  for(j=ztvec[3]+1;j<=ztvec[3]+border;j++)
	    {
	      if(i<=nx-ztvec[2])
		{
		  image1[i][j] = subvecs[k][j-ztvec[3]] + (subvecs[k+1][j-ztvec[3]] - subvecs[k][j-ztvec[3]])*(1.0*i-1.0*(ztvec[1]+(k-1)*avstep+halfblock))/(1.0*avstep-1.0);
		}
	    }
	}
    }

  for(i=ztvec[1]+(blocknum-1)*avstep+halfblock+1;i<=nx-ztvec[2];i++)
    {
      for(j=ztvec[3]+1;j<=ztvec[3]+border;j++)
	{
	  image1[i][j] = subvecs[blocknum][j-ztvec[3]];
	}
    }

  printf("Did bottom OK\n");
  fflush(stdout);

  /*top*/
  for(k=1;k<=blocknum;k++)
    {
      avstart = ztvec[1] + (k-1)*avstep + 1;
      avend = ztvec[1] + k*avstep;
      if(avend>nx-ztvec[2])
	{
	  avend = nx-ztvec[2];
	}
      for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4];j++)
	{
	  for(i=avstart;i<=avend;i++)
	    {
	      avgbox[j-(ny-ztvec[4]+1-border)+1][i-avstart+1] = image[i][j];
	    }
	  creepvec01(avgbox[j-(ny-ztvec[4]+1-border)+1],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	  subvecs[k][j-(ny-ztvec[4]+1-border)+1] = data1;
	}
    }
  for(i=ztvec[1]+1;i<=ztvec[1]+halfblock;i++)
    {
      for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4];j++)
	{
	  image1[i][j] = subvecs[1][j-(ny-ztvec[4]+1-border)+1];
	}
    }
  for(k=1;k<=blocknum-1;k++)
    {
      for(i=ztvec[1]+(k-1)*avstep+halfblock+1;i<=ztvec[1]+k*avstep+halfblock;i++)
	{
	  for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4];j++)
	    {
	      if(i<=nx-ztvec[2])
		{
		  image1[i][j] = subvecs[k][j-(ny-ztvec[4]+1-border)+1] + (subvecs[k+1][j-(ny-ztvec[4]+1-border)+1] - subvecs[k][j-(ny-ztvec[4]+1-border)+1])*(1.0*i-1.0*(ztvec[1]+(k-1)*avstep+halfblock))/(1.0*avstep-1.0);
		}
	    }
	}
    }

  for(i=ztvec[1]+(blocknum-1)*avstep+halfblock+1;i<=nx-ztvec[2];i++)
    {
      for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4];j++)
	{
	  image1[i][j] = subvecs[blocknum][j-(ny-ztvec[4]+1-border)+1];
	}
    }

  free_matrix(subvecs,1,blocknum,1,border);

  printf("Did top OK\n");
  fflush(stdout);

  /*Vertical Borders at Left and Right*/
  /*y ranges from ztvec[3]+1 to ny-ztvec[4]*/
  blocknum = (ny-ztvec[4]-ztvec[3])/avstep + 1;
  subvecs = matrix(1,blocknum,1,border);
  /*left side*/
  for(k=1;k<=blocknum;k++)
    {
      avstart = ztvec[3] + (k-1)*avstep + 1;
      avend = ztvec[3] + k*avstep;
      if(avend>ny-ztvec[4])
	{
	  avend = ny-ztvec[4];
	}
      for(i=ztvec[1]+1;i<=ztvec[1]+border;i++)
	{
	  for(j=avstart;j<=avend;j++)
	    {
	      avgbox[i-ztvec[1]][j-avstart+1] = image[i][j];
	    }
	  creepvec01(avgbox[i-ztvec[1]],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	  subvecs[k][i-ztvec[1]] = data1;
	}
    }
  for(j=ztvec[3]+1;j<=ztvec[3]+halfblock;j++)
    {
      for(i=ztvec[1]+1;i<=ztvec[1]+border;i++)
	{
	  image2[i][j] = subvecs[1][i-ztvec[1]];
	}
    }

  for(k=1;k<=blocknum-1;k++)
    {
      for(j=ztvec[3]+(k-1)*avstep+halfblock+1;j<=ztvec[3]+k*avstep+halfblock;j++)
	{
	  for(i=ztvec[1]+1;i<=ztvec[1]+border;i++)
	    {
	      if(j<=ny-ztvec[4])
		{
		  image2[i][j] = subvecs[k][i-ztvec[1]] + (subvecs[k+1][i-ztvec[1]] - subvecs[k][i-ztvec[1]])*(1.0*j-1.0*(ztvec[3]+(k-1)*avstep+halfblock+1))/(1.0*avstep-1.0);
													       
		}
	    }
	}
    }
     
  for(j=ztvec[3]+(blocknum-1)*avstep+halfblock+1;j<=ny-ztvec[4];j++)
    {
      for(i=ztvec[1]+1;i<=ztvec[1]+border;i++)
	{
	  image2[i][j] = subvecs[blocknum][i-ztvec[1]];
	}
    }

  /*right side*/
  for(k=1;k<=blocknum;k++)
    {
      avstart = ztvec[3] + (k-1)*avstep + 1;
      avend = ztvec[3] + k*avstep;
      if(avend>ny-ztvec[4])
	{
	  avend = ny-ztvec[4];
	}
      for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2];i++)
	{
	  for(j=avstart;j<=avend;j++)
	    {
	      avgbox[i-(nx-ztvec[2]-border+1)+1][j-avstart+1] = image[i][j];
	    }
	  creepvec01(avgbox[i-(nx-ztvec[2]-border+1)+1],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	  subvecs[k][i-(nx-ztvec[2]-border+1)+1] = data1;
	}
    }
  for(j=ztvec[3]+1;j<=ztvec[3]+halfblock;j++)
    {
      for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2];i++)
	{
	  image2[i][j] = subvecs[1][i-(nx-ztvec[2]-border+1)+1];
	}
    }
  for(k=1;k<=blocknum-1;k++)
    {
      for(j=ztvec[3]+(k-1)*avstep+halfblock+1;j<=ztvec[3]+k*avstep+halfblock;j++)
	{
	  for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2];i++)
	    {
	      if(j<=ny-ztvec[4])
		{
		  image2[i][j] = subvecs[k][i-(nx-ztvec[2]-border+1)+1] + (subvecs[k+1][i-(nx-ztvec[2]-border+1)+1] - subvecs[k][i-(nx-ztvec[2]-border+1)+1])*(1.0*j-1.0*(ztvec[3]+(k-1)*avstep+halfblock+1))/(1.0*avstep-1.0);
		}
	    }
	}
    }

  for(j=ztvec[3]+(blocknum-1)*avstep+halfblock+1;j<=ny-ztvec[4];j++)
    {
      for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2];i++)
	{
	  image2[i][j] = subvecs[blocknum][i-(nx-ztvec[2]-border+1)+1];
	}
    }


  free_matrix(subvecs,1,blocknum,1,border);


  /*Circular cut*/
  blocknum = 2.0*PI*cvec[3]/avstep + 1;
  subvecs = matrix(1,blocknum,1,border);
  circlegood = ivector(1,blocknum);

  for(k=1;k<=blocknum;k++)
    {
      theta = 1.0*((k-1)*avstep+1)/cvec[3];
      rad = cvec[3];
      xb = cvec[1] + rad*cos(theta);
      yb = cvec[2] + rad*sin(theta);
      theta = 1.0*(k*avstep)/cvec[3];
      xe = cvec[1] + rad*cos(theta);
      ye = cvec[2] + rad*sin(theta);
      if(xb>ztvec[1]&&xe>ztvec[1]&&xb<=nx-ztvec[2]&&xe<=nx-ztvec[2]&&yb>ztvec[3]&&ye>ztvec[3]&&yb<=ny-ztvec[4]&&ye<=ny-ztvec[4])
	{
	  circlegood[k] = 1;
	  for(j=1;j<=border;j++)
	    {
	      for(i=(k-1)*avstep+1;i<=k*avstep;i++)
		{
		  theta = 1.0*i/cvec[3];
		  rad = cvec[3]-1.0*(j-1);
		  xb = cvec[1] + rad*cos(theta);
		  yb = cvec[2] + rad*sin(theta);
		  ipx = xb+0.5;
		  ipy = yb+0.5;
		  avgbox[j][i-((k-1)*avstep+1)+1] = image[ipx][ipy];
		}
	      creepvec01(avgbox[j],avstep,COLFUDGEREJ,&data1,&data2);
	      subvecs[k][j] = data1;
	    }
	}
      else{
	circlegood[k] = 0;
      }
    }
  if(circlegood[1]==1)
    {
      for(j=1;j<=border;j++)
	{
	  for(i=1;i<=halfblock;i++)
	    {
	      theta = 1.0*i/cvec[3];
	      rad = cvec[3]-1.0*(j-1);
	      xb = cvec[1] + rad*cos(theta);
	      yb = cvec[2] + rad*sin(theta);
	      ipx = xb+0.5;
	      ipy = yb+0.5;
	      image3[ipx][ipy] = subvecs[1][j];
	    }
	}
    }
  if(circlegood[blocknum]==1)
    {
      for(j=1;j<=border;j++)
	{
	  for(i=(blocknum-1)*avstep+halfblock+1;i<=blocknum*avstep;i++)
	    {
	      if(i<=2*PI*cvec[3])
		{
		  theta = 1.0*i/cvec[3];
		  rad = cvec[3]-1.0*(j-1);
		  xb = cvec[1] + rad*cos(theta);
		  yb = cvec[2] + rad*sin(theta);
		  ipx = xb+0.5;
		  ipy = yb+0.5;
		  image3[ipx][ipy] = subvecs[blocknum][j];
		}
	    }
	}
    }
  for(k=2;k<=blocknum-1;k++)
    {
      if(circlegood[k]==1)
	{
	  if(circlegood[k-1]==0&&circlegood[k+1]==0)
	    {
	      for(j=1;j<=border;j++)
		{
		  for(i=(k-1)*avstep+1;i<=k*avstep;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k][j];
		    }
		}
	    }
	  if(circlegood[k-1]==1&&circlegood[k+1]==0)
	    {
	      for(j=1;j<=border;j++)
		{
		  for(i=(k-1)*avstep+1;i<=(k-1)*avstep+halfblock;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k-1][j] + (subvecs[k][j]-subvecs[k-1][j])*(1.0*i-1.0*((k-2)*avstep + halfblock))/(1.0*avstep);
		    }
		}
	    }
	  if(circlegood[k-1]==0&&circlegood[k+1]==1)
	    {
	      for(j=1;j<=border;j++)
		{
		  for(i=(k-1)*avstep+halfblock+1;i<=k*avstep;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k][j] + (subvecs[k+1][j]-subvecs[k-1][j])*(1.0*i-1.0*((k-1)*avstep + halfblock))/(1.0*avstep);
		    }
		}
	    }
	  if(circlegood[k-1]==1&&circlegood[k+1]==1)
	    {
	      for(j=1;j<=border;j++)
		{
		  for(i=(k-1)*avstep+1;i<=(k-1)*avstep+halfblock;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k-1][j] + (subvecs[k][j]-subvecs[k-1][j])*(1.0*i-1.0*((k-2)*avstep + halfblock))/(1.0*avstep);
		    }
		  for(i=(k-1)*avstep+halfblock+1;i<=k*avstep;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k][j] + (subvecs[k+1][j]-subvecs[k][j])*(1.0*i-1.0*((k-1)*avstep + halfblock))/(1.0*avstep);
		    }
		}
	    }
	}
    }

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  data1 = data2 = 0.0;
	  if(image1[i][j]!=0.0)
	    {
	      data1+=1;
	      data2+=image1[i][j];
	    }
	  if(image2[i][j]!=0.0)
	    {
	      data1+=1;
	      data2+=image2[i][j];
	    }
	  if(image3[i][j]!=0.0)
	    {
	      data1+=1;
	      data2+=image3[i][j];
	    }
	  if(data1>0.0)
	    {
	      image1[i][j] = data2/data1;
	      image[i][j]-=data2/data1;
	    }
	}
    }
  free_matrix(subvecs,1,blocknum,1,border);
  free_ivector(circlegood,1,blocknum);

  writeim01(nx,ny,"junk01.txt",image1);

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  if(i<=ztvec[1]||i>=nx-ztvec[2]+1||j<=ztvec[3]||j>=ny-ztvec[4]+1)
	    {
	      image[i][j] = 0.0;
	    }
	  if(pow(pow(1.0*i-cvec[1],2.0)+pow(1.0*j-cvec[2],2.0),0.5)>=cvec[3])
	    {
	      image[i][j] = 0.0;
	    }
	}
    }

  free_matrix(avgbox,1,border,1,avstep);
  free_matrix(image1,1,nx,1,ny);
  free_matrix(image2,1,nx,1,ny);
  free_matrix(image3,1,nx,1,ny);

  return(1);
}


/*zerotrim03bcs: description of
zerotrim03: like zerotrim02 in its cutting geometry,
but attempts to remove edge glow by subtracting an averaged
border vector in a manner similar to colfudge02.
zerotrim03bcs is exactly like zerotrim03 except
that it only subtracts the average border vector,
and does not actually trim the image.  This is
because it is for use the the bicubic spline
rotations and shifts shift03, rotate03, and
rotateshift03, which do their own zero trimming.*/
int zerotrim03bcs(float **image,int nx,int ny, int *ztvec,float *cvec,int border,int avstep)
{
  int i,j,k;
  float **image1,**image2,**image3,**avgbox,**subvecs;
  int blocknum,avstart,avend,halfblock,*circlegood,ipx,ipy,maxtrim;
  float data1,data2,rad,theta,px,py,xb,yb,xe,ye;
  int fullcirc,*numpoints,circborder;
  float ffullcirc;

  maxtrim = 0;
  for(i=1;i<=4;i++)
    {
      if(ztvec[i]>maxtrim)
	{
	  maxtrim = ztvec[i];
	}
    }

  avgbox = matrix(1,border+maxtrim,1,avstep);
  image1 = matrix(1,nx,1,ny);
  image2 = matrix(1,nx,1,ny);
  image3 = matrix(1,nx,1,ny);

  halfblock = avstep/2;
  imzero(image1,nx,ny);
  imzero(image2,nx,ny);
  imzero(image3,nx,ny);

  /*Horizontal Borders Along Top and Bottom*/

  blocknum = nx/avstep + 1;
  /*bottom*/
  subvecs = matrix(1,blocknum,1,border+maxtrim);
  /*construction of averaged vector for each block along bottom*/
  for(k=1;k<=blocknum;k++)
    {
      printf("k = %d\n",k);
      fflush(stdout);
      avstart = (k-1)*avstep + 1;
      avend = k*avstep;
      if(avend>nx)
	{
	  avend = nx;
	}
      for(j=1;j<=ztvec[3]+border;j++)
	{
	  for(i=avstart;i<=avend;i++)
	    {
	      avgbox[j][i-avstart+1] = image[i][j];
	    }
	  creepvec01(avgbox[j],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	  subvecs[k][j] = data1;
	}
    }
  /*fill averaged vector into image1 for lower left corner*/
  for(i=1;i<=halfblock;i++)
    {
      for(j=1;j<=ztvec[3]+border;j++)
	{
	  image1[i][j] = subvecs[1][j];
	}
    }
  /*fill averaged vector into image1 for middle of bottom strip*/
  for(k=1;k<=blocknum-1;k++)
    {
      for(i=(k-1)*avstep+halfblock+1;i<=k*avstep+halfblock;i++)
	{
	  for(j=1;j<=ztvec[3]+border;j++)
	    {
	      if(i<=nx)
		{
		  image1[i][j] = subvecs[k][j] + (subvecs[k+1][j] - subvecs[k][j])*(1.0*i-1.0*(ztvec[1]+(k-1)*avstep+halfblock))/(1.0*avstep-1.0);
		}
	    }
	}
    }
  /*fill averaged vector into image1 for lower right corner*/
  for(i=(blocknum-1)*avstep+halfblock+1;i<=nx;i++)
    {
      for(j=1;j<=ztvec[3]+border;j++)
	{
	  image1[i][j] = subvecs[blocknum][j];
	}
    }



  printf("Did bottom OK\n");
  fflush(stdout);

  /*top*/
  /*construction of averaged vector for each block along top*/
  for(k=1;k<=blocknum;k++)
    {
      avstart = (k-1)*avstep + 1;
      avend = k*avstep;
      if(avend>nx)
	{
	  avend = nx;
	}
      for(j=ny-ztvec[4]+1-border;j<=ny;j++)
	{
	  for(i=avstart;i<=avend;i++)
	    {
	      avgbox[j-(ny-ztvec[4]+1-border)+1][i-avstart+1] = image[i][j];
	    }
	  creepvec01(avgbox[j-(ny-ztvec[4]+1-border)+1],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	  subvecs[k][j-(ny-ztvec[4]+1-border)+1] = data1;
	}
    }
  /*fill in upper left corner of image1 with averaged vector*/
  for(i=1;i<=halfblock;i++)
    {
      for(j=ny-ztvec[4]+1-border;j<=ny;j++)
	{
	  image1[i][j] = subvecs[1][j-(ny-ztvec[4]+1-border)+1];
	}
    }
  /*fill in middle of top of image1 with averaged vector*/
  for(k=1;k<=blocknum-1;k++)
    {
      for(i=(k-1)*avstep+halfblock+1;i<=k*avstep+halfblock;i++)
	{
	  for(j=ny-ztvec[4]+1-border;j<=ny;j++)
	    {
	      if(i<=nx)
		{
		  image1[i][j] = subvecs[k][j-(ny-ztvec[4]+1-border)+1] + (subvecs[k+1][j-(ny-ztvec[4]+1-border)+1] - subvecs[k][j-(ny-ztvec[4]+1-border)+1])*(1.0*i-1.0*(ztvec[1]+(k-1)*avstep+halfblock))/(1.0*avstep-1.0);
		}
	    }
	}
    }
  /*fill in upper right corner of image1 with averaged vector*/
  for(i=(blocknum-1)*avstep+halfblock+1;i<=nx;i++)
    {
      for(j=ny-ztvec[4]+1-border;j<=ny;j++)
	{
	  image1[i][j] = subvecs[blocknum][j-(ny-ztvec[4]+1-border)+1];
	}
    }

  free_matrix(subvecs,1,blocknum,1,border+maxtrim);
  printf("Did top OK\n");
  fflush(stdout);

  /*Vertical Borders at Left and Right*/
  blocknum = ny/avstep + 1;
  subvecs = matrix(1,blocknum,1,border+maxtrim);
  /*left side*/
  /*construction of averaged vector for each block along left side*/
  for(k=1;k<=blocknum;k++)
    {
      avstart = (k-1)*avstep + 1;
      avend = k*avstep;
      if(avend>ny)
	{
	  avend = ny;
	}
      for(i=1;i<=ztvec[1]+border;i++)
	{
	  for(j=avstart;j<=avend;j++)
	    {
	      avgbox[i][j-avstart+1] = image[i][j];
	    }
	  creepvec01(avgbox[i],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	  subvecs[k][i] = data1;
	}
    }
  /*fill in lower left corner of image2 with averaged vector*/
  for(j=1;j<=halfblock;j++)
    {
      for(i=1;i<=ztvec[1]+border;i++)
	{
	  image2[i][j] = subvecs[1][i];
	}
    }
  /*fill in middle of left side of image2 with averaged vector*/
  for(k=1;k<=blocknum-1;k++)
    {
      for(j=(k-1)*avstep+halfblock+1;j<=k*avstep+halfblock;j++)
	{
	  for(i=1;i<=ztvec[1]+border;i++)
	    {
	      if(j<=ny)
		{
		  image2[i][j] = subvecs[k][i] + (subvecs[k+1][i] - subvecs[k][i])*(1.0*j-1.0*(ztvec[3]+(k-1)*avstep+halfblock+1))/(1.0*avstep-1.0);				       
		}
	    }
	}
    }
  /*fill in upper left corner of image2 with averaged vector*/
  for(j=(blocknum-1)*avstep+halfblock+1;j<=ny;j++)
    {
      for(i=1;i<=ztvec[1]+border;i++)
	{
	  image2[i][j] = subvecs[blocknum][i];
	}
    }

  /*right side*/
  /*create averaged vector in each block for right edge of image*/
  for(k=1;k<=blocknum;k++)
    {
      avstart = (k-1)*avstep + 1;
      avend = k*avstep;
      if(avend>ny)
	{
	  avend = ny;
	}
      for(i=nx-ztvec[2]-border+1;i<=nx;i++)
	{
	  for(j=avstart;j<=avend;j++)
	    {
	      avgbox[i-(nx-ztvec[2]-border+1)+1][j-avstart+1] = image[i][j];
	    }
	  creepvec01(avgbox[i-(nx-ztvec[2]-border+1)+1],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	  subvecs[k][i-(nx-ztvec[2]-border+1)+1] = data1;
	}
    }
  /*fill in lower right corner of image2 with averaged vector*/
  for(j=1;j<=halfblock;j++)
    {
      for(i=nx-ztvec[2]-border+1;i<=nx;i++)
	{
	  image2[i][j] = subvecs[1][i-(nx-ztvec[2]-border+1)+1];
	}
    }
  /*fill in middle of right side of image2 with averaged vector*/
  for(k=1;k<=blocknum-1;k++)
    {
      for(j=(k-1)*avstep+halfblock+1;j<=k*avstep+halfblock;j++)
	{
	  for(i=nx-ztvec[2]-border+1;i<=nx;i++)
	    {
	      if(j<=ny)
		{
		  image2[i][j] = subvecs[k][i-(nx-ztvec[2]-border+1)+1] + (subvecs[k+1][i-(nx-ztvec[2]-border+1)+1] - subvecs[k][i-(nx-ztvec[2]-border+1)+1])*(1.0*j-1.0*(ztvec[3]+(k-1)*avstep+halfblock+1))/(1.0*avstep-1.0);
		}
	    }
	}
    }
  /*fill in upper right corner of image2 with averaged vector*/
  for(j=(blocknum-1)*avstep+halfblock+1;j<=ny;j++)
    {
      for(i=nx-ztvec[2]-border+1;i<=nx;i++)
	{
	  image2[i][j] = subvecs[blocknum][i-(nx-ztvec[2]-border+1)+1];
	}
    }


  free_matrix(subvecs,1,blocknum,1,border+maxtrim);
  free_matrix(avgbox,1,border+maxtrim,1,avstep);

  /*Circular cut*/
  /*get distance from center to most distant corner*/
  ffullcirc = pow(pow(cvec[1]-1.0,2.0)+pow(cvec[2]-1.0,2.0),0.5);
  if(pow(pow(cvec[1]-1.0*nx,2.0)+pow(cvec[2]-1.0,2.0),0.5)>ffullcirc)
    {
      ffullcirc = pow(pow(cvec[1]-1.0*nx,2.0)+pow(cvec[2]-1.0,2.0),0.5);
    }
  if(pow(pow(cvec[1]-1.0,2.0)+pow(cvec[2]-1.0*ny,2.0),0.5)>ffullcirc)
    {
      ffullcirc = pow(pow(cvec[1]-1.0,2.0)+pow(cvec[2]-1.0*ny,2.0),0.5);
    }
  if(pow(pow(cvec[1]-1.0*nx,2.0)+pow(cvec[2]-1.0*ny,2.0),0.5)>ffullcirc)
    {
      ffullcirc = pow(pow(cvec[1]-1.0*nx,2.0)+pow(cvec[2]-1.0*ny,2.0),0.5);
    }
  circborder = ffullcirc - cvec[3] + 1.0*border + 1.0;

  blocknum = 2.0*PI*ffullcirc/avstep + 1;
  subvecs = matrix(1,blocknum,1,circborder);
  circlegood = ivector(1,blocknum);
  numpoints = ivector(1,circborder);
  avgbox = matrix(1,circborder,1,avstep);

  for(k=1;k<=blocknum;k++)
    {
      theta = 1.0*((k-1)*avstep+1)/ffullcirc;
      rad = cvec[3];
      xb = cvec[1] + rad*cos(theta);
      yb = cvec[2] + rad*sin(theta);
      theta = 1.0*(k*avstep)/ffullcirc;
      xe = cvec[1] + rad*cos(theta);
      ye = cvec[2] + rad*sin(theta);
      /*MY BRAIN WILL EXPLODE*/
      if((xb>=1&&xb<=nx&&yb>=1&&yb<=ny)||(xe>=1&&xe<=nx&&ye>=1&&ye<=ny))
	{
	  circlegood[k] = 1;
	  for(j=1;j<=circborder;j++)
	    {
	      numpoints[j] = 0;
	      for(i=(k-1)*avstep+1;i<=k*avstep;i++)
		{
		  theta = 1.0*i/ffullcirc;
		  rad = cvec[3]-1.0*border + 1.0*(j-1);
		  xb = cvec[1] + rad*cos(theta);
		  yb = cvec[2] + rad*sin(theta);
		  ipx = xb+0.5;
		  ipy = yb+0.5;
		  if(ipx>=1&&ipx<=nx&&ipy>=1&&ipy<=ny)
		    {
		      numpoints[j]+=1;
		      avgbox[j][numpoints[j]] = image[ipx][ipy];
		    }
		}
	      if(numpoints[j]>=2)
		{
		  creepvec01(avgbox[j],numpoints[j],COLFUDGEREJ,&data1,&data2);
		  subvecs[k][j] = data1;
		}
	      else if(numpoints[j]==1)
		{
		  subvecs[k][j] = avgbox[j][1];
		}
	      else
		{
		  subvecs[k][j] = 0.0;
		}
	    }
	}
      else{
	circlegood[k] = 0;
      }
    }
  if(circlegood[1]==1)
    {
      for(j=1;j<=circborder;j++)
	{
	  for(i=1;i<=halfblock;i++)
	    {
	      theta = 1.0*i/ffullcirc;
	      rad = cvec[3]-1.0*border + 1.0*(j-1);
	      xb = cvec[1] + rad*cos(theta);
	      yb = cvec[2] + rad*sin(theta);
	      ipx = xb+0.5;
	      ipy = yb+0.5;
	      if(ipx>=1&&ipx<=nx&&ipy>=1&&ipy<=ny)
		{
		  image3[ipx][ipy] = subvecs[1][j];
		}
	    }
	}
    }
  if(circlegood[blocknum]==1)
    {
      for(j=1;j<=circborder;j++)
	{
	  for(i=(blocknum-1)*avstep+halfblock+1;i<=blocknum*avstep;i++)
	    {
	      if(i<=2*PI*ffullcirc)
		{
		  theta = 1.0*i/ffullcirc;
		  rad = cvec[3]-1.0*border + 1.0*(j-1);
		  xb = cvec[1] + rad*cos(theta);
		  yb = cvec[2] + rad*sin(theta);
		  ipx = xb+0.5;
		  ipy = yb+0.5;
		  if(ipx>=1&&ipx<=nx&&ipy>=1&&ipy<=ny)
		    {
		      image3[ipx][ipy] = subvecs[blocknum][j];
		    }
		}
	    }
	}
    }
  for(k=2;k<=blocknum-1;k++)
    {
      if(circlegood[k]==1)
	{
	  if(circlegood[k-1]==0&&circlegood[k+1]==0)
	    {
	      for(j=1;j<=circborder;j++)
		{
		  for(i=(k-1)*avstep+1;i<=k*avstep;i++)
		    {
		      theta = 1.0*i/ffullcirc;
		      rad = cvec[3]-1.0*border + 1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      if(ipx>=1&&ipx<=nx&&ipy>=1&&ipy<=ny)
			{
			  image3[ipx][ipy] = subvecs[k][j];
			}
		    }
		}
	    }
	  if(circlegood[k-1]==1&&circlegood[k+1]==0)
	    {
	      for(j=1;j<=circborder;j++)
		{
		  for(i=(k-1)*avstep+1;i<=(k-1)*avstep+halfblock;i++)
		    {
		      theta = 1.0*i/ffullcirc;
		      rad = cvec[3]-1.0*border + 1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      if(ipx>=1&&ipx<=nx&&ipy>=1&&ipy<=ny)
			{
			  image3[ipx][ipy] = subvecs[k-1][j] + (subvecs[k][j]-subvecs[k-1][j])*(1.0*i-1.0*((k-2)*avstep + halfblock))/(1.0*avstep);
			}
		    }
		}
	    }
	  if(circlegood[k-1]==0&&circlegood[k+1]==1)
	    {
	      for(j=1;j<=circborder;j++)
		{
		  for(i=(k-1)*avstep+halfblock+1;i<=k*avstep;i++)
		    {
		      theta = 1.0*i/ffullcirc;
		      rad = cvec[3]-1.0*border + 1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      if(ipx>=1&&ipx<=nx&&ipy>=1&&ipy<=ny)
			{
			  image3[ipx][ipy] = subvecs[k][j] + (subvecs[k+1][j]-subvecs[k-1][j])*(1.0*i-1.0*((k-1)*avstep + halfblock))/(1.0*avstep);
			}
		    }
		}
	    }
	  if(circlegood[k-1]==1&&circlegood[k+1]==1)
	    {
	      for(j=1;j<=circborder;j++)
		{
		  for(i=(k-1)*avstep+1;i<=(k-1)*avstep+halfblock;i++)
		    {
		      theta = 1.0*i/ffullcirc;
		      rad = cvec[3]-1.0*border + 1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      if(ipx>=1&&ipx<=nx&&ipy>=1&&ipy<=ny)
			{
			  image3[ipx][ipy] = subvecs[k-1][j] + (subvecs[k][j]-subvecs[k-1][j])*(1.0*i-1.0*((k-2)*avstep + halfblock))/(1.0*avstep);
			}
		    }
		  for(i=(k-1)*avstep+halfblock+1;i<=k*avstep;i++)
		    {
		      theta = 1.0*i/ffullcirc;
		      rad = cvec[3]-1.0*border + 1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      if(ipx>=1&&ipx<=nx&&ipy>=1&&ipy<=ny)
			{
			  image3[ipx][ipy] = subvecs[k][j] + (subvecs[k+1][j]-subvecs[k][j])*(1.0*i-1.0*((k-1)*avstep + halfblock))/(1.0*avstep);
			}
		    }
		}
	    }
	}
    }

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  data1 = data2 = 0.0;
	  if(image1[i][j]!=0.0)
	    {
	      data1+=1;
	      data2+=image1[i][j];
	    }
	  if(image2[i][j]!=0.0)
	    {
	      data1+=1;
	      data2+=image2[i][j];
	    }
	  if(image3[i][j]!=0.0)
	    {
	      data1+=1;
	      data2+=image3[i][j];
	    }
	  if(data1>0.0)
	    {
	      image1[i][j] = data2/data1;
	      image[i][j]-=data2/data1;
	    }
	}
    }
  free_matrix(subvecs,1,blocknum,1,circborder);
  free_ivector(circlegood,1,blocknum);
  free_ivector(numpoints,1,circborder);
  free_matrix(avgbox,1,circborder,1,avstep);

  writeim01(nx,ny,"junk01.txt",image1);

  free_matrix(image1,1,nx,1,ny);
  free_matrix(image2,1,nx,1,ny);
  free_matrix(image3,1,nx,1,ny);

  return(1);
}



/*zerotrim04: like zerotrim03 but does not
consider pixels that deviate from zero by more
than a set amount*/
int zerotrim04(float **image,int nx,int ny, int *ztvec,float *cvec,int border,int avstep)
{
  int i,j,k;
  float **image1,**image2,**image3,**avgbox,**subvecs;
  int blocknum,avstart,avend,halfblock,*circlegood,ipx,ipy;
  float data1,data2,rad,theta,px,py,xb,yb,xe,ye;

  avgbox = matrix(1,border,1,avstep);
  image1 = matrix(1,nx,1,ny);
  image2 = matrix(1,nx,1,ny);
  image3 = matrix(1,nx,1,ny);

  halfblock = avstep/2;
  imzero(image1,nx,ny);
  imzero(image2,nx,ny);
  imzero(image3,nx,ny);

  /*Horizontal Borders Along Top and Bottom*/

  /*x ranges from ztvec[1]+1 up to nx-ztvec[2]*/
  blocknum = (nx-ztvec[2]-ztvec[1])/avstep + 1;
  /*bottom*/
  subvecs = matrix(1,blocknum,1,border);
  for(k=1;k<=blocknum;k++)
    {
      printf("k = %d\n",k);
      fflush(stdout);
      avstart = ztvec[1] + (k-1)*avstep + 1;
      avend = ztvec[1] + k*avstep;
      if(avend>nx-ztvec[2])
	{
	  avend = nx-ztvec[2];
	}
      for(j=ztvec[3]+1;j<=ztvec[3]+border;j++)
	{
	  for(i=avstart;i<=avend;i++)
	    {
	      avgbox[j-ztvec[3]][i-avstart+1] = image[i][j];
	    }
	  creepvec01(avgbox[j-ztvec[3]],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	  subvecs[k][j-ztvec[3]] = data1;
	}
    }
  for(i=ztvec[1]+1;i<=ztvec[1]+halfblock;i++)
    {
      for(j=ztvec[3]+1;j<=ztvec[3]+border;j++)
	{
	  image1[i][j] = subvecs[1][j-ztvec[3]];
	}
    }
  for(k=1;k<=blocknum-1;k++)
    {
      for(i=ztvec[1]+(k-1)*avstep+halfblock+1;i<=ztvec[1]+k*avstep+halfblock;i++)
	{
	  for(j=ztvec[3]+1;j<=ztvec[3]+border;j++)
	    {
	      if(i<=nx-ztvec[2])
		{
		  image1[i][j] = subvecs[k][j-ztvec[3]] + (subvecs[k+1][j-ztvec[3]] - subvecs[k][j-ztvec[3]])*(1.0*i-1.0*(ztvec[1]+(k-1)*avstep+halfblock))/(1.0*avstep-1.0);
		}
	    }
	}
    }

  printf("Did bottom OK\n");
  fflush(stdout);

  for(i=ztvec[1]+(blocknum-1)*avstep+halfblock+1;i<=nx-ztvec[2];i++)
    {
      for(j=ztvec[3]+1;j<=ztvec[3]+border;j++)
	{
	  image1[i][j] = subvecs[k][j-ztvec[3]];
	}
    }

  /*top*/
  for(k=1;k<=blocknum;k++)
    {
      avstart = ztvec[1] + (k-1)*avstep + 1;
      avend = ztvec[1] + k*avstep;
      if(avend>nx-ztvec[2])
	{
	  avend = nx-ztvec[2];
	}
      for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4];j++)
	{
	  for(i=avstart;i<=avend;i++)
	    {
	      avgbox[j-(ny-ztvec[4]+1-border)+1][i-avstart+1] = image[i][j];
	    }
	  creepvec01(avgbox[j-(ny-ztvec[4]+1-border)+1],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	  subvecs[k][j-(ny-ztvec[4]+1-border)+1] = data1;
	}
    }
  for(i=ztvec[1]+1;i<=ztvec[1]+halfblock;i++)
    {
      for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4];j++)
	{
	  image1[i][j] = subvecs[1][j-(ny-ztvec[4]+1-border)+1];
	}
    }
  for(k=1;k<=blocknum-1;k++)
    {
      for(i=ztvec[1]+(k-1)*avstep+halfblock+1;i<=ztvec[1]+k*avstep+halfblock;i++)
	{
	  for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4];j++)
	    {
	      if(i<=nx-ztvec[2])
		{
		  image1[i][j] = subvecs[k][j-(ny-ztvec[4]+1-border)+1] + (subvecs[k+1][j-(ny-ztvec[4]+1-border)+1] - subvecs[k][j-(ny-ztvec[4]+1-border)+1])*(1.0*i-1.0*(ztvec[1]+(k-1)*avstep+halfblock))/(1.0*avstep-1.0);
		}
	    }
	}
    }

  for(i=ztvec[1]+(blocknum-1)*avstep+halfblock+1;i<=nx-ztvec[2];i++)
    {
      for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4];j++)
	{
	  image1[i][j] = subvecs[k][j-(ny-ztvec[4]+1-border)+1];
	}
    }

  free_matrix(subvecs,1,blocknum,1,border);

  printf("Did top OK\n");
  fflush(stdout);

  /*Vertical Borders at Left and Right*/
  /*y ranges from ztvec[3]+1 to ny-ztvec[4]*/
  blocknum = (ny-ztvec[4]-ztvec[3])/avstep + 1;
  subvecs = matrix(1,blocknum,1,border);
  /*left side*/
  for(k=1;k<=blocknum;k++)
    {
      avstart = ztvec[3] + (k-1)*avstep + 1;
      avend = ztvec[3] + k*avstep;
      if(avend>ny-ztvec[4])
	{
	  avend = ny-ztvec[4];
	}
      for(i=ztvec[1]+1;i<=ztvec[1]+border;i++)
	{
	  for(j=avstart;j<=avend;j++)
	    {
	      avgbox[i-ztvec[1]][j-avstart+1] = image[i][j];
	    }
	  creepvec01(avgbox[i-ztvec[1]],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	  subvecs[k][i-ztvec[1]] = data1;
	}
    }
  for(j=ztvec[3]+1;j<=ztvec[3]+halfblock;j++)
    {
      for(i=ztvec[1]+1;i<=ztvec[1]+border;i++)
	{
	  image2[i][j] = subvecs[1][i-ztvec[1]];
	}
    }

  for(k=1;k<=blocknum-1;k++)
    {
      for(j=ztvec[3]+(k-1)*avstep+halfblock+1;j<=ztvec[3]+k*avstep+halfblock;j++)
	{
	  for(i=ztvec[1]+1;i<=ztvec[1]+border;i++)
	    {
	      if(j<=ny-ztvec[4])
		{
		  image2[i][j] = subvecs[k][i-ztvec[1]] + (subvecs[k+1][i-ztvec[1]] - subvecs[k][i-ztvec[1]])*(1.0*j-1.0*(ztvec[3]+(k-1)*avstep+halfblock+1))/(1.0*avstep-1.0);
													       
		}
	    }
	}
    }
     
  for(j=ztvec[3]+(blocknum-1)*avstep+halfblock+1;j<=ny-ztvec[4];j++)
    {
      for(i=ztvec[1]+1;i<=ztvec[1]+border;i++)
	{
	  image2[i][j] = subvecs[k][i-ztvec[1]];
	}
    }

  /*right side*/
  for(k=1;k<=blocknum;k++)
    {
      avstart = ztvec[3] + (k-1)*avstep + 1;
      avend = ztvec[3] + k*avstep;
      if(avend>ny-ztvec[4])
	{
	  avend = ny-ztvec[4];
	}
      for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2];i++)
	{
	  for(j=avstart;j<=avend;j++)
	    {
	      avgbox[i-(nx-ztvec[2]-border+1)+1][j-avstart+1] = image[i][j];
	    }
	  creepvec01(avgbox[i-(nx-ztvec[2]-border+1)+1],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	  subvecs[k][i-(nx-ztvec[2]-border+1)+1] = data1;
	}
    }
  for(j=ztvec[3]+1;j<=ztvec[3]+halfblock;j++)
    {
      for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2];i++)
	{
	  image2[i][j] = subvecs[1][i-(nx-ztvec[2]-border+1)+1];
	}
    }
  for(k=1;k<=blocknum-1;k++)
    {
      for(j=ztvec[3]+(k-1)*avstep+halfblock+1;j<=ztvec[3]+k*avstep+halfblock;j++)
	{
	  for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2];i++)
	    {
	      if(j<=ny-ztvec[4])
		{
		  image2[i][j] = subvecs[k][i-(nx-ztvec[2]-border+1)+1] + (subvecs[k+1][i-(nx-ztvec[2]-border+1)+1] - subvecs[k][i-(nx-ztvec[2]-border+1)+1])*(1.0*j-1.0*(ztvec[3]+(k-1)*avstep+halfblock+1))/(1.0*avstep-1.0);
		}
	    }
	}
    }

  for(j=ztvec[3]+(blocknum-1)*avstep+halfblock+1;j<=ny-ztvec[4];j++)
    {
      for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2];i++)
	{
	  image2[i][j] = subvecs[k][i-(nx-ztvec[2]-border+1)+1];
	}
    }


  free_matrix(subvecs,1,blocknum,1,border);


  /*Circular cut*/
  blocknum = 2.0*PI*cvec[3]/avstep + 1;
  subvecs = matrix(1,blocknum,1,border);
  circlegood = ivector(1,blocknum);

  for(k=1;k<=blocknum;k++)
    {
      theta = 1.0*((k-1)*avstep+1)/cvec[3];
      rad = cvec[3];
      xb = cvec[1] + rad*cos(theta);
      yb = cvec[2] + rad*sin(theta);
      theta = 1.0*(k*avstep)/cvec[3];
      xe = cvec[1] + rad*cos(theta);
      ye = cvec[2] + rad*sin(theta);
      if(xb>ztvec[1]&&xe>ztvec[1]&&xb<=nx-ztvec[2]&&xe<=nx-ztvec[2]&&yb>ztvec[3]&&ye>ztvec[3]&&yb<=ny-ztvec[4]&&ye<=ny-ztvec[4])
	{
	  circlegood[k] = 1;
	  for(j=1;j<=border;j++)
	    {
	      for(i=(k-1)*avstep+1;i<=k*avstep;i++)
		{
		  theta = 1.0*i/cvec[3];
		  rad = cvec[3]-1.0*(j-1);
		  xb = cvec[1] + rad*cos(theta);
		  yb = cvec[2] + rad*sin(theta);
		  ipx = xb+0.5;
		  ipy = yb+0.5;
		  avgbox[j][i-((k-1)*avstep+1)+1] = image[ipx][ipy];
		}
	      creepvec01(avgbox[j],avstep,COLFUDGEREJ,&data1,&data2);
	      subvecs[k][j] = data1;
	    }
	}
      else{
	circlegood[k] = 0;
      }
    }
  if(circlegood[1]==1)
    {
      for(j=1;j<=border;j++)
	{
	  for(i=1;i<=halfblock;i++)
	    {
	      theta = 1.0*i/cvec[3];
	      rad = cvec[3]-1.0*(j-1);
	      xb = cvec[1] + rad*cos(theta);
	      yb = cvec[2] + rad*sin(theta);
	      ipx = xb+0.5;
	      ipy = yb+0.5;
	      image3[ipx][ipy] = subvecs[1][j];
	    }
	}
    }
  if(circlegood[blocknum]==1)
    {
      for(j=1;j<=border;j++)
	{
	  for(i=(blocknum-1)*avstep+halfblock+1;i<=blocknum*avstep;i++)
	    {
	      if(i<=2*PI*cvec[3])
		{
		  theta = 1.0*i/cvec[3];
		  rad = cvec[3]-1.0*(j-1);
		  xb = cvec[1] + rad*cos(theta);
		  yb = cvec[2] + rad*sin(theta);
		  ipx = xb+0.5;
		  ipy = yb+0.5;
		  image3[ipx][ipy] = subvecs[blocknum][j];
		}
	    }
	}
    }
  for(k=2;k<=blocknum-1;k++)
    {
      if(circlegood[k]==1)
	{
	  if(circlegood[k-1]==0&&circlegood[k+1]==0)
	    {
	      for(j=1;j<=border;j++)
		{
		  for(i=(k-1)*avstep+1;i<=k*avstep;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k][j];
		    }
		}
	    }
	  if(circlegood[k-1]==1&&circlegood[k+1]==0)
	    {
	      for(j=1;j<=border;j++)
		{
		  for(i=(k-1)*avstep+1;i<=(k-1)*avstep+halfblock;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k-1][j] + (subvecs[k][j]-subvecs[k-1][j])*(1.0*i-1.0*((k-2)*avstep + halfblock))/(1.0*avstep);
		    }
		}
	    }
	  if(circlegood[k-1]==0&&circlegood[k+1]==1)
	    {
	      for(j=1;j<=border;j++)
		{
		  for(i=(k-1)*avstep+halfblock+1;i<=k*avstep;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k][j] + (subvecs[k+1][j]-subvecs[k-1][j])*(1.0*i-1.0*((k-1)*avstep + halfblock))/(1.0*avstep);
		    }
		}
	    }
	  if(circlegood[k-1]==1&&circlegood[k+1]==1)
	    {
	      for(j=1;j<=border;j++)
		{
		  for(i=(k-1)*avstep+1;i<=(k-1)*avstep+halfblock;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k-1][j] + (subvecs[k][j]-subvecs[k-1][j])*(1.0*i-1.0*((k-2)*avstep + halfblock))/(1.0*avstep);
		    }
		  for(i=(k-1)*avstep+halfblock+1;i<=k*avstep;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k][j] + (subvecs[k+1][j]-subvecs[k][j])*(1.0*i-1.0*((k-1)*avstep + halfblock))/(1.0*avstep);
		    }
		}
	    }
	}
    }

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  data1 = data2 = 0.0;
	  if(image1[i][j]!=0.0)
	    {
	      data1+=1;
	      data2+=image1[i][j];
	    }
	  if(image2[i][j]!=0.0)
	    {
	      data1+=1;
	      data2+=image2[i][j];
	    }
	  if(image3[i][j]!=0.0)
	    {
	      data1+=1;
	      data2+=image3[i][j];
	    }
	  if(data1>0.0)
	    {
	      image1[i][j] = data2/data1;
	      image[i][j]-=data2/data1;
	    }
	}
    }
  free_matrix(subvecs,1,blocknum,1,border);
  free_ivector(circlegood,1,blocknum);

  writeim01(nx,ny,"junk01.txt",image1);

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  if(i<=ztvec[1]||i>=nx-ztvec[2]+1||j<=ztvec[3]||j>=ny-ztvec[4]+1)
	    {
	      image[i][j] = 0.0;
	    }
	  if(pow(pow(1.0*i-cvec[1],2.0)+pow(1.0*j-cvec[2],2.0),0.5)>=cvec[3])
	    {
	      image[i][j] = 0.0;
	    }
	}
    }

  free_matrix(avgbox,1,border,1,avstep);
  free_matrix(image1,1,nx,1,ny);
  free_matrix(image2,1,nx,1,ny);
  free_matrix(image3,1,nx,1,ny);

  return(1);
}


/*zerotrim05: Like zerotrim03, except that it allows
the zero subtraction to fade over a fade length fadelen,
so that in cases where it has been subtracting the halo of
a bright star, there will be no hard edges in the image.
zerotrim05 also allows the calling function to supply
a limit lim, which sets the maximum deviation from zero
that zerotrim05 will allow in its input image.  If the
pixel is more than lim away from zero, zerotrim05
considers it to be zero.  Of course, lim can easily be
set so high that it has no effect, if desired.*/
int zerotrim05(float **image,int nx,int ny, int *ztvec,float *cvec,int bord,int avstep,int fadelen,float lim)
{
  int i,j,k,border;
  float **image1,**image2,**image3,**avgbox,**subvecs;
  int blocknum,avstart,avend,halfblock,*circlegood,ipx,ipy;
  float data1,data2,rad,theta,px,py,xb,yb,xe,ye;


  border = bord+fadelen;

  avgbox = matrix(1,border,1,avstep);
  image1 = matrix(1,nx,1,ny);
  image2 = matrix(1,nx,1,ny);
  image3 = matrix(1,nx,1,ny);

  halfblock = avstep/2;
  imzero(image1,nx,ny);
  imzero(image2,nx,ny);
  imzero(image3,nx,ny);

  printf("zerotrim05 has recieved limit = %f\n",lim);

  /*Horizontal Borders Along Top and Bottom*/

  /*x ranges from ztvec[1]+1 up to nx-ztvec[2]*/
  blocknum = (nx-ztvec[2]-ztvec[1])/avstep + 1;
  /*bottom*/
  subvecs = matrix(1,blocknum,1,border);
  for(k=1;k<=blocknum;k++)
    {
      printf("k = %d\n",k);
      fflush(stdout);
      avstart = ztvec[1] + (k-1)*avstep + 1;
      avend = ztvec[1] + k*avstep;
      if(avend>nx-ztvec[2])
	{
	  avend = nx-ztvec[2];
	}
      for(j=ztvec[3]+1;j<=ztvec[3]+border;j++)
	{
	  for(i=avstart;i<=avend;i++)
	    {
	      if(pow(pow(image[i][j],2.0),0.5)<=lim)
		{
		  avgbox[j-ztvec[3]][i-avstart+1] = image[i][j];
		}
	      else{
		avgbox[j-ztvec[3]][i-avstart+1] = 0.0;
	      }
	    }
	  creepvec01(avgbox[j-ztvec[3]],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	  subvecs[k][j-ztvec[3]] = data1;
	}
    }
  for(i=ztvec[1]+1;i<=ztvec[1]+halfblock;i++)
    {
      for(j=ztvec[3]+1;j<=ztvec[3]+bord;j++)
	{
	  image1[i][j] = subvecs[1][j-ztvec[3]];
	}
      for(j=ztvec[3]+bord+1;j<=ztvec[3]+border;j++)
	{
	  image1[i][j] = (subvecs[1][j-ztvec[3]])*(1.0*ztvec[3]+1.0*border-1.0*j)/(1.0*fadelen);
	}
    }
  for(k=1;k<=blocknum-1;k++)
    {
      for(i=ztvec[1]+(k-1)*avstep+halfblock+1;i<=ztvec[1]+k*avstep+halfblock;i++)
	{
	  for(j=ztvec[3]+1;j<=ztvec[3]+bord;j++)
	    {
	      if(i<=nx-ztvec[2])
		{
		  image1[i][j] = subvecs[k][j-ztvec[3]] + (subvecs[k+1][j-ztvec[3]] - subvecs[k][j-ztvec[3]])*(1.0*i-1.0*(ztvec[1]+(k-1)*avstep+halfblock))/(1.0*avstep-1.0);
		}
	    }
	  for(j=ztvec[3]+bord+1;j<=ztvec[3]+border;j++)
	    {
	      if(i<=nx-ztvec[2])
		{
		  image1[i][j] = (subvecs[k][j-ztvec[3]] + (subvecs[k+1][j-ztvec[3]] - subvecs[k][j-ztvec[3]])*(1.0*i-1.0*(ztvec[1]+(k-1)*avstep+halfblock))/(1.0*avstep-1.0))*(1.0*(ztvec[3]+border)-1.0*j)/(1.0*fadelen);
		}
	    }

	}
    }

  printf("Did bottom OK\n");
  fflush(stdout);

  for(i=ztvec[1]+(blocknum-1)*avstep+halfblock+1;i<=nx-ztvec[2];i++)
    {
      for(j=ztvec[3]+1;j<=ztvec[3]+bord;j++)
	{
	  image1[i][j] = subvecs[k][j-ztvec[3]];
	}
      for(j=ztvec[3]+bord+1;j<=ztvec[3]+border;j++)
	{
	  image1[i][j] = (subvecs[k][j-ztvec[3]])*(1.0*ztvec[3]+1.0*border - 1.0*j)/(1.0*fadelen);
	}

    }

  /*top*/
  for(k=1;k<=blocknum;k++)
    {
      avstart = ztvec[1] + (k-1)*avstep + 1;
      avend = ztvec[1] + k*avstep;
      if(avend>nx-ztvec[2])
	{
	  avend = nx-ztvec[2];
	}
      for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4];j++)
	{
	  for(i=avstart;i<=avend;i++)
	    {
	      if(pow(pow(image[i][j],2.0),0.5)<=lim)
		{
		  avgbox[j-(ny-ztvec[4]+1-border)+1][i-avstart+1] = image[i][j];
		}
	      else{
		avgbox[j-(ny-ztvec[4]+1-border)+1][i-avstart+1] = 0.0;
	      }
	    }
	  creepvec01(avgbox[j-(ny-ztvec[4]+1-border)+1],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	  subvecs[k][j-(ny-ztvec[4]+1-border)+1] = data1;
	}
    }
  for(i=ztvec[1]+1;i<=ztvec[1]+halfblock;i++)
    {
      for(j=ny-ztvec[4]+1-bord;j<=ny-ztvec[4];j++)
	{
	  image1[i][j] = subvecs[1][j-(ny-ztvec[4]+1-border)+1];
	}
      for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4]-bord;j++)
	{
	  image1[i][j] = (subvecs[1][j-(ny-ztvec[4]+1-border)+1])*(1.0*j-1.0*(ny-ztvec[4]+1-border))/(1.0*fadelen);
	}
    }
  for(k=1;k<=blocknum-1;k++)
    {
      for(i=ztvec[1]+(k-1)*avstep+halfblock+1;i<=ztvec[1]+k*avstep+halfblock;i++)
	{
	  for(j=ny-ztvec[4]+1-bord;j<=ny-ztvec[4];j++)
	    {
	      if(i<=nx-ztvec[2])
		{
		  image1[i][j] = subvecs[k][j-(ny-ztvec[4]+1-border)+1] + (subvecs[k+1][j-(ny-ztvec[4]+1-border)+1] - subvecs[k][j-(ny-ztvec[4]+1-border)+1])*(1.0*i-1.0*(ztvec[1]+(k-1)*avstep+halfblock))/(1.0*avstep-1.0);
		}
	    }
	  for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4]-bord;j++)
	    {
	      if(i<=nx-ztvec[2])
		{
		  image1[i][j] = (subvecs[k][j-(ny-ztvec[4]+1-border)+1] + (subvecs[k+1][j-(ny-ztvec[4]+1-border)+1] - subvecs[k][j-(ny-ztvec[4]+1-border)+1])*(1.0*i-1.0*(ztvec[1]+(k-1)*avstep+halfblock))/(1.0*avstep-1.0))*(1.0*j-1.0*(ny-ztvec[4]+1-border))/(1.0*fadelen);
		}
	    }
	}
    }

  for(i=ztvec[1]+(blocknum-1)*avstep+halfblock+1;i<=nx-ztvec[2];i++)
    {
      for(j=ny-ztvec[4]+1-bord;j<=ny-ztvec[4];j++)
	{
	  image1[i][j] = subvecs[k][j-(ny-ztvec[4]+1-border)+1];
	}
      for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4]-bord;j++)
	{
	  image1[i][j] = (subvecs[k][j-(ny-ztvec[4]+1-border)+1])*(1.0*j-1.0*(ny-ztvec[4]+1-border))/(1.0*fadelen);
	}
    }

  free_matrix(subvecs,1,blocknum,1,border);

  printf("Did top OK\n");
  fflush(stdout);

  /*Vertical Borders at Left and Right*/
  /*y ranges from ztvec[3]+1 to ny-ztvec[4]*/
  blocknum = (ny-ztvec[4]-ztvec[3])/avstep + 1;
  subvecs = matrix(1,blocknum,1,border);
  /*left side*/
  for(k=1;k<=blocknum;k++)
    {
      avstart = ztvec[3] + (k-1)*avstep + 1;
      avend = ztvec[3] + k*avstep;
      if(avend>ny-ztvec[4])
	{
	  avend = ny-ztvec[4];
	}
      for(i=ztvec[1]+1;i<=ztvec[1]+border;i++)
	{
	  for(j=avstart;j<=avend;j++)
	    {
	      if(pow(pow(image[i][j],2.0),0.5)<=lim)
		{
		  avgbox[i-ztvec[1]][j-avstart+1] = image[i][j];
		}
	      else{
		avgbox[i-ztvec[1]][j-avstart+1] = 0.0;
	      }
	    }
	  creepvec01(avgbox[i-ztvec[1]],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	  subvecs[k][i-ztvec[1]] = data1;
	}
    }
  for(j=ztvec[3]+1;j<=ztvec[3]+halfblock;j++)
    {
      for(i=ztvec[1]+1;i<=ztvec[1]+bord;i++)
	{
	  image2[i][j] = subvecs[1][i-ztvec[1]];
	}
      for(i=ztvec[1]+bord+1;i<=ztvec[1]+border;i++)
	{
	  image2[i][j] = (subvecs[1][i-ztvec[1]])*(1.0*(ztvec[1]+border)-1.0*i)/(1.0*fadelen);
	}
    }

  for(k=1;k<=blocknum-1;k++)
    {
      for(j=ztvec[3]+(k-1)*avstep+halfblock+1;j<=ztvec[3]+k*avstep+halfblock;j++)
	{
	  for(i=ztvec[1]+1;i<=ztvec[1]+bord;i++)
	    {
	      if(j<=ny-ztvec[4])
		{
		  image2[i][j] = subvecs[k][i-ztvec[1]] + (subvecs[k+1][i-ztvec[1]] - subvecs[k][i-ztvec[1]])*(1.0*j-1.0*(ztvec[3]+(k-1)*avstep+halfblock+1))/(1.0*avstep-1.0);
													       
		}
	    }
	  for(i=ztvec[1]+bord+1;i<=ztvec[1]+border;i++)
	    {
	      if(j<=ny-ztvec[4])
		{
		  image2[i][j] = (subvecs[k][i-ztvec[1]] + (subvecs[k+1][i-ztvec[1]] - subvecs[k][i-ztvec[1]])*(1.0*j-1.0*(ztvec[3]+(k-1)*avstep+halfblock+1))/(1.0*avstep-1.0))*(1.0*(ztvec[1]+border)-1.0*i)/(1.0*fadelen);
													       
		}
	    }
	}
    }
     
  for(j=ztvec[3]+(blocknum-1)*avstep+halfblock+1;j<=ny-ztvec[4];j++)
    {
      for(i=ztvec[1]+1;i<=ztvec[1]+bord;i++)
	{
	  image2[i][j] = subvecs[k][i-ztvec[1]];
	}
      for(i=ztvec[1]+bord+1;i<=ztvec[1]+border;i++)
	{
	  image2[i][j] = (subvecs[k][i-ztvec[1]])*(1.0*(ztvec[1]+border)-1.0*i)/(1.0*fadelen);
	}
    }

  /*right side*/
  for(k=1;k<=blocknum;k++)
    {
      avstart = ztvec[3] + (k-1)*avstep + 1;
      avend = ztvec[3] + k*avstep;
      if(avend>ny-ztvec[4])
	{
	  avend = ny-ztvec[4];
	}
      for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2];i++)
	{
	  for(j=avstart;j<=avend;j++)
	    {
	      if(pow(pow(image[i][j],2.0),0.5)<=lim)
		{
		  avgbox[i-(nx-ztvec[2]-border+1)+1][j-avstart+1] = image[i][j];
		}
	      else{
		avgbox[i-(nx-ztvec[2]-border+1)+1][j-avstart+1] = 0.0;
	      }
	    }
	  creepvec01(avgbox[i-(nx-ztvec[2]-border+1)+1],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	  subvecs[k][i-(nx-ztvec[2]-border+1)+1] = data1;
	}
    }
  for(j=ztvec[3]+1;j<=ztvec[3]+halfblock;j++)
    {
      for(i=nx-ztvec[2]-bord+1;i<=nx-ztvec[2];i++)
	{
	  image2[i][j] = subvecs[1][i-(nx-ztvec[2]-border+1)+1];
	}
      for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2]-bord;i++)
	{
	  image2[i][j] = subvecs[1][i-(nx-ztvec[2]-border+1)+1]*(1.0*i-1.0*(nx-ztvec[2]-border+1))/(1.0*fadelen);
	}
    }
  for(k=1;k<=blocknum-1;k++)
    {
      for(j=ztvec[3]+(k-1)*avstep+halfblock+1;j<=ztvec[3]+k*avstep+halfblock;j++)
	{
	  for(i=nx-ztvec[2]-bord+1;i<=nx-ztvec[2];i++)
	    {
	      if(j<=ny-ztvec[4])
		{
		  image2[i][j] = subvecs[k][i-(nx-ztvec[2]-border+1)+1] + (subvecs[k+1][i-(nx-ztvec[2]-border+1)+1] - subvecs[k][i-(nx-ztvec[2]-border+1)+1])*(1.0*j-1.0*(ztvec[3]+(k-1)*avstep+halfblock+1))/(1.0*avstep-1.0);
		}
	    }
	  for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2]-bord;i++)
	    {
	      if(j<=ny-ztvec[4])
		{
		  image2[i][j] = (subvecs[k][i-(nx-ztvec[2]-border+1)+1] + (subvecs[k+1][i-(nx-ztvec[2]-border+1)+1] - subvecs[k][i-(nx-ztvec[2]-border+1)+1])*(1.0*j-1.0*(ztvec[3]+(k-1)*avstep+halfblock+1))/(1.0*avstep-1.0))*(1.0*i-1.0*(nx-ztvec[2]-border+1))/(1.0*fadelen);
		}
	    }
	}
    }

  for(j=ztvec[3]+(blocknum-1)*avstep+halfblock+1;j<=ny-ztvec[4];j++)
    {
      for(i=nx-ztvec[2]-bord+1;i<=nx-ztvec[2];i++)
	{
	  image2[i][j] = subvecs[k][i-(nx-ztvec[2]-border+1)+1];
	}
      for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2]-bord;i++)
	{
	  image2[i][j] = (subvecs[k][i-(nx-ztvec[2]-border+1)+1])*(1.0*i-1.0*(nx-ztvec[2]-border+1))/(1.0*fadelen);
	}
    }


  free_matrix(subvecs,1,blocknum,1,border);


  /*Circular cut*/
  blocknum = 2.0*PI*cvec[3]/avstep + 1;
  subvecs = matrix(1,blocknum,1,border);
  circlegood = ivector(1,blocknum);

  for(k=1;k<=blocknum;k++)
    {
      theta = 1.0*((k-1)*avstep+1)/cvec[3];
      rad = cvec[3];
      xb = cvec[1] + rad*cos(theta);
      yb = cvec[2] + rad*sin(theta);
      theta = 1.0*(k*avstep)/cvec[3];
      xe = cvec[1] + rad*cos(theta);
      ye = cvec[2] + rad*sin(theta);
      if(xb>ztvec[1]&&xe>ztvec[1]&&xb<=nx-ztvec[2]&&xe<=nx-ztvec[2]&&yb>ztvec[3]&&ye>ztvec[3]&&yb<=ny-ztvec[4]&&ye<=ny-ztvec[4])
	{
	  circlegood[k] = 1;
	  for(j=1;j<=border;j++)
	    {
	      for(i=(k-1)*avstep+1;i<=k*avstep;i++)
		{
		  theta = 1.0*i/cvec[3];
		  rad = cvec[3]-1.0*(j-1);
		  xb = cvec[1] + rad*cos(theta);
		  yb = cvec[2] + rad*sin(theta);
		  ipx = xb+0.5;
		  ipy = yb+0.5;
		  if(pow(pow(image[ipx][ipy],2.0),0.5)<lim)
		    {
		      avgbox[j][i-((k-1)*avstep+1)+1] = image[ipx][ipy];
		    }
		  else{
		    avgbox[j][i-((k-1)*avstep+1)+1] = 0.0;
		  }
		}
	      creepvec01(avgbox[j],avstep,COLFUDGEREJ,&data1,&data2);
	      subvecs[k][j] = data1;
	    }
	}
      else{
	circlegood[k] = 0;
      }
    }
  if(circlegood[1]==1)
    {
      for(j=1;j<=bord;j++)
	{
	  for(i=1;i<=halfblock;i++)
	    {
	      theta = 1.0*i/cvec[3];
	      rad = cvec[3]-1.0*(j-1);
	      xb = cvec[1] + rad*cos(theta);
	      yb = cvec[2] + rad*sin(theta);
	      ipx = xb+0.5;
	      ipy = yb+0.5;
	      image3[ipx][ipy] = subvecs[1][j];
	    }
	}
      for(j=bord+1;j<=border;j++)
	{
	  for(i=1;i<=halfblock;i++)
	    {
	      theta = 1.0*i/cvec[3];
	      rad = cvec[3]-1.0*(j-1);
	      xb = cvec[1] + rad*cos(theta);
	      yb = cvec[2] + rad*sin(theta);
	      ipx = xb+0.5;
	      ipy = yb+0.5;
	      image3[ipx][ipy] = subvecs[1][j]*(1.0*border-1.0*j)/(1.0*fadelen);
	    }
	}
    }
  if(circlegood[blocknum]==1)
    {
      for(j=1;j<=bord;j++)
	{
	  for(i=(blocknum-1)*avstep+halfblock+1;i<=blocknum*avstep;i++)
	    {
	      if(i<=2*PI*cvec[3])
		{
		  theta = 1.0*i/cvec[3];
		  rad = cvec[3]-1.0*(j-1);
		  xb = cvec[1] + rad*cos(theta);
		  yb = cvec[2] + rad*sin(theta);
		  ipx = xb+0.5;
		  ipy = yb+0.5;
		  image3[ipx][ipy] = subvecs[blocknum][j];
		}
	    }
	}
      for(j=bord+1;j<=border;j++)
	{
	  for(i=(blocknum-1)*avstep+halfblock+1;i<=blocknum*avstep;i++)
	    {
	      if(i<=2*PI*cvec[3])
		{
		  theta = 1.0*i/cvec[3];
		  rad = cvec[3]-1.0*(j-1);
		  xb = cvec[1] + rad*cos(theta);
		  yb = cvec[2] + rad*sin(theta);
		  ipx = xb+0.5;
		  ipy = yb+0.5;
		  image3[ipx][ipy] = subvecs[blocknum][j]*(1.0*border-1.0*j)/(1.0*fadelen);
		}
	    }
	}
    }
  for(k=2;k<=blocknum-1;k++)
    {
      if(circlegood[k]==1)
	{
	  if(circlegood[k-1]==0&&circlegood[k+1]==0)
	    {
	      for(j=1;j<=bord;j++)
		{
		  for(i=(k-1)*avstep+1;i<=k*avstep;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k][j];
		    }
		}
	      for(j=bord+1;j<=border;j++)
		{
		  for(i=(k-1)*avstep+1;i<=k*avstep;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k][j]*(1.0*border-1.0*j);
		    }
		}
	    }
	  if(circlegood[k-1]==1&&circlegood[k+1]==0)
	    {
	      for(j=1;j<=bord;j++)
		{
		  for(i=(k-1)*avstep+1;i<=(k-1)*avstep+halfblock;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k-1][j] + (subvecs[k][j]-subvecs[k-1][j])*(1.0*i-1.0*((k-2)*avstep + halfblock))/(1.0*avstep);
		    }
		}
	      for(j=bord+1;j<=border;j++)
		{
		  for(i=(k-1)*avstep+1;i<=(k-1)*avstep+halfblock;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = (subvecs[k-1][j] + (subvecs[k][j]-subvecs[k-1][j])*(1.0*i-1.0*((k-2)*avstep + halfblock))/(1.0*avstep))*(1.0*border-1.0*j);
		    }
		}
	    }
	  if(circlegood[k-1]==0&&circlegood[k+1]==1)
	    {
	      for(j=1;j<=bord;j++)
		{
		  for(i=(k-1)*avstep+halfblock+1;i<=k*avstep;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k][j] + (subvecs[k+1][j]-subvecs[k-1][j])*(1.0*i-1.0*((k-1)*avstep + halfblock))/(1.0*avstep);
		    }
		}
	      for(j=bord+1;j<=border;j++)
		{
		  for(i=(k-1)*avstep+halfblock+1;i<=k*avstep;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = (subvecs[k][j] + (subvecs[k+1][j]-subvecs[k-1][j])*(1.0*i-1.0*((k-1)*avstep + halfblock))/(1.0*avstep))*(1.0*border-1.0*j)/(1.0*fadelen);
		    }
		}
	    }
	  if(circlegood[k-1]==1&&circlegood[k+1]==1)
	    {
	      for(j=1;j<=bord;j++)
		{
		  for(i=(k-1)*avstep+1;i<=(k-1)*avstep+halfblock;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k-1][j] + (subvecs[k][j]-subvecs[k-1][j])*(1.0*i-1.0*((k-2)*avstep + halfblock))/(1.0*avstep);
		    }
		  for(i=(k-1)*avstep+halfblock+1;i<=k*avstep;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k][j] + (subvecs[k+1][j]-subvecs[k][j])*(1.0*i-1.0*((k-1)*avstep + halfblock))/(1.0*avstep);
		    }
		}
	      for(j=bord+1;j<=border;j++)
		{
		  for(i=(k-1)*avstep+1;i<=(k-1)*avstep+halfblock;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = (subvecs[k-1][j] + (subvecs[k][j]-subvecs[k-1][j])*(1.0*i-1.0*((k-2)*avstep + halfblock))/(1.0*avstep))*(1.0*border-1.0*j)/(1.0*fadelen);
		    }
		  for(i=(k-1)*avstep+halfblock+1;i<=k*avstep;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = (subvecs[k][j] + (subvecs[k+1][j]-subvecs[k][j])*(1.0*i-1.0*((k-1)*avstep + halfblock))/(1.0*avstep))*(1.0*border-1.0*j)/(1.0*fadelen);
		    }
		}
	    }
	}
    }

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  data1 = data2 = 0.0;
	  if(image1[i][j]!=0.0)
	    {
	      data1+=1;
	      data2+=image1[i][j];
	    }
	  if(image2[i][j]!=0.0)
	    {
	      data1+=1;
	      data2+=image2[i][j];
	    }
	  if(image3[i][j]!=0.0)
	    {
	      data1+=1;
	      data2+=image3[i][j];
	    }
	  if(data1>0.0)
	    {
	      image1[i][j] = data2/data1;
	      image[i][j]-=data2/data1;
	    }
	}
    }
  free_matrix(subvecs,1,blocknum,1,border);
  free_ivector(circlegood,1,blocknum);

  writeim01(nx,ny,"junk01.txt",image1);

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  if(i<=ztvec[1]||i>=nx-ztvec[2]+1||j<=ztvec[3]||j>=ny-ztvec[4]+1)
	    {
	      image[i][j] = 0.0;
	    }
	  if(pow(pow(1.0*i-cvec[1],2.0)+pow(1.0*j-cvec[2],2.0),0.5)>=cvec[3])
	    {
	      image[i][j] = 0.0;
	    }
	}
    }

  free_matrix(avgbox,1,border,1,avstep);
  free_matrix(image1,1,nx,1,ny);
  free_matrix(image2,1,nx,1,ny);
  free_matrix(image3,1,nx,1,ny);

  return(1);
}


/*zerotrim05f: Like zerotrim05, but works better*/
int zerotrim05f(float **image,int nx,int ny, int *ztvec,float *cvec,int bord,int avstep,int fadelen,float lim)
{
  int i,j,k,border;
  float **image1,**image2,**image3,**avgbox,**subvecs;
  int blocknum,avstart,avend,halfblock,*circlegood,ipx,ipy;
  float data1,data2,rad,theta,px,py,xb,yb,xe,ye,*thetavec;
  int sgct,intrad,intthet;

  border = bord+fadelen;

  avgbox = matrix(1,border,1,avstep);
  image1 = matrix(1,nx,1,ny);
  image2 = matrix(1,nx,1,ny);
  image3 = matrix(1,nx,1,ny);

  halfblock = avstep/2;
  imzero(image1,nx,ny);
  imzero(image2,nx,ny);
  imzero(image3,nx,ny);

  printf("zerotrim05f has recieved limit = %f\n",lim);

  /*Horizontal Borders Along Top and Bottom*/

  /*x ranges from ztvec[1]+1 up to nx-ztvec[2]*/
  blocknum = (nx-ztvec[2]-ztvec[1])/avstep + 1;
  /*bottom*/
  subvecs = matrix(1,blocknum,1,border);
  for(k=1;k<=blocknum;k++)
    {
      printf("k = %d\n",k);
      fflush(stdout);
      avstart = ztvec[1] + (k-1)*avstep + 1;
      avend = ztvec[1] + k*avstep;
      if(avend>nx-ztvec[2])
	{
	  avend = nx-ztvec[2];
	}
      for(j=ztvec[3]+1;j<=ztvec[3]+border;j++)
	{
	  sgct = 0;
	  for(i=avstart;i<=avend;i++)
	    {
	      if(fabs(image[i][j])<=lim)
		{
		  sgct+=1;
		  avgbox[j-ztvec[3]][sgct] = image[i][j];
		}
	    }
	  if(sgct>(avend-avstart+1)/ZTLOSSFAC)
	    {
	      creepvec01(avgbox[j-ztvec[3]],sgct,COLFUDGEREJ,&data1,&data2);
	    }
	  else
	    {
	      data1 = 0.0;
	    }
	  subvecs[k][j-ztvec[3]] = data1;
	}
    }
  for(i=ztvec[1]+1;i<=ztvec[1]+halfblock;i++)
    {
      for(j=ztvec[3]+1;j<=ztvec[3]+bord;j++)
	{
	  image1[i][j] = subvecs[1][j-ztvec[3]];
	}
      for(j=ztvec[3]+bord+1;j<=ztvec[3]+border;j++)
	{
	  image1[i][j] = (subvecs[1][j-ztvec[3]])*(1.0*ztvec[3]+1.0*border-1.0*j)/(1.0*fadelen);
	}
    }
  for(k=1;k<=blocknum-1;k++)
    {
      for(i=ztvec[1]+(k-1)*avstep+halfblock+1;i<=ztvec[1]+k*avstep+halfblock;i++)
	{
	  for(j=ztvec[3]+1;j<=ztvec[3]+bord;j++)
	    {
	      if(i<=nx-ztvec[2])
		{
		  image1[i][j] = subvecs[k][j-ztvec[3]] + (subvecs[k+1][j-ztvec[3]] - subvecs[k][j-ztvec[3]])*(1.0*i-1.0*(ztvec[1]+(k-1)*avstep+halfblock))/(1.0*avstep-1.0);
		}
	    }
	  for(j=ztvec[3]+bord+1;j<=ztvec[3]+border;j++)
	    {
	      if(i<=nx-ztvec[2])
		{
		  image1[i][j] = (subvecs[k][j-ztvec[3]] + (subvecs[k+1][j-ztvec[3]] - subvecs[k][j-ztvec[3]])*(1.0*i-1.0*(ztvec[1]+(k-1)*avstep+halfblock))/(1.0*avstep-1.0))*(1.0*(ztvec[3]+border)-1.0*j)/(1.0*fadelen);
		}
	    }

	}
    }

  for(i=ztvec[1]+(blocknum-1)*avstep+halfblock+1;i<=nx-ztvec[2];i++)
    {
      for(j=ztvec[3]+1;j<=ztvec[3]+bord;j++)
	{
	  image1[i][j] = subvecs[blocknum][j-ztvec[3]];
	}
      for(j=ztvec[3]+bord+1;j<=ztvec[3]+border;j++)
	{
	  image1[i][j] = (subvecs[blocknum][j-ztvec[3]])*(1.0*ztvec[3]+1.0*border - 1.0*j)/(1.0*fadelen);
	}

    }


  printf("Did bottom OK\n");
  fflush(stdout);

  /*top*/
  for(k=1;k<=blocknum;k++)
    {
      avstart = ztvec[1] + (k-1)*avstep + 1;
      avend = ztvec[1] + k*avstep;
      if(avend>nx-ztvec[2])
	{
	  avend = nx-ztvec[2];
	}
      for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4];j++)
	{
	  sgct = 0;
	  for(i=avstart;i<=avend;i++)
	    {
	      if(fabs(image[i][j])<=lim)
		{
		  sgct=+1;
		  avgbox[j-(ny-ztvec[4]+1-border)+1][sgct] = image[i][j];
		}
	    }
	  if(sgct>(avend-avstart+1)/ZTLOSSFAC)
	    {
	      creepvec01(avgbox[j-(ny-ztvec[4]+1-border)+1],sgct,COLFUDGEREJ,&data1,&data2);
	    }
	  else
	    {
	      data1 = 0.0;
	    }
	  subvecs[k][j-(ny-ztvec[4]+1-border)+1] = data1;
	}
    }
  for(i=ztvec[1]+1;i<=ztvec[1]+halfblock;i++)
    {
      for(j=ny-ztvec[4]+1-bord;j<=ny-ztvec[4];j++)
	{
	  image1[i][j] = subvecs[1][j-(ny-ztvec[4]+1-border)+1];
	}
      for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4]-bord;j++)
	{
	  image1[i][j] = (subvecs[1][j-(ny-ztvec[4]+1-border)+1])*(1.0*j-1.0*(ny-ztvec[4]+1-border))/(1.0*fadelen);
	}
    }
  for(k=1;k<=blocknum-1;k++)
    {
      for(i=ztvec[1]+(k-1)*avstep+halfblock+1;i<=ztvec[1]+k*avstep+halfblock;i++)
	{
	  for(j=ny-ztvec[4]+1-bord;j<=ny-ztvec[4];j++)
	    {
	      if(i<=nx-ztvec[2])
		{
		  image1[i][j] = subvecs[k][j-(ny-ztvec[4]+1-border)+1] + (subvecs[k+1][j-(ny-ztvec[4]+1-border)+1] - subvecs[k][j-(ny-ztvec[4]+1-border)+1])*(1.0*i-1.0*(ztvec[1]+(k-1)*avstep+halfblock))/(1.0*avstep-1.0);
		}
	    }
	  for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4]-bord;j++)
	    {
	      if(i<=nx-ztvec[2])
		{
		  image1[i][j] = (subvecs[k][j-(ny-ztvec[4]+1-border)+1] + (subvecs[k+1][j-(ny-ztvec[4]+1-border)+1] - subvecs[k][j-(ny-ztvec[4]+1-border)+1])*(1.0*i-1.0*(ztvec[1]+(k-1)*avstep+halfblock))/(1.0*avstep-1.0))*(1.0*j-1.0*(ny-ztvec[4]+1-border))/(1.0*fadelen);
		}
	    }
	}
    }

  for(i=ztvec[1]+(blocknum-1)*avstep+halfblock+1;i<=nx-ztvec[2];i++)
    {
      for(j=ny-ztvec[4]+1-bord;j<=ny-ztvec[4];j++)
	{
	  image1[i][j] = subvecs[blocknum][j-(ny-ztvec[4]+1-border)+1];
	}
      for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4]-bord;j++)
	{
	  image1[i][j] = (subvecs[blocknum][j-(ny-ztvec[4]+1-border)+1])*(1.0*j-1.0*(ny-ztvec[4]+1-border))/(1.0*fadelen);
	}
    }

  free_matrix(subvecs,1,blocknum,1,border);

  printf("Did top OK\n");
  fflush(stdout);

  /*Vertical Borders at Left and Right*/
  /*y ranges from ztvec[3]+1 to ny-ztvec[4]*/
  blocknum = (ny-ztvec[4]-ztvec[3])/avstep + 1;
  subvecs = matrix(1,blocknum,1,border);
  /*left side*/
  for(k=1;k<=blocknum;k++)
    {
      avstart = ztvec[3] + (k-1)*avstep + 1;
      avend = ztvec[3] + k*avstep;
      if(avend>ny-ztvec[4])
	{
	  avend = ny-ztvec[4];
	}
      for(i=ztvec[1]+1;i<=ztvec[1]+border;i++)
	{
	  sgct=0;
	  for(j=avstart;j<=avend;j++)
	    {
	      if(fabs(image[i][j])<=lim)
		{
		  sgct+=1;
		  avgbox[i-ztvec[1]][sgct] = image[i][j];
		}
	    }
	  if(sgct>(avend-avstart+1)/ZTLOSSFAC)
	    {
	      creepvec01(avgbox[i-ztvec[1]],sgct,COLFUDGEREJ,&data1,&data2);
	    }
	  else
	    {
	      data1 = 0.0;
	    }
	  subvecs[k][i-ztvec[1]] = data1;
	}
    }
  for(j=ztvec[3]+1;j<=ztvec[3]+halfblock;j++)
    {
      for(i=ztvec[1]+1;i<=ztvec[1]+bord;i++)
	{
	  image2[i][j] = subvecs[1][i-ztvec[1]];
	}
      for(i=ztvec[1]+bord+1;i<=ztvec[1]+border;i++)
	{
	  image2[i][j] = (subvecs[1][i-ztvec[1]])*(1.0*(ztvec[1]+border)-1.0*i)/(1.0*fadelen);
	}
    }

  for(k=1;k<=blocknum-1;k++)
    {
      for(j=ztvec[3]+(k-1)*avstep+halfblock+1;j<=ztvec[3]+k*avstep+halfblock;j++)
	{
	  for(i=ztvec[1]+1;i<=ztvec[1]+bord;i++)
	    {
	      if(j<=ny-ztvec[4])
		{
		  image2[i][j] = subvecs[k][i-ztvec[1]] + (subvecs[k+1][i-ztvec[1]] - subvecs[k][i-ztvec[1]])*(1.0*j-1.0*(ztvec[3]+(k-1)*avstep+halfblock+1))/(1.0*avstep-1.0);
													       
		}
	    }
	  for(i=ztvec[1]+bord+1;i<=ztvec[1]+border;i++)
	    {
	      if(j<=ny-ztvec[4])
		{
		  image2[i][j] = (subvecs[k][i-ztvec[1]] + (subvecs[k+1][i-ztvec[1]] - subvecs[k][i-ztvec[1]])*(1.0*j-1.0*(ztvec[3]+(k-1)*avstep+halfblock+1))/(1.0*avstep-1.0))*(1.0*(ztvec[1]+border)-1.0*i)/(1.0*fadelen);
													       
		}
	    }
	}
    }
     
  for(j=ztvec[3]+(blocknum-1)*avstep+halfblock+1;j<=ny-ztvec[4];j++)
    {
      for(i=ztvec[1]+1;i<=ztvec[1]+bord;i++)
	{
	  image2[i][j] = subvecs[blocknum][i-ztvec[1]];
	}
      for(i=ztvec[1]+bord+1;i<=ztvec[1]+border;i++)
	{
	  image2[i][j] = (subvecs[blocknum][i-ztvec[1]])*(1.0*(ztvec[1]+border)-1.0*i)/(1.0*fadelen);
	}
    }

  /*right side*/
  for(k=1;k<=blocknum;k++)
    {
      avstart = ztvec[3] + (k-1)*avstep + 1;
      avend = ztvec[3] + k*avstep;
      if(avend>ny-ztvec[4])
	{
	  avend = ny-ztvec[4];
	}
      for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2];i++)
	{
	  sgct = 0;
	  for(j=avstart;j<=avend;j++)
	    {
	      if(fabs(image[i][j])<=lim)
		{
		  sgct+=1;
		  avgbox[i-(nx-ztvec[2]-border+1)+1][sgct] = image[i][j];
		}
	    }
	  if(sgct>(avend-avstart+1)/ZTLOSSFAC)
	    {
	      creepvec01(avgbox[i-(nx-ztvec[2]-border+1)+1],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	    }
	  else
	    {
	      data1 = 0.0;
	    }
	  subvecs[k][i-(nx-ztvec[2]-border+1)+1] = data1;
	}
    }
  for(j=ztvec[3]+1;j<=ztvec[3]+halfblock;j++)
    {
      for(i=nx-ztvec[2]-bord+1;i<=nx-ztvec[2];i++)
	{
	  image2[i][j] = subvecs[1][i-(nx-ztvec[2]-border+1)+1];
	}
      for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2]-bord;i++)
	{
	  image2[i][j] = subvecs[1][i-(nx-ztvec[2]-border+1)+1]*(1.0*i-1.0*(nx-ztvec[2]-border+1))/(1.0*fadelen);
	}
    }
  for(k=1;k<=blocknum-1;k++)
    {
      for(j=ztvec[3]+(k-1)*avstep+halfblock+1;j<=ztvec[3]+k*avstep+halfblock;j++)
	{
	  for(i=nx-ztvec[2]-bord+1;i<=nx-ztvec[2];i++)
	    {
	      if(j<=ny-ztvec[4])
		{
		  image2[i][j] = subvecs[k][i-(nx-ztvec[2]-border+1)+1] + (subvecs[k+1][i-(nx-ztvec[2]-border+1)+1] - subvecs[k][i-(nx-ztvec[2]-border+1)+1])*(1.0*j-1.0*(ztvec[3]+(k-1)*avstep+halfblock+1))/(1.0*avstep-1.0);
		}
	    }
	  for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2]-bord;i++)
	    {
	      if(j<=ny-ztvec[4])
		{
		  image2[i][j] = (subvecs[k][i-(nx-ztvec[2]-border+1)+1] + (subvecs[k+1][i-(nx-ztvec[2]-border+1)+1] - subvecs[k][i-(nx-ztvec[2]-border+1)+1])*(1.0*j-1.0*(ztvec[3]+(k-1)*avstep+halfblock+1))/(1.0*avstep-1.0))*(1.0*i-1.0*(nx-ztvec[2]-border+1))/(1.0*fadelen);
		}
	    }
	}
    }

  for(j=ztvec[3]+(blocknum-1)*avstep+halfblock+1;j<=ny-ztvec[4];j++)
    {
      for(i=nx-ztvec[2]-bord+1;i<=nx-ztvec[2];i++)
	{
	  image2[i][j] = subvecs[blocknum][i-(nx-ztvec[2]-border+1)+1];
	}
      for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2]-bord;i++)
	{
	  image2[i][j] = (subvecs[blocknum][i-(nx-ztvec[2]-border+1)+1])*(1.0*i-1.0*(nx-ztvec[2]-border+1))/(1.0*fadelen);
	}
    }


  free_matrix(subvecs,1,blocknum,1,border);


  /*Circular cut*/
  blocknum = 2.0*PI*cvec[3]/avstep + 1;
  subvecs = matrix(1,blocknum,1,border);
  thetavec = vector(1,blocknum);
  printf("beginning circular cut\n");
  fflush(stdout);
  for(k=1;k<=blocknum;k++)
    {
      thetavec[k] = 1.0*((k-1)*avstep+avstep/2)/cvec[3];
      for(j=1;j<=border;j++)
	{
	  sgct = 0;
	  for(i=(k-1)*avstep+1;i<=k*avstep;i++)
	    {
	      theta = 1.0*i/cvec[3];
	      rad = cvec[3]-1.0*(j-1);
	      xb = cvec[1] + rad*cos(theta);
	      yb = cvec[2] + rad*sin(theta);
	      ipx = xb+0.5;
	      ipy = yb+0.5;

	      if(ipx>ztvec[1]&&ipx<=nx-ztvec[2]&&ipy>ztvec[3]&&ipy<=ny-ztvec[4]&&ipx>=1&&ipx<=nx&&ipy>=1&&ipy<=ny)
		{
		  if(fabs(image[ipx][ipy])<lim)
		    {
		      sgct+=1;
		      avgbox[j][sgct] = image[ipx][ipy];
		    }
		}
	    }
	  if(sgct>avstep/ZTLOSSFAC)
	    {
	      creepvec01(avgbox[j],avstep,COLFUDGEREJ,&data1,&data2);
	    }
	  else
	    {
	      data1 = 0.0;
	    }
	  subvecs[k][j] = data1;
	}
    }
  printf("beginning circular interpolation\n");
  fflush(stdout);
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  if(i>ztvec[1]&&i<=nx-ztvec[2]&&j>ztvec[3]&&j<=ny-ztvec[3])
	    {
	      /*do stuff*/
	      xb = 1.0*i-cvec[1];
	      yb = 1.0*j-cvec[2];
	      rad = pow(pow(xb,2.0)+pow(yb,2.0),0.5);
	      if(rad>cvec[3]||rad<=cvec[3]-border)
		{
		  image3[i][j] = 0.0;
		}
	      else
		{
		  /*Find theta*/
		  if(yb>0.0)
		    {
		      theta = PI/2.0 - atan(xb/yb);
		    }
		  else if(yb<0.0)
		    {
		      theta = 3.0*PI/2.0 - atan(xb/yb);
		    }
		  else if(yb==0.0)
		    {
		      if(xb>=0.0)
			{
			  theta = 0.0;
			}
		      else
			{
			  theta = PI;
			}
		    }
		  intrad = 1.0*(cvec[3]-rad+1.5);
		  if(intrad>=1&&intrad<=bord)
		    {
		      /*We are in the full subtraction regime*/
		      /*Use theta to find appropriate interpolation value*/
		      intthet = 0;
		      if(theta<=thetavec[1])
			{
			  intthet = 1;
			  image3[i][j] = subvecs[intthet][intrad];
			}
		      else if(theta>thetavec[blocknum-1])
			{
			  intthet = blocknum;
			  image3[i][j] = subvecs[intthet][intrad];
			}
		      else 
			{
			  for(k=1;k<=blocknum-2;k++)
			    {
			      if(theta>thetavec[k]&&theta<=thetavec[k+1])
				{
				  intthet = k;
				}
			    }
			  image3[i][j] = subvecs[intthet][intrad] + (subvecs[intthet+1][intrad]-subvecs[intthet][intrad])*(theta-thetavec[intthet])/(thetavec[intthet+1]-thetavec[intthet]);
			}
		      if(intthet==0)
			{
			  image3[i][j] = 0.0;
			}
		    }
		  else if(intrad>bord&&intrad<=border)
		    {
		      /*We are in the partial subtraction regime*/
		      /*Use theta to find appropriate interpolation value*/
		      intthet = 0;
		      if(theta<=thetavec[1])
			{
			  intthet = 1;
			  image3[i][j] = subvecs[intthet][intrad]*(1.0*border-1.0*intrad)/(1.0*fadelen);
			}
		      else if(theta>thetavec[blocknum-1])
			{
			  intthet = blocknum;
			  image3[i][j] = subvecs[intthet][intrad]*(1.0*border-1.0*intrad)/(1.0*fadelen);
			}
		      else 
			{
			  for(k=1;k<=blocknum-2;k++)
			    {
			      if(theta>thetavec[k]&&theta<=thetavec[k+1])
				{
				  intthet = k;
				}
			    }
			  image3[i][j] = subvecs[intthet][intrad] + (subvecs[intthet+1][intrad]-subvecs[intthet][intrad])*(theta-thetavec[intthet])/(thetavec[intthet+1]-thetavec[intthet])*(1.0*border-1.0*intrad)/(1.0*fadelen);
			}
		      if(intthet==0)
			{
			  image3[i][j] = 0.0;
			}
		    }
		  else{
		    image3[i][j] = 0.0;
		  }
		}
	    }
	  else
	    {
	      image3[i][j] = 0.0;
	    }
	}
    }

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  data1 = data2 = 0.0;
	  if(image1[i][j]!=0.0)
	    {
	      data1+=1;
	      data2+=image1[i][j];
	    }
	  if(image2[i][j]!=0.0)
	    {
	      data1+=1;
	      data2+=image2[i][j];
	    }
	  if(image3[i][j]!=0.0)
	    {
	      data1+=1;
	      data2+=image3[i][j];
	    }
	  if(data1>0.0)
	    {
	      image1[i][j] = data2/data1;
	      image[i][j]-=data2/data1;
	    }
	}
    }
  free_matrix(subvecs,1,blocknum,1,border);
  free_vector(thetavec,1,blocknum);

  writeim01(nx,ny,"junk01.txt",image1);

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  if(i<=ztvec[1]||i>=nx-ztvec[2]+1||j<=ztvec[3]||j>=ny-ztvec[4]+1)
	    {
	      image[i][j] = 0.0;
	    }
	  if(pow(pow(1.0*i-cvec[1],2.0)+pow(1.0*j-cvec[2],2.0),0.5)>=cvec[3])
	    {
	      image[i][j] = 0.0;
	    }
	}
    }

  free_matrix(avgbox,1,border,1,avstep);
  free_matrix(image1,1,nx,1,ny);
  free_matrix(image2,1,nx,1,ny);
  free_matrix(image3,1,nx,1,ny);

  return(1);
}


/*zerotrim05fbcs: Like zerotrim05f, but 
only subtracts the average border vector,
and does not actually trim the image.  This is
because it is for use the the bicubic spline
rotations and shifts shift03, rotate03, and
rotateshift03, which do their own zero trimming.*/
int zerotrim05fbcs(float **image,int nx,int ny, int *ztvec,float *cvec,int bord,int avstep,int fadelen,float lim)
{
  int i,j,k,border;
  float **image1,**image2,**image3,**avgbox,**subvecs;
  int blocknum,avstart,avend,halfblock,*circlegood,ipx,ipy;
  float data1,data2,rad,theta,px,py,xb,yb,xe,ye,*thetavec;
  int sgct,intrad,intthet,maxtrim;
  int fullcirc,*numpoints,circborder;
  float ffullcirc;

  border = bord+fadelen;

  maxtrim = 0;
  for(i=1;i<=4;i++)
    {
      if(ztvec[i]>maxtrim)
	{
	  maxtrim = ztvec[i];
	}
    }

  avgbox = matrix(1,border+maxtrim,1,avstep);
  image1 = matrix(1,nx,1,ny);
  image2 = matrix(1,nx,1,ny);
  image3 = matrix(1,nx,1,ny);

  halfblock = avstep/2;
  imzero(image1,nx,ny);
  imzero(image2,nx,ny);
  imzero(image3,nx,ny);

  printf("zerotrim05fbcs has recieved limit = %f\n",lim);

  /*Horizontal Borders Along Top and Bottom*/
  blocknum = nx/avstep + 1;
  /*bottom*/
  subvecs = matrix(1,blocknum,1,border+maxtrim);
  for(k=1;k<=blocknum;k++)
    {
      printf("k = %d\n",k);
      fflush(stdout);
      avstart = (k-1)*avstep + 1;
      avend = k*avstep;
      if(avend>nx)
	{
	  avend = nx;
	}
      for(j=1;j<=ztvec[3]+border;j++)
	{
	  sgct = 0;
	  for(i=avstart;i<=avend;i++)
	    {
	      if(fabs(image[i][j])<=lim)
		{
		  sgct+=1;
		  avgbox[j][sgct] = image[i][j];
		}
	    }
	  if(sgct>(avend-avstart+1)/ZTLOSSFAC)
	    {
	      creepvec01(avgbox[j],sgct,COLFUDGEREJ,&data1,&data2);
	    }
	  else
	    {
	      data1 = 0.0;
	    }
	  subvecs[k][j] = data1;
	}
    }
  for(i=1;i<=halfblock;i++)
    {
      for(j=1;j<=ztvec[3]+bord;j++)
	{
	  image1[i][j] = subvecs[1][j];
	}
      for(j=ztvec[3]+bord+1;j<=ztvec[3]+border;j++)
	{
	  image1[i][j] = (subvecs[1][j])*(1.0*ztvec[3]+1.0*border-1.0*j)/(1.0*fadelen);
	}
    }
  for(k=1;k<=blocknum-1;k++)
    {
      for(i=(k-1)*avstep+halfblock+1;i<=k*avstep+halfblock;i++)
	{
	  for(j=1;j<=ztvec[3]+bord;j++)
	    {
	      if(i<=nx)
		{
		  image1[i][j] = subvecs[k][j] + (subvecs[k+1][j] - subvecs[k][j])*(1.0*i-1.0*((k-1)*avstep+halfblock))/(1.0*avstep-1.0);
		}
	    }
	  for(j=ztvec[3]+bord+1;j<=ztvec[3]+border;j++)
	    {
	      if(i<=nx)
		{
		  image1[i][j] = (subvecs[k][j] + (subvecs[k+1][j] - subvecs[k][j])*(1.0*i-1.0*((k-1)*avstep+halfblock))/(1.0*avstep-1.0))*(1.0*(ztvec[3]+border)-1.0*j)/(1.0*fadelen);
		}
	    }

	}
    }

  for(i=(blocknum-1)*avstep+halfblock+1;i<=nx;i++)
    {
      for(j=1;j<=ztvec[3]+bord;j++)
	{
	  image1[i][j] = subvecs[blocknum][j];
	}
      for(j=ztvec[3]+bord+1;j<=ztvec[3]+border;j++)
	{
	  image1[i][j] = (subvecs[blocknum][j])*(1.0*ztvec[3]+1.0*border - 1.0*j)/(1.0*fadelen);
	}

    }

  printf("Did bottom OK\n");
  fflush(stdout);

  /*top*/
  for(k=1;k<=blocknum;k++)
    {
      avstart = (k-1)*avstep + 1;
      avend = k*avstep;
      if(avend>nx)
	{
	  avend = nx;
	}
      for(j=ny-ztvec[4]+1-border;j<=ny;j++)
	{
	  sgct = 0;
	  for(i=avstart;i<=avend;i++)
	    {
	      if(fabs(image[i][j])<=lim)
		{
		  sgct=+1;
		  avgbox[j-(ny-ztvec[4]+1-border)+1][sgct] = image[i][j];
		}
	    }
	  if(sgct>(avend-avstart+1)/ZTLOSSFAC)
	    {
	      creepvec01(avgbox[j-(ny-ztvec[4]+1-border)+1],sgct,COLFUDGEREJ,&data1,&data2);
	    }
	  else
	    {
	      data1 = 0.0;
	    }
	  subvecs[k][j-(ny-ztvec[4]+1-border)+1] = data1;
	}
    }
  for(i=1;i<=halfblock;i++)
    {
      for(j=ny-ztvec[4]+1-bord;j<=ny;j++)
	{
	  image1[i][j] = subvecs[1][j-(ny-ztvec[4]+1-border)+1];
	}
      for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4]-bord;j++)
	{
	  image1[i][j] = (subvecs[1][j-(ny-ztvec[4]+1-border)+1])*(1.0*j-1.0*(ny-ztvec[4]+1-border))/(1.0*fadelen);
	}
    }
  for(k=1;k<=blocknum-1;k++)
    {
      for(i=(k-1)*avstep+halfblock+1;i<=k*avstep+halfblock;i++)
	{
	  for(j=ny-ztvec[4]+1-bord;j<=ny;j++)
	    {
	      if(i<=nx)
		{
		  image1[i][j] = subvecs[k][j-(ny-ztvec[4]+1-border)+1] + (subvecs[k+1][j-(ny-ztvec[4]+1-border)+1] - subvecs[k][j-(ny-ztvec[4]+1-border)+1])*(1.0*i-1.0*((k-1)*avstep+halfblock))/(1.0*avstep-1.0);
		}
	    }
	  for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4]-bord;j++)
	    {
	      if(i<=nx)
		{
		  image1[i][j] = (subvecs[k][j-(ny-ztvec[4]+1-border)+1] + (subvecs[k+1][j-(ny-ztvec[4]+1-border)+1] - subvecs[k][j-(ny-ztvec[4]+1-border)+1])*(1.0*i-1.0*((k-1)*avstep+halfblock))/(1.0*avstep-1.0))*(1.0*j-1.0*(ny-ztvec[4]+1-border))/(1.0*fadelen);
		}
	    }
	}
    }

  for(i=(blocknum-1)*avstep+halfblock+1;i<=nx;i++)
    {
      for(j=ny-ztvec[4]+1-bord;j<=ny;j++)
	{
	  image1[i][j] = subvecs[blocknum][j-(ny-ztvec[4]+1-border)+1];
	}
      for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4]-bord;j++)
	{
	  image1[i][j] = (subvecs[blocknum][j-(ny-ztvec[4]+1-border)+1])*(1.0*j-1.0*(ny-ztvec[4]+1-border))/(1.0*fadelen);
	}
    }

  free_matrix(subvecs,1,blocknum,1,border+maxtrim);

  printf("Did top OK\n");
  fflush(stdout);

  /*Vertical Borders at Left and Right*/
  /*y ranges from ztvec[3]+1 to ny-ztvec[4]*/
  blocknum = ny/avstep + 1;
  subvecs = matrix(1,blocknum,1,border+maxtrim);
  /*left side*/
  for(k=1;k<=blocknum;k++)
    {
      avstart = (k-1)*avstep + 1;
      avend = k*avstep;
      if(avend>ny)
	{
	  avend = ny;
	}
      for(i=1;i<=ztvec[1]+border;i++)
	{
	  sgct=0;
	  for(j=avstart;j<=avend;j++)
	    {
	      if(fabs(image[i][j])<=lim)
		{
		  sgct+=1;
		  avgbox[i][sgct] = image[i][j];
		}
	    }
	  if(sgct>(avend-avstart+1)/ZTLOSSFAC)
	    {
	      creepvec01(avgbox[i],sgct,COLFUDGEREJ,&data1,&data2);
	    }
	  else
	    {
	      data1 = 0.0;
	    }
	  subvecs[k][i] = data1;
	}
    }
  for(j=1;j<=halfblock;j++)
    {
      for(i=1;i<=ztvec[1]+bord;i++)
	{
	  image2[i][j] = subvecs[1][i];
	}
      for(i=ztvec[1]+bord+1;i<=ztvec[1]+border;i++)
	{
	  image2[i][j] = (subvecs[1][i])*(1.0*(ztvec[1]+border)-1.0*i)/(1.0*fadelen);
	}
    }

  for(k=1;k<=blocknum-1;k++)
    {
      for(j=(k-1)*avstep+halfblock+1;j<=k*avstep+halfblock;j++)
	{
	  for(i=1;i<=ztvec[1]+bord;i++)
	    {
	      if(j<=ny)
		{
		  image2[i][j] = subvecs[k][i] + (subvecs[k+1][i] - subvecs[k][i])*(1.0*j-1.0*((k-1)*avstep+halfblock+1))/(1.0*avstep-1.0);
		}
	    }
	  for(i=ztvec[1]+bord+1;i<=ztvec[1]+border;i++)
	    {
	      if(j<=ny)
		{
		  image2[i][j] = (subvecs[k][i] + (subvecs[k+1][i] - subvecs[k][i])*(1.0*j-1.0*((k-1)*avstep+halfblock+1))/(1.0*avstep-1.0))*(1.0*(ztvec[1]+border)-1.0*i)/(1.0*fadelen);
		}
	    }
	}
    }
     
  for(j=(blocknum-1)*avstep+halfblock+1;j<=ny;j++)
    {
      for(i=1;i<=ztvec[1]+bord;i++)
	{
	  image2[i][j] = subvecs[blocknum][i];
	}
      for(i=ztvec[1]+bord+1;i<=ztvec[1]+border;i++)
	{
	  image2[i][j] = (subvecs[blocknum][i])*(1.0*(ztvec[1]+border)-1.0*i)/(1.0*fadelen);
	}
    }

  /*right side*/
  for(k=1;k<=blocknum;k++)
    {
      avstart = (k-1)*avstep + 1;
      avend = k*avstep;
      if(avend>ny)
	{
	  avend = ny;
	}
      for(i=nx-ztvec[2]-border+1;i<=nx;i++)
	{
	  sgct = 0;
	  for(j=avstart;j<=avend;j++)
	    {
	      if(fabs(image[i][j])<=lim)
		{
		  sgct+=1;
		  avgbox[i-(nx-ztvec[2]-border+1)+1][sgct] = image[i][j];
		}
	    }
	  if(sgct>(avend-avstart+1)/ZTLOSSFAC)
	    {
	      creepvec01(avgbox[i-(nx-ztvec[2]-border+1)+1],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	    }
	  else
	    {
	      data1 = 0.0;
	    }
	  subvecs[k][i-(nx-ztvec[2]-border+1)+1] = data1;
	}
    }
  for(j=1;j<=halfblock;j++)
    {
      for(i=nx-ztvec[2]-bord+1;i<=nx;i++)
	{
	  image2[i][j] = subvecs[1][i-(nx-ztvec[2]-border+1)+1];
	}
      for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2]-bord;i++)
	{
	  image2[i][j] = subvecs[1][i-(nx-ztvec[2]-border+1)+1]*(1.0*i-1.0*(nx-ztvec[2]-border+1))/(1.0*fadelen);
	}
    }
  for(k=1;k<=blocknum-1;k++)
    {
      for(j=(k-1)*avstep+halfblock+1;j<=k*avstep+halfblock;j++)
	{
	  for(i=nx-ztvec[2]-bord+1;i<=nx;i++)
	    {
	      if(j<=ny)
		{
		  image2[i][j] = subvecs[k][i-(nx-ztvec[2]-border+1)+1] + (subvecs[k+1][i-(nx-ztvec[2]-border+1)+1] - subvecs[k][i-(nx-ztvec[2]-border+1)+1])*(1.0*j-1.0*((k-1)*avstep+halfblock+1))/(1.0*avstep-1.0);
		}
	    }
	  for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2]-bord;i++)
	    {
	      if(j<=ny)
		{
		  image2[i][j] = (subvecs[k][i-(nx-ztvec[2]-border+1)+1] + (subvecs[k+1][i-(nx-ztvec[2]-border+1)+1] - subvecs[k][i-(nx-ztvec[2]-border+1)+1])*(1.0*j-1.0*((k-1)*avstep+halfblock+1))/(1.0*avstep-1.0))*(1.0*i-1.0*(nx-ztvec[2]-border+1))/(1.0*fadelen);
		}
	    }
	}
    }

  for(j=(blocknum-1)*avstep+halfblock+1;j<=ny;j++)
    {
      for(i=nx-ztvec[2]-bord+1;i<=nx;i++)
	{
	  image2[i][j] = subvecs[blocknum][i-(nx-ztvec[2]-border+1)+1];
	}
      for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2]-bord;i++)
	{
	  image2[i][j] = (subvecs[blocknum][i-(nx-ztvec[2]-border+1)+1])*(1.0*i-1.0*(nx-ztvec[2]-border+1))/(1.0*fadelen);
	}
    }


  free_matrix(subvecs,1,blocknum,1,border+maxtrim);
  free_matrix(avgbox,1,border+maxtrim,1,avstep);

  /*Circular cut*/
  /*get distance from center to most distant corner*/
  ffullcirc = pow(pow(cvec[1]-1.0,2.0)+pow(cvec[2]-1.0,2.0),0.5);
  if(pow(pow(cvec[1]-1.0*nx,2.0)+pow(cvec[2]-1.0,2.0),0.5)>ffullcirc)
    {
      ffullcirc = pow(pow(cvec[1]-1.0*nx,2.0)+pow(cvec[2]-1.0,2.0),0.5);
    }
  if(pow(pow(cvec[1]-1.0,2.0)+pow(cvec[2]-1.0*ny,2.0),0.5)>ffullcirc)
    {
      ffullcirc = pow(pow(cvec[1]-1.0,2.0)+pow(cvec[2]-1.0*ny,2.0),0.5);
    }
  if(pow(pow(cvec[1]-1.0*nx,2.0)+pow(cvec[2]-1.0*ny,2.0),0.5)>ffullcirc)
    {
      ffullcirc = pow(pow(cvec[1]-1.0*nx,2.0)+pow(cvec[2]-1.0*ny,2.0),0.5);
    }
  circborder = ffullcirc - cvec[3] + 1.0*border + 1.0;

  blocknum = 2.0*PI*ffullcirc/avstep + 1;
  subvecs = matrix(1,blocknum,1,circborder);
  circlegood = ivector(1,blocknum);
  numpoints = ivector(1,circborder);
  avgbox = matrix(1,circborder,1,avstep);

  thetavec = vector(1,blocknum);
  printf("beginning circular cut\n");
  fflush(stdout);
  for(k=1;k<=blocknum;k++)
    {
      thetavec[k] = 1.0*((k-1)*avstep+avstep/2)/ffullcirc;
      for(j=1;j<=circborder;j++)
	{
	  sgct = 0;
	  for(i=(k-1)*avstep+1;i<=k*avstep;i++)
	    {
	      theta = 1.0*i/ffullcirc;
	      rad = cvec[3]-1.0*border + 1.0*(j-1);
	      xb = cvec[1] + rad*cos(theta);
	      yb = cvec[2] + rad*sin(theta);
	      ipx = xb+0.5;
	      ipy = yb+0.5;

	      if(ipx>=1&&ipx<=nx&&ipy>=1&&ipy<=ny)
		{
		  if(fabs(image[ipx][ipy])<lim)
		    {
		      sgct+=1;
		      avgbox[j][sgct] = image[ipx][ipy];
		    }
		}
	    }
	  if(sgct>avstep/ZTLOSSFAC)
	    {
	      creepvec01(avgbox[j],avstep,COLFUDGEREJ,&data1,&data2);
	    }
	  else
	    {
	      data1 = 0.0;
	    }
	  subvecs[k][j] = data1;
	}
    }
  printf("beginning circular interpolation\n");
  fflush(stdout);
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  /*do stuff*/
	  xb = 1.0*i-cvec[1];
	  yb = 1.0*j-cvec[2];
	  rad = pow(pow(xb,2.0)+pow(yb,2.0),0.5);
	  if(rad<=cvec[3]-border)
	    {
	      image3[i][j] = 0.0;
	    }
	  else 
	    {
	      /*Find theta*/
	      if(yb>0.0)
		{
		  theta = PI/2.0 - atan(xb/yb);
		}
	      else if(yb<0.0)
		{
		  theta = 3.0*PI/2.0 - atan(xb/yb);
		}
	      else if(yb==0.0)
		{
		  if(xb>=0.0)
		    {
		      theta = 0.0;
		    }
		  else 
		    {
		      theta = PI;
		    }
		}
	      intrad = 1.0*(rad - (cvec[3]-1.0*border) + 1.0);
	      if(intrad>bord&&intrad<=circborder)
		    {
		      /*We are in the full subtraction regime*/
		      /*Use theta to find appropriate interpolation value*/
		      intthet = 0;
		      if(theta<=thetavec[1])
			{
			  intthet = 1;
			  image3[i][j] = subvecs[intthet][intrad];
			}
		      else if(theta>thetavec[blocknum-1])
			{
			  intthet = blocknum;
			  image3[i][j] = subvecs[intthet][intrad];
			}
		      else 
			{
			  for(k=1;k<=blocknum-2;k++)
			    {
			      if(theta>thetavec[k]&&theta<=thetavec[k+1])
				{
				  intthet = k;
				}
			    }
			  image3[i][j] = subvecs[intthet][intrad] + (subvecs[intthet+1][intrad]-subvecs[intthet][intrad])*(theta-thetavec[intthet])/(thetavec[intthet+1]-thetavec[intthet]);
			}
		      if(intthet==0)
			{
			  image3[i][j] = 0.0;
			}
		    }
		  else if(intrad>=1&&intrad<=bord)
		    {
		      /*We are in the partial subtraction regime*/
		      /*Use theta to find appropriate interpolation value*/
		      intthet = 0;
		      if(theta<=thetavec[1])
			{
			  intthet = 1;
			  image3[i][j] = subvecs[intthet][intrad]*(1.0*intrad)/(1.0*fadelen);
			}
		      else if(theta>thetavec[blocknum-1])
			{
			  intthet = blocknum;
			  image3[i][j] = subvecs[intthet][intrad]*(1.0*intrad)/(1.0*fadelen);
			}
		      else 
			{
			  for(k=1;k<=blocknum-2;k++)
			    {
			      if(theta>thetavec[k]&&theta<=thetavec[k+1])
				{
				  intthet = k;
				}
			    }
			  image3[i][j] = subvecs[intthet][intrad] + (subvecs[intthet+1][intrad]-subvecs[intthet][intrad])*(theta-thetavec[intthet])/(thetavec[intthet+1]-thetavec[intthet])*(1.0*intrad)/(1.0*fadelen);
			}
		      if(intthet==0)
			{
			  image3[i][j] = 0.0;
			}
		    }
		  else{
		    image3[i][j] = 0.0;
		  }
	    }
	}
    }

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  data1 = data2 = 0.0;
	  if(image1[i][j]!=0.0)
	    {
	      data1+=1;
	      data2+=image1[i][j];
	    }
	  if(image2[i][j]!=0.0)
	    {
	      data1+=1;
	      data2+=image2[i][j];
	    }
	  if(image3[i][j]!=0.0)
	    {
	      data1+=1;
	      data2+=image3[i][j];
	    }
	  if(data1>0.0)
	    {
	      image1[i][j] = data2/data1;
	      image[i][j]-=data2/data1;
	    }
	}
    }

  free_matrix(subvecs,1,blocknum,1,circborder);
  free_matrix(avgbox,1,circborder,1,avstep);
  free_vector(thetavec,1,blocknum);

  writeim01(nx,ny,"junk01.txt",image1);

  free_matrix(image1,1,nx,1,ny);
  free_matrix(image2,1,nx,1,ny);
  free_matrix(image3,1,nx,1,ny);

  return(1);
}




/*zerotrim06: Like zerotrim03, except that it allows
the zero subtraction to fade over a fade length fadelen,
so that in cases where it has been subtracting the halo of
a bright star, there will be no hard edges in the image.
Unlike zerotrim05, zerotrim06 considers all pixels no matter how
much they deviate from zero*/
int zerotrim06(float **image,int nx,int ny, int *ztvec,float *cvec,int bord,int avstep,int fadelen)
{
  int i,j,k,border;
  float **image1,**image2,**image3,**avgbox,**subvecs;
  int blocknum,avstart,avend,halfblock,*circlegood,ipx,ipy;
  float data1,data2,rad,theta,px,py,xb,yb,xe,ye;

  border = bord+fadelen;

  avgbox = matrix(1,border,1,avstep);
  image1 = matrix(1,nx,1,ny);
  image2 = matrix(1,nx,1,ny);
  image3 = matrix(1,nx,1,ny);

  halfblock = avstep/2;
  imzero(image1,nx,ny);
  imzero(image2,nx,ny);
  imzero(image3,nx,ny);

  /*Horizontal Borders Along Top and Bottom*/

  /*x ranges from ztvec[1]+1 up to nx-ztvec[2]*/
  blocknum = (nx-ztvec[2]-ztvec[1])/avstep + 1;
  /*bottom*/
  subvecs = matrix(1,blocknum,1,border);
  for(k=1;k<=blocknum;k++)
    {
      printf("k = %d\n",k);
      fflush(stdout);
      avstart = ztvec[1] + (k-1)*avstep + 1;
      avend = ztvec[1] + k*avstep;
      if(avend>nx-ztvec[2])
	{
	  avend = nx-ztvec[2];
	}
      for(j=ztvec[3]+1;j<=ztvec[3]+border;j++)
	{
	  for(i=avstart;i<=avend;i++)
	    {
		  avgbox[j-ztvec[3]][i-avstart+1] = image[i][j];
	    }
	  creepvec01(avgbox[j-ztvec[3]],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	  subvecs[k][j-ztvec[3]] = data1;
	}
    }
  for(i=ztvec[1]+1;i<=ztvec[1]+halfblock;i++)
    {
      for(j=ztvec[3]+1;j<=ztvec[3]+bord;j++)
	{
	  image1[i][j] = subvecs[1][j-ztvec[3]];
	}
      for(j=ztvec[3]+bord+1;j<=ztvec[3]+border;j++)
	{
	  image1[i][j] = (subvecs[1][j-ztvec[3]])*(1.0*ztvec[3]+1.0*border-1.0*j)/(1.0*fadelen);
	}
    }
  for(k=1;k<=blocknum-1;k++)
    {
      for(i=ztvec[1]+(k-1)*avstep+halfblock+1;i<=ztvec[1]+k*avstep+halfblock;i++)
	{
	  for(j=ztvec[3]+1;j<=ztvec[3]+bord;j++)
	    {
	      if(i<=nx-ztvec[2])
		{
		  image1[i][j] = subvecs[k][j-ztvec[3]] + (subvecs[k+1][j-ztvec[3]] - subvecs[k][j-ztvec[3]])*(1.0*i-1.0*(ztvec[1]+(k-1)*avstep+halfblock))/(1.0*avstep-1.0);
		}
	    }
	  for(j=ztvec[3]+bord+1;j<=ztvec[3]+border;j++)
	    {
	      if(i<=nx-ztvec[2])
		{
		  image1[i][j] = (subvecs[k][j-ztvec[3]] + (subvecs[k+1][j-ztvec[3]] - subvecs[k][j-ztvec[3]])*(1.0*i-1.0*(ztvec[1]+(k-1)*avstep+halfblock))/(1.0*avstep-1.0))*(1.0*(ztvec[3]+border)-1.0*j)/(1.0*fadelen);
		}
	    }

	}
    }

  printf("Did bottom OK\n");
  fflush(stdout);

  for(i=ztvec[1]+(blocknum-1)*avstep+halfblock+1;i<=nx-ztvec[2];i++)
    {
      for(j=ztvec[3]+1;j<=ztvec[3]+bord;j++)
	{
	  image1[i][j] = subvecs[k][j-ztvec[3]];
	}
      for(j=ztvec[3]+bord+1;j<=ztvec[3]+border;j++)
	{
	  image1[i][j] = (subvecs[k][j-ztvec[3]])*(1.0*ztvec[3]+1.0*border - 1.0*j)/(1.0*fadelen);
	}

    }

  /*top*/
  for(k=1;k<=blocknum;k++)
    {
      avstart = ztvec[1] + (k-1)*avstep + 1;
      avend = ztvec[1] + k*avstep;
      if(avend>nx-ztvec[2])
	{
	  avend = nx-ztvec[2];
	}
      for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4];j++)
	{
	  for(i=avstart;i<=avend;i++)
	    {
		  avgbox[j-(ny-ztvec[4]+1-border)+1][i-avstart+1] = image[i][j];
	    }
	  creepvec01(avgbox[j-(ny-ztvec[4]+1-border)+1],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	  subvecs[k][j-(ny-ztvec[4]+1-border)+1] = data1;
	}
    }
  for(i=ztvec[1]+1;i<=ztvec[1]+halfblock;i++)
    {
      for(j=ny-ztvec[4]+1-bord;j<=ny-ztvec[4];j++)
	{
	  image1[i][j] = subvecs[1][j-(ny-ztvec[4]+1-border)+1];
	}
      for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4]-bord;j++)
	{
	  image1[i][j] = (subvecs[1][j-(ny-ztvec[4]+1-border)+1])*(1.0*j-1.0*(ny-ztvec[4]+1-border))/(1.0*fadelen);
	}
    }
  for(k=1;k<=blocknum-1;k++)
    {
      for(i=ztvec[1]+(k-1)*avstep+halfblock+1;i<=ztvec[1]+k*avstep+halfblock;i++)
	{
	  for(j=ny-ztvec[4]+1-bord;j<=ny-ztvec[4];j++)
	    {
	      if(i<=nx-ztvec[2])
		{
		  image1[i][j] = subvecs[k][j-(ny-ztvec[4]+1-border)+1] + (subvecs[k+1][j-(ny-ztvec[4]+1-border)+1] - subvecs[k][j-(ny-ztvec[4]+1-border)+1])*(1.0*i-1.0*(ztvec[1]+(k-1)*avstep+halfblock))/(1.0*avstep-1.0);
		}
	    }
	  for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4]-bord;j++)
	    {
	      if(i<=nx-ztvec[2])
		{
		  image1[i][j] = (subvecs[k][j-(ny-ztvec[4]+1-border)+1] + (subvecs[k+1][j-(ny-ztvec[4]+1-border)+1] - subvecs[k][j-(ny-ztvec[4]+1-border)+1])*(1.0*i-1.0*(ztvec[1]+(k-1)*avstep+halfblock))/(1.0*avstep-1.0))*(1.0*j-1.0*(ny-ztvec[4]+1-border))/(1.0*fadelen);
		}
	    }
	}
    }

  for(i=ztvec[1]+(blocknum-1)*avstep+halfblock+1;i<=nx-ztvec[2];i++)
    {
      for(j=ny-ztvec[4]+1-bord;j<=ny-ztvec[4];j++)
	{
	  image1[i][j] = subvecs[k][j-(ny-ztvec[4]+1-border)+1];
	}
      for(j=ny-ztvec[4]+1-border;j<=ny-ztvec[4]-bord;j++)
	{
	  image1[i][j] = (subvecs[k][j-(ny-ztvec[4]+1-border)+1])*(1.0*j-1.0*(ny-ztvec[4]+1-border))/(1.0*fadelen);
	}
    }

  free_matrix(subvecs,1,blocknum,1,border);

  printf("Did top OK\n");
  fflush(stdout);

  /*Vertical Borders at Left and Right*/
  /*y ranges from ztvec[3]+1 to ny-ztvec[4]*/
  blocknum = (ny-ztvec[4]-ztvec[3])/avstep + 1;
  subvecs = matrix(1,blocknum,1,border);
  /*left side*/
  for(k=1;k<=blocknum;k++)
    {
      avstart = ztvec[3] + (k-1)*avstep + 1;
      avend = ztvec[3] + k*avstep;
      if(avend>ny-ztvec[4])
	{
	  avend = ny-ztvec[4];
	}
      for(i=ztvec[1]+1;i<=ztvec[1]+border;i++)
	{
	  for(j=avstart;j<=avend;j++)
	    {
		  avgbox[i-ztvec[1]][j-avstart+1] = image[i][j];
	    }
	  creepvec01(avgbox[i-ztvec[1]],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	  subvecs[k][i-ztvec[1]] = data1;
	}
    }
  for(j=ztvec[3]+1;j<=ztvec[3]+halfblock;j++)
    {
      for(i=ztvec[1]+1;i<=ztvec[1]+bord;i++)
	{
	  image2[i][j] = subvecs[1][i-ztvec[1]];
	}
      for(i=ztvec[1]+bord+1;i<=ztvec[1]+border;i++)
	{
	  image2[i][j] = (subvecs[1][i-ztvec[1]])*(1.0*(ztvec[1]+border)-1.0*i)/(1.0*fadelen);
	}
    }

  for(k=1;k<=blocknum-1;k++)
    {
      for(j=ztvec[3]+(k-1)*avstep+halfblock+1;j<=ztvec[3]+k*avstep+halfblock;j++)
	{
	  for(i=ztvec[1]+1;i<=ztvec[1]+bord;i++)
	    {
	      if(j<=ny-ztvec[4])
		{
		  image2[i][j] = subvecs[k][i-ztvec[1]] + (subvecs[k+1][i-ztvec[1]] - subvecs[k][i-ztvec[1]])*(1.0*j-1.0*(ztvec[3]+(k-1)*avstep+halfblock+1))/(1.0*avstep-1.0);
													       
		}
	    }
	  for(i=ztvec[1]+bord+1;i<=ztvec[1]+border;i++)
	    {
	      if(j<=ny-ztvec[4])
		{
		  image2[i][j] = (subvecs[k][i-ztvec[1]] + (subvecs[k+1][i-ztvec[1]] - subvecs[k][i-ztvec[1]])*(1.0*j-1.0*(ztvec[3]+(k-1)*avstep+halfblock+1))/(1.0*avstep-1.0))*(1.0*(ztvec[1]+border)-1.0*i)/(1.0*fadelen);
													       
		}
	    }
	}
    }
     
  for(j=ztvec[3]+(blocknum-1)*avstep+halfblock+1;j<=ny-ztvec[4];j++)
    {
      for(i=ztvec[1]+1;i<=ztvec[1]+bord;i++)
	{
	  image2[i][j] = subvecs[k][i-ztvec[1]];
	}
      for(i=ztvec[1]+bord+1;i<=ztvec[1]+border;i++)
	{
	  image2[i][j] = (subvecs[k][i-ztvec[1]])*(1.0*(ztvec[1]+border)-1.0*i)/(1.0*fadelen);
	}
    }

  /*right side*/
  for(k=1;k<=blocknum;k++)
    {
      avstart = ztvec[3] + (k-1)*avstep + 1;
      avend = ztvec[3] + k*avstep;
      if(avend>ny-ztvec[4])
	{
	  avend = ny-ztvec[4];
	}
      for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2];i++)
	{
	  for(j=avstart;j<=avend;j++)
	    {
		  avgbox[i-(nx-ztvec[2]-border+1)+1][j-avstart+1] = image[i][j];
	    }
	  creepvec01(avgbox[i-(nx-ztvec[2]-border+1)+1],avend-avstart+1,COLFUDGEREJ,&data1,&data2);
	  subvecs[k][i-(nx-ztvec[2]-border+1)+1] = data1;
	}
    }
  for(j=ztvec[3]+1;j<=ztvec[3]+halfblock;j++)
    {
      for(i=nx-ztvec[2]-bord+1;i<=nx-ztvec[2];i++)
	{
	  image2[i][j] = subvecs[1][i-(nx-ztvec[2]-border+1)+1];
	}
      for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2]-bord;i++)
	{
	  image2[i][j] = subvecs[1][i-(nx-ztvec[2]-border+1)+1]*(1.0*i-1.0*(nx-ztvec[2]-border+1))/(1.0*fadelen);
	}
    }
  for(k=1;k<=blocknum-1;k++)
    {
      for(j=ztvec[3]+(k-1)*avstep+halfblock+1;j<=ztvec[3]+k*avstep+halfblock;j++)
	{
	  for(i=nx-ztvec[2]-bord+1;i<=nx-ztvec[2];i++)
	    {
	      if(j<=ny-ztvec[4])
		{
		  image2[i][j] = subvecs[k][i-(nx-ztvec[2]-border+1)+1] + (subvecs[k+1][i-(nx-ztvec[2]-border+1)+1] - subvecs[k][i-(nx-ztvec[2]-border+1)+1])*(1.0*j-1.0*(ztvec[3]+(k-1)*avstep+halfblock+1))/(1.0*avstep-1.0);
		}
	    }
	  for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2]-bord;i++)
	    {
	      if(j<=ny-ztvec[4])
		{
		  image2[i][j] = (subvecs[k][i-(nx-ztvec[2]-border+1)+1] + (subvecs[k+1][i-(nx-ztvec[2]-border+1)+1] - subvecs[k][i-(nx-ztvec[2]-border+1)+1])*(1.0*j-1.0*(ztvec[3]+(k-1)*avstep+halfblock+1))/(1.0*avstep-1.0))*(1.0*i-1.0*(nx-ztvec[2]-border+1))/(1.0*fadelen);
		}
	    }
	}
    }

  for(j=ztvec[3]+(blocknum-1)*avstep+halfblock+1;j<=ny-ztvec[4];j++)
    {
      for(i=nx-ztvec[2]-bord+1;i<=nx-ztvec[2];i++)
	{
	  image2[i][j] = subvecs[k][i-(nx-ztvec[2]-border+1)+1];
	}
      for(i=nx-ztvec[2]-border+1;i<=nx-ztvec[2]-bord;i++)
	{
	  image2[i][j] = (subvecs[k][i-(nx-ztvec[2]-border+1)+1])*(1.0*i-1.0*(nx-ztvec[2]-border+1))/(1.0*fadelen);
	}
    }


  free_matrix(subvecs,1,blocknum,1,border);


  /*Circular cut*/
  blocknum = 2.0*PI*cvec[3]/avstep + 1;
  subvecs = matrix(1,blocknum,1,border);
  circlegood = ivector(1,blocknum);

  for(k=1;k<=blocknum;k++)
    {
      theta = 1.0*((k-1)*avstep+1)/cvec[3];
      rad = cvec[3];
      xb = cvec[1] + rad*cos(theta);
      yb = cvec[2] + rad*sin(theta);
      theta = 1.0*(k*avstep)/cvec[3];
      xe = cvec[1] + rad*cos(theta);
      ye = cvec[2] + rad*sin(theta);
      if(xb>ztvec[1]&&xe>ztvec[1]&&xb<=nx-ztvec[2]&&xe<=nx-ztvec[2]&&yb>ztvec[3]&&ye>ztvec[3]&&yb<=ny-ztvec[4]&&ye<=ny-ztvec[4])
	{
	  circlegood[k] = 1;
	  for(j=1;j<=border;j++)
	    {
	      for(i=(k-1)*avstep+1;i<=k*avstep;i++)
		{
		  theta = 1.0*i/cvec[3];
		  rad = cvec[3]-1.0*(j-1);
		  xb = cvec[1] + rad*cos(theta);
		  yb = cvec[2] + rad*sin(theta);
		  ipx = xb+0.5;
		  ipy = yb+0.5;
		      avgbox[j][i-((k-1)*avstep+1)+1] = image[ipx][ipy];
		}
	      creepvec01(avgbox[j],avstep,COLFUDGEREJ,&data1,&data2);
	      subvecs[k][j] = data1;
	    }
	}
      else{
	circlegood[k] = 0;
      }
    }
  if(circlegood[1]==1)
    {
      for(j=1;j<=bord;j++)
	{
	  for(i=1;i<=halfblock;i++)
	    {
	      theta = 1.0*i/cvec[3];
	      rad = cvec[3]-1.0*(j-1);
	      xb = cvec[1] + rad*cos(theta);
	      yb = cvec[2] + rad*sin(theta);
	      ipx = xb+0.5;
	      ipy = yb+0.5;
	      image3[ipx][ipy] = subvecs[1][j];
	    }
	}
      for(j=bord+1;j<=border;j++)
	{
	  for(i=1;i<=halfblock;i++)
	    {
	      theta = 1.0*i/cvec[3];
	      rad = cvec[3]-1.0*(j-1);
	      xb = cvec[1] + rad*cos(theta);
	      yb = cvec[2] + rad*sin(theta);
	      ipx = xb+0.5;
	      ipy = yb+0.5;
	      image3[ipx][ipy] = subvecs[1][j]*(1.0*border-1.0*j)/(1.0*fadelen);
	    }
	}
    }
  if(circlegood[blocknum]==1)
    {
      for(j=1;j<=bord;j++)
	{
	  for(i=(blocknum-1)*avstep+halfblock+1;i<=blocknum*avstep;i++)
	    {
	      if(i<=2*PI*cvec[3])
		{
		  theta = 1.0*i/cvec[3];
		  rad = cvec[3]-1.0*(j-1);
		  xb = cvec[1] + rad*cos(theta);
		  yb = cvec[2] + rad*sin(theta);
		  ipx = xb+0.5;
		  ipy = yb+0.5;
		  image3[ipx][ipy] = subvecs[blocknum][j];
		}
	    }
	}
      for(j=bord+1;j<=border;j++)
	{
	  for(i=(blocknum-1)*avstep+halfblock+1;i<=blocknum*avstep;i++)
	    {
	      if(i<=2*PI*cvec[3])
		{
		  theta = 1.0*i/cvec[3];
		  rad = cvec[3]-1.0*(j-1);
		  xb = cvec[1] + rad*cos(theta);
		  yb = cvec[2] + rad*sin(theta);
		  ipx = xb+0.5;
		  ipy = yb+0.5;
		  image3[ipx][ipy] = subvecs[blocknum][j]*(1.0*border-1.0*j)/(1.0*fadelen);
		}
	    }
	}
    }
  for(k=2;k<=blocknum-1;k++)
    {
      if(circlegood[k]==1)
	{
	  if(circlegood[k-1]==0&&circlegood[k+1]==0)
	    {
	      for(j=1;j<=bord;j++)
		{
		  for(i=(k-1)*avstep+1;i<=k*avstep;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k][j];
		    }
		}
	      for(j=bord+1;j<=border;j++)
		{
		  for(i=(k-1)*avstep+1;i<=k*avstep;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k][j]*(1.0*border-1.0*j);
		    }
		}
	    }
	  if(circlegood[k-1]==1&&circlegood[k+1]==0)
	    {
	      for(j=1;j<=bord;j++)
		{
		  for(i=(k-1)*avstep+1;i<=(k-1)*avstep+halfblock;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k-1][j] + (subvecs[k][j]-subvecs[k-1][j])*(1.0*i-1.0*((k-2)*avstep + halfblock))/(1.0*avstep);
		    }
		}
	      for(j=bord+1;j<=border;j++)
		{
		  for(i=(k-1)*avstep+1;i<=(k-1)*avstep+halfblock;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = (subvecs[k-1][j] + (subvecs[k][j]-subvecs[k-1][j])*(1.0*i-1.0*((k-2)*avstep + halfblock))/(1.0*avstep))*(1.0*border-1.0*j);
		    }
		}
	    }
	  if(circlegood[k-1]==0&&circlegood[k+1]==1)
	    {
	      for(j=1;j<=bord;j++)
		{
		  for(i=(k-1)*avstep+halfblock+1;i<=k*avstep;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k][j] + (subvecs[k+1][j]-subvecs[k-1][j])*(1.0*i-1.0*((k-1)*avstep + halfblock))/(1.0*avstep);
		    }
		}
	      for(j=bord+1;j<=border;j++)
		{
		  for(i=(k-1)*avstep+halfblock+1;i<=k*avstep;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = (subvecs[k][j] + (subvecs[k+1][j]-subvecs[k-1][j])*(1.0*i-1.0*((k-1)*avstep + halfblock))/(1.0*avstep))*(1.0*border-1.0*j)/(1.0*fadelen);
		    }
		}
	    }
	  if(circlegood[k-1]==1&&circlegood[k+1]==1)
	    {
	      for(j=1;j<=bord;j++)
		{
		  for(i=(k-1)*avstep+1;i<=(k-1)*avstep+halfblock;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k-1][j] + (subvecs[k][j]-subvecs[k-1][j])*(1.0*i-1.0*((k-2)*avstep + halfblock))/(1.0*avstep);
		    }
		  for(i=(k-1)*avstep+halfblock+1;i<=k*avstep;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = subvecs[k][j] + (subvecs[k+1][j]-subvecs[k][j])*(1.0*i-1.0*((k-1)*avstep + halfblock))/(1.0*avstep);
		    }
		}
	      for(j=bord+1;j<=border;j++)
		{
		  for(i=(k-1)*avstep+1;i<=(k-1)*avstep+halfblock;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = (subvecs[k-1][j] + (subvecs[k][j]-subvecs[k-1][j])*(1.0*i-1.0*((k-2)*avstep + halfblock))/(1.0*avstep))*(1.0*border-1.0*j)/(1.0*fadelen);
		    }
		  for(i=(k-1)*avstep+halfblock+1;i<=k*avstep;i++)
		    {
		      theta = 1.0*i/cvec[3];
		      rad = cvec[3]-1.0*(j-1);
		      xb = cvec[1] + rad*cos(theta);
		      yb = cvec[2] + rad*sin(theta);
		      ipx = xb+0.5;
		      ipy = yb+0.5;
		      image3[ipx][ipy] = (subvecs[k][j] + (subvecs[k+1][j]-subvecs[k][j])*(1.0*i-1.0*((k-1)*avstep + halfblock))/(1.0*avstep))*(1.0*border-1.0*j)/(1.0*fadelen);
		    }
		}
	    }
	}
    }

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  data1 = data2 = 0.0;
	  if(image1[i][j]!=0.0)
	    {
	      data1+=1;
	      data2+=image1[i][j];
	    }
	  if(image2[i][j]!=0.0)
	    {
	      data1+=1;
	      data2+=image2[i][j];
	    }
	  if(image3[i][j]!=0.0)
	    {
	      data1+=1;
	      data2+=image3[i][j];
	    }
	  if(data1>0.0)
	    {
	      image1[i][j] = data2/data1;
	      image[i][j]-=data2/data1;
	    }
	}
    }
  free_matrix(subvecs,1,blocknum,1,border);
  free_ivector(circlegood,1,blocknum);

  writeim01(nx,ny,"junk01.txt",image1);

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  if(i<=ztvec[1]||i>=nx-ztvec[2]+1||j<=ztvec[3]||j>=ny-ztvec[4]+1)
	    {
	      image[i][j] = 0.0;
	    }
	  if(pow(pow(1.0*i-cvec[1],2.0)+pow(1.0*j-cvec[2],2.0),0.5)>=cvec[3])
	    {
	      image[i][j] = 0.0;
	    }
	}
    }

  free_matrix(avgbox,1,border,1,avstep);
  free_matrix(image1,1,nx,1,ny);
  free_matrix(image2,1,nx,1,ny);
  free_matrix(image3,1,nx,1,ny);

  return(1);
}


/*shift01: given an image, nx, ny, and floating point shift
values xshift and yshift, moves the light in the image by 
xshift,yshift relative to the pixel grid, using linear
interpolation*/
int shift01(float **image,int nx,int ny,float xshift,float yshift)
{
  float **image2;
  int i,j;
  float xpos,ypos,xint1,xint2,yint;
  int llpx,llpy;

  image2 = matrix(1,nx,1,ny);

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  xpos = 1.0*i-xshift;
	  ypos = 1.0*j-yshift;
	  llpx = xpos;
	  llpy = ypos;
	  if(llpx>=1&&llpx<nx&&llpy>=1&&llpy<ny)
	    {
	      xint1 = image[llpx][llpy]+(image[llpx+1][llpy]-image[llpx][llpy])*(xpos - 1.0*llpx);
	      xint2 = image[llpx][llpy+1]+(image[llpx+1][llpy+1]-image[llpx][llpy+1])*(xpos - 1.0*llpx);
	      image2[i][j] = xint1+(xint2-xint1)*(ypos-1.0*llpy);
	    }
	  else{
	    image2[i][j] = 0.0;
	  }
	}
    }
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image[i][j] = image2[i][j];
	}
    }	

  free_matrix(image2,1,nx,1,ny);
  return(1);
}

/*shift02: given an image, nx, ny, and floating point shift
values xshift and yshift, moves the light in the image by 
xshift,yshift relative to the pixel grid, using bicubic
spline interpolation*/
int shift02(float **image,int nx,int ny,float xshift,float yshift)
{
  float **image2,**y2a;
  int i,j;
  float xpos,ypos,xint1,xint2,yint,*xposvec,*yposvec,yval;
  int llpx,llpy;

  xposvec = vector(1,nx);
  yposvec = vector(1,ny);
  y2a = matrix(1,nx,1,ny);
  image2 = matrix(1,nx,1,ny);


  for(i=1;i<=nx;i++)
    {
      xposvec[i] = 1.0*i;
    }
  for(j=1;j<=ny;j++)
    {
      yposvec[j] = 1.0*j;
    }

  splie2(xposvec,yposvec,image,nx,ny,y2a);

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  xpos = 1.0*i-xshift;
	  ypos = 1.0*j-yshift;
	  if(xpos>=1&&xpos<=nx&&ypos>=1&&ypos<=ny)
	    {
	      splin2(xposvec,yposvec,image,y2a,nx,ny,xpos,ypos,&yval);
	      image2[i][j] = yval;
	    }
	  else{
	    image2[i][j] = 0.0;
	  }
	}
    }
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image[i][j] = image2[i][j];
	}
    }	

  xposvec = vector(1,nx);
  yposvec = vector(1,ny);
  y2a = matrix(1,nx,1,ny);
  free_matrix(image2,1,nx,1,ny);
  return(1);
}


/*shift03: given an image, nx, ny, and floating point shift
values xshift and yshift, moves the light in the image by 
xshift,yshift relative to the pixel grid, using bicubic
spline interpolation.  Simultaneously, zero trims and zero
pads the image, so that, provided the zero pads are chosen
properly, none of the image is lost off the edge of the
new image.  The calling function is reponsible to ensure
that the new image, image3, has the right dimensions.  If
a 250x250 image is to be shifted +30 pixels in the x direction
and +10 in the y direction, and a 30 pixel zero pad is chosen 
all around, the new image will of course be 310x310.  The light 
in pixel 1,1 on the old image will be on pixel 61,41 on the new,
and the light in pixel 250,250 on the old image will be in pixel
310,290 on the new, so no light will be lost, except whatever
is deliberately trimmed off in the zero trim.  shift03 allows
the zero trim to shave off set amounts from the left side, right
side, top, and bottom of the image, with these parameters
being set in the four-element integer vector ztvec.  If
ctrim == 1, it also allows a radial zero trim using the
floating point vector cvec, which contains the center
x and y coords and then the radius of a circle on the image.
Any pixels lying outside this circle will be set to zero.
Both ztvec and cvec reference coordinates on the old,
unshifted image.  The four-element integer vector zpvec holds the
zero pads for the left, right, top, and bottom of the images.
nx and ny also refer to the unshifted, un-zero-padded image.*/
int shift03(float **image,float **imageout,int nx,int ny,float xshift,float yshift,int *ztvec,float *cvec,int ctrim,int *zpvec)
{
  float **image2,**y2a;
  int i,j,nx2,ny2;
  float xpos,ypos,xint1,xint2,yint,*xposvec,*yposvec,yval;
  int llpx,llpy;
  float radius;

  nx2 = nx+zpvec[1]+zpvec[2];
  ny2 = ny+zpvec[3]+zpvec[4];

  xposvec = vector(1,nx);
  yposvec = vector(1,ny);
  y2a = matrix(1,nx,1,ny);
  image2 = matrix(1,nx2,1,ny2);

  for(i=1;i<=nx;i++)
    {
      xposvec[i] = 1.0*i;
    }
  for(j=1;j<=ny;j++)
    {
      yposvec[j] = 1.0*j;
    }

  splie2(xposvec,yposvec,image,nx,ny,y2a);

  if(ctrim!=1)
    {
      /*Circular zero trimming will not be used*/
      for(i=1;i<=nx2;i++)
	{
	  for(j=1;j<=ny2;j++)
	    {
	      xpos = 1.0*i-xshift-1.0*zpvec[1];
	      ypos = 1.0*j-yshift-1.0*zpvec[3];
	      if(xpos>=ztvec[1]+1&&xpos<=nx-ztvec[2]&&ypos>=ztvec[3]+1&&ypos<=ny-ztvec[4])
		{
		  splin2(xposvec,yposvec,image,y2a,nx,ny,xpos,ypos,&yval);
		  image2[i][j] = yval;
		}
	      else{
		image2[i][j] = 0.0;
	      }
	    }
	}
    }
  else
    {
      /*Circular zero trimming will be used*/
      for(i=1;i<=nx2;i++)
	{
	  for(j=1;j<=ny2;j++)
	    {
	      xpos = 1.0*i-xshift-1.0*zpvec[1];
	      ypos = 1.0*j-yshift-1.0*zpvec[3];
	      radius = pow(pow(xpos-cvec[1],2.0)+pow(ypos-cvec[2],2.0),0.5);
	      if(xpos>=ztvec[1]+1&&xpos<=nx-ztvec[2]&&ypos>=ztvec[3]+1&&ypos<=ny-ztvec[4]&&radius<=cvec[3])
		{
		  splin2(xposvec,yposvec,image,y2a,nx,ny,xpos,ypos,&yval);
		  image2[i][j] = yval;
		}
	      else{
		image2[i][j] = 0.0;
	      }
	    }
	}
    }


  for(i=1;i<=nx2;i++)
    {
      for(j=1;j<=ny2;j++)
	{
	  imageout[i][j] = image2[i][j];
	}
    }	

  xposvec = vector(1,nx);
  yposvec = vector(1,ny);
  y2a = matrix(1,nx,1,ny);
  free_matrix(image2,1,nx2,1,ny2);
  return(1);
}



/*rotate01: given an image, nx, ny, floating point rotation
in degrees, and floating point center coordinates xcen, ycen,
rotates the light in the image by rotation degrees about
xcen,ycen, clockwise relative to the pixel grid, using linear interpolation.
THE VARIABLE rotation IS EXPECTED IN UNITS OF DEGREES, NOT RADIANS.*/
int rotate01(float **image,int nx,int ny,float rotation,float xcen,float ycen)
{
  float **image2;
  int i,j;
  float xpos,ypos,xint1,xint2,yint;
  int llpx,llpy;

  image2 = matrix(1,nx,1,ny);
  rotation*=(PI/180.0);
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  xpos = xcen + (1.0*i-xcen)*cos(rotation)-(1.0*j-ycen)*sin(rotation);
	  ypos = ycen + (1.0*j-ycen)*cos(rotation)+(1.0*i-xcen)*sin(rotation);
	  llpx = xpos;
	  llpy = ypos;
	  if(llpx>=1&&llpx<nx&&llpy>=1&&llpy<ny)
	    {
	      xint1 = image[llpx][llpy]+(image[llpx+1][llpy]-image[llpx][llpy])*(xpos - 1.0*llpx);
	      xint2 = image[llpx][llpy+1]+(image[llpx+1][llpy+1]-image[llpx][llpy+1])*(xpos - 1.0*llpx);
	      image2[i][j] = xint1+(xint2-xint1)*(ypos-1.0*llpy);
	    }
	  else{
	    image2[i][j] = 0.0;
	  }
	}
    }
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image[i][j] = image2[i][j];
	}
    }	

  free_matrix(image2,1,nx,1,ny);
  return(1);
}

/*rotate02: given an image, nx, ny, floating point rotation
in degrees, and floating point center coordinates xcen, ycen,
rotates the light in the image by rotation degrees about
xcen,ycen, clockwise relative to the pixel grid, 
using BICUBIC SPLINE interpolation.
THE VARIABLE rotation IS EXPECTED IN UNITS OF DEGREES, NOT RADIANS.*/
int rotate02(float **image,int nx,int ny,float rotation,float xcen,float ycen)
{
  float **image2,**y2a;
  int i,j;
  float xpos,ypos,xint1,xint2,yint,*xposvec,*yposvec,yval;
  int llpx,llpy;

  xposvec = vector(1,nx);
  yposvec = vector(1,ny);
  y2a = matrix(1,nx,1,ny);
  image2 = matrix(1,nx,1,ny);

  for(i=1;i<=nx;i++)
    {
      xposvec[i] = 1.0*i;
    }
  for(j=1;j<=ny;j++)
    {
      yposvec[j] = 1.0*j;
    }

  splie2(xposvec,yposvec,image,nx,ny,y2a);

  rotation*=(PI/180.0);
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  xpos = xcen + (1.0*i-xcen)*cos(rotation)-(1.0*j-ycen)*sin(rotation);
	  ypos = ycen + (1.0*j-ycen)*cos(rotation)+(1.0*i-xcen)*sin(rotation);
	  if(xpos>=1&&xpos<=nx&&ypos>=1&&ypos<=ny)
	    {
	      splin2(xposvec,yposvec,image,y2a,nx,ny,xpos,ypos,&yval);
	      image2[i][j] = yval;
	    }
	  else{
	    image2[i][j] = 0.0;
	  }
	}
    }
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image[i][j] = image2[i][j];
	}
    }	

  free_vector(xposvec,1,nx);
  free_vector(yposvec,1,ny);
  free_matrix(y2a,1,nx,1,ny);
  free_matrix(image2,1,nx,1,ny);
  return(1);
}

/*rotate03: given an image, nx, ny, floating point rotation
in degrees, and floating point center coordinates xcen, ycen,
rotates the light in the image by rotation degrees about
xcen,ycen, clockwise relative to the pixel grid, 
using BICUBIC SPLINE interpolation.
THE VARIABLE rotation IS EXPECTED IN UNITS OF DEGREES, NOT RADIANS.
Simultaneously, zero trims and zero
pads the image, so that, provided the zero pads are chosen
properly, none of the image is lost off the edge of the
new image.  The calling function is reponsible to ensure
that the new image, image3, has the right dimensions.  Provided
the zero pads are set properly, no light should be lost except what  
is deliberately trimmed off in the zero trim.  rotate03 allows
the zero trim to shave off set amounts from the left side, right
side, top, and bottom of the image, with these parameters
being set in the four-element integer vector ztvec.  If
ctrim == 1, it also allows a radial zero trim using the
floating point vector cvec, which contains the center
x and y coords and then the radius of a circle on the image.
Any pixels lying outside this circle will be set to zero.
Both ztvec and cvec reference coordinates on the old,
unpadded image.  The four-element integer vector zpvec holds the
zero pads for the left, right, top, and bottom of the images.
nx and ny also refer to the un-zero-padded image.
Similarly, xcen and ycen are the coordinates of the
center of rotation on the un-zero-padded image.*/
int rotate03(float **image,float **imageout,int nx,int ny,float rotation,float xcen,float ycen,int *ztvec,float *cvec,int ctrim,int *zpvec)
{
  float **image2,**y2a,radius;
  int i,j,nx2,ny2;
  float xpos,ypos,xint1,xint2,yint,*xposvec,*yposvec,yval;
  int llpx,llpy;

  nx2 = nx+zpvec[1]+zpvec[2];
  ny2 = ny+zpvec[3]+zpvec[4];

  xposvec = vector(1,nx);
  yposvec = vector(1,ny);
  y2a = matrix(1,nx,1,ny);
  image2 = matrix(1,nx2,1,ny2);

  for(i=1;i<=nx;i++)
    {
      xposvec[i] = 1.0*i;
    }
  for(j=1;j<=ny;j++)
    {
      yposvec[j] = 1.0*j;
    }

  splie2(xposvec,yposvec,image,nx,ny,y2a);

  rotation*=(PI/180.0);
  if(ctrim!=1)
    {
      /*Circular zero trimming will not be used*/
      for(i=1;i<=nx2;i++)
	{
	  for(j=1;j<=ny2;j++)
	    {
	      xpos = xcen + (1.0*i-1.0*zpvec[1]-xcen)*cos(rotation)-(1.0*j-1.0*zpvec[3]-ycen)*sin(rotation);
	      ypos = ycen + (1.0*j-1.0*zpvec[3]-ycen)*cos(rotation)+(1.0*i-1.0*zpvec[1]-xcen)*sin(rotation);
	      if(xpos>=ztvec[1]+1&&xpos<=nx-ztvec[2]&&ypos>=ztvec[3]+1&&ypos<=ny-ztvec[4])
		{
		  splin2(xposvec,yposvec,image,y2a,nx,ny,xpos,ypos,&yval);
		  image2[i][j] = yval;
		}
	      else{
		image2[i][j] = 0.0;
	      }
	    }
	}
    }
  else
    {
      /*Circular zero trimming will be used*/
      for(i=1;i<=nx2;i++)
	{
	  for(j=1;j<=ny2;j++)
	    {
	      xpos = xcen + (1.0*i-1.0*zpvec[1]-xcen)*cos(rotation)-(1.0*j-1.0*zpvec[3]-ycen)*sin(rotation);
	      ypos = ycen + (1.0*j-1.0*zpvec[3]-ycen)*cos(rotation)+(1.0*i-1.0*zpvec[1]-xcen)*sin(rotation);
	      radius = pow(pow(xpos-cvec[1],2.0)+pow(ypos-cvec[2],2.0),0.5);
	      if(xpos>=ztvec[1]+1&&xpos<=nx-ztvec[2]&&ypos>=ztvec[3]+1&&ypos<=ny-ztvec[4]&&radius<=cvec[3])
		{
		  splin2(xposvec,yposvec,image,y2a,nx,ny,xpos,ypos,&yval);
		  image2[i][j] = yval;
		}
	      else{
		image2[i][j] = 0.0;
	      }
	    }
	}
    }


  for(i=1;i<=nx2;i++)
    {
      for(j=1;j<=ny2;j++)
	{
	  imageout[i][j] = image2[i][j];
	}
    }	


  free_vector(xposvec,1,nx);
  free_vector(yposvec,1,ny);
  free_matrix(y2a,1,nx,1,ny);
  free_matrix(image2,1,nx2,1,ny2);
  return(1);
}



/*rotateshift01: given an image, nx, ny, shifts in x and y, a
floating point rotation in degrees, and floating point 
center coordinates xcen, ycen, shifts the light in the image by
xshift and yshift relative to the pixel grid, and then
rotates the light in the image by rotation degrees about
xcen, ycen, in the post-shift pixel grid, clockwise relative 
to the pixel grid.  Both shift and rotation are performed in
a single bilinear interpolation.
THE VARIABLE rotation IS EXPECTED IN UNITS OF DEGREES, NOT RADIANS.*/
int rotateshift01(float **image,int nx,int ny,float xshift,float yshift,float rotation,float xcen,float ycen)
{
  float **image2;
  int i,j;
  float xpos,ypos,xint1,xint2,yint,xposp,yposp;
  int llpx,llpy;

  image2 = matrix(1,nx,1,ny);
  rotation*=(PI/180.0);
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  xposp = 1.0*i-xshift;
	  yposp = 1.0*j-yshift;
	  xpos = xcen-xshift + (xposp-xcen+xshift)*cos(rotation) - (yposp-ycen+yshift)*sin(rotation);
	  ypos = ycen-yshift + (yposp-ycen+yshift)*cos(rotation) + (xposp-xcen+xshift)*sin(rotation);
	  llpx = xpos;
	  llpy = ypos;
	  if(llpx>=1&&llpx<nx&&llpy>=1&&llpy<ny)
	    {
	      xint1 = image[llpx][llpy]+(image[llpx+1][llpy]-image[llpx][llpy])*(xpos - 1.0*llpx);
	      xint2 = image[llpx][llpy+1]+(image[llpx+1][llpy+1]-image[llpx][llpy+1])*(xpos - 1.0*llpx);
	      image2[i][j] = xint1+(xint2-xint1)*(ypos-1.0*llpy);
	    }
	  else{
	    image2[i][j] = 0.0;
	  }
	}
    }
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image[i][j] = image2[i][j];
	}
    }	

  free_matrix(image2,1,nx,1,ny);
  return(1);
}

/*rotateshift02: given an image, nx, ny, shifts in x and y, a
floating point rotation in degrees, and floating point 
center coordinates xcen, ycen, shifts the light in the image by
xshift and yshift relative to the pixel grid, and then
rotates the light in the image by rotation degrees about
xcen, ycen, in the post-shift pixel grid, clockwise relative 
to the pixel grid.  Both shift and rotation are performed in
a single BICUBIC SPLINE interpolation.
THE VARIABLE rotation IS EXPECTED IN UNITS OF DEGREES, NOT RADIANS.*/
int rotateshift02(float **image,int nx,int ny,float xshift,float yshift,float rotation,float xcen,float ycen)
{
  float **image2,**y2a;
  int i,j;
  float xpos,ypos,xint1,xint2,yint,xposp,yposp,*xposvec,*yposvec,yval;
  int llpx,llpy;

  xposvec = vector(1,nx);
  yposvec = vector(1,ny);
  image2 = matrix(1,nx,1,ny);
  y2a = matrix(1,nx,1,ny);

  for(i=1;i<=nx;i++)
    {
      xposvec[i] = 1.0*i;
    }
  for(j=1;j<=ny;j++)
    {
      yposvec[j] = 1.0*j;
    }

  splie2(xposvec,yposvec,image,nx,ny,y2a);

  rotation*=(PI/180.0);
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  xposp = 1.0*i-xshift;
	  yposp = 1.0*j-yshift;
	  xpos = xcen-xshift + (xposp-xcen+xshift)*cos(rotation) - (yposp-ycen+yshift)*sin(rotation);
	  ypos = ycen-yshift + (yposp-ycen+yshift)*cos(rotation) + (xposp-xcen+xshift)*sin(rotation);
	  if(xpos>=1&&xpos<=nx&&ypos>=1&&ypos<=ny)
	    {
	      splin2(xposvec,yposvec,image,y2a,nx,ny,xpos,ypos,&yval);
	      image2[i][j] = yval;
	    }
	  else{
	    image2[i][j] = 0.0;
	  }
	}
    }
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image[i][j] = image2[i][j];
	}
    }	

  free_vector(xposvec,1,nx);
  free_vector(yposvec,1,ny);
  free_matrix(image2,1,nx,1,ny);
  free_matrix(y2a,1,nx,1,ny);

  return(1);
}

/*rotateshift03: given an image, nx, ny, shifts in x and y, a
floating point rotation in degrees, and floating point 
center coordinates xcen, ycen, shifts the light in the image by
xshift and yshift relative to the pixel grid, and then
rotates the light in the image by rotation degrees about
xcen, ycen, in the post-shift pixel grid, clockwise relative 
to the pixel grid.  Both shift and rotation are performed in
a single BICUBIC SPLINE interpolation.
THE VARIABLE rotation IS EXPECTED IN UNITS OF DEGREES, NOT RADIANS.
Simultaneously, zero trims and zero
pads the image, so that, provided the zero pads are chosen
properly, none of the image is lost off the edge of the
new image.  The calling function is reponsible to ensure
that the new image, image3, has the right dimensions.  Provided
the zero pads are set properly, no light should be lost except what  
is deliberately trimmed off in the zero trim.  rotate03 allows
the zero trim to shave off set amounts from the left side, right
side, top, and bottom of the image, with these parameters
being set in the four-element integer vector ztvec.  If
ctrim == 1, it also allows a radial zero trim using the
floating point vector cvec, which contains the center
x and y coords and then the radius of a circle on the image.
Any pixels lying outside this circle will be set to zero.
Both ztvec and cvec reference coordinates on the old,
unpadded image.  The four-element integer vector zpvec holds the
zero pads for the left, right, top, and bottom of the images.
nx and ny also refer to the un-zero-padded image.
However, xcen and ycen refer to the center of rotation
ON THE SHIFTED AND ZERO-PADDED IMAGE.*/
int rotateshift03(float **image,float **imageout,int nx,int ny,float xshift,float yshift,float rotation,float xcen,float ycen,int *ztvec,float *cvec,int ctrim,int *zpvec)
{
  float **image2,**y2a,radius;
  int i,j,nx2,ny2;
  float xpos,ypos,xint1,xint2,yint,xposp,yposp,*xposvec,*yposvec,yval;
  int llpx,llpy;

  nx2 = nx+zpvec[1]+zpvec[2];
  ny2 = ny+zpvec[3]+zpvec[4];

  printf("in rotateshift03.  nx2 = %d ny2 = %d\n",nx2,ny2);
  fflush(stdout);

  xposvec = vector(1,nx);
  yposvec = vector(1,ny);
  image2 = matrix(1,nx2,1,ny2);
  y2a = matrix(1,nx,1,ny);

  for(i=1;i<=nx;i++)
    {
      xposvec[i] = 1.0*i;
    }
  for(j=1;j<=ny;j++)
    {
      yposvec[j] = 1.0*j;
    }

  splie2(xposvec,yposvec,image,nx,ny,y2a);

  rotation*=(PI/180.0);
  if(ctrim!=1)
    {
      /*Circular zero trimming will not be used*/
      for(i=1;i<=nx2;i++)
	{
	  for(j=1;j<=ny2;j++)
	    {
	      xpos = xcen-xshift-1.0*zpvec[1] + (1.0*i-xcen)*cos(rotation) - (1.0*j-ycen)*sin(rotation);
	      ypos = ycen-yshift-1.0*zpvec[3] + (1.0*j-ycen)*cos(rotation) + (1.0*i-xcen)*sin(rotation);
	      if(xpos>=ztvec[1]+1&&xpos<=nx-ztvec[2]&&ypos>=ztvec[3]+1&&ypos<=ny-ztvec[4])
		{
		  splin2(xposvec,yposvec,image,y2a,nx,ny,xpos,ypos,&yval);
		  image2[i][j] = yval;
		}
	      else{
		image2[i][j] = 0.0;
	      }
	    }
	}
    }
  else
    {
      /*Circular zero trimming will be used*/
      for(i=1;i<=nx2;i++)
	{
	  for(j=1;j<=ny2;j++)
	    {
	      xpos = xcen-xshift-1.0*zpvec[1] + (1.0*i-xcen)*cos(rotation) - (1.0*j-ycen)*sin(rotation);
	      ypos = ycen-yshift-1.0*zpvec[3] + (1.0*j-ycen)*cos(rotation) + (1.0*i-xcen)*sin(rotation);
	      radius = pow(pow(xpos-cvec[1],2.0)+pow(ypos-cvec[2],2.0),0.5);
	      if(xpos>=ztvec[1]+1&&xpos<=nx-ztvec[2]&&ypos>=ztvec[3]+1&&ypos<=ny-ztvec[4]&&radius<=cvec[3])
		{
		  splin2(xposvec,yposvec,image,y2a,nx,ny,xpos,ypos,&yval);
		  image2[i][j] = yval;
		}
	      else{
		image2[i][j] = 0.0;
	      }
	    }
	}
    }


  for(i=1;i<=nx2;i++)
    {
      for(j=1;j<=ny2;j++)
	{
	  imageout[i][j] = image2[i][j];
	}
    }	

  free_vector(xposvec,1,nx);
  free_vector(yposvec,1,ny);
  free_matrix(image2,1,nx2,1,ny2);
  free_matrix(y2a,1,nx,1,ny);

  return(1);
}


/*scale01: Given an input image and a scale factor scale = outpix/inpix, scales
the input into a bigger image using bilinear interpolation.  outpix/inpix
refers to the size of the output pixels divided by the size of
the input pixels, that is, if it is 0.2 the dimensions of the image are
multiplied by 5.0.  This value should always be less than 1.0, since
interpolation is used.  The dimensions of the output will be nx2,ny2, but
these should be given by the input as nx2 = nx/scale, ny2 = ny/scale, or
else the whole image may not be present in the scaled version, or there
may be a large swaths of zeros.  Any source with a position x1,y1 on
the input image should have a position x1/scale,y1/scale on the output.*/
int scale01(float **image,int nx,int ny,float scale,float **image2,int nx2,int ny2)
{
  int i,j;
  float xpos,ypos,xint1,xint2,yint;
  int llpx,llpy;

  for(i=1;i<=nx2;i++)
    {
      for(j=1;j<=ny2;j++)
	{
	  xpos = (1.0*i-0.5)*scale;
	  ypos = (1.0*j-0.5)*scale;
	  llpx = xpos;
	  llpy = ypos;
	  if(llpx>=1&&llpx<nx&&llpy>=1&&llpy<ny)
	    {
	      xint1 = image[llpx][llpy]+(image[llpx+1][llpy]-image[llpx][llpy])*(xpos - 1.0*llpx);
	      xint2 = image[llpx][llpy+1]+(image[llpx+1][llpy+1]-image[llpx][llpy+1])*(xpos - 1.0*llpx);
	      image2[i][j] = xint1+(xint2-xint1)*(ypos-1.0*llpy);
	    }
	  else{
	    image2[i][j] = 0.0;
	  }
	}
    }
  return(1);
}



/*colfix01: given an image, and a range of rows, that is, a range in y,
averages together the range of rows into a vector.  Proceeds along this
vector.  At each point, finds the mean and rms of the CFIXP1 = 5
columns on either side of the column under consideration.  If the value
of the column differs from the average value of the columns CFIXP2 = 1
columns on either side of it by more than sigclip times the rms of the CFIXP1
adjacent columns, that column in the image is interpolated across.*/
int colfix01(float **image,int nx,int ny,int yl,int yh,float sigclip,int *ncol)
{
  float *colvec,mean1,rms,mean2,norm1,norm2;
  int i,j,k;


  colvec = vector(1,nx);
  *ncol = 0;
  if(yh<yl||yl<=1||yh>=ny)
    {
      printf("ERROR: colfix01 GIVEN BAD AVERAGING STRIP PARAMETERS\n");
      printf("ABORTING\n");
      return(0);
    }
  for(i=1;i<=nx;i++)
    {
      colvec[i] = 0.0;
      for(j=yl;j<=yh;j++)
	{
	  colvec[i]+=image[i][j];
	}
      colvec[i]/=(1.0*yh-1.0*yl+1.0);
    }
  fflush(stdout);

  for(i=1;i<=nx;i++)
    {
      fflush(stdout);
      norm1 = mean1 = 0.0;
      for(k=i-CFIXP1;k<=i+CFIXP1;k++)
	{
	  if(k!=i&&k>=1&&k<=nx)
	    {
	      norm1+=1.0;
	      mean1+=colvec[k];
	    }
	}
      mean1/=norm1;
      rms = norm1 = 0.0;
      for(k=i-CFIXP1;k<=i+CFIXP1;k++)
	{
	  if(k!=i&&k>=1&&k<=nx)
	    {
	      norm1+=1.0;
	      rms+=pow(colvec[k]-mean1,2.0);
	    }
	}
      rms = pow(rms/(norm1-1.0),0.5);
      mean2 = norm2 = 0.0;
      for(k=i-CFIXP2;k<=i+CFIXP2;k++)
	{
	  if(k!=i&&k>=1&&k<=nx)
	    {
	      norm2+=1.0;
	      mean2+=colvec[k];
	    }
	}
      mean2/=norm2;
      if(pow(pow(mean2-colvec[i],2.0),0.5)>sigclip*rms)
	{
	  *ncol = *ncol+1;
	  for(j=1;j<=ny;j++)
	    {
	      if(i==1)
		{
		  image[i][j] = image[i+1][j];
		}
	      else if(i==nx)
		{
		  image[i][j] = image[i-1][j];
		}
	      else{
		image[i][j] = 0.5*(image[i-1][j]+image[i+1][j]);
	      }
	    }
	}
    }
  free_vector(colvec,1,nx);
  return(1);
}

/*Like colfix01, but applies sigma clip to averaging along
columns in the construction of the average column vector.*/
int colfix02(float **image,int nx,int ny,int yl,int yh,float sigclip,int *ncol)
{
  float *colvec,mean1,rms,mean2,norm1,norm2;
  int i,j,k;

  printf("In colfix02: nx = %d, ny = %d, yl = %d, yh = %d, sigclip = %d\n",nx,ny,yl,yh,sigclip);
  fflush(stdout);

  colvec = vector(1,nx);
  *ncol = 0;
  if(yh<yl||yl<=0||yh>=ny)
    {
      printf("ERROR: colfix02 GIVEN BAD AVERAGING STRIP PARAMETERS\n");
      printf("ABORTING\n");
      return(0);
    }
  for(i=1;i<=nx;i++)
    {
      mean1 = norm1 = 0.0;
      for(j=yl;j<=yh;j++)
	{
	  norm1+=1.0;
	  mean1+=image[i][j];
	}
      mean1/=norm1;
      rms = norm1 = 0.0;
      for(j=yl;j<=yh;j++)
	{
	  norm1+=1.0;
	  rms+=pow(image[i][j]-mean1,2.0);
	}
      rms = pow(rms/norm1,0.5);
      mean2 = norm2 = 0.0;
      for(j=yl;j<=yh;j++)
	{
	  if(pow(pow(image[i][j]-mean1,2.0),0.5)<=sigclip*rms)
	    {
	      norm2+=1.0;
	      mean2+=image[i][j];
	    }
	}
      if(norm2!=0.0)
	{
	  colvec[i] = mean2;
	}
      else{
	colvec[i] = mean1;
	printf("WARNING: COLFIX02 FINDS ZERO VALID PIXLES\n");
	printf("PROCESSING WILL CONTINUE BUT THIS IS LOGICALLY IMPOSSILBE\n");
      }
    }

  for(i=1;i<=nx;i++)
    {
      norm1 = mean1 = 0.0;
      for(k=i-CFIXP1;k<=i+CFIXP1;k++)
	{
	  if(k!=i&&k>=1&&k<=nx)
	    {
	      norm1+=1.0;
	      mean1+=colvec[k];
	    }
	}
      mean1/=norm1;
      rms = norm1 = 0.0;
      for(k=i-CFIXP1;k<=i+CFIXP1;k++)
	{
	  if(k!=i&&k>=1&&k<=nx)
	    {
	      norm1+=1.0;
	      rms+=pow(colvec[k]-mean1,2.0);
	    }
	}
      rms = pow(rms/(norm1-1.0),0.5);
      mean2 = norm2 = 0.0;
      for(k=i-CFIXP2;k<=i+CFIXP2;k++)
	{
	  if(k!=i&&k>=1&&k<=nx)
	    {
	      norm2+=1.0;
	      mean2+=colvec[k];
	    }
	}
      mean2/=norm2;
      if(pow(pow(mean2-colvec[i],2.0),0.5)>sigclip*rms)
	{
	  *ncol = *ncol+1;
	  for(j=1;j<=ny;j++)
	    {
	      if(i==1)
		{
		  image[i][j] = image[i+1][j];
		}
	      else if(i==nx)
		{
		  image[i][j] = image[i-1][j];
		}
	      else{
		image[i][j] = 0.5*(image[i-1][j]+image[i+1][j]);
	      }
	    }
	}
    }
  free_vector(colvec,1,nx);
  return(1);
}


/*colfudge01: a program to correct column-column
variations that do not involve the whole column.*/
int colfudge01(float **image,int nx,int ny, int block,float lim)
{
  int i,j,k,l,nbx,nby,kbot,ktop,lbot,ltop;
  float **image2,**image3,nblockx,nblocky,**blockav,**colav;
  float norm1,norm2,bintxh,bintxl,bint,colint;
  int lowlockx,lowlocky,highlockx,highlocky,highnormx,highnormy;
  float flowlockx,flowlocky,fhighlockx,fhighlocky,fhighnormx,fhighnormy;
  float ximin,ximax,yimin,yimax;

  image2 = matrix(1,nx,1,ny);
  image3 = matrix(1,nx,1,ny);

  imcopy01(image,image2,nx,ny);
  /*unsharp mask image2*/
  unsharp01(image2,nx,ny,10);

  nblockx = 1.0*nx/(1.0*block);
  nblocky = 1.0*ny/(1.0*block);
  nbx = 1.0*(nblockx + 1.0);
  nby = 1.0*(nblocky + 1.0);

  if((1.0*nbx)-nblockx==1.0)
    {
      nbx-=1;
    }
  if((1.0*nby)-nblocky==1.0)
    {
      nby-=1;
    }


  blockav = matrix(1,nbx,1,nby);
  colav = matrix(1,nx,1,nby);

  for(i=1;i<=nbx;i++)
    {
      for(j=1;j<=nby;j++)
	{
	  blockav[i][j] = norm1 = 0.0;
	  kbot = (i-1)*block+1;
	  ktop = i*block;
	  lbot = (j-1)*block+1;
	  ltop = j*block;
	  if(ktop>nx)
	    {
	      ktop = nx;
	    }
	  if(ltop>ny)
	    {
	      ltop = ny;
	    }
	  for(k=kbot;k<=ktop;k++)
	    {
	      colav[k][j] = norm2 = 0.0;
	      for(l=lbot;l<=ltop;l++)
		{
		  if(pow(pow(image2[k][l],2.0),0.5)<lim)
		    {
		      blockav[i][j]+=image2[k][l];
		      norm1+=1.0;
		      colav[k][j]+=image2[k][l];
		      norm2+=1.0;
		    }
		}
	      if(norm2!=0.0)
		{
		  colav[k][j]/=norm2;
		}
	      else{
		colav[k][j] = 0.0;
	      }
	    }
	  if(norm1!=0.0)
	    {
	      blockav[i][j]/=norm1;
	    }
	  else{
	    blockav[i][j] = 0.0;
	  }
	}
    }
  /*Now we construct an interpolated image*/
  /*The idea is to add to each pixel the amount
    that would be necessary to make its interpolated
    column average equal to the interpolated block mean*/
  lowlockx = flowlockx = 1.0*(0.5*block + 0.5);
  lowlocky = flowlocky = 1.0*(0.5*block + 0.5);
  highlockx = fhighlockx = 1.0*(1.0*nx - 0.5*(1.0*nx - (1.0*nbx-1.0)*(1.0*block) + 1.0));
  highlocky = fhighlocky = 1.0*(1.0*ny - 0.5*(1.0*ny - (1.0*nby-1.0)*(1.0*block) + 1.0));
  highnormx = fhighnormx = 1.0*(1.0*nbx-2.0)*(1.0*block) + 1.0*(0.5*block+0.5);
  highnormy = fhighnormy = 1.0*(1.0*nby-2.0)*(1.0*block) + 1.0*(0.5*block+0.5);
  /*lower left corner*/
  for(k=1;k<=lowlockx;k++)
    {
      for(l=1;l<=lowlocky;l++)
	{
	  bint = blockav[1][1];
	  colint = colav[k][1];
	  image3[k][l] = bint - colint;
	}
    }
				
  /*lower right interp*/
  for(k=highnormx+1;k<=highlockx;k++)
    {
      for(l=1;l<=lowlocky;l++)
	{
	  bint = blockav[nbx-1][1] + (blockav[nbx][1]-blockav[nbx-1][1])*(1.0*k-fhighnormx)/(fhighlockx - fhighnormx);
	  colint = colav[k][1];
	  image3[k][l] = bint - colint;
	}
    }
  /*lower right lock*/
  for(k=highlockx+1;k<=nx;k++)
    {
      for(l=1;l<=lowlocky;l++)
	{
	  bint = blockav[nbx][1];
	  colint = colav[k][1];
	  image3[k][l] = bint - colint;
	}
    }
  /*rest of bottom of image*/
  for(k=lowlockx+1;k<=highnormx;k++)
    {
      i = (1.0*k+0.5*block-0.5)/(1.0*block);
      ximin = (1.0*i-1.0)*(1.0*block)+0.5*block+0.5;
      ximax = ximin+1.0*block;
      for(l=1;l<=lowlocky;l++)
	{
	  bint = blockav[i][1]+(blockav[i+1][1]-blockav[i][1])*(1.0*k-ximin)/(ximax-ximin);
	  colint = colav[k][1];
	  image3[k][l] = bint - colint;
	}
    }
  /*upper left lock corner*/
  for(k=1;k<=lowlockx;k++)
    {
      for(l=highlocky+1;l<=ny;l++)
	{
	  bint = blockav[1][nby];
	  colint = colav[k][nby];
	  image3[k][l] = bint-colint;
	}
    }
  /*upper right xy lock corner*/
  for(k=highlockx+1;k<=nx;k++)
    {
      for(l=highlocky+1;l<=ny;l++)
	{
	  bint = blockav[nbx][nby];
	  colint = colav[k][nby];
	  image3[k][l] = bint-colint;
	}
    }
  /*upper right int x lock y corner*/
  for(k=highnormx+1;k<=highlockx;k++)
    {
      for(l=highlocky+1;l<=ny;l++)
	{
	  bint = blockav[nbx-1][nby] + (blockav[nbx][nby]-blockav[nbx-1][nby])*(1.0*k-fhighnormx)/(fhighlockx - fhighnormx);
	  colint = colav[k][nby];
	  image3[k][l] = bint - colint;
	}
    }
  /*rest of top y lock strip*/
  for(k=lowlockx+1;k<=highnormx;k++)
    {
      i = (1.0*k+0.5*block-0.5)/(1.0*block);
      ximin = (1.0*i-1.0)*(1.0*block)+0.5*block+0.5;
      ximax = ximin+1.0*block;
      for(l=highlocky+1;l<=ny;l++)
	{
	  bint = blockav[i][nby]+(blockav[i+1][nby]-blockav[i][nby])*(1.0*k-ximin)/(ximax-ximin);
	  colint = colav[k][nby];
	  image3[k][l] = bint - colint;
	}
    }
  /*upper left x lock y int corner*/
  for(k=1;k<=lowlockx;k++)
    {
      for(l=highnormy+1;l<=highlocky;l++)
	{
	  bint = blockav[1][nby-1] + (blockav[1][nby]-blockav[1][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  colint = colav[k][nby-1] + (colav[k][nby]-colav[k][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  image3[k][l] = bint - colint;
	}
    }
  /*upper right x lock y int corner*/
  for(k=highlockx+1;k<=nx;k++)
    {
      for(l=highnormy+1;l<=highlocky;l++)
	{
	  bint = blockav[nbx][nby-1] + (blockav[nbx][nby]-blockav[nbx][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  colint = colav[k][nby-1] + (colav[k][nby]-colav[k][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  image3[k][l] = bint - colint;
	}
    }
  /*upper right x int y int corner*/
  for(k=highnormx+1;k<=highlockx;k++)
    {
      for(l=highnormy+1;l<=highlocky;l++)
	{
	  bintxh = blockav[nbx][nby-1] + (blockav[nbx][nby]-blockav[nbx][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  bintxl = blockav[nbx-1][nby-1] + (blockav[nbx-1][nby]-blockav[nbx-1][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  bint = bintxl + (bintxh-bintxl)*(1.0*k - fhighnormx)/(fhighlockx - fhighnormx);
	  colint = colav[k][nby-1] + (colav[k][nby]-colav[k][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  image3[k][l] = bint - colint;
	}
    }
  /*rest of top y int, x normal strip*/
  for(k=lowlockx+1;k<=highnormx;k++)
    {
      i = (1.0*k+0.5*block-0.5)/(1.0*block);
      ximin = (1.0*i-1.0)*(1.0*block)+0.5*block+0.5;
      ximax = ximin+1.0*block;
      for(l=highnormy+1;l<=highlocky;l++)
	{
	  bintxh = blockav[i+1][nby-1] + (blockav[i+1][nby]-blockav[i+1][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  bintxl = blockav[i][nby-1] + (blockav[i][nby]-blockav[i][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  bint = bintxl + (bintxh-bintxl)*(1.0*k-ximin)/(ximax-ximin);
	  colint = colav[k][nby-1] + (colav[k][nby]-colav[k][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  image3[k][l] = bint - colint;
	}
    }
  /*left hand x lock y normal strip*/
  for(k=1;k<=lowlockx;k++)
    {
      for(l=lowlocky+1;l<=highnormy;l++)
	{
	  j = (1.0*l+0.5*block-0.5)/(1.0*block);
	  yimin = (1.0*j-1.0)*(1.0*block)+0.5*block+0.5;
	  yimax = yimin+(1.0*block);
	  bint = blockav[1][j] + (blockav[1][j+1]-blockav[1][j])*(1.0*l-yimin)/(yimax-yimin);
	  colint = colav[k][j] + (colav[k][j+1]-colav[k][j])*(1.0*l-yimin)/(yimax-yimin);
	  image3[k][l] = bint-colint;
	}
    }
  /*right hand x lock y normal strip*/
  for(k=highlockx+1;k<=nx;k++)
    {
      for(l=lowlocky+1;l<=highnormy;l++)
	{
	  j = (1.0*l+0.5*block-0.5)/(1.0*block);
	  yimin = (1.0*j-1.0)*(1.0*block)+0.5*block+0.5;
	  yimax = yimin+(1.0*block);
	  bint = blockav[nbx][j] + (blockav[nbx][j+1]-blockav[nbx][j])*(1.0*l-yimin)/(yimax-yimin);
	  colint = colav[k][j] + (colav[k][j+1]-colav[k][j])*(1.0*l-yimin)/(yimax-yimin);
	  image3[k][l] = bint-colint;
	}
    }
  /*right hand x int y normal strip*/
  for(k=highnormx+1;k<=highlockx;k++)
    {
      for(l=lowlocky+1;l<=highnormy;l++)
	{
	  j = (1.0*l+0.5*block-0.5)/(1.0*block);
	  yimin = (1.0*j-1.0)*(1.0*block)+0.5*block+0.5;
	  yimax = yimin+(1.0*block);
	  bintxh = blockav[nbx][j] + (blockav[nbx][j+1]-blockav[nbx][j])*(1.0*l-yimin)/(yimax-yimin);
	  bintxl = blockav[nbx-1][j] + (blockav[nbx-1][j+1]-blockav[nbx-1][j])*(1.0*l-yimin)/(yimax-yimin);
	  bint = bintxl + (bintxh-bintxl)*(1.0*k-fhighnormx)/(fhighlockx-fhighnormx);
	  colint = colav[k][j] + (colav[k][j+1]-colav[k][j])*(1.0*l-yimin)/(yimax-yimin);
	  image3[k][l] = bint-colint;
	}
    }
  /*remainder of image*/
  for(k=lowlockx+1;k<=highnormx;k++)
    {
      i = (1.0*k+0.5*block-0.5)/(1.0*block);
      ximin = (1.0*i-1.0)*(1.0*block)+0.5*block+0.5;
      ximax = ximin+1.0*block;
      for(l=lowlocky+1;l<=highnormy;l++)
	{
	  j = (1.0*l+0.5*block-0.5)/(1.0*block);
	  yimin = (1.0*j-1.0)*(1.0*block)+0.5*block+0.5;
	  yimax = yimin+(1.0*block);
	  bintxh = blockav[i+1][j] + (blockav[i+1][j+1]-blockav[i+1][j])*(1.0*l-yimin)/(yimax-yimin);
	  bintxl = blockav[i][j] + (blockav[i][j+1]-blockav[i][j])*(1.0*l-yimin)/(yimax-yimin);
	  bint = bintxl + (bintxh-bintxl)*(1.0*k-ximin)/(ximax-ximin);
	  colint = colav[k][j] + (colav[k][j+1]-colav[k][j])*(1.0*l-yimin)/(yimax-yimin);
	  image3[k][l] = bint-colint;
	}
    }
  /*add this image to image 1*/
  for(k=1;k<=nx;k++)
    {
      for(l=1;l<=ny;l++)
	{
	  image[k][l]+=image3[k][l];
	}
    }

  free_matrix(image2,1,nx,1,ny);
  free_matrix(image3,1,nx,1,ny);
  free_matrix(blockav,1,nbx,1,nby);
  free_matrix(colav,1,nx,1,nby);

  return(1);
}

/*colfudge02: a program to correct column-column
variations that do not involve the whole column.
It works exactly like colfudge01 except that in
the initial creation of the averaged column vectors,
etc, it uses creeping mean combination with
a rejection fraction of COLFUDGEREJ, currently
50%..*/
int colfudge02(float **image,int nx,int ny, int block,float lim)
{
  int i,j,k,l,nbx,nby,kbot,ktop,lbot,ltop;
  float **image2,**image3,nblockx,nblocky,**blockav,**colav;
  float norm1,norm2,bintxh,bintxl,bint,colint;
  int lowlockx,lowlocky,highlockx,highlocky,highnormx,highnormy;
  float flowlockx,flowlocky,fhighlockx,fhighlocky,fhighnormx,fhighnormy;
  float ximin,ximax,yimin,yimax;
  float *ccvec,*cboxvec,data1,data2;
  int ccnum,cboxnum,runct,lossct;

  image2 = matrix(1,nx,1,ny);
  image3 = matrix(1,nx,1,ny);
  ccvec = vector(1,2*block);
  cboxvec = vector(1,4*block*block);


  imcopy01(image,image2,nx,ny);
  /*unsharp mask image2*/
  unsharp01(image2,nx,ny,10);

  nblockx = 1.0*nx/(1.0*block);
  nblocky = 1.0*ny/(1.0*block);
  nbx = 1.0*(nblockx + 1.0);
  nby = 1.0*(nblocky + 1.0);

  lossct = runct = 0;

  if((1.0*nbx)-nblockx==1.0)
    {
      nbx-=1;
    }
  if((1.0*nby)-nblocky==1.0)
    {
      nby-=1;
    }


  blockav = matrix(1,nbx,1,nby);
  colav = matrix(1,nx,1,nby);

  for(i=1;i<=nbx;i++)
    {
      for(j=1;j<=nby;j++)
	{
	  blockav[i][j] = 0.0;
	  cboxnum = 0;
	  kbot = (i-1)*block+1;
	  ktop = i*block;
	  lbot = (j-1)*block+1;
	  ltop = j*block;
	  if(ktop>nx)
	    {
	      ktop = nx;
	    }
	  if(ltop>ny)
	    {
	      ltop = ny;
	    }
	  for(k=kbot;k<=ktop;k++)
	    {
	      colav[k][j] = 0.0;
	      ccnum = 0;
	      for(l=lbot;l<=ltop;l++)
		{
		  if(pow(pow(image2[k][l],2.0),0.5)<lim)
		    {
		      cboxnum+=1;
		      cboxvec[cboxnum] = image2[k][l];
		      ccnum+=1;
		      ccvec[ccnum] = image2[k][l];
		    }
		}
	      if(ccnum<=(ltop-lbot+1)/2)
		{
		  lossct+=1;
		}
	      runct+=1;
	      if(ccnum>1)
		{
		  creepvec01(ccvec,ccnum,COLFUDGEREJ,&data1,&data2);
		  colav[k][j] = data1;
		}
	      else if(ccnum==1)
		{
		  colav[k][j] = ccvec[1];
		}
	      else{
		colav[k][j] = 0.0;
	      }
	    }
	  if(cboxnum!=0)
	    {
	      creepvec01(cboxvec,cboxnum,COLFUDGEREJ,&data1,&data2);
	      blockav[i][j] = data1;
	    }
	  else{
	    blockav[i][j] = 0.0;
	  }
	}
    }
  /*Now we construct an interpolated image*/
  /*The idea is to add to each pixel the amount
    that would be necessary to make its interpolated
    column average equal to the interpolated block mean*/
  lowlockx = flowlockx = 1.0*(0.5*block + 0.5);
  lowlocky = flowlocky = 1.0*(0.5*block + 0.5);
  highlockx = fhighlockx = 1.0*(1.0*nx - 0.5*(1.0*nx - (1.0*nbx-1.0)*(1.0*block) + 1.0));
  highlocky = fhighlocky = 1.0*(1.0*ny - 0.5*(1.0*ny - (1.0*nby-1.0)*(1.0*block) + 1.0));
  highnormx = fhighnormx = 1.0*(1.0*nbx-2.0)*(1.0*block) + 1.0*(0.5*block+0.5);
  highnormy = fhighnormy = 1.0*(1.0*nby-2.0)*(1.0*block) + 1.0*(0.5*block+0.5);
  /*lower left corner*/
  for(k=1;k<=lowlockx;k++)
    {
      for(l=1;l<=lowlocky;l++)
	{
	  bint = blockav[1][1];
	  colint = colav[k][1];
	  image3[k][l] = bint - colint;
	}
    }
				
  /*lower right interp*/
  for(k=highnormx+1;k<=highlockx;k++)
    {
      for(l=1;l<=lowlocky;l++)
	{
	  bint = blockav[nbx-1][1] + (blockav[nbx][1]-blockav[nbx-1][1])*(1.0*k-fhighnormx)/(fhighlockx - fhighnormx);
	  colint = colav[k][1];
	  image3[k][l] = bint - colint;
	}
    }
  /*lower right lock*/
  for(k=highlockx+1;k<=nx;k++)
    {
      for(l=1;l<=lowlocky;l++)
	{
	  bint = blockav[nbx][1];
	  colint = colav[k][1];
	  image3[k][l] = bint - colint;
	}
    }
  /*rest of bottom of image*/
  for(k=lowlockx+1;k<=highnormx;k++)
    {
      i = (1.0*k+0.5*block-0.5)/(1.0*block);
      ximin = (1.0*i-1.0)*(1.0*block)+0.5*block+0.5;
      ximax = ximin+1.0*block;
      for(l=1;l<=lowlocky;l++)
	{
	  bint = blockav[i][1]+(blockav[i+1][1]-blockav[i][1])*(1.0*k-ximin)/(ximax-ximin);
	  colint = colav[k][1];
	  image3[k][l] = bint - colint;
	}
    }
  /*upper left lock corner*/
  for(k=1;k<=lowlockx;k++)
    {
      for(l=highlocky+1;l<=ny;l++)
	{
	  bint = blockav[1][nby];
	  colint = colav[k][nby];
	  image3[k][l] = bint-colint;
	}
    }
  /*upper right xy lock corner*/
  for(k=highlockx+1;k<=nx;k++)
    {
      for(l=highlocky+1;l<=ny;l++)
	{
	  bint = blockav[nbx][nby];
	  colint = colav[k][nby];
	  image3[k][l] = bint-colint;
	}
    }
  /*upper right int x lock y corner*/
  for(k=highnormx+1;k<=highlockx;k++)
    {
      for(l=highlocky+1;l<=ny;l++)
	{
	  bint = blockav[nbx-1][nby] + (blockav[nbx][nby]-blockav[nbx-1][nby])*(1.0*k-fhighnormx)/(fhighlockx - fhighnormx);
	  colint = colav[k][nby];
	  image3[k][l] = bint - colint;
	}
    }
  /*rest of top y lock strip*/
  for(k=lowlockx+1;k<=highnormx;k++)
    {
      i = (1.0*k+0.5*block-0.5)/(1.0*block);
      ximin = (1.0*i-1.0)*(1.0*block)+0.5*block+0.5;
      ximax = ximin+1.0*block;
      for(l=highlocky+1;l<=ny;l++)
	{
	  bint = blockav[i][nby]+(blockav[i+1][nby]-blockav[i][nby])*(1.0*k-ximin)/(ximax-ximin);
	  colint = colav[k][nby];
	  image3[k][l] = bint - colint;
	}
    }
  /*upper left x lock y int corner*/
  for(k=1;k<=lowlockx;k++)
    {
      for(l=highnormy+1;l<=highlocky;l++)
	{
	  bint = blockav[1][nby-1] + (blockav[1][nby]-blockav[1][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  colint = colav[k][nby-1] + (colav[k][nby]-colav[k][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  image3[k][l] = bint - colint;
	}
    }
  /*upper right x lock y int corner*/
  for(k=highlockx+1;k<=nx;k++)
    {
      for(l=highnormy+1;l<=highlocky;l++)
	{
	  bint = blockav[nbx][nby-1] + (blockav[nbx][nby]-blockav[nbx][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  colint = colav[k][nby-1] + (colav[k][nby]-colav[k][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  image3[k][l] = bint - colint;
	}
    }
  /*upper right x int y int corner*/
  for(k=highnormx+1;k<=highlockx;k++)
    {
      for(l=highnormy+1;l<=highlocky;l++)
	{
	  bintxh = blockav[nbx][nby-1] + (blockav[nbx][nby]-blockav[nbx][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  bintxl = blockav[nbx-1][nby-1] + (blockav[nbx-1][nby]-blockav[nbx-1][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  bint = bintxl + (bintxh-bintxl)*(1.0*k - fhighnormx)/(fhighlockx - fhighnormx);
	  colint = colav[k][nby-1] + (colav[k][nby]-colav[k][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  image3[k][l] = bint - colint;
	}
    }
  /*rest of top y int, x normal strip*/
  for(k=lowlockx+1;k<=highnormx;k++)
    {
      i = (1.0*k+0.5*block-0.5)/(1.0*block);
      ximin = (1.0*i-1.0)*(1.0*block)+0.5*block+0.5;
      ximax = ximin+1.0*block;
      for(l=highnormy+1;l<=highlocky;l++)
	{
	  bintxh = blockav[i+1][nby-1] + (blockav[i+1][nby]-blockav[i+1][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  bintxl = blockav[i][nby-1] + (blockav[i][nby]-blockav[i][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  bint = bintxl + (bintxh-bintxl)*(1.0*k-ximin)/(ximax-ximin);
	  colint = colav[k][nby-1] + (colav[k][nby]-colav[k][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  image3[k][l] = bint - colint;
	}
    }
  /*left hand x lock y normal strip*/
  for(k=1;k<=lowlockx;k++)
    {
      for(l=lowlocky+1;l<=highnormy;l++)
	{
	  j = (1.0*l+0.5*block-0.5)/(1.0*block);
	  yimin = (1.0*j-1.0)*(1.0*block)+0.5*block+0.5;
	  yimax = yimin+(1.0*block);
	  bint = blockav[1][j] + (blockav[1][j+1]-blockav[1][j])*(1.0*l-yimin)/(yimax-yimin);
	  colint = colav[k][j] + (colav[k][j+1]-colav[k][j])*(1.0*l-yimin)/(yimax-yimin);
	  image3[k][l] = bint-colint;
	}
    }
  /*right hand x lock y normal strip*/
  for(k=highlockx+1;k<=nx;k++)
    {
      for(l=lowlocky+1;l<=highnormy;l++)
	{
	  j = (1.0*l+0.5*block-0.5)/(1.0*block);
	  yimin = (1.0*j-1.0)*(1.0*block)+0.5*block+0.5;
	  yimax = yimin+(1.0*block);
	  bint = blockav[nbx][j] + (blockav[nbx][j+1]-blockav[nbx][j])*(1.0*l-yimin)/(yimax-yimin);
	  colint = colav[k][j] + (colav[k][j+1]-colav[k][j])*(1.0*l-yimin)/(yimax-yimin);
	  image3[k][l] = bint-colint;
	}
    }
  /*right hand x int y normal strip*/
  for(k=highnormx+1;k<=highlockx;k++)
    {
      for(l=lowlocky+1;l<=highnormy;l++)
	{
	  j = (1.0*l+0.5*block-0.5)/(1.0*block);
	  yimin = (1.0*j-1.0)*(1.0*block)+0.5*block+0.5;
	  yimax = yimin+(1.0*block);
	  bintxh = blockav[nbx][j] + (blockav[nbx][j+1]-blockav[nbx][j])*(1.0*l-yimin)/(yimax-yimin);
	  bintxl = blockav[nbx-1][j] + (blockav[nbx-1][j+1]-blockav[nbx-1][j])*(1.0*l-yimin)/(yimax-yimin);
	  bint = bintxl + (bintxh-bintxl)*(1.0*k-fhighnormx)/(fhighlockx-fhighnormx);
	  colint = colav[k][j] + (colav[k][j+1]-colav[k][j])*(1.0*l-yimin)/(yimax-yimin);
	  image3[k][l] = bint-colint;
	}
    }
  /*remainder of image*/
  for(k=lowlockx+1;k<=highnormx;k++)
    {
      i = (1.0*k+0.5*block-0.5)/(1.0*block);
      ximin = (1.0*i-1.0)*(1.0*block)+0.5*block+0.5;
      ximax = ximin+1.0*block;
      for(l=lowlocky+1;l<=highnormy;l++)
	{
	  j = (1.0*l+0.5*block-0.5)/(1.0*block);
	  yimin = (1.0*j-1.0)*(1.0*block)+0.5*block+0.5;
	  yimax = yimin+(1.0*block);
	  bintxh = blockav[i+1][j] + (blockav[i+1][j+1]-blockav[i+1][j])*(1.0*l-yimin)/(yimax-yimin);
	  bintxl = blockav[i][j] + (blockav[i][j+1]-blockav[i][j])*(1.0*l-yimin)/(yimax-yimin);
	  bint = bintxl + (bintxh-bintxl)*(1.0*k-ximin)/(ximax-ximin);
	  colint = colav[k][j] + (colav[k][j+1]-colav[k][j])*(1.0*l-yimin)/(yimax-yimin);
	  image3[k][l] = bint-colint;
	}
    }
  /*add this image to image 1*/
  for(k=1;k<=nx;k++)
    {
      for(l=1;l<=ny;l++)
	{
	  image[k][l]+=image3[k][l];
	}
    }

  printf("Ran creepvec %d times.  50%% or more of the points\n",runct);
  printf("were out of range on %d of these\n",lossct);

  free_matrix(image2,1,nx,1,ny);
  free_matrix(image3,1,nx,1,ny);
  free_matrix(blockav,1,nbx,1,nby);
  free_matrix(colav,1,nx,1,nby);
  free_vector(ccvec,1,2*block);
  free_vector(cboxvec,1,4*block*block);
  return(1);
}

/*colfudge02f: Exactly like colfudge02, but works better*/
int colfudge02f(float **image,int nx,int ny, int block,float lim)
{
  int i,j,k,l,nbx,nby,kbot,ktop,lbot,ltop;
  float **image2,**image3,nblockx,nblocky,**blockav,**colav;
  float norm1,norm2,bintxh,bintxl,bint,colint;
  int lowlockx,lowlocky,highlockx,highlocky,highnormx,highnormy;
  float flowlockx,flowlocky,fhighlockx,fhighlocky,fhighnormx,fhighnormy;
  float ximin,ximax,yimin,yimax;
  float *ccvec,*cboxvec,data1,data2;
  int ccnum,cboxnum,runct,lossct;

  image2 = matrix(1,nx,1,ny);
  image3 = matrix(1,nx,1,ny);
  ccvec = vector(1,2*block);
  cboxvec = vector(1,4*block*block);


  imcopy01(image,image2,nx,ny);
  /*unsharp mask image2*/
  unsharp01(image2,nx,ny,10);

  nblockx = 1.0*nx/(1.0*block);
  nblocky = 1.0*ny/(1.0*block);
  nbx = 1.0*(nblockx + 1.0);
  nby = 1.0*(nblocky + 1.0);

  lossct = runct = 0;

  if((1.0*nbx)-nblockx==1.0)
    {
      nbx-=1;
    }
  if((1.0*nby)-nblocky==1.0)
    {
      nby-=1;
    }


  blockav = matrix(1,nbx,1,nby);
  colav = matrix(1,nx,1,nby);

  for(i=1;i<=nbx;i++)
    {
      for(j=1;j<=nby;j++)
	{
	  blockav[i][j] = 0.0;
	  cboxnum = 0;
	  kbot = (i-1)*block+1;
	  ktop = i*block;
	  lbot = (j-1)*block+1;
	  ltop = j*block;
	  if(ktop>nx)
	    {
	      ktop = nx;
	    }
	  if(ltop>ny)
	    {
	      ltop = ny;
	    }
	  for(k=kbot;k<=ktop;k++)
	    {
	      for(l=lbot;l<=ltop;l++)
		{
		  if(pow(pow(image2[k][l],2.0),0.5)<lim)
		    {
		      cboxnum+=1;
		      cboxvec[cboxnum] = image2[k][l];
		    }
		}
	    }
	  if(cboxnum!=0)
	    {
	      creepvec01(cboxvec,cboxnum,COLFUDGEREJ,&data1,&data2);
	      blockav[i][j] = data1;
	    }
	  else{
	    blockav[i][j] = 0.0;
	  }
	  for(k=kbot;k<=ktop;k++)
	    {
	      colav[k][j] = 0.0;
	      ccnum = 0;
	      for(l=lbot;l<=ltop;l++)
		{
		  if(pow(pow(image2[k][l],2.0),0.5)<lim)
		    {
		      ccnum+=1;
		      ccvec[ccnum] = image2[k][l];
		    }
		}
	      if(ccnum<=(ltop-lbot+1)/2)
		{
		  lossct+=1;
		}
	      runct+=1;
	      if(ccnum>(ltop-lbot+1)/CFLOSSFAC)
		{
		  creepvec01(ccvec,ccnum,COLFUDGEREJ,&data1,&data2);
		  colav[k][j] = data1;
		}
	      else{
		colav[k][j] = blockav[i][j];
	      }
	    }
	}
    }

  /*Now we construct an interpolated image*/
  /*The idea is to add to each pixel the amount
    that would be necessary to make its interpolated
    column average equal to the interpolated block mean*/
  lowlockx = flowlockx = 1.0*(0.5*block + 0.5);
  lowlocky = flowlocky = 1.0*(0.5*block + 0.5);
  highlockx = fhighlockx = 1.0*(1.0*nx - 0.5*(1.0*nx - (1.0*nbx-1.0)*(1.0*block) + 1.0));
  highlocky = fhighlocky = 1.0*(1.0*ny - 0.5*(1.0*ny - (1.0*nby-1.0)*(1.0*block) + 1.0));
  highnormx = fhighnormx = 1.0*(1.0*nbx-2.0)*(1.0*block) + 1.0*(0.5*block+0.5);
  highnormy = fhighnormy = 1.0*(1.0*nby-2.0)*(1.0*block) + 1.0*(0.5*block+0.5);
  /*lower left corner*/
  for(k=1;k<=lowlockx;k++)
    {
      for(l=1;l<=lowlocky;l++)
	{
	  bint = blockav[1][1];
	  colint = colav[k][1];
	  image3[k][l] = bint - colint;
	}
    }
				
  /*lower right interp*/
  for(k=highnormx+1;k<=highlockx;k++)
    {
      for(l=1;l<=lowlocky;l++)
	{
	  bint = blockav[nbx-1][1] + (blockav[nbx][1]-blockav[nbx-1][1])*(1.0*k-fhighnormx)/(fhighlockx - fhighnormx);
	  colint = colav[k][1];
	  image3[k][l] = bint - colint;
	}
    }
  /*lower right lock*/
  for(k=highlockx+1;k<=nx;k++)
    {
      for(l=1;l<=lowlocky;l++)
	{
	  bint = blockav[nbx][1];
	  colint = colav[k][1];
	  image3[k][l] = bint - colint;
	}
    }
  /*rest of bottom of image*/
  for(k=lowlockx+1;k<=highnormx;k++)
    {
      i = (1.0*k+0.5*block-0.5)/(1.0*block);
      ximin = (1.0*i-1.0)*(1.0*block)+0.5*block+0.5;
      ximax = ximin+1.0*block;
      for(l=1;l<=lowlocky;l++)
	{
	  bint = blockav[i][1]+(blockav[i+1][1]-blockav[i][1])*(1.0*k-ximin)/(ximax-ximin);
	  colint = colav[k][1];
	  image3[k][l] = bint - colint;
	}
    }
  /*upper left lock corner*/
  for(k=1;k<=lowlockx;k++)
    {
      for(l=highlocky+1;l<=ny;l++)
	{
	  bint = blockav[1][nby];
	  colint = colav[k][nby];
	  image3[k][l] = bint-colint;
	}
    }
  /*upper right xy lock corner*/
  for(k=highlockx+1;k<=nx;k++)
    {
      for(l=highlocky+1;l<=ny;l++)
	{
	  bint = blockav[nbx][nby];
	  colint = colav[k][nby];
	  image3[k][l] = bint-colint;
	}
    }
  /*upper right int x lock y corner*/
  for(k=highnormx+1;k<=highlockx;k++)
    {
      for(l=highlocky+1;l<=ny;l++)
	{
	  bint = blockav[nbx-1][nby] + (blockav[nbx][nby]-blockav[nbx-1][nby])*(1.0*k-fhighnormx)/(fhighlockx - fhighnormx);
	  colint = colav[k][nby];
	  image3[k][l] = bint - colint;
	}
    }
  /*rest of top y lock strip*/
  for(k=lowlockx+1;k<=highnormx;k++)
    {
      i = (1.0*k+0.5*block-0.5)/(1.0*block);
      ximin = (1.0*i-1.0)*(1.0*block)+0.5*block+0.5;
      ximax = ximin+1.0*block;
      for(l=highlocky+1;l<=ny;l++)
	{
	  bint = blockav[i][nby]+(blockav[i+1][nby]-blockav[i][nby])*(1.0*k-ximin)/(ximax-ximin);
	  colint = colav[k][nby];
	  image3[k][l] = bint - colint;
	}
    }
  /*upper left x lock y int corner*/
  for(k=1;k<=lowlockx;k++)
    {
      for(l=highnormy+1;l<=highlocky;l++)
	{
	  bint = blockav[1][nby-1] + (blockav[1][nby]-blockav[1][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  colint = colav[k][nby-1] + (colav[k][nby]-colav[k][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  image3[k][l] = bint - colint;
	}
    }
  /*upper right x lock y int corner*/
  for(k=highlockx+1;k<=nx;k++)
    {
      for(l=highnormy+1;l<=highlocky;l++)
	{
	  bint = blockav[nbx][nby-1] + (blockav[nbx][nby]-blockav[nbx][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  colint = colav[k][nby-1] + (colav[k][nby]-colav[k][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  image3[k][l] = bint - colint;
	}
    }
  /*upper right x int y int corner*/
  for(k=highnormx+1;k<=highlockx;k++)
    {
      for(l=highnormy+1;l<=highlocky;l++)
	{
	  bintxh = blockav[nbx][nby-1] + (blockav[nbx][nby]-blockav[nbx][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  bintxl = blockav[nbx-1][nby-1] + (blockav[nbx-1][nby]-blockav[nbx-1][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  bint = bintxl + (bintxh-bintxl)*(1.0*k - fhighnormx)/(fhighlockx - fhighnormx);
	  colint = colav[k][nby-1] + (colav[k][nby]-colav[k][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  image3[k][l] = bint - colint;
	}
    }
  /*rest of top y int, x normal strip*/
  for(k=lowlockx+1;k<=highnormx;k++)
    {
      i = (1.0*k+0.5*block-0.5)/(1.0*block);
      ximin = (1.0*i-1.0)*(1.0*block)+0.5*block+0.5;
      ximax = ximin+1.0*block;
      for(l=highnormy+1;l<=highlocky;l++)
	{
	  bintxh = blockav[i+1][nby-1] + (blockav[i+1][nby]-blockav[i+1][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  bintxl = blockav[i][nby-1] + (blockav[i][nby]-blockav[i][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  bint = bintxl + (bintxh-bintxl)*(1.0*k-ximin)/(ximax-ximin);
	  colint = colav[k][nby-1] + (colav[k][nby]-colav[k][nby-1])*(1.0*l - fhighnormy)/(fhighlocky-fhighnormy);
	  image3[k][l] = bint - colint;
	}
    }
  /*left hand x lock y normal strip*/
  for(k=1;k<=lowlockx;k++)
    {
      for(l=lowlocky+1;l<=highnormy;l++)
	{
	  j = (1.0*l+0.5*block-0.5)/(1.0*block);
	  yimin = (1.0*j-1.0)*(1.0*block)+0.5*block+0.5;
	  yimax = yimin+(1.0*block);
	  bint = blockav[1][j] + (blockav[1][j+1]-blockav[1][j])*(1.0*l-yimin)/(yimax-yimin);
	  colint = colav[k][j] + (colav[k][j+1]-colav[k][j])*(1.0*l-yimin)/(yimax-yimin);
	  image3[k][l] = bint-colint;
	}
    }
  /*right hand x lock y normal strip*/
  for(k=highlockx+1;k<=nx;k++)
    {
      for(l=lowlocky+1;l<=highnormy;l++)
	{
	  j = (1.0*l+0.5*block-0.5)/(1.0*block);
	  yimin = (1.0*j-1.0)*(1.0*block)+0.5*block+0.5;
	  yimax = yimin+(1.0*block);
	  bint = blockav[nbx][j] + (blockav[nbx][j+1]-blockav[nbx][j])*(1.0*l-yimin)/(yimax-yimin);
	  colint = colav[k][j] + (colav[k][j+1]-colav[k][j])*(1.0*l-yimin)/(yimax-yimin);
	  image3[k][l] = bint-colint;
	}
    }
  /*right hand x int y normal strip*/
  for(k=highnormx+1;k<=highlockx;k++)
    {
      for(l=lowlocky+1;l<=highnormy;l++)
	{
	  j = (1.0*l+0.5*block-0.5)/(1.0*block);
	  yimin = (1.0*j-1.0)*(1.0*block)+0.5*block+0.5;
	  yimax = yimin+(1.0*block);
	  bintxh = blockav[nbx][j] + (blockav[nbx][j+1]-blockav[nbx][j])*(1.0*l-yimin)/(yimax-yimin);
	  bintxl = blockav[nbx-1][j] + (blockav[nbx-1][j+1]-blockav[nbx-1][j])*(1.0*l-yimin)/(yimax-yimin);
	  bint = bintxl + (bintxh-bintxl)*(1.0*k-fhighnormx)/(fhighlockx-fhighnormx);
	  colint = colav[k][j] + (colav[k][j+1]-colav[k][j])*(1.0*l-yimin)/(yimax-yimin);
	  image3[k][l] = bint-colint;
	}
    }
  /*remainder of image*/
  for(k=lowlockx+1;k<=highnormx;k++)
    {
      i = (1.0*k+0.5*block-0.5)/(1.0*block);
      ximin = (1.0*i-1.0)*(1.0*block)+0.5*block+0.5;
      ximax = ximin+1.0*block;
      for(l=lowlocky+1;l<=highnormy;l++)
	{
	  j = (1.0*l+0.5*block-0.5)/(1.0*block);
	  yimin = (1.0*j-1.0)*(1.0*block)+0.5*block+0.5;
	  yimax = yimin+(1.0*block);
	  bintxh = blockav[i+1][j] + (blockav[i+1][j+1]-blockav[i+1][j])*(1.0*l-yimin)/(yimax-yimin);
	  bintxl = blockav[i][j] + (blockav[i][j+1]-blockav[i][j])*(1.0*l-yimin)/(yimax-yimin);
	  bint = bintxl + (bintxh-bintxl)*(1.0*k-ximin)/(ximax-ximin);
	  colint = colav[k][j] + (colav[k][j+1]-colav[k][j])*(1.0*l-yimin)/(yimax-yimin);
	  image3[k][l] = bint-colint;
	}
    }
  /*add this image to image 1*/
  for(k=1;k<=nx;k++)
    {
      for(l=1;l<=ny;l++)
	{
	  image[k][l]+=image3[k][l];
	}
    }

  printf("Ran creepvec %d times.  50%% or more of the points\n",runct);
  printf("were out of range on %d of these\n",lossct);

  free_matrix(image2,1,nx,1,ny);
  free_matrix(image3,1,nx,1,ny);
  free_matrix(blockav,1,nbx,1,nby);
  free_matrix(colav,1,nx,1,nby);
  free_vector(ccvec,1,2*block);
  free_vector(cboxvec,1,4*block*block);
  return(1);
}



/*planetp01: a program to put a planet in at
a specified separation and celestial position angle
from a star.  The amplitude, position angle,
and separation in pixels must be input, along 
with the position of the star and the
angle the image would have to be
rotated by rotate01 to get north up.
The image is assumed to be a mirror-imaged
astronomical image, i.e. one that will have
north up and east right after rotation by
rotate01.  Both pa and rotation are
expected to be in degrees.*/
int planetp01(float **image,int nx,int ny,float amp,float sigma,float cenx,float ceny,float rotation,float sep,float pa)
{
  float xp,yp,*gvec;
  gvec = vector(1,4);

  /*rotate01 will rotate the light in the image rotation degrees
    with respect to the pixel grid in order to get north up.
    Therefore north is currently located rotation degrees
    counterclockwise from up.  If pa is, say 45 degrees east of
    north, on a mirror-imaged astronomical image that will be
    45 degrees clockwise fron north.  Thus to find the position
    of the planet we may start the vector pointing up and then
    rotate it rotation - pa degrees counterclockwise.*/

  rotation*=(PI/180.0);
  pa*=(PI/180.0);

  xp = cenx - sep*sin(rotation-pa);
  yp = ceny + sep*cos(rotation-pa);

  /*gvec should have x,y,sigma,amp*/
  gvec[1] = xp;
  gvec[2] = yp;
  gvec[3] = sigma;
  gvec[4] = amp;
  putgauss01(nx,ny,image,gvec);
  free_vector(gvec,1,4);
  return(1);
}


/*planetp02: Like planetput01 but instead
of using a gaussian of specified amplitude
and sigma, uses an input psf image which must
be square and have an odd number of pixels
on a side, with the center of the psf in
the exact center.  Scales this image to an
integrated flux*/
int planetp02(float **image,int nx,int ny,float **image2,int nx2,float flux,float cenx,float ceny,float rotation,float sep,float pa,float aprad, float *skyrads)
{
  float xp,yp;
  int px,py,i,j,x,y,skysubyes;
  float xshift,yshift,**image3,norm,*cen;
  image3 = matrix(1,nx2,1,nx2);
  cen = vector(1,2);

  cen[1] = cen[2] = 0.5*((float)nx2 + 1.0);

  /*rotate01 will rotate the light in the image rotation degrees
    clockwise with respect to the pixel grid in order to get north up.
    Therefore north is currently located rotation degrees
    counterclockwise from up.  If pa is, say 45 degrees east of
    north, on a correct astronomical image that will be
    45 degrees counterclockwise fron north.  Thus to find the position
    of the planet we may start the vector pointing up and then
    rotate it rotation + pa degrees counterclockwise.*/

  rotation*=(PI/180.0);
  pa*=(PI/180.0);

  xp = cenx - sep*sin(rotation+pa);
  yp = ceny + sep*cos(rotation+pa);
  px = xp;
  py = yp;
  xshift = xp - 1.0*px;
  yshift = yp - 1.0*py;

  imcopy01(image2,image3,nx2,nx2);
  if(skyrads[1]==0.0&&skyrads[2]==0.0)
    {
      skysubyes = 0;
    }
  else
    {
      skysubyes = 1;
    }

  norm = 0.0;
  rphot01(image3,nx2,nx2,cen,skyrads,skysubyes,1,aprad,&norm);

  for(i=1;i<=nx2;i++)
    {
      for(j=1;j<=nx2;j++)
	{
	  image3[i][j]*=(flux/norm);
	}
    }

  shift01(image3,nx2,nx2,xshift,yshift);

  for(i=1;i<=nx2;i++)
    {
      for(j=1;j<=nx2;j++)
	{
	  x = px - (nx2+1)/2 + i;
	  y = py - (nx2+1)/2 + j;
	  if(x>=1&&x<=nx&&y>=1&&y<=nx)
	    {
	      image[x][y]+=image3[i][j];
	    }
	}
    }

  free_vector(cen,1,2);
  free_matrix(image3,1,nx2,1,nx2);
  return(1);
}

/*planetp03: Like planetput02 but the
rotation is chosen to match data file
rotations for a mirror-flipped image.
This is the usual case with Clio images.*/
int planetp03(float **image,int nx,int ny,float **image2,int nx2,float flux,float cenx,float ceny,float rotation,float sep,float pa,float aprad,float *skyrads)
{
  float xp,yp;
  int px,py,i,j,x,y,skysubyes;
  float xshift,yshift,**image3,norm,*cen;
  image3 = matrix(1,nx2,1,nx2);
  cen = vector(1,2);

  cen[1] = cen[2] = 0.5*((float)nx2 + 1.0);

  /*rotate01 will rotate the light in the image rotation degrees
    clockwise with respect to the pixel grid in order to get north up.
    Therefore north is currently located rotation degrees
    counterclockwise from up.  If pa is, say 45 degrees east of
    north, on a mirror-imaged astronomical image that will be
    45 degrees clockwise fron north.  Thus to find the position
    of the planet we may start the vector pointing up and then
    rotate it rotation - pa degrees counterclockwise.*/

  rotation*=(PI/180.0);
  pa*=(PI/180.0);

  /*The sign of the x term in these equations is the only
    difference from planetput02.*/
  xp = cenx + sep*sin(rotation+pa);
  yp = ceny + sep*cos(rotation+pa);
  px = xp;
  py = yp;
  xshift = xp - 1.0*px;
  yshift = yp - 1.0*py;

  imcopy01(image2,image3,nx2,nx2);

  if(skyrads[1]==0.0&&skyrads[2]==0.0)
    {
      skysubyes = 0;
    }
  else
    {
      skysubyes = 1;
    }

  norm = 0.0;
  rphot01(image3,nx2,nx2,cen,skyrads,skysubyes,1,aprad,&norm);

  for(i=1;i<=nx2;i++)
    {
      for(j=1;j<=nx2;j++)
	{
	  image3[i][j]*=(flux/norm);
	}
    }

  shift01(image3,nx2,nx2,xshift,yshift);

  for(i=1;i<=nx2;i++)
    {
      for(j=1;j<=nx2;j++)
	{
	  x = px - (nx2+1)/2 + i;
	  y = py - (nx2+1)/2 + j;
	  if(x>=1&&x<=nx&&y>=1&&y<=nx)
	    {
	      image[x][y]+=image3[i][j];
	    }
	}
    }

  free_matrix(image3,1,nx2,1,nx2);
  free_vector(cen,1,2);
  return(1);
}


/*Given 2 images and 2 positions, creates a third image by dividing
the first two images along a cut exactly between and maximally
distant from the two positions.  Saves the part of the first image
that is on the side of the cut nearer the second position, and the
part of the second image that is on the side of the cut nearer
the first position.  Combines these two parts to make the
third image.  Does not alter the other two images.*/
int imdivide01(int nx,int ny,float **image1,float **image2,float **image3,float x1,float y1,float x2,float y2)
{
  int i,j;
  float  mfit,bfit,x3,y3;

  if(y1==y2)
    {
      if(x1==x2)
	{
	  printf("ERROR: imdivide01 RECIEVED DEGNERATE POSITIONS.  ABORTING\n");
	  return(0);
	}
      x3 = 0.5*(x1+x2);
      if(x1>x3)
	{
	  for(i=1;i<=nx;i++)
	    {
	      for(j=1;j<=ny;j++)
		{
		  if(i>=x3)
		    {
		      image3[i][j] = image2[i][j];
		    }
		  else{
		    image3[i][j] = image1[i][j];
		  }
		}
	    }
	  return(1);
	}
      else{
	  for(i=1;i<=nx;i++)
	    {
	      for(j=1;j<=ny;j++)
		{
		  if(i>=x3)
		    {
		      image3[i][j] = image1[i][j];
		    }
		  else{
		    image3[i][j] = image2[i][j];
		  }
		}
	    }
	  return(1);
      }
    }

  mfit = (x2-x1)/(y1-y2);
  x3 = 0.5*(x1+x2);
  y3 = 0.5*(y1+y2);
  bfit = y3 - mfit*x3;

  if(y1>(mfit*x1+bfit))
    {
      for(i=1;i<=nx;i++)
	{
	  for(j=1;j<=ny;j++)
	    {
	      if(j>mfit*i+bfit)
		{
		  image3[i][j] = image2[i][j];
		}
	      else{
		image3[i][j] = image1[i][j];
	      }
	    }
	}
      return(1);
    }
  else{
    {
      for(i=1;i<=nx;i++)
	{
	  for(j=1;j<=ny;j++)
	    {
	      if(j>mfit*i+bfit)
		{
		  image3[i][j] = image1[i][j];
		}
	      else{
		image3[i][j] = image2[i][j];
	      }
	    }
	}
    }
      return(1);
  }
}


/*imdivide02: exactly like imdivide01, but scales image2 to match
mean brightness of image1 over a box before combining.  The scaling
is performed on a copy, so neither image2 or image1 are changed
by this program.*/
int imdivide02(int nx,int ny,float **image1,float **image2,float **image3,float x1,float y1,float x2,float y2,int *sbox)
{
  int i,j;
  float  mfit,bfit,x3,y3,**image4,mean1,mean2,rmsj;

  image4 = matrix(1,nx,1,ny);

  statsim03(image1,nx,ny,sbox,&rmsj,&mean1,CANSCLIP);
  statsim03(image2,nx,ny,sbox,&rmsj,&mean2,CANSCLIP);

  mathimc03(image2,image4,nx,ny,mean1/mean2);

  if(y1==y2)
    {
      if(x1==x2)
	{
	  printf("ERROR: imdivide02 RECIEVED DEGNERATE POSITIONS.  ABORTING\n");
	  free_matrix(image4,1,nx,1,ny);
	  return(0);
	}
      x3 = 0.5*(x1+x2);
      if(x1>x3)
	{
	  for(i=1;i<=nx;i++)
	    {
	      for(j=1;j<=ny;j++)
		{
		  if(i>=x3)
		    {
		      image3[i][j] = image4[i][j];
		    }
		  else{
		    image3[i][j] = image1[i][j];
		  }
		}
	    }
	  free_matrix(image4,1,nx,1,ny);
	  return(1);
	}
      else{
	  for(i=1;i<=nx;i++)
	    {
	      for(j=1;j<=ny;j++)
		{
		  if(i>=x3)
		    {
		      image3[i][j] = image1[i][j];
		    }
		  else{
		    image3[i][j] = image4[i][j];
		  }
		}
	    }
	  free_matrix(image4,1,nx,1,ny);
	  return(1);
      }
    }

  mfit = (x2-x1)/(y1-y2);
  x3 = 0.5*(x1+x2);
  y3 = 0.5*(y1+y2);
  bfit = y3 - mfit*x3;

  if(y1>(mfit*x1+bfit))
    {
      for(i=1;i<=nx;i++)
	{
	  for(j=1;j<=ny;j++)
	    {
	      if(j>mfit*i+bfit)
		{
		  image3[i][j] = image4[i][j];
		}
	      else{
		image3[i][j] = image1[i][j];
	      }
	    }
	}
      free_matrix(image4,1,nx,1,ny);
      return(1);
    }
  else{
    {
      for(i=1;i<=nx;i++)
	{
	  for(j=1;j<=ny;j++)
	    {
	      if(j>mfit*i+bfit)
		{
		  image3[i][j] = image1[i][j];
		}
	      else{
		image3[i][j] = image4[i][j];
	      }
	    }
	}
    }
    free_matrix(image4,1,nx,1,ny);
    return(1);
  }
}

/*imdivide02c: exactly like imdivide02, but uses psuedocreep01
rather than a stright sigma clip to get the means for image scaling*/
int imdivide02c(int nx,int ny,float **image1,float **image2,float **image3,float x1,float y1,float x2,float y2,int *sbox)
{
  int i,j;
  float  mfit,bfit,x3,y3,**image4,mean1,mean2,rmsj;

  image4 = matrix(1,nx,1,ny);

  statsim03c(image1,nx,ny,sbox,&rmsj,&mean1,CANRLEV);
  statsim03c(image2,nx,ny,sbox,&rmsj,&mean2,CANRLEV);

  mathimc03(image2,image4,nx,ny,mean1/mean2);

  if(y1==y2)
    {
      if(x1==x2)
	{
	  printf("ERROR: imdivide02 RECIEVED DEGNERATE POSITIONS.  ABORTING\n");
	  free_matrix(image4,1,nx,1,ny);
	  return(0);
	}
      x3 = 0.5*(x1+x2);
      if(x1>x3)
	{
	  for(i=1;i<=nx;i++)
	    {
	      for(j=1;j<=ny;j++)
		{
		  if(i>=x3)
		    {
		      image3[i][j] = image4[i][j];
		    }
		  else{
		    image3[i][j] = image1[i][j];
		  }
		}
	    }
	  free_matrix(image4,1,nx,1,ny);
	  return(1);
	}
      else{
	  for(i=1;i<=nx;i++)
	    {
	      for(j=1;j<=ny;j++)
		{
		  if(i>=x3)
		    {
		      image3[i][j] = image1[i][j];
		    }
		  else{
		    image3[i][j] = image4[i][j];
		  }
		}
	    }
	  free_matrix(image4,1,nx,1,ny);
	  return(1);
      }
    }

  mfit = (x2-x1)/(y1-y2);
  x3 = 0.5*(x1+x2);
  y3 = 0.5*(y1+y2);
  bfit = y3 - mfit*x3;

  if(y1>(mfit*x1+bfit))
    {
      for(i=1;i<=nx;i++)
	{
	  for(j=1;j<=ny;j++)
	    {
	      if(j>mfit*i+bfit)
		{
		  image3[i][j] = image4[i][j];
		}
	      else{
		image3[i][j] = image1[i][j];
	      }
	    }
	}
      free_matrix(image4,1,nx,1,ny);
      return(1);
    }
  else{
    {
      for(i=1;i<=nx;i++)
	{
	  for(j=1;j<=ny;j++)
	    {
	      if(j>mfit*i+bfit)
		{
		  image3[i][j] = image1[i][j];
		}
	      else{
		image3[i][j] = image4[i][j];
	      }
	    }
	}
    }
    free_matrix(image4,1,nx,1,ny);
    return(1);
  }
}



/*creepmean01: Given a list of names in namefile, a number of images imnum,
and a rejection level rlev, performs a creeping mean combination of
all images with the rejection of rlev*imnum values for each pixel.
rlev is logically constrained to be between 1.0 and 0.0.  If rlev*imnum
is less than 0.5, creepmean01 will simply combine the images without
rejection.  If rlev is 1.0 creepmean01 will still retain one measurement
for each pixel.  rlev is recommended to be 0.05 to 0.2; 0.5 is a very
agressive value.  creepmean01 is optimized to be slow but not to make
inordinated demands on memory.*/
int creepmean01(char *namefile,int imnum,float rlev,int nx,int ny,float **image)
{
  float **holdim,**image1,swapv,mean1,norm1,emax,errn;
  int i,j,k,numrej,nrn,wp;
  FILE *fp1;
  char imname[NML];

  holdim = matrix(1,nx,1,imnum);
  image1 = matrix(1,nx,1,ny);

  numrej = 1.0*(rlev*imnum);

  /*Let it serve as a simple, crude combine if it's set to reject no images*/
  if(numrej<=0)
    {
      fp1 = fopen(namefile,"r");
      printf("WARNING: creepmean01 NOT REJECTING ANY IMAGE\n");
      imzero(image,nx,ny);
      for(k=1;k<=imnum;k++)
	{
	  fscanf(fp1,"%s",imname);
	  readim01(nx,ny,imname,image1);
	  mathimtim01(image,image,nx,ny,image1);
	}
      mathimc04(image,image,nx,ny,1.0*imnum);
      fclose(fp1);
      free_matrix(image1,1,nx,1,ny);
      free_matrix(holdim,1,nx,1,imnum);
      return(1);
    }
  /*No rejection case finished*/

  /*Make it reject all images except one if it's set too high*/
  if(numrej>=imnum)
    {
      printf("WARNING: creepmean01 WILL KEEP ONLY ONE IMAGE\n");
      numrej = imnum-1;
    }

  printf("creepmean01 will reject %d images of %d\n",numrej,imnum);

  /*Main work starts here*/
  for(j=1;j<=ny;j++)
    {
      fp1 = fopen(namefile,"r");
      imzero(holdim,nx,imnum);
      /*Fill up holdim with a row from every image*/
      for(k=1;k<=imnum;k++)
	{
	  fscanf(fp1,"%s",imname);
	  readim01(nx,ny,imname,image1);
	  for(i=1;i<=nx;i++)
	    {
	      holdim[i][k] = image1[i][j];
	    }
	}
      printf("Successfully read for row %d image %d called %s\n",j,k,imname);
      fclose(fp1);
      fflush(stdout);
      /*Now perform creeping mean on every pixel in this row*/
      for(i=1;i<=nx;i++)
	{
	  for(nrn=0;nrn<=numrej;nrn++)
	    {
	      /*Calculate initial mean*/
	      mean1 = norm1 = 0.0;
	      for(k=1;k<=imnum-nrn;k++)
		{
		  mean1+=holdim[i][k];
		  norm1+=1.0;
		}
	      mean1/=norm1;

	      /*Find most deviant remaining point*/
	      emax=pow(pow(holdim[i][1]-mean1,2.0),0.5);
	      wp = 1;
	      for(k=2;k<=imnum-nrn;k++)
		{
		  errn = pow(pow(holdim[i][k]-mean1,2.0),0.5);
		  if(errn>emax);
		  {
		    emax = errn;
		    wp = k;
		  }
		}

	      /*Swap most deviant point into the k value that's about to be dropped*/
	      swapv = holdim[i][imnum-nrn];
	      holdim[i][imnum-nrn] = holdim[i][wp];
	      holdim[i][wp] = swapv;
	    }
	  image[i][j] = mean1;
	}
    }
  free_matrix(image1,1,nx,1,ny);
  free_matrix(holdim,1,nx,1,imnum);
  return(1);
}

/*creepmean02: Like creepmean01 but trades economy of memory for speed.*/
int creepmean02(char *namefile,int imnum,float rlev,int nx,int ny,float **image)
{
  float **holdim,**image1,swapv,mean1,norm1,emax,errn,*avgvec;
  int i,j,k,numrej,nrn,wp;
  FILE *fp1;
  char imname[NML];

  holdim = matrix(1,nx,1,ny*imnum);
  image1 = matrix(1,nx,1,ny);
  avgvec = vector(1,imnum);

  numrej = 1.0*(rlev*imnum);

  /*Let it serve as a simple, crude combine if it's set to reject no images*/
  if(numrej<=0)
    {
      fp1 = fopen(namefile,"r");
      printf("WARNING: creepmean02 NOT REJECTING ANY IMAGE\n");
      imzero(image,nx,ny);
      for(k=1;k<=imnum;k++)
	{
	  fscanf(fp1,"%s",imname);
	  readim01(nx,ny,imname,image1);
	  mathimtim01(image,image,nx,ny,image1);
	}
      mathimc04(image,image,nx,ny,1.0*imnum);
      fclose(fp1);
      free_matrix(image1,1,nx,1,ny);
      free_matrix(holdim,1,nx,1,ny*imnum);
      return(1);
    }
  /*No rejection case finished*/

  printf("creepmean02 will reject %d images of %d\n",numrej,imnum);

  /*Main work starts here*/
  fp1 = fopen(namefile,"r");
  for(k=1;k<=imnum;k++)
    {
      fscanf(fp1,"%s",imname);
      readim01(nx,ny,imname,image1);
      for(i=1;i<=nx;i++)
	{
	  for(j=1;j<=ny;j++)
	    {
	      holdim[i][(k-1)*ny+j] = image1[i][j];
	    }
	}
    }
  fclose(fp1);
  for(i=1;i<=nx;i++)
    {
      printf("creepmean02 processing column %d\n",i);
      for(j=1;j<=ny;j++)
	{
	  for(k=1;k<=imnum;k++)
	    {
	      avgvec[k] = holdim[i][(k-1)*ny+j];
	    }
	  creepvec01(avgvec,imnum,rlev,&mean1,&errn);
	  image[i][j] = mean1;
	}
    }

  free_matrix(image1,1,nx,1,ny);
  free_matrix(holdim,1,nx,1,ny*imnum);
  return(1);
}

/*blockcreepmean02: Like creepmean02 but handles images in blocks, so that
it works on very large images without needing too much RAM.  Slower
than creepmean02 if there is enough RAM for either.*/
int blockcreepmean02(char *namefile,int imnum,float rlev,int nx,int ny,float **image,int blocksize)
{
  float **holdim,**image1,swapv,mean1,norm1,emax,errn,*avgvec;
  int i,j,k,l,m,numrej,nrn,wp;
  FILE *fp1;
  char imname[NML];
  int xblocknum,yblocknum,xblockstart,xblockend,yblockstart,yblockend;

  holdim = matrix(1,blocksize,1,blocksize*imnum);
  image1 = matrix(1,nx,1,ny);
  avgvec = vector(1,imnum);

  xblocknum = nx/blocksize + 1;
  yblocknum = ny/blocksize + 1;

  numrej = 1.0*(rlev*imnum);

  /*Let it serve as a simple, crude combine if it's set to reject no images*/
  if(numrej<=0)
    {
      fp1 = fopen(namefile,"r");
      printf("WARNING: blockcreepmean02 NOT REJECTING ANY IMAGE\n");
      imzero(image,nx,ny);
      for(k=1;k<=imnum;k++)
	{
	  fscanf(fp1,"%s",imname);
	  readim01(nx,ny,imname,image1);
	  mathimtim01(image,image,nx,ny,image1);
	}
      mathimc04(image,image,nx,ny,1.0*imnum);
      fclose(fp1);
      free_matrix(image1,1,nx,1,ny);
      free_matrix(holdim,1,blocksize,1,blocksize*imnum);
      return(1);
    }
  /*No rejection case finished*/

  printf("blockcreepmean02 will reject %d images of %d\n",numrej,imnum);
  imzero(image,nx,ny);
  /*Main work starts here*/
  /*Go through images in blocks, doing creeping mean
    combine for the whole stack of images in each given block*/
  for(l=1;l<=xblocknum;l++)
    {
      for(m=1;m<=yblocknum;m++)
	{
	  /*Zero holdim just to be on the safe side*?
	  imzero(holdim,xblocksize,yblocksize);
	  /*Set the beginning and ending x and y values,
	  in pixel coords on the science images.*/
	  printf("blockcreepmean02 processing block %d,%d (total %d,%d)\n",l,m,xblocknum,yblocknum);
	  xblockstart = (l-1)*blocksize + 1;
	  xblockend = l*blocksize;
	  yblockstart = (m-1)*blocksize + 1;
	  yblockend = m*blocksize;
	  if(xblockend-xblockstart!=blocksize-1||yblockend-yblockstart!=blocksize-1||xblockstart>nx||yblockstart>ny)
	    {
	      printf("ERROR: blockcreepmean02 HAS IMPOSSIBLE BLOCK\n");
	      printf("SPECIFICATIONS!\n");
	      printf("nx = %d, ny = %d, l = %d, m = %d,\n,xblockstart = %d, xblockend = %d, yblockstart = %d, yblockend = %d\n",nx,ny,l,m,xblockstart,xblockend,yblockstart,yblockend);
	      printf("ABORTING!\n");
	      return(0);
	    }
	  if(xblockend > nx)
	    xblockend = nx;
	  if(yblockend > ny)
	    yblockend = ny;

	  /*Open the image list file.  Note it will be
            opened and closed for each block.*/
	  fp1 = fopen(namefile,"r");
	  for(k=1;k<=imnum;k++)
	    {
	      fscanf(fp1,"%s",imname);
	      readim01(nx,ny,imname,image1);
	      for(i=xblockstart;i<=xblockend;i++)
		{
		  for(j=yblockstart;j<=yblockend;j++)
		    {
		      /*Read the correct block from every image into holdim*/
                      /*The long coordinate specifications for holdim
                        simply make sure the indices go from 1 to blocksize
                        in both dimensions, unless of course we hit the
                        edge of the image, in which case holdim is not
                        full.*/
		      holdim[i-xblockstart+1][(k-1)*blocksize+j-yblockstart+1] = image1[i][j];
		    }
		}
	    }
	  /*Closing of the file*/
	  fclose(fp1);
	  for(i=xblockstart;i<=xblockend;i++)
	    {
	      printf("blockcreepmean02 processing column %d, block %d,%d\n",i,l,m);
	      for(j=yblockstart;j<=yblockend;j++)
		{
		  for(k=1;k<=imnum;k++)
		    {
		      avgvec[k] = holdim[i-xblockstart+1][(k-1)*blocksize+j-yblockstart+1];
		    }
		  creepvec01(avgvec,imnum,rlev,&mean1,&errn);
		  /*The block is simply read into the image.  The
                    only complicated part is the indices on holdim*/
		  image[i][j] = mean1;
		}
	    }
	}
    }

  free_matrix(image1,1,nx,1,ny);
  free_matrix(holdim,1,blocksize,1,blocksize*imnum);
  return(1);
}


/*creepmean03: Like creepmean02 but does not consider zero a valid data value*/
int creepmean03(char *namefile,int imnum,float rlev,int nx,int ny,float **image)
{
  char imname[80];
  FILE *fp1;
  float *averagevector,**image1,**holdim;
  int i,j,imct,goodct,nrej,rejnum,worstp;
  float averageval,rms,norm,maxerr,errn;

  averagevector = vector(1,imnum);
  image1 = matrix(1,nx,1,ny);
  holdim = matrix(1,nx*imnum,1,ny);

  fp1 = fopen(namefile,"r");
  /*Read all images into holdim*/
  for(imct=1;imct<=imnum;imct++)
    {
      fscanf(fp1,"%s",imname);
      printf("creepmean03 reading image %s\n",imname);
      readim01(nx,ny,imname,image1);
      for(i=1;i<=nx;i++)
	{
	  for(j=1;j<=ny;j++)
	    {
	      holdim[(imct-1)*nx+i][j] = image1[i][j];
	    }
	}
    }
  rejnum = 1.0*(rlev*(1.0*imnum));
  if(rlev<=0.0)
    {
      for(i=1;i<=nx;i++)
	{
	  for(j=1;j<=ny;j++)
	    {
	      goodct = 0;
	      for(imct=1;imct<=imnum;imct++)
		{
		  if(holdim[(imct-1)*nx+i][j]!=0.0)
		    {
		      goodct+=1;
		      averagevector[goodct] = holdim[(imct-1)*nx+i][j];
		    }
		}
	      if(goodct>1)
		{
		  meanrms01(averagevector,goodct,&averageval,&rms);
		  image[i][j] = averageval;
		}
	      else if(goodct==1)
		{
		  image[i][j] = averagevector[1];
		}
	      else
		{
		  image[i][j] = 0.0;
		}
	    }
	}
    }

  else
    {
      for(i=1;i<=nx;i++)
	{
	  for(j=1;j<=ny;j++)
	    {
	      goodct = 0;
	      for(imct=1;imct<=imnum;imct++)
		{
		  if(holdim[(imct-1)*nx+i][j]!=0.0)
		    {
		      goodct+=1;
		      averagevector[goodct] = holdim[(imct-1)*nx+i][j];
		    }
		}
	      if(goodct>1)
		{
		  creepvec01(averagevector,goodct,rlev,&averageval,&rms);
		  image[i][j] = averageval;
		}
	      else if(goodct==1)
		{
		  image[i][j] = averagevector[1];
		}
	      else
		{
		  image[i][j] = 0.0;
		}
	    }
	}
    }

  free_vector(averagevector,1,imnum);
  free_matrix(image1,1,nx,1,ny);
  free_matrix(holdim,1,nx*imnum,1,ny);

  return(0);
}



 /*blockcreepmean03: Like blockcreepmean02 but does not consider
zero a valid data value.*/
int blockcreepmean03(char *namefile,int imnum,float rlev,int nx,int ny,float **image,int blocksize)
{
  float **holdim,**image1,swapv,mean1,norm1,emax,errn,*avgvec;
  int i,j,k,l,m,numrej,nrn,wp,goodct;
  FILE *fp1;
  char imname[NML];
  int xblocknum,yblocknum,xblockstart,xblockend,yblockstart,yblockend;
  float **avgim;

  holdim = matrix(1,blocksize,1,blocksize*imnum);
  image1 = matrix(1,nx,1,ny);
  avgvec = vector(1,imnum);
  avgim = matrix(1,nx,1,ny);

  xblocknum = nx/blocksize + 1;
  yblocknum = ny/blocksize + 1;

  numrej = 1.0*(rlev*imnum);

  /*Let it serve as a simple, crude combine if it's set to reject no images*/
  if(numrej<=0)
    {
      imzero(avgim,nx,ny);
      fp1 = fopen(namefile,"r");
      printf("WARNING: blockcreepmean03 NOT REJECTING ANY IMAGE\n");
      imzero(image,nx,ny);
      for(k=1;k<=imnum;k++)
	{
	  fscanf(fp1,"%s",imname);
	  readim01(nx,ny,imname,image1);
	  /*avgim will hold the number of times a given
            pixel has been nonzero*/
	  for(i=1;i<=nx;i++)
	    {
	      for(j=1;j<=ny;j++)
		{
		  if(image1[i][j]!=0.0)
		    {
		      avgim[i][j] += 1.0;
		      image[i][j] += image1[i][j];
		    }
		}
	    }
	}
      for(i=1;i<=nx;i++)
	{
	  for(j=1;j<=ny;j++)
	    {
	      if(avgim[i][j]==0.0)
		{
		  image[i][j] = 0.0;
		}
	      else
		{
		  image[i][j]/=avgim[i][j];
		}
	    }
	}
      fclose(fp1);
      free_matrix(image1,1,nx,1,ny);
      free_matrix(avgim,1,nx,1,ny);
      free_matrix(holdim,1,blocksize,1,ny*blocksize);
      return(1);
    }
  /*No rejection case finished*/

  printf("blockcreepmean03 will reject %d images of %d\n",numrej,imnum);
  imzero(image,nx,ny);
  /*Main work starts here*/
  /*Go through images in blocks, doing creeping mean
    combine for the whole stack of images in each given block*/
  for(l=1;l<=xblocknum;l++)
    {
      for(m=1;m<=yblocknum;m++)
	{
	  /*Zero holdim just to be on the safe side*?
	  imzero(holdim,xblocksize,yblocksize);
	  /*Set the beginning and ending x and y values,
	  in pixel coords on the science images.*/
	  printf("blockcreepmean03 processing block %d,%d (total %d,%d)\n",l,m,xblocknum,yblocknum);
	  xblockstart = (l-1)*blocksize + 1;
	  xblockend = l*blocksize;
	  yblockstart = (m-1)*blocksize + 1;
	  yblockend = m*blocksize;
	  if(xblockend-xblockstart!=blocksize-1||yblockend-yblockstart!=blocksize-1||xblockstart>nx||yblockstart>ny)
	    {
	      printf("ERROR: blockcreepmean02 HAS IMPOSSIBLE BLOCK\n");
	      printf("SPECIFICATIONS!\n");
	      printf("nx = %d, ny = %d, l = %d, m = %d,\n,xblockstart = %d, xblockend = %d, yblockstart = %d, yblockend = %d\n",nx,ny,l,m,xblockstart,xblockend,yblockstart,yblockend);
	      printf("ABORTING!\n");
	      return(0);
	    }
	  if(xblockend > nx)
	    xblockend = nx;
	  if(yblockend > ny)
	    yblockend = ny;

	  /*Open the image list file.  Note it will be
            opened and closed for each block.*/
	  fp1 = fopen(namefile,"r");
	  for(k=1;k<=imnum;k++)
	    {
	      fscanf(fp1,"%s",imname);
	      readim01(nx,ny,imname,image1);
	      for(i=xblockstart;i<=xblockend;i++)
		{
		  for(j=yblockstart;j<=yblockend;j++)
		    {
		      /*Read the correct block from every image into holdim*/
                      /*The long coordinate specifications for holdim
                        simply make sure the indices go from 1 to blocksize
                        in both dimensions, unless of course we hit the
                        edge of the image, in which case holdim is not
                        full.*/
		      holdim[i-xblockstart+1][(k-1)*blocksize+j-yblockstart+1] = image1[i][j];
		    }
		}
	    }
	  /*Closing of the file*/
	  fclose(fp1);
	  for(i=xblockstart;i<=xblockend;i++)
	    {
	      printf("blockcreepmean02 processing column %d, block %d,%d\n",i,l,m);
	      for(j=yblockstart;j<=yblockend;j++)
		{
		  goodct = 0;
		  for(k=1;k<=imnum;k++)
		    {
		      if(holdim[i-xblockstart+1][(k-1)*blocksize+j-yblockstart+1]!=0.0)
			{
			  goodct+=1;
			  avgvec[goodct] = holdim[i-xblockstart+1][(k-1)*blocksize+j-yblockstart+1];
			}
		    }
		  if(goodct>1)
		    {
		      creepvec01(avgvec,goodct,rlev,&mean1,&errn);
		    }
		  else if(goodct==1)
		    {
		      mean1 = avgvec[1];
		    }
		  else if(goodct==0)
		    {
		      mean1 = 0.0;
		    }

		  /*Then the block is simply read into the image.  The
                    only complicated part is the indices on holdim
                    and keeping track, above, of how many nonzero
                    values there were.*/
		  image[i][j] = mean1;
		}
	    }
	}
    }

  free_matrix(image1,1,nx,1,ny);
  free_matrix(avgim,1,nx,1,ny);
  free_matrix(holdim,1,blocksize,1,blocksize*imnum);
  return(1);
}
     

/*creepmean04: Like creepmean03 but uses pseudocreep rather than a true
creeping mean, so that the runtime will be reduced for extremely large
data sets at high rejection*/
int creepmean04(char *namefile,int imnum,float rlev,int nx,int ny,float **image)
{
  float **holdim,**image1,swapv,mean1,norm1,emax,errn,*jvec;
  int i,j,k,numrej,wp,sgct,nrej;
  FILE *fp1;
  char imname[NML];
  float meanerror,crms;

  holdim = matrix(1,nx,1,ny*imnum);
  image1 = matrix(1,nx,1,ny);
  jvec = vector(1,imnum);

  numrej = 1.0*(rlev*imnum);

  /*Make it reject all images except one if it's set too high*/
  if(numrej>=imnum)
    {
      printf("WARNING: creepmean02 WILL KEEP ONLY ONE IMAGE\n");
      numrej = imnum-1;
    }
  /*Make it keep all images if it's set too low*/
  if(numrej<=0)
    {
      numrej = 0;
    }

  printf("creepmean04 will reject %d images of %d\n",numrej,imnum);

  /*Main work starts here*/
  fp1 = fopen(namefile,"r");
  for(k=1;k<=imnum;k++)
    {
      fscanf(fp1,"%s",imname);
      readim01(nx,ny,imname,image1);
      for(i=1;i<=nx;i++)
	{
	  for(j=1;j<=ny;j++)
	    {
	      holdim[i][(k-1)*ny+j] = image1[i][j];
	    }
	}
    }
  fclose(fp1);
  for(i=1;i<=nx;i++)
    {
      printf("creepmean04 processing column %d\n",i);
      for(j=1;j<=ny;j++)
	{
	  sgct = 0;
	  for(k=1;k<=imnum;k++)
	    {
	      if(holdim[i][(k-1)*ny+j]!=0.0)
		{
		  sgct+=1;
		  jvec[sgct] = holdim[i][(k-1)*ny+j];
		}
	    }
	  if(sgct>1)
	    {
	      pseudocreep01(jvec,sgct,rlev,&mean1,&meanerror,&crms);
	    }
	  else if(sgct==1)
	    {
	      mean1 = jvec[1];
	    }
	  else
	    {
	      mean1 = 0.0;
	    }
	  image[i][j] = mean1;
	}
    }

  free_matrix(image1,1,nx,1,ny);
  free_matrix(holdim,1,nx,1,ny*imnum);
  free_vector(jvec,1,imnum);
  return(1);
}

/*creepmean05: Like creepmean02 in that it does consider zero a valid data value,
but uses pseudocreep rather than a true creeping mean, so that the runtime will 
be reduced for extremely large data sets at high rejection*/
int creepmean05(char *namefile,int imnum,float rlev,int nx,int ny,float **image)
{
  float **holdim,**image1,swapv,mean1,norm1,emax,errn,*jvec;
  int i,j,k,numrej,wp,nrej;
  FILE *fp1;
  char imname[NML];
  float meanerror,crms;

  printf("in creepmean05 OK\n");
  fflush(stdout);
  printf("nx = %d, ny = %d, imnum = %d, ny*imnum = %d\n",nx,ny,imnum,ny*imnum);
  fflush(stdout);
  image1 = matrix(1,nx,1,ny);
  jvec = vector(1,imnum);
  printf("small matrices allocated OK\n");
  fflush(stdout);
  printf("nx = %d, ny = %d, imnum = %d, ny*imnum = %d\n",nx,ny,imnum,ny*imnum);
  fflush(stdout);
  holdim = matrix(1,nx,1,ny*imnum);

  numrej = 1.0*(rlev*imnum);

  /*Make it reject all images except one if it's set too high*/
  if(numrej>=imnum)
    {
      printf("WARNING: creepmean02 WILL KEEP ONLY ONE IMAGE\n");
      numrej = imnum-1;
    }
  /*Make it keep all images if it's set too low*/
  if(numrej<=0)
    {
      numrej = 0;
    }

  printf("creepmean05 will reject %d images of %d\n",numrej,imnum);

  /*Main work starts here*/
  fp1 = fopen(namefile,"r");
  for(k=1;k<=imnum;k++)
    {
      fscanf(fp1,"%s",imname);
      readim01(nx,ny,imname,image1);
      for(i=1;i<=nx;i++)
	{
	  for(j=1;j<=ny;j++)
	    {
	      holdim[i][(k-1)*ny+j] = image1[i][j];
	    }
	}
    }
  fclose(fp1);
  for(i=1;i<=nx;i++)
    {
      printf("creepmean05 processing column %d\n",i);
      for(j=1;j<=ny;j++)
	{
	  for(k=1;k<=imnum;k++)
	    {
	      jvec[k] = holdim[i][(k-1)*ny+j];
	    }
	  if(imnum>1)
	    {
	      pseudocreep01(jvec,imnum,rlev,&mean1,&meanerror,&crms);
	    }
	  else if(imnum==1)
	    {
	      mean1 = jvec[1];
	    }
	  else
	    {
	      mean1 = 0.0;
	    }
	  image[i][j] = mean1;
	}
    }

  free_matrix(image1,1,nx,1,ny);
  free_matrix(holdim,1,nx,1,ny*imnum);
  free_vector(jvec,1,imnum);
  return(1);
}

/*median03: Modeled on creepmean03, but does a median with a sigma
clip, rather than a creeping mean*/
int median03(char *namefile,int imnum,float sigclip,int nx,int ny,float **image)
{
  char imname[80];
  FILE *fp1;
  float *averagevector,**image1,**holdim;
  int i,j,imct,goodct,nrej,rejnum,worstp;
  float median;

  averagevector = vector(1,imnum);
  image1 = matrix(1,nx,1,ny);
  holdim = matrix(1,nx*imnum,1,ny);

  fp1 = fopen(namefile,"r");
  /*Read all images into holdim*/
  for(imct=1;imct<=imnum;imct++)
    {
      fscanf(fp1,"%s",imname);
      printf("creepmean03 reading image %s\n",imname);
      readim01(nx,ny,imname,image1);
      for(i=1;i<=nx;i++)
	{
	  for(j=1;j<=ny;j++)
	    {
	      holdim[(imct-1)*nx+i][j] = image1[i][j];
	    }
	}
    }
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  goodct = 0;
	  for(imct=1;imct<=imnum;imct++)
	    {
	      if(holdim[(imct-1)*nx+i][j]!=0.0)
		{
		  goodct+=1;
		  averagevector[goodct] = holdim[(imct-1)*nx+i][j];
		}
	    }
	  if(goodct>1)
	    {
	      mediansig01(averagevector,goodct,sigclip,&median);
	      image[i][j] = median;
	    }
	  else if(goodct==1)
	    {
	      image[i][j] = averagevector[1];
	    }
	  else
	    {
	      image[i][j] = 0.0;
	    }
	}
    }

  free_vector(averagevector,1,imnum);
  free_matrix(image1,1,nx,1,ny);
  free_matrix(holdim,1,nx*imnum,1,ny);

  return(0);
}

/*distradec01: given two input positions in RA and DEC
in hours, minutes, and seconds, and degrees, arcminutes,
and arcseconds, respectively, calculates the distance
between the two points in arcseconds, and the celestial
position angle of the line from the first to the second
in degrees.  Distradec01 uses spherical geometry.*/
int distradec01(float *ra,float *dec,float *dist,float *pa)
{
  double ra1,ra2,dec1,dec2,mdec,radiff,decdiff;
  double initpos[3],polepos[3],newpos[3],oldpolera;

  /*Get ra and dec in radians*/
  ra1 = ra[1]*PI/12.0 + ra[2]*PI/720.0 + ra[3]*PI/43200.0;
  ra2 = ra[4]*PI/12.0 + ra[5]*PI/720.0 + ra[6]*PI/43200.0;
  dec1 = dec[1]*PI/180.0 + dec[2]*PI/10800.0 + dec[3]*PI/648000.0;
  dec2 = dec[4]*PI/180.0 + dec[5]*PI/10800.0 + dec[6]*PI/648000.0;


  /*poleswitch01: given a double precision input vector
    containing the position in radians of a source on a 
    spherical coordinate system, another vector containing
    the position of the pole of a new coordinate system
    on the old coordinate system, calculates the position
    of the point in the new coordinate system, and outputs
    this in a third double precision vector.  The desired
    RA for the old pole in the new coordinates is also required.
    NOTE: the coords must be located in positions 1 and 2
    of the double precision vectors, following the NRC
    convention, NOT positions 0 and 1.*/
  initpos[1] = ra2;
  initpos[2] = dec2;
  polepos[1] = ra1;
  polepos[2] = dec1;
  oldpolera = 0.0;
  poleswitch01(initpos,polepos,newpos,oldpolera);

  /*Calculate distance and position angle*/
  *dist = (PI/2.0 - newpos[2])*ASECPRAD;
  *pa = (2.0*PI-newpos[1])*180.0/PI;

  return(1);
}

/*distradec02: Exactly like distradec01 but takes RA and
DEC in units of decimal degrees, as they are given in
the GSC.  The vectors ra and dec thus have now only
two entries.*/
int distradec02(float *ra,float *dec,float *dist,float *pa)
{
  double ra1,ra2,dec1,dec2,mdec,radiff,decdiff;
  double initpos[3],polepos[3],newpos[3],oldpolera,circerr;

  /*Get RA and DEC in radians*/
  ra1 = ra[1]*PI/180.0;
  ra2 = ra[2]*PI/180.0;
  dec1 = dec[1]*PI/180.0;
  dec2 = dec[2]*PI/180.0;

  /*poleswitch01: given a double precision input vector
    containing the position in radians of a source on a 
    spherical coordinate system, another vector containing
    the position of the pole of a new coordinate system
    on the old coordinate system, calculates the position
    of the point in the new coordinate system, and outputs
    this in a third double precision vector.  The desired
    RA for the old pole in the new coordinates is also required.
    NOTE: the coords must be located in positions 1 and 2
    of the double precision vectors, following the NRC
    convention, NOT positions 0 and 1.*/
  initpos[1] = ra2;
  initpos[2] = dec2;
  polepos[1] = ra1;
  polepos[2] = dec1;
  oldpolera = 0.0;
  poleswitch01(initpos,polepos,newpos,oldpolera);

  /*Calculate distance and position angle*/
  *dist = (PI/2.0 - newpos[2])*ASECPRAD;
  *pa = (2.0*PI-newpos[1])*180.0/PI;


  return(1);
}


/*distradec03: exactly like distradec01, but, given an
input error on the position in arcseconds, calculates the
error on the distance and position angle.  Assumes a circular
error on both positions.  The errors are allowed to be
different, and supplied in the two-element vector errs.
dist and pa become two-element vectors with the errors
given in the second element.  The small angle approximation
is used in the calculation of the error on the position
angle, so the results will be inaccurate if the error
is not small compared to a radian.*/
int distradec03(float *ra,float *dec,float *errs,float *dist,float *pa)
{
  double ra1,ra2,dec1,dec2,mdec,radiff,decdiff;
  double initpos[3],polepos[3],newpos[3],oldpolera,circerr;

  /*Get ra and dec in radians*/
  ra1 = ra[1]*PI/12.0 + ra[2]*PI/720.0 + ra[3]*PI/43200.0;
  ra2 = ra[4]*PI/12.0 + ra[5]*PI/720.0 + ra[6]*PI/43200.0;
  dec1 = dec[1]*PI/180.0 + dec[2]*PI/10800.0 + dec[3]*PI/648000.0;
  dec2 = dec[4]*PI/180.0 + dec[5]*PI/10800.0 + dec[6]*PI/648000.0;


  /*poleswitch01: given a double precision input vector
    containing the position in radians of a source on a 
    spherical coordinate system, another vector containing
    the position of the pole of a new coordinate system
    on the old coordinate system, calculates the position
    of the point in the new coordinate system, and outputs
    this in a third double precision vector.  The desired
    RA for the old pole in the new coordinates is also required.
    NOTE: the coords must be located in positions 1 and 2
    of the double precision vectors, following the NRC
    convention, NOT positions 0 and 1.*/
  initpos[1] = ra2;
  initpos[2] = dec2;
  polepos[1] = ra1;
  polepos[2] = dec1;
  oldpolera = 0.0;

  printf("initpos = %f : %f\n",initpos[1],initpos[2]);
  printf("polepos = %f : %f\n",polepos[1],polepos[2]);
  poleswitch01(initpos,polepos,newpos,oldpolera);
  printf("newpos = %f : %f\n",newpos[1],newpos[2]);


  /*Calculate distance and position angle*/
  dist[1] = (PI/2.0 - newpos[2])*ASECPRAD;
  pa[1] = (2.0*PI-newpos[1])*180.0/PI;

  /*Calculate circular error*/
  circerr = pow(pow(errs[1],2.0)+pow(errs[2],2.0),0.5);
  /*Calculate error on distance*/
  dist[2] = circerr;
  /*Calculate error on pa*/
  pa[2] = (180.0/PI)*(circerr/dist[1]);

  return(1);
}

/*distradec04: Exactly like distradec03 but takes RA and
DEC in units of decimal degrees, as they are given in
the GSC.  The vectors ra and dec thus have now only
two entries.*/
int distradec04(float *ra,float *dec,float *errs,float *dist,float *pa)
{
  double ra1,ra2,dec1,dec2,mdec,radiff,decdiff;
  double initpos[3],polepos[3],newpos[3],oldpolera,circerr;

  /*Get RA and DEC in radians*/
  ra1 = ra[1]*PI/180.0;
  ra2 = ra[2]*PI/180.0;
  dec1 = dec[1]*PI/180.0;
  dec2 = dec[2]*PI/180.0;

  /*poleswitch01: given a double precision input vector
    containing the position in radians of a source on a 
    spherical coordinate system, another vector containing
    the position of the pole of a new coordinate system
    on the old coordinate system, calculates the position
    of the point in the new coordinate system, and outputs
    this in a third double precision vector.  The desired
    RA for the old pole in the new coordinates is also required.
    NOTE: the coords must be located in positions 1 and 2
    of the double precision vectors, following the NRC
    convention, NOT positions 0 and 1.*/
  initpos[1] = ra2;
  initpos[2] = dec2;
  polepos[1] = ra1;
  polepos[2] = dec1;
  oldpolera = 0.0;
  poleswitch01(initpos,polepos,newpos,oldpolera);

  /*Calculate distance and position angle*/
  dist[1] = (PI/2.0 - newpos[2])*ASECPRAD;
  pa[1] = (2.0*PI-newpos[1])*180.0/PI;

  /*Calculate circular error*/
  circerr = pow(pow(errs[1],2.0)+pow(errs[2],2.0),0.5);
  /*Calculate error on distance*/
  dist[2] = circerr;
  /*Calculate error on pa*/
  pa[2] = (180.0/PI)*(circerr/dist[1]);

  return(1);
}

/*distpix01: Takes in two x,y positions on an images, with
circular errors, and calculates the separation between them in pixels
and the celestial position angle in degrees assuming north
is exactly up and the image is not mirror-reversed.
NOTE THAT xp HOLD THE X POSTION OF BOTH POINTS, AND
yp HOLDS THE Y POSITION OF BOTH POINTS.*/
int distpix01(float *xp,float *yp,float *errs,float *dist,float *pa)
{
  float xdiff,ydiff;
  float circerr;

  xdiff = xp[2] - xp[1];
  ydiff = yp[2] - yp[1];

  /*Calculate distance*/
  dist[1] = pow(pow(xdiff,2.0)+pow(ydiff,2.0),0.5);

  if(xdiff==0.0)
    {
      if(ydiff>=0.0)
	{
	  pa[1] = 0.0;
	}
      else{
	pa[1] = 180.0;
      }
    }
  else if(xdiff>0.0)
    {
      pa[1] = 270.0 + 180.0*atan(ydiff/xdiff)/PI;
    }
  else if(xdiff<0.0)
    {
      pa[1] = 90.0 + 180.0*atan(ydiff/xdiff)/PI;
    }

  /*Calculate circular error*/
  circerr = pow(pow(errs[1],2.0)+pow(errs[2],2.0),0.5);
  /*Calculate error on distance*/
  dist[2] = circerr;
  /*Calculate error on pa*/
  pa[2] = (180.0/PI)*(circerr/dist[1]);

  return(1);
}

/*distpix02: Takes in two x,y positions on an images, with
circular errors, and calculates the separation between them in pixels
and the celestial position angle in degrees assuming north
is exactly up and the image is not mirror-reversed.
Differs from distpix01 only in its more rational convention:
cen1 HOLD THE X AND Y POSITIONS FOR POINT 1 and CEN2 HOLDS
THE X AND Y POSTIONS FOR POINT 2*/
int distpix02(float *cen1,float *cen2,float *errs,float *dist,float *pa)
{
  float xdiff,ydiff;
  float circerr;

  xdiff = cen2[1]-cen1[1];
  ydiff = cen2[2]-cen1[2];

  /*Calculate distance*/
  dist[1] = pow(pow(xdiff,2.0)+pow(ydiff,2.0),0.5);

  if(xdiff==0.0)
    {
      if(ydiff>=0.0)
	{
	  pa[1] = 0.0;
	}
      else{
	pa[1] = 180.0;
      }
    }
  else if(xdiff>0.0)
    {
      pa[1] = 270.0 + 180.0*atan(ydiff/xdiff)/PI;
    }
  else if(xdiff<0.0)
    {
      pa[1] = 90.0 + 180.0*atan(ydiff/xdiff)/PI;
    }

  /*Calculate circular error*/
  circerr = pow(pow(errs[1],2.0)+pow(errs[2],2.0),0.5);
  /*Calculate error on distance*/
  dist[2] = circerr;
  /*Calculate error on pa*/
  pa[2] = (180.0/PI)*(circerr/dist[1]);

  return(1);
}



/*creepvec01: Given a vector, its length, and
a rejection factor, carries out creeping mean
averaging of the vector and outputs the result.
Also outputs the rms of the values that were
retained.  If there was only one value, the rms
is set to -1 to signify this.*/

int creepvec01(float *invec,int pnum,float rejfac,float *output,float *error)
{
  int rejnum, i, j, nrej;
  float norm,rms,*invec2;
  double mean1;
  float sval, maxerr;
  int beginning, end;
  float del1, del2;
  int length;

  invec2 = vector(1,pnum);

  for(i=1;i<=pnum;i++)
    {
      invec2[i] = invec[i];
    }

  /*Determine how many entries will be rejected*/
  rejnum = rejfac*pnum;
  
    if(rejnum>=pnum)
    {
      printf("Warning: you have asked creepvecss to\n");
      printf("reject all of your points!\nAll but one will be rejected.\n");
      rejnum = pnum-1;
    }

  /*If the answer is zero let it work as an ordinary average*/
  if(rejnum<=0)
    {
      /*printf("Warning: creepvec01 is not rejecting any points\n");*/
      norm = mean1 = 0.0;
      for(i=1;i<=pnum;i++)
	{
	  norm+=1.0;
	  mean1+=invec2[i];
	}
      mean1/=norm;
      rms = 0.0;
      for(i=1;i<=pnum;i++)
	{
	  rms+=pow(mean1 - invec2[i],2.0);
	}
      if(norm==1.0)
	{
	  rms = -1.0;
	  /*printf("Warning: creepvec01 called with only one point!\n");*/
	}
      else{
	rms = pow(rms/(norm-1.0),0.5);
      }
    }
  else{
    /* Sort the array */
    sort(pnum,invec2);
    
    /* Magic happens here */
    
    /* Compute mean */
    norm = mean1 = 0.0;
    for(i=1;i<=pnum;i++)
      {
	norm+=1.0;
	mean1+=invec2[i];
      }
    mean1/=norm;
    
    beginning = 1;
    end = pnum;
    
    for(nrej=0;nrej<rejnum;nrej++)
      {
	del1 = fabs(invec2[beginning]- mean1);
	del2 = fabs(invec2[end] - mean1);
	
	if(del1 < del2) {
	  mean1 = (mean1*(double)norm - (double)invec2[end])/((double)norm-(double)1);
	  end--;

	}
	else {
	  mean1 = (mean1*(double)norm - (double)invec2[beginning])/((double)norm-(double)1);
	  beginning++;

	  mean1 = 0.0;
	  for(i=beginning;i<=end;i++)
	    {
	      mean1 += invec2[i];
	    }
	  mean1 /= norm-1;
	}
	norm--;
      }

    /* Recompute Mean */
    mean1 = 0.0;
    for(i=beginning;i<=end;i++)
      {
	mean1 += invec2[i];
      }
    mean1 /= norm;

    rms = 0.0;
    for(i=beginning;i<=end;i++)
      {
	rms+=pow(invec2[i]-mean1,2.0);
	/*printf("invec2[i] = %f\tmean1 = %f\trms = %f\n",invec2[i],mean1,rms);*/
      }
    if(norm==1.0)
      {
	rms = -1.0;
	/*printf("Warning: creepvec01 has rejected all but one point\n");*/
      }
    else{
      rms = pow(rms/(norm-1.0),0.5);
    }
  }    

  /*  printf("Test:%f %f %f\n",mean1,rms,norm); */
   
  *output = (float)mean1;
    
  if(rms==-1.0)
    {
      *error = -1.0;
    }
  else{
    *error = rms;
    /**error = rms/pow(1.0*pnum-1.0*rejnum,0.5);*/
  }
  
  free_vector(invec2,1,pnum);
  return(1);
}

/*mediansig01*/
int mediansig01(float *invec,int pnum,float sigclip,float *median)
{
  int i, j,middle;
  float floatmiddle,*invec2;
  double norm,rms;
  float sval, maxerr;
  int beginning, end;
  float median2;
  int length;

  invec2 = vector(1,pnum);

  for(i=1;i<=pnum;i++)
    {
      invec2[i] = invec[i];
    }

  /*Determine how many entries will be rejected*/
  /*If the answer is zero let it work as an ordinary average*/
  if(sigclip<=0)
    {
      printf("Warning: mediansig01 has zero or negative sigmaclip\n");
      printf("and will therefore perform an unclipped median.\n");
      if(pnum<1)
	{
	  printf("ERROR: mediansig01 CALLED WITH NO POINTS!\n");
	  printf("ABORTING WITH MEDIAN SET TO ZERO\n");
	  *median = 0.0;
	  return(0);
	}
      else if(pnum==1)
	{
	  *median = invec2[1];
	  printf("Warning: mediansig01 called with only one point\n");
	}
      else
	{
	  /* Sort the array */
	  sort(pnum,invec2);
	  /*Compute median*/
	  floatmiddle = (float)pnum/2.0 + 0.5;
	  middle = floatmiddle;
	  *median = invec2[middle];
	}
    }
  else
    {
      if(pnum<1)
	{
	  printf("ERROR: mediansig01 CALLED WITH NO POINTS!\n");
	  printf("ABORTING WITH MEDIAN SET TO ZERO\n");
	  *median = 0.0;
	  return(0);
	}
      else if(pnum==1)
	{
	  *median = invec2[1];
	  printf("Warning: mediansig01 called with only one point\n");
	}
      else
	{
	  /* Sort the array */
	  sort(pnum,invec2);
	  /*Compute median*/
	  floatmiddle = (float)pnum/2.0 + 0.5;
	  middle = floatmiddle;
	  median2 = invec2[middle];

	  /*Compute rms from median*/
	  norm = rms = 0.0;
	  for(i=1;i<=pnum;i++)
	    {
	      norm+=1.0;
	      rms+=pow(invec2[1]-median2,2.0);
	    }
	  rms = pow(rms/(norm-1.0),0.5);
	  /*Reload invec2 with only points that deviate less than sigclip
            from the median*/
	  length = 0;
	  for(i=1;i<=pnum;i++)
	    {
	      if(fabs(invec[i]-median2)<=rms*sigclip)
		{
		  length+=1;
		  invec2[length] = invec[i];
		}
	    }
	  if(length==0)
	    {
	      printf("ERROR: mediansig01 GOT SIGCLIP SO HIGH THAT\n");
	      printf("ALL POINTS WERE REJECTED!\n");
	      printf("THIS SHOULD BE IMPOSSIBLE FOR A MEDIAN!!!\n");
	      *median = median2;
	      return(0);
	    }
	  else
	    {
	      /*Sort the new array*/
	      sort(length,invec2);
	      /*Compute median*/
	      floatmiddle = (float)length/2.0 + 0.5;
	      middle = floatmiddle;
	      *median = invec2[middle];
	    }
	}
    }
  
  free_vector(invec2,1,pnum);
  return(1);
}

/*creepvec02: Exactly like creepvec01 except that it
rejects a set number of the input points, rather than
a set fraction of them.*/

int creepvec02(float *invec,int pnum,int rejn,float *output,float *error)
{
  int rejnum, i, j, nrej;
  float norm,rms,*invec2;
  double mean1;
  float sval, maxerr;
  int beginning, end;
  float del1, del2;
  int length;

  invec2 = vector(1,pnum);

  for(i=1;i<=pnum;i++)
    {
      invec2[i] = invec[i];
    }

  /*Determine how many entries will be rejected*/
  rejnum = rejn;
  
    if(rejnum>=pnum)
    {
      printf("Warning: you have asked creepvecss to\n");
      printf("reject all of your points!\nAll but one will be rejected.\n");
      rejnum = pnum-1;
    }

  /*If the answer is zero let it work as an ordinary average*/
  if(rejnum<=0)
    {
      /*printf("Warning: creepvec01 is not rejecting any points\n");*/
      norm = mean1 = 0.0;
      for(i=1;i<=pnum;i++)
	{
	  norm+=1.0;
	  mean1+=invec2[i];
	}
      mean1/=norm;
      rms = 0.0;
      for(i=1;i<=pnum;i++)
	{
	  rms+=pow(mean1 - invec2[i],2.0);
	}
      if(norm==1.0)
	{
	  rms = -1.0;
	  /*printf("Warning: creepvec01 called with only one point!\n");*/
	}
      else{
	rms = pow(rms/(norm-1.0),0.5);
      }
    }
  else{
    /* Sort the array */
    sort(pnum,invec2);
    
    /* Magic happens here */
    
    /* Compute mean */
    norm = mean1 = 0.0;
    for(i=1;i<=pnum;i++)
      {
	norm+=1.0;
	mean1+=invec2[i];
      }
    mean1/=norm;
    
    beginning = 1;
    end = pnum;
    
    for(nrej=0;nrej<rejnum;nrej++)
      {
	del1 = fabs(invec2[beginning]- mean1);
	del2 = fabs(invec2[end] - mean1);
	
	if(del1 < del2) {
	  mean1 = (mean1*(double)norm - (double)invec2[end])/((double)norm-(double)1);
	  end--;	  

	}
	else {
	  mean1 = (mean1*(double)norm - (double)invec2[beginning])/((double)norm-(double)1);
	  beginning++;
	}
	norm--;
      }

    /* Recompute Mean */
    mean1 = 0.0;
    for(i=beginning;i<=end;i++)
      {
	mean1 += invec2[i];
      }
    mean1 /= norm;
    
    rms = 0.0;
    for(i=beginning;i<=end;i++)
      {
	rms+=pow(invec2[i]-mean1,2.0);
	/*printf("invec2[i] = %f\tmean1 = %f\trms = %f\n",invec2[i],mean1,rms);*/
      }
    if(norm==1.0)
      {
	rms = -1.0;
	/*printf("Warning: creepvec01 has rejected all but one point\n");*/
      }
    else{
      rms = pow(rms/(norm-1.0),0.5);
    }
  }    
   
  /*  printf("Test:%f %f\n",rms,norm); */

  *output = (float)mean1;
    
  if(rms==-1.0)
    {
      *error = -1.0;
    }
  else{
    *error = rms;
    /**error = rms/pow(1.0*pnum-1.0*rejnum,0.5);*/
  }
  
  free_vector(invec2,1,pnum);
  return(1);
}


/*sigclipvec01: given a vector, its length, an iteration number,
and a sigma clip, performs the specified number of iterations
at the given sigma clip and outputs the resulting mean
and standard deviation.  Runs silently as long
as one or more points are supplied if silentyes = 1.
If given a negative or zero number of points, prints
an error and returns zero values.  If given one point,
returns the value of this point as the average and its
absolute value is the rms.  If silentyes is not 1,
prints a warning message*/
int sigclipvec01(float *invec,int pnum,int itnum,float sigclip,float *mean,float *rms,int silentyes)
{
  float pmean,prms,*tempvec1,*tempvec2;
  int sgct1,sgct2,i,j;

  if(pnum<1)
    {
      printf("Error: sigclipvec01 recieved %d points\n",pnum);
      printf("ABORTING; RETURNED VALUES WILL BE ZERO\n");
      *mean = 0.0;
      *rms = 0.0;
      return(0);
    }

  if(pnum==1)
    {
      *mean = invec[1];
      *rms = fabs(invec[1]);
      if(silentyes!=1)
	{
	  printf("Warning: sigclipvec01 called with only 1 point\n");
	  printf("Program will run OK but returned rms will be\n");
	  printf("the absolute value of the point\n");
	}
      return(1);
    }

  tempvec1 = vector(1,pnum);
  tempvec2 = vector(1,pnum);
  for(j=1;j<=pnum;j++)
    {
      tempvec1[j] = invec[j];
    }
  sgct1 = pnum;

  meanrms01(tempvec1,sgct1,&pmean,&prms);
  for(i=1;i<=itnum;i++)
    {
      sgct2 = 0;
      for(j=1;j<=sgct1;j++)
	{
	  if(fabs(tempvec1[j]-pmean)<sigclip*prms)
	    {
	      sgct2+=1;
	      tempvec2[sgct2] = tempvec1[j];
	    }
	}
      if(sgct2<2)
	{
	  *mean = pmean;
	  *rms = prms;
	  free_vector(tempvec1,1,pnum);
	  free_vector(tempvec2,1,pnum);
	  return(1);
	}
      else
	{
	  for(j=1;j<=sgct2;j++)
	    {
	      tempvec1[j] = tempvec2[j];
	    }
	  sgct1 = sgct2;
	}
      meanrms01(tempvec1,sgct1,&pmean,&prms);
    }

  *mean = pmean;
  *rms = prms;

  free_vector(tempvec1,1,pnum);
  free_vector(tempvec2,1,pnum);

  return(1);
}

/*centroiderr01: calculates a centroid with sky subtraction
in 5 iterations of a constant input radius, using sky
subtraction from a constant input annulus.  On the last
iteration, calculates the error of the final centroid.
This error is stored in three parts, the x error, the
y error, and the circular error, in the 3-element vector
cerr.  The image is assumed to be flatfielded, but the
flat must be included for error calculation purposes.
As long as the flat that is used is the real flat used to
process the image, it need not be normalized.  If the
errors are not going to be used and the real flat
is not available, a unit image may be used.  A
starting guess at the centroid is held in the two-element
vector cen and is replaced with the result.  The three
element vector rads contains the centroiding radius,
and the inner and outer sky annulus radii.*/
int centroiderr01(float **image,int nx,int ny,float **flat,float *cen,float *cerr,float *rads,float gain)
{
  float cx1,cy1,cx2,cy2,*skyvec,r,norm;
  int hcbox,i,j,k,skynum,skymax,icx,icy,skyct;
  float skyval,skyerr,cxerr,cyerr,normerr;

  hcbox = rads[3] + 5;
  skymax = PI*(pow(rads[3],2.0)-pow(rads[2],2.0))*2;

  skyvec = vector(1,skymax);

  cx1 = cen[1];
  cy1 = cen[2];

  for(k=1;k<=5;k++)
    {
      icx = cx1+0.5;
      icy = cy1+0.5;
      skynum = 0;
      for(i=icx-hcbox;i<=icx+hcbox;i++)
	{
	  for(j=icy-hcbox;j<=icy+hcbox;j++)
	    {
	      r = pow(pow(1.0*i-cx1,2.0)+pow(1.0*j-cy1,2.0),0.5);
	      if(i>=1&&i<=nx&&j>=1&&j<=ny&&r>rads[2]&&r<rads[3])
		{
		  skynum+=1;
		  skyvec[skynum] = image[i][j];
		  /*printf("skynum = %d\tskyvec = %f\n",skynum,skyvec[skynum]);*/
		}
	    }
	}
      creepvec01(skyvec,skynum,0.5,&skyval,&skyerr);
      cx2 = cy2 = norm = 0.0;
      cxerr = cyerr = normerr = 0.0;
      printf("Skyval = %f\tSkyerr = %f\n",skyval,skyerr);
      for(i=icx-hcbox;i<=icx+hcbox;i++)
	{
	  for(j=icy-hcbox;j<=icy+hcbox;j++)
	    {
	      r = pow(pow(1.0*i-cx1,2.0)+pow(1.0*j-cy1,2.0),0.5);
	      if(i>=1&&i<=nx&&j>=1&&j<=ny&&r<=rads[1])
		{
		  /*printf("in loop: %d,%d\t image = %f\n",i,j,image[i][j]);*/
		  norm+=(image[i][j]-skyval);
		  cx2+=(image[i][j]-skyval)*(1.0*i-1.0*icx);
		  cy2+=(image[i][j]-skyval)*(1.0*j-1.0*icy);
		  /*IF statements deal with the case that photon noise from
                    the sky is or is not negligible*/
		  if(skyval>=SKYSET)
		    {
		      normerr+=(image[i][j])/(gain*flat[i][j])+pow(skyerr,2.0);
		      cxerr+=pow(1.0*i-1.0*icx,2.0)*(pow(pow(image[i][j],2.0),0.5)/(gain*flat[i][j])+pow(skyerr,2.0));
		      cyerr+=pow(1.0*j-1.0*icy,2.0)*(pow(pow(image[i][j],2.0),0.5)/(gain*flat[i][j])+pow(skyerr,2.0));
		    }
		  else{
		    normerr+=(image[i][j]-skyval)/(gain*flat[i][j])+pow(skyerr,2.0);
		    cxerr+=pow(1.0*i-1.0*icx,2.0)*(pow(pow(image[i][j]-skyval,2.0),0.5)/(gain*flat[i][j])+pow(skyerr,2.0));
		    cyerr+=pow(1.0*j-1.0*icy,2.0)*(pow(pow(image[i][j]-skyval,2.0),0.5)/(gain*flat[i][j])+pow(skyerr,2.0));
		  }
		}
	    }
	}
      /*printf("cxerr = %f\n",cxerr);*/
      cx2/=norm;
      cy2/=norm;
      cxerr = pow(cxerr,0.5);
      cyerr = pow(cyerr,0.5);
      /*printf("cxerr = %f\n",cxerr);*/
      /*printf("normerr = %f\n",normerr);*/
      if(normerr<0.0)
	{
	  printf("WARNING: CENTROIDERR FINDS NORMERR TO BE NEGATIVE\n");
	  printf("THE INPUT STAR COORDINATES MAY HAVE BEEN WRONG\n");
	  printf("THE FORMAL ERROR WILL CERTAINLY BE QUESTIONABLE\n");
	  printf("normerr = %f, multiplying by the Buckner coefficient -1\n",normerr);
	  printf("NORM = %f\n",norm);
	  normerr = -normerr;
	}
      normerr = pow(normerr,0.5);
      /*printf("cxerr = %f\tnorm = %f\tnormerr = %f\tcx2 = %f\n",cxerr,norm,normerr,cx2);*/
      cxerr = pow(pow(cxerr/norm,2.0)+pow(normerr*cx2/norm,2.0),0.5);
      cyerr = pow(pow(cyerr/norm,2.0)+pow(normerr*cy2/norm,2.0),0.5);
      /*printf("cxerr = %f\n",cxerr);*/
      cx2+=1.0*icx;
      cy2+=1.0*icy;
      cx1 = cx2;
      cy1 = cy2;
      printf("Iteration %d found center at %f,%f\n",k,cx1,cy1);
    }
  cen[1] = cx2;
  cen[2] = cy2;
  cerr[1] = cxerr;
  cerr[2] = cyerr;
  cerr[3] = pow(pow(cxerr,2.0)+pow(cyerr,2.0),0.5);

  free_vector(skyvec,1,skymax);

}

/*centphoterr01: Like centroiderr01 but accepts one additional
radius entry, which is the radius of a photometry aperture,
and takes one additional five element vector, *phots, the first
element of which is set to the measured flux within the photometry
aperture, the second to the formal error on this flux, the
third to the average sky background, the fourth to the error
on this sky background, and the fifth to the ratio of star flux
to sky background flux.*/ 
int centphoterr01(float **image,int nx,int ny,float **flat,float *cen,float *cerr,float *rads,float gain,float *phots)
{
  float cx1,cy1,cx2,cy2,*skyvec,r,norm,norm2;
  int hcbox,i,j,k,skynum,skymax,icx,icy,skyct;
  float skyval,skyerr,cxerr,cyerr,normerr,crms;

  hcbox = rads[3] + 5;
  skymax = PI*(pow(rads[3],2.0)-pow(rads[2],2.0))*2;

  skyvec = vector(1,skymax);

  cx1 = cen[1];
  cy1 = cen[2];

  printf("centphoterr01 recieved radii %f %f %f %f\n",rads[1],rads[2],rads[3],rads[4]);

  if(rads[4]>rads[3])
    {
      printf("ERROR: centphoterr01 CALLED WITH PHOTOMETRIC RADIUS\n");
      printf("LARGER THAN OUTER SKY SUBTRACTION RADIUS!\n");
      printf("ABORTING!!\n");
      return(0);
    }

  for(k=1;k<=5;k++)
    {
      icx = cx1+0.5;
      icy = cy1+0.5;
      skynum = 0;
      for(i=icx-hcbox;i<=icx+hcbox;i++)
	{
	  for(j=icy-hcbox;j<=icy+hcbox;j++)
	    {
	      r = pow(pow(1.0*i-cx1,2.0)+pow(1.0*j-cy1,2.0),0.5);
	      if(i>=1&&i<=nx&&j>=1&&j<=ny&&r>rads[2]&&r<rads[3])
		{
		  skynum+=1;
		  skyvec[skynum] = image[i][j];
		  /*printf("skynum = %d\tskyvec = %f\n",skynum,skyvec[skynum]);*/
		}
	    }
	}
      pseudocreep01(skyvec,skynum,0.5,&skyval,&skyerr,&crms);
      cx2 = cy2 = norm = 0.0;
      cxerr = cyerr = normerr = 0.0;
      printf("Skyval = %f\tSkyerr = %f\n",skyval,skyerr);
      for(i=icx-hcbox;i<=icx+hcbox;i++)
	{
	  for(j=icy-hcbox;j<=icy+hcbox;j++)
	    {
	      r = pow(pow(1.0*i-cx1,2.0)+pow(1.0*j-cy1,2.0),0.5);
	      if(i>=1&&i<=nx&&j>=1&&j<=ny&&r<=rads[1])
		{
		  /*printf("in loop: %d,%d\t image = %f\n",i,j,image[i][j]);*/
		  norm+=(image[i][j]-skyval);
		  cx2+=(image[i][j]-skyval)*(1.0*i-1.0*icx);
		  cy2+=(image[i][j]-skyval)*(1.0*j-1.0*icy);
		  /*IF statements deal with the case that photon noise from
                    the sky is or is not negligible*/
		  if(skyval>=SKYSET)
		    {
		      normerr+=(image[i][j])/(gain*flat[i][j])+pow(skyerr,2.0);
		      cxerr+=pow(1.0*i-1.0*icx,2.0)*(pow(pow(image[i][j],2.0),0.5)/(gain*flat[i][j])+pow(skyerr,2.0));
		      cyerr+=pow(1.0*j-1.0*icy,2.0)*(pow(pow(image[i][j],2.0),0.5)/(gain*flat[i][j])+pow(skyerr,2.0));
		    }
		  else{
		    normerr+=(image[i][j]-skyval)/(gain*flat[i][j])+pow(skyerr,2.0);
		    cxerr+=pow(1.0*i-1.0*icx,2.0)*(pow(pow(image[i][j]-skyval,2.0),0.5)/(gain*flat[i][j])+pow(skyerr,2.0));
		    cyerr+=pow(1.0*j-1.0*icy,2.0)*(pow(pow(image[i][j]-skyval,2.0),0.5)/(gain*flat[i][j])+pow(skyerr,2.0));
		  }
		}
	    }
	}
      /*printf("cxerr = %f\n",cxerr);*/
      cx2/=norm;
      cy2/=norm;
      cxerr = pow(cxerr,0.5);
      cyerr = pow(cyerr,0.5);
      /*printf("cxerr = %f\n",cxerr);*/
      /*printf("normerr = %f\n",normerr);*/
      if(normerr<0.0)
	{
	  printf("WARNING: CENTPHOTERR FINDS NORMERR TO BE NEGATIVE\n");
	  printf("THE INPUT STAR COORDINATES MAY HAVE BEEN WRONG\n");
	  printf("THE FORMAL ERROR WILL CERTAINLY BE QUESTIONABLE\n");
	  printf("normerr = %f, multiplying by the Buckner coefficient -1\n",normerr);
	  printf("NORM = %f\n",norm);
	  normerr = -normerr;
	}
      normerr = pow(normerr,0.5);
      /*printf("cxerr = %f\tnorm = %f\tnormerr = %f\tcx2 = %f\n",cxerr,norm,normerr,cx2);*/
      cxerr = pow(pow(cxerr/norm,2.0)+pow(normerr*cx2/norm,2.0),0.5);
      cyerr = pow(pow(cyerr/norm,2.0)+pow(normerr*cy2/norm,2.0),0.5);
      /*printf("cxerr = %f\n",cxerr);*/
      cx2+=1.0*icx;
      cy2+=1.0*icy;
      cx1 = cx2;
      cy1 = cy2;
      printf("Iteration %d found center at %f,%f\n",k,cx1,cy1);
    }
  cen[1] = cx2;
  cen[2] = cy2;
  cerr[1] = cxerr;
  cerr[2] = cyerr;
  cerr[3] = pow(pow(cxerr,2.0)+pow(cyerr,2.0),0.5);

  norm = norm2 = 0.0;
  for(i=icx-hcbox;i<=icx+hcbox;i++)
    {
      for(j=icy-hcbox;j<=icy+hcbox;j++)
	{
	  r = pow(pow(1.0*i-cen[1],2.0)+pow(1.0*j-cen[2],2.0),0.5);
	  if(i>=1&&i<=nx&&j>=1&&j<=ny&&r<=rads[4])
	    {
	      norm+=(image[i][j]-skyval);
	      norm2+=skyval;
	      if(skyval>=SKYSET)
		{
		  normerr+=(image[i][j])/(gain*flat[i][j])+pow(skyerr,2.0);
		}
	      else{
		normerr+=(image[i][j]-skyval)/(gain*flat[i][j])+pow(skyerr,2.0);
	      }
	    }
	}
    }
  if(normerr<0.0)
    {
      printf("WARNING: CENTPHOTERR FINDS FORMAL PHOTOMETRIC ERROR TO BE NEGATIVE\n");
      printf("THE INPUT STAR COORDINATES MAY HAVE BEEN WRONG\n");
      printf("THE FORMAL ERROR WILL CERTAINLY BE MEANINGLESS\n");
      printf("photerr = %f, phot = %f\n",normerr,norm);
      printf("NORM = %f\n",norm);
      normerr = -normerr;
    }
  normerr = pow(normerr,0.5);
  phots[1] = norm;
  phots[2] = normerr;
  phots[3] = skyval;
  phots[4] = skyerr;
  phots[5] = norm/norm2;

  free_vector(skyvec,1,skymax);

}


/*divmean01: a simple program to normalize an image by
dividing it by the mean pixel value within a specified box, 
as calculated by statsim03.*/
int divmean01(float **image,float sigclip,int nx,int ny,int *boxvec)
{
  int statsim03(float **image,int nx,int ny,int *boxvec,float *rms,float *mean,float sigclip);

  int i,j;
  float norm,rms;
  statsim03(image,nx,ny,boxvec,&rms,&norm,sigclip);

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image[i][j]/=norm;
	}
    }
  return(1);
}

/*divmean01c: Exactly like divmean01, but uses a pseudo-creeping mean
  combine to calculate the image mean, rather than a sigma-clip*/
int divmean01c(float **image,float rlev,int nx,int ny,int *boxvec)
{

  int i,j;
  float norm,rms;
  statsim03c(image,nx,ny,boxvec,&rms,&norm,rlev);

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image[i][j]/=norm;
	}
    }
  return(1);
}

/*airmassget01: given the input of an IRAF header file, looks
for a keyword AIRMASS.  If it is found, reads the float after
the = sign and returns this as the airmass.  If it is not found,
prints an error message and returns 1.0*/
float airmassget01(char *imname)
{
  FILE *fp1;
  char strtest[80],hold[80];
  int c,lnum,i,airmassfound;
  float airmass;

  strcpy(hold,"AIRMASS");
  /*printf("%s\n",hold);*/

  fp1 = fopen(imname,"r");
  lnum = 0;
  while(c!=EOF)
    {
      c = getc(fp1);
      if(c=='\n')
	{
	  lnum+=1;
	}
    }
  fclose(fp1);
  fp1 = fopen(imname,"r");
  airmassfound = 0;
  for(i=1;i<=lnum;i++)
    {
      c = 0;
      fscanf(fp1,"%s",strtest);
      /*printf("%s\n",strtest);*/
      if(strcmp(hold,strtest)==0)
	{
	  airmassfound = 1;
	  c = getc(fp1);
	  while(c!='=')
	    {
	      c = getc(fp1);
	    }
	  fscanf(fp1,"%f",&airmass);
	  printf("AIRMASS is %f\n",airmass);
	  fclose(fp1);
	  return(airmass);
	}
      else{
	while(c!='\n'&&c!=EOF)
	  {
	    c = getc(fp1);
	  }
      }
    }
  printf("ERROR: airmassget01 DOES NOT FIND AIRMASS KEYWORD IN HEADER FILE!\n");
  printf("ABORTING WITH AIRMASS SET TO 1.0\n");
  fclose(fp1);
  return(1.0);
}


/*dateget01: given the input of an IRAF header file, looks
for a keyword DATE-OBS.  If it is found, looks
after the = for a date of the form %d:%d:%d, where
the order is year, month, day, and returns these
in the three-element vector date.*/
int dateget01(char *imname,int *date)
{
  FILE *fp1;
  char strtest[80],hold[80];
  int c,lnum,i,datefound;
  int year,month,day;

  strcpy(hold,"DATE-OBS=");

  fp1 = fopen(imname,"r");
  lnum = 0;
  while(c!=EOF)
    {
      c = getc(fp1);
      if(c=='\n')
	{
	  lnum+=1;
	}
    }
  fclose(fp1);
  fp1 = fopen(imname,"r");
  datefound = 0;
  for(i=1;i<=lnum;i++)
    {
      c = 0;
      fscanf(fp1,"%s",strtest);
      if(strcmp(hold,strtest)==0)
	{
	  datefound = 1;
	  c = getc(fp1);
	  c = getc(fp1);
	  fscanf(fp1,"%d",&year);
	  c = getc(fp1);
	  fscanf(fp1,"%d",&month);
	  c = getc(fp1);
	  fscanf(fp1,"%d",&day);
	  printf("date found as %d-%d-%d\n",year,month,day);
	  date[1] = year;
	  date[2] = month;
	  date[3] = day;
	  fclose(fp1);
	  return(1);
	}
      else{
	while(c!='\n'&&c!=EOF)
	  {
	    c = getc(fp1);
	  }
      }
    }
  fclose(fp1);
  printf("ERROR: dateget01 DOES NOT FIND DATE-OBS KEYWORD IN HEADER FILE!\n");
  printf("ABORTING!\n");
  return(0);
}

/*dateget02: given the input of an IRAF header file, looks
for a keyword DATE.  If it is found, looks
after the = for a date of the form %d-%d-%dT%d:%d:%d, where
the order is year, month, day, hour, minute, second, and returns the
date in the 3-element vector date and the ut
in the 3-element vector ut.*/
int dateget02(char *imname,int *date,int *ut)
{
  FILE *fp1;
  char strtest[80],hold[80];
  int c,lnum,i,datefound,j;
  int year,month,day;
  int hour,minute,second,quotefound;

  strcpy(hold,"DATE");

  fp1 = fopen(imname,"r");
  lnum = 0;
  while(c!=EOF)
    {
      c = getc(fp1);
      if(c=='\n')
	{
	  lnum+=1;
	}
    }
  fclose(fp1);
  printf("dateget02 found %d lines\n",lnum);
  fp1 = fopen(imname,"r");
  datefound = 0;
  for(i=1;i<=lnum;i++)
    {
      c = 0;
      fscanf(fp1,"%s",strtest);
      if(strcmp(hold,strtest)==0)
	{
	  datefound = 1;
	  quotefound = 0;
	  while(quotefound==0)
	    {
	      c = getc(fp1);
	      if(c == '=')
		quotefound=1;
	    }

	  c = getc(fp1);
	  c = getc(fp1);
	  fscanf(fp1,"%d",&year);
	  c = getc(fp1);
	  fscanf(fp1,"%d",&month);
	  c = getc(fp1);
	  fscanf(fp1,"%d",&day);
	  printf("date found as %d-%d-%d\n",year,month,day);
	  c = getc(fp1);
	  fscanf(fp1,"%d",&hour);
	  c = getc(fp1);
	  fscanf(fp1,"%d",&minute);
	  c = getc(fp1);
	  fscanf(fp1,"%d",&second);
	  printf("UT found is %d:%d:%d\n",hour,minute,second);
	  date[1] = year;
	  date[2] = month;
	  date[3] = day;
	  ut[1] = hour;
	  ut[2] = minute;
	  ut[3] = second;
	  fclose(fp1);
	  return(1);
	}
      else{
	while(c!='\n'&&c!=EOF)
	  {
	    c = getc(fp1);
	  }
      }
    }
  fclose(fp1);
  printf("ERROR: dateget02 DOES NOT FIND DATE KEYWORD IN HEADER FILE!\n");
  printf("ABORTING!\n");
  return(0);
}


/*utget01: given the input of an IRAF header file, looks
for a keyword UT.  If it is found, looks
after the = for the UT in the form hh:mm:ss,
and returns these in the three-element vector ut.*/
int utget01(char *imname,int *ut)
{
  FILE *fp1;
  char strtest[80],hold[80];
  int c,lnum,i,utfound;
  int hour,minute,second;

  strcpy(hold,"UT");

  fp1 = fopen(imname,"r");
  lnum = 0;
  while(c!=EOF)
    {
      c = getc(fp1);
      if(c=='\n')
	{
	  lnum+=1;
	}
    }
  fclose(fp1);
  fp1 = fopen(imname,"r");
  utfound = 0;
  for(i=1;i<=lnum;i++)
    {
      c = 0;
      fscanf(fp1,"%s",strtest);
      if(strcmp(hold,strtest)==0)
	{
	  utfound = 1;
	  c = getc(fp1);
	  while(c!='=')
	    {
	      c = getc(fp1);
	    }
	  c = getc(fp1);
	  c = getc(fp1);
	  fscanf(fp1,"%d",&hour);
	  c = getc(fp1);
	  fscanf(fp1,"%d",&minute);
	  c = getc(fp1);
	  fscanf(fp1,"%d",&second);
	  printf("UT found to be %d:%d:%d\n",hour,minute,second);
	  ut[1] = hour;
	  ut[2] = minute;
	  ut[3] = second;
	  fclose(fp1);
	  return(1);
	}
      else{
	while(c!='\n'&&c!=EOF)
	  {
	    c = getc(fp1);
	  }
      }
    }
  fclose(fp1);
  printf("ERROR: utget01 DOES NOT FIND UT KEYWORD IN HEADER FILE!\n");
  printf("ABORTING!\n");
  return(0);
}


/*utget02: utget optimized for Mont4K headers.  Expects
a whole fits image to be input as a raw file, not
just the header.  Looks for a UT keyword for MAXSEARCHCHARS.
The second time the character sequence UT is found, looks after
the = for the UT in the form hh:mm:ss.ss,
and returns these in the three-element vector ut.
Note that ut is a floating point vector here,
unlike for utget01*/
int utget02(char *imname,float *ut)
{
  FILE *fp1;
  char strtest[3],hold[3];
  int c,i,utfound;
  float hour,minute,second;

  strcpy(hold,"UT");
  strtest[2] = '\0';
  strtest[0] = 0;
  strtest[1] = 0;

  printf("hold = %s\n",hold);

  utfound = 0;
  fp1 = fopen(imname,"r");
  c = i = 0;
  while(i<=MAXSEARCHCHARS && c!=EOF)
    {
      c = getc(fp1);
      i+=1;
      strtest[0] = strtest[1];
      strtest[1] = c;
      /*See if UT string has been found*/
      if(strcmp(strtest,hold)==0)
	{
	  utfound+=1;
	}
      /*If this is the second time UT has been found,
        read to 2 characters past the = sign and then
        read the UT*/
      if(utfound==2)
	{
	  c = 0;
	  while(c!='=')
	    {
	      c = getc(fp1);
	    }
	  c = getc(fp1);
	  c = getc(fp1);
	  fscanf(fp1,"%f",&hour);
	  c = getc(fp1);
	  fscanf(fp1,"%f",&minute);
	  c = getc(fp1);
	  fscanf(fp1,"%f",&second);
	  printf("UT found to be %.0f:%.0f:%.2f\n",hour,minute,second);
	  ut[1] = hour;
	  ut[2] = minute;
	  ut[3] = second;
	  c = EOF;
	}
    }
  fclose(fp1);

  if(utfound!=2)
    {
      printf("ERROR: utget02 DOES NOT FIND UT KEYWORD IN HEADER FILE!\n");
      printf("ABORTING!\n");
      return(0);
    }
  return(1);
}

/*airmassget02: airmassget optimized for Mont4K headers.  Expects
a whole fits image to be input as a raw file, not
just the header.  Looks for an AIRMASS keyword for MAXSEARCHCHARS.
When it is found, looks after the = for the floating point airmass
and returns it.*/
int airmassget02(char *imname,float *airmass)
{
  FILE *fp1;
  char strtest[8],hold[8];
  int c,i,airmassfound;
  float airm;

  strcpy(hold,"AIRMASS");
  strtest[7] = '\0';
  strtest[0] = 0;
  strtest[1] = 0;
  strtest[2] = 0;
  strtest[3] = 0;
  strtest[4] = 0;
  strtest[5] = 0;
  strtest[6] = 0;

  airmassfound = 0;
  fp1 = fopen(imname,"r");
  c = i = 0;
  while(i<=MAXSEARCHCHARS && c!=EOF)
    {
      c = getc(fp1);
      i+=1;
      strtest[0] = strtest[1];
      strtest[1] = strtest[2];
      strtest[2] = strtest[3];
      strtest[3] = strtest[4];
      strtest[4] = strtest[5];
      strtest[5] = strtest[6];
      strtest[6] = c;

      /*See if AIRMASS string has been found*/
      if(strcmp(strtest,hold)==0)
	{
	  /*The AIRMASS keyword has been found.*/
	  airmassfound = 1;
	  /*Read to the = and then 2 characters more*/
	  c = 0;
	  while(c!='=')
	    {
	      c = getc(fp1);
	    }
	  c = getc(fp1);
	  c = getc(fp1);
	  fscanf(fp1,"%f",&airm);
	  *airmass = airm;
	  c = EOF;
	}
    }
  fclose(fp1);

  if(airmassfound==0)
    {
      printf("ERROR: airmassget02 DOES NOT FIND the AIRMASS KEYWORD IN HEADER FILE!\n");
      printf("ABORTING!\n");
      return(0);
    }
  return(1);
}



/*linfit01: The simple linear fit program I should
have written years ago.  Takes in pointnum, vector
x, vector y, and fits y = a + bx.  In the output
vector, gives a, b, rms, sig a, and sig b.  Also
outputs the most deviant point in wp, and
its absolute deviation in wdev*/
int linfit01(int pointnum,float *x, float *y,float *outvec,int *wp,float *wdev)
{
  int i;
  double a,b,delta,xal,yal,xty,xsq,nsum,rms,err,errmax;
  double siga,sigb;


  if(pointnum<=1)
    {
      printf("ERROR: linfit01 CALLED WITH ONLY ONE POINT\n");
      printf("ABORTING!!\n");
      for(i=1;i<=5;i++)
	{
	  outvec[i] = 0.0;
	}
      return(0);
    }

  xal = yal = xty = xsq = nsum = 0.0;
  for(i=1;i<=pointnum;i++)
    {
      xal+=x[i];
      yal+=y[i];
      xsq+=pow(x[i],2.0);
      xty += x[i]*y[i];
      nsum+=1.0;
    }
  delta = nsum*xsq - pow(xal,2.0);
  a = (xsq*yal - xal*xty)/delta;
  b = (nsum*xty - xal*yal)/delta;

  if(pointnum>2)
    {
      rms = errmax = 0.0;
      for(i=1;i<=pointnum;i++)
	{
	  rms+=pow(y[i] - (a + b*x[i]),2.0);
	  err = pow(pow(y[i] - (a + b*x[i]),2.0),0.5);
	  if(err>errmax)
	    {
	      errmax = err;
	      *wp = i;
	      *wdev = errmax;
	    }
	}
      rms/=(nsum-2.0);
      siga = pow(rms*xsq/delta,0.5);
      sigb = pow(nsum*rms/delta,0.5);
      rms = pow(rms,0.5);
      outvec[3] = rms;
      outvec[4] = siga;
      outvec[5] = sigb;
    }
  else{
    printf("WARNING: linfit01 CALLED WITH ONLY TWO POINTS\n");
    printf("UNCERTAINTIES ARE ALL SET TO ZERO\n");
    outvec[3] = 0.0;
    outvec[4] = 0.0;
    outvec[5] = 0.0;
    *wp = 0;
    *wdev = 0.0;
  }
  outvec[1] = a;
  outvec[2] = b;
  return(1);

}

/*linfit02: The weighted linear fit program I should
have written years ago.  Takes in pointnum, vector
x, vector y, and vector yerr, and fits y = a + bx.  In the output
vector, gives a, b, reduced chi-square, sig a, and sig b.  Also
outputs the most deviant point in wp, and
its absolute deviation in wdev*/
int linfit02(int pointnum,float *x, float *y,float *yerr,float *outvec)
{
  int i;
  float a,b,delta,xal,yal,xty,xsq,nsum,rms,err,errmax;
  float siga,sigb,*model;

  model = vector(1,pointnum);

  if(pointnum<=1)
    {
      printf("ERROR: linfit02 CALLED WITH ONLY ONE POINT\n");
      printf("ABORTING!!\n");
      for(i=1;i<=5;i++)
	{
	  outvec[i] = 0.0;
	}
      return(0);
    }

  xal = yal = xty = xsq = nsum = 0.0;
  for(i=1;i<=pointnum;i++)
    {
      xal+=x[i]/pow(yerr[i],2.0);
      yal+=y[i]/pow(yerr[i],2.0);
      xsq+=pow(x[i],2.0)/pow(yerr[i],2.0);
      xty += x[i]*y[i]/pow(yerr[i],2.0);
      nsum+=1.0/pow(yerr[i],2.0);
    }
  delta = nsum*xsq - pow(xal,2.0);
  a = (xsq*yal - xal*xty)/delta;
  b = (nsum*xty - xal*yal)/delta;

  if(pointnum>2)
    {
      rms = errmax = 0.0;
      for(i=1;i<=pointnum;i++)
	{
	  model[i] = a + b*x[i];
	}
      rms = getchisq01(y,model,yerr,pointnum);
      siga = xsq/delta;
      sigb = nsum/delta;
      outvec[3] = rms;
      outvec[4] = siga;
      outvec[5] = sigb;
    }
  else{
    printf("WARNING: linfit02 CALLED WITH ONLY TWO POINTS\n");
    printf("CHI-SQUARE VALUE SET TO ZERO\n");
    outvec[3] = xsq/delta;
    outvec[4] = nsum/delta;
    outvec[5] = 0.0;
  }
  outvec[1] = a;
  outvec[2] = b;
  free_vector(model,1,pointnum);
  return(1);

}


/*linfit02cm: A weighted linear fit program with creeping
mean rejection of the worst rejnum points.  The points
are rejected by absolute deviation from the best-fit
line, not by deviation relative to their uncertainties.
Rejection stops when only two points are left even if
the required number has not yet been rejected.*/
int linfit02cm(int pointnum,float *x, float *y,float *yerr,float *outvec,int rejnum)
{
  int i,nrej,wp;
  float data,err,errmax,*xvec,*yvec,*lfitvec,*yevec;

  xvec = vector(1,pointnum);
  yvec = vector(1,pointnum);
  yevec = vector(1,pointnum);
  lfitvec = vector(1,5);

  for(i=1;i<=pointnum;i++)
    {
      xvec[i] = x[i];
      yvec[i] = y[i];
      yevec[i] = yerr[i];
    }

  if(pointnum<=1)
    {
      printf("ERROR: linfit02cm CALLED WITH ONLY ONE POINT\n");
      printf("ABORTING!!\n");
      for(i=1;i<=5;i++)
	{
	  outvec[i] = 0.0;
	}
      return(0);
    }

  for(nrej=0;nrej<=rejnum;nrej++)
    {
      if(pointnum-nrej>=2)
	{
	  /*Make linear fit with remaining points*/
	  linfit02(pointnum-nrej,xvec,yvec,yevec,lfitvec);
	}
      if(pointnum-nrej>2&&nrej<rejnum)
	{
	  /*If we haven't yet rejected enough, reject another point*/
	  wp = 1;
	  errmax = fabs(yvec[1]-lfitvec[1]-lfitvec[2]*xvec[1]);
	  for(i=2;i<=pointnum-nrej;i++)
	    {
	      err = fabs(yvec[i]-lfitvec[1]-lfitvec[2]*xvec[i]);
	      if(err>errmax)
		{
		  errmax = err;
		  wp = i;
		}
	    }
	  data = xvec[wp];
	  xvec[wp] = xvec[pointnum-nrej];
	  xvec[pointnum-nrej] = data;
	  data = yvec[wp];
	  yvec[wp] = yvec[pointnum-nrej];
	  yvec[pointnum-nrej] = data;
	  data = yevec[wp];
	  yevec[wp] = yevec[pointnum-nrej];
	  yevec[pointnum-nrej] = data;
	}
    }
      
  for(i=1;i<=5;i++)
    {
      outvec[i] = lfitvec[i];
    }

  free_vector(xvec,1,pointnum);
  free_vector(yevec,1,pointnum);
  free_vector(yvec,1,pointnum);
  free_vector(lfitvec,1,5);
  return(1);

}



/*fixzero01: Removes pixels that are zero or less than
  zero from a flat image, replacing them with rep*/
int fixzero01(float **image,int nx,int ny,float rep,int *nrep)
{
  int i,j,pfix;

  pfix = 0;
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  if(image[i][j]<=0.0)
	    {
	      image[i][j] = rep;
	      pfix+=1;
	    }
	}
    }
  *nrep = pfix;
  return(1);
}



/*fixzero02: Removes pixels that are less than
  lowlim from a flat image, replacing them with rep*/
int fixzero02(float **image,int nx,int ny,float rep,int *nrep,float lowlim)
{
  int i,j,pfix;

  pfix = 0;
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  if(image[i][j]<lowlim)
	    {
	      image[i][j] = rep;
	      pfix+=1;
	    }
	}
    }
  *nrep = pfix;
  return(1);
}

/*skyfind01: Uses creeping mean in a sky annulus to find the
  sky background level.  Requires an image, the dimensions
nx and ny, a two element vector rads giving the inner and
outer radii of the annulus, and a two-element vector cen
giving the center of the annulus.  Outputs the sky
background level and the estimated error of this determination.*/

int skyfind01(float **image,int nx,int ny,float *rads,float *skylev,float *skyerr,float *cen)
{
  int i,j,hcbox,icx,icy,skynum,skymax;
  float *skyvec,r,crms;

  if(rads[2]<rads[1])
    {
      printf("ERROR: skyfind01 has recieved bad sky annulus\n");
      printf("Annulus from radius %f to %f\n",rads[1],rads[2]);
      printf("ABORTING WITH OUTPUT SET TO ZERO\n");
      *skylev = 0.0;
      *skyerr = 0.0;
      return(0);
    }


  skymax = PI*(pow(rads[2],2.0)-pow(rads[1],2.0))*2;

  skyvec = vector(1,skymax);

  hcbox = rads[2] + 5;

  icx = cen[1]+0.5;
  icy = cen[2]+0.5;
  skynum = 0;
  for(i=icx-hcbox;i<=icx+hcbox;i++)
    {
      for(j=icy-hcbox;j<=icy+hcbox;j++)
	{
	  r = pow(pow(1.0*i-cen[1],2.0)+pow(1.0*j-cen[2],2.0),0.5);
	  if(i>=1&&i<=nx&&j>=1&&j<=ny&&r>rads[1]&&r<rads[2])
	    {
	      skynum+=1;
	      skyvec[skynum] = image[i][j];
	      /*printf("skynum = %d\tskyvec = %f\n",skynum,skyvec[skynum]);*/
	    }
	}
    }
  pseudocreep01(skyvec,skynum,0.5,skylev,skyerr,&crms);
  free_vector(skyvec,1,skymax);
  return(1);
}

/*skyfind02: Exactly like skyfind01 but reports the rms of
  the sky background rather than the approximate sky error*/

int skyfind02(float **image,int nx,int ny,float *rads,float *skylev,float *skyerr,float *cen)
{
  int i,j,hcbox,icx,icy,skynum,skymax;
  float *skyvec,r,crms;

  if(rads[2]<rads[1])
    {
      printf("ERROR: skyfind02 has recieved bad sky annulus\n");
      printf("Annulus from radius %f to %f\n",rads[1],rads[2]);
      printf("ABORTING WITH OUTPUT SET TO ZERO\n");
      *skylev = 0.0;
      *skyerr = 0.0;
      return(0);
    }


  skymax = PI*(pow(rads[2],2.0)-pow(rads[1],2.0))*2;

  skyvec = vector(1,skymax);

  hcbox = rads[2] + 5;

  icx = cen[1]+0.5;
  icy = cen[2]+0.5;
  skynum = 0;
  for(i=icx-hcbox;i<=icx+hcbox;i++)
    {
      for(j=icy-hcbox;j<=icy+hcbox;j++)
	{
	  r = pow(pow(1.0*i-cen[1],2.0)+pow(1.0*j-cen[2],2.0),0.5);
	  if(i>=1&&i<=nx&&j>=1&&j<=ny&&r>=rads[1]&&r<=rads[2])
	    {
	      skynum+=1;
	      skyvec[skynum] = image[i][j];
	      /*printf("skynum = %d\tskyvec = %f\n",skynum,skyvec[skynum]);*/
	    }
	}
    }
  pseudocreep01(skyvec,skynum,0.5,skylev,&crms,skyerr);
  free_vector(skyvec,1,skymax);
  return(1);
}

/*skyfind03: Exactly like skyfind02 but uses a one-iteration
5-sigma sigclip instead of a creeping mean to get the sky
brightness.*/
int skyfind03(float **image,int nx,int ny,float *rads,float *skylev,float *skyerr,float *cen)
{
  int i,j,hcbox,icx,icy,skynum,skymax;
  float *skyvec,r,crms;

  if(rads[2]<rads[1])
    {
      printf("ERROR: skyfind03 has recieved bad sky annulus\n");
      printf("Annulus from radius %f to %f\n",rads[1],rads[2]);
      printf("ABORTING WITH OUTPUT SET TO ZERO\n");
      *skylev = 0.0;
      *skyerr = 0.0;
      return(0);
    }

  skymax = PI*(pow(rads[2],2.0)-pow(rads[1],2.0))*2;

  skyvec = vector(1,skymax);

  hcbox = rads[2] + 5;

  icx = cen[1]+0.5;
  icy = cen[2]+0.5;
  skynum = 0;
  for(i=icx-hcbox;i<=icx+hcbox;i++)
    {
      for(j=icy-hcbox;j<=icy+hcbox;j++)
	{
	  r = pow(pow(1.0*i-cen[1],2.0)+pow(1.0*j-cen[2],2.0),0.5);
	  if(i>=1&&i<=nx&&j>=1&&j<=ny&&r>=rads[1]&&r<=rads[2])
	    {
	      skynum+=1;
	      skyvec[skynum] = image[i][j];
	      /*printf("skynum = %d\tskyvec = %f\n",skynum,skyvec[skynum]);*/
	    }
	}
    }
  sigclipvec01(skyvec,skynum,1,5.0,skylev,skyerr,1);
  free_vector(skyvec,1,skymax);
  return(1);
}


/*nlc01: a program to apply a 12-parameter nonlinearity
correction output by nonlinfit04.c to an image.  It
requires a zeropoint, which it is critical and must
be accurate to obtain good results.  nlc01 corrects
the image channel by channel.  Another version,
nlc02, applies the same correction to the whole image.*/
int nlc01(char *nlcpars,float **image,int nx,int ny,float zeropoint,int *nzero)
{
  FILE *fp1;
  float a1,b1,c1,d1,s1,a2,b2,c2,d2,c3,d3,s2,a3,b3,c4,d4;
  int quatim,k,i,j,nz;
  float **finalpars,fit,xval;

  finalpars = matrix(1,4,1,16);
  fp1=fopen(nlcpars,"r");
  for(k=1;k<=4;k++)
    {
      for(i=1;i<=16;i++)
	{
	  fscanf(fp1,"%f",finalpars[k]+i);
	}
    }
  fclose(fp1);

  quatim = nx/4;
  nz = 0;
  for(k=1;k<=4;k++)
    {
      a1 = finalpars[k][1];
      b1 = finalpars[k][2];
      c1 = finalpars[k][3];
      d1 = finalpars[k][4];
      s1 = finalpars[k][5];
      a2 = finalpars[k][6];
      b2 = finalpars[k][7];
      c2 = finalpars[k][8];
      d2 = finalpars[k][9];
      c3 = finalpars[k][10];
      d3 = finalpars[k][11];
      s2 = finalpars[k][12];
      a3 = finalpars[k][13];
      b3 = finalpars[k][14];
      c4 = finalpars[k][15];
      d4 = finalpars[k][16];
      for(i=1;i<=quatim;i++)
	{
	  for(j=1;j<=ny;j++)
	    {
	      xval = image[(i-1)*4+k][j]-zeropoint;
	      if(xval<s1)
		{
		  fit = a1 + b1*xval - d1*exp(c1*(xval-s1));
		}
	      if(xval>=s1&&xval<s2)
		{
		  fit = a2 + b2*xval - d2*exp(c2*(s1 - xval)) + d3*exp(c3*(xval - s2));
		}
	      if(xval>=s2)
		{
		  fit = a3 + b3*xval + d4*exp(c4*(s2 - xval));
		}
	      if(fit>=0.0)
		{
		  image[(i-1)*4+k][j] = fit;
		}
	      else{
		nz+=1;
		image[(i-1)*4+k][j] = 0.0;
	      }
	    }
	}
    }
  *nzero = nz;
  free_matrix(finalpars,1,4,1,16);
  return(1);
}

/*nlc02: a program to apply a 12-parameter nonlinearity
correction output by nonlinfit04.c to an image.  It
requires a zeropoint, which it is critical and must
be accurate to obtain good results.  nlc02 corrects every
point on the image by the averaged channel by channel fit.  
Another version, nlc02, corrects channel by channel.*/
int nlc02(char *nlcpars,float **image,int nx,int ny,float zeropoint,int *nzero)
{
  FILE *fp1;
  float a1,b1,c1,d1,s1,a2,b2,c2,d2,c3,d3,s2,a3,b3,c4,d4;
  int k,i,j,nz;
  float **finalpars,fit,xval,sumfit;

  finalpars = matrix(1,4,1,16);
  fp1=fopen(nlcpars,"r");
  for(k=1;k<=4;k++)
    {
      for(i=1;i<=16;i++)
	{
	  fscanf(fp1,"%f",finalpars[k]+i);
	}
    }
  fclose(fp1);

  nz = 0;

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  sumfit = 0.0;
	  for(k=1;k<=4;k++)
	    {
	      a1 = finalpars[k][1];
	      b1 = finalpars[k][2];
	      c1 = finalpars[k][3];
	      d1 = finalpars[k][4];
	      s1 = finalpars[k][5];
	      a2 = finalpars[k][6];
	      b2 = finalpars[k][7];
	      c2 = finalpars[k][8];
	      d2 = finalpars[k][9];
	      c3 = finalpars[k][10];
	      d3 = finalpars[k][11];
	      s2 = finalpars[k][12];
	      a3 = finalpars[k][13];
	      b3 = finalpars[k][14];
	      c4 = finalpars[k][15];
	      d4 = finalpars[k][16];
	      xval = image[i][j]-zeropoint;
	      if(xval<s1)
		{
		  fit = a1 + b1*xval - d1*exp(c1*(xval-s1));
		}
	      if(xval>=s1&&xval<s2)
		{
		  fit = a2 + b2*xval - d2*exp(c2*(s1 - xval)) + d3*exp(c3*(xval - s2));
		}
	      if(xval>=s2)
		{
		  fit = a3 + b3*xval + d4*exp(c4*(s2 - xval));
		}
	      sumfit+=0.25*fit;
	    }
	  if(sumfit>=0.0)
	    {
	      image[i][j] = sumfit;
	    }
	  else{
	    nz+=1;
	    image[i][j] = 0.0;
	  }
	}
    }

  *nzero = nz;
  free_matrix(finalpars,1,4,1,16);
  return(1);
}

/*nlc03: a program to apply a 7-parameter nonlinearity
correction output by nonlinfit05.c to an image.  It
requires a zeropoint, which it is critical and must
be accurate to obtain good results.  nlc03 corrects every
point on the image by the averaged channel by channel fit.*/
int nlc03(char *nlcpars,float **image,int nx,int ny,float zeropoint,int *nzero)
{
  FILE *fp1;
  float a1,b1,c1,d1,s1,a2,b2,c2,d2;
  int k,i,j,nz;
  float **finalpars,fit,xval,sumfit;

  finalpars = matrix(1,4,1,9);

  fp1=fopen(nlcpars,"r");
  for(k=1;k<=4;k++)
    {
      for(i=1;i<=9;i++)
	{
	  fscanf(fp1,"%f",finalpars[k]+i);
	}
    }
  fclose(fp1);
  nz = 0;
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  sumfit = 0.0;
	  for(k=1;k<=4;k++)
	    {
	      a1 = finalpars[k][1];
	      b1 = finalpars[k][2];
	      c1 = finalpars[k][3];
	      d1 = finalpars[k][4];
	      s1 = finalpars[k][5];
	      a2 = finalpars[k][6];
	      b2 = finalpars[k][7];
	      c2 = finalpars[k][8];
	      d2 = finalpars[k][9];
	      xval = image[i][j]-zeropoint;
	      if(xval<s1)
		{
		  fit = a1 + b1*xval + d1*exp(c1*(xval-s1));
		}
	      if(xval>=s1)
		{
		  fit = a2 + b2*xval + d2*exp(c2*(s1 - xval));
		}
	      sumfit+=0.25*fit;
	    }
	  if(sumfit>=0.0)
	    {
	      image[i][j] = sumfit;
	    }
	  else{
	    image[i][j] = 0.0;
	    nz+=1;
	  }
	}
    }
  *nzero = nz;
  free_matrix(finalpars,1,4,1,9);
  return(1);
}


/*afpdarkdiff01: A method to remove as many bad
pixels as possible from dark images prior to
combining, when extremely low noise darks
are required.  It takes in two darks, identifies
bad pixels on their difference using the
same algorithm as afp01, and then corrects
the bad pixels on both images using vertical
interpolation only.*/
int afpdarkdiff01(float **image1,float **image2,int nx,int ny,float sigclip,int *numfix)
{
  int i,j,k,l;
  float mean3,mean5,rms,norm3,norm5;
  float **image;

  image = matrix(1,nx,1,ny);

  /*Subtract image2 from image1, store result in image*/
  mathimtim02(image1,image,nx,ny,image2);

  *numfix = 0;
  /*Find bad pixels on difference of the two images*/
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  mean3 = norm3 = 0.0;
	  for(k=i-1;k<=i+1;k++)
	    {
	      for(l=j-1;l<=j+1;l++)
		{
		  if(k>=1&&k<=nx&&l>=1&&l<=nx)
		    {
		      if(k==i&&l==j)
			{
			  ;
			}
		      else{
			mean3+=image[k][l];
			norm3+=1.0;
		      }
		    }
		}
	    }
	  mean3/=norm3;
	  mean5 = norm5 = 0.0;
	  for(k=i-2;k<=i+2;k++)
	    {
	      for(l=j-2;l<=j+2;l++)
		{
		  if(k>=1&&k<=nx&&l>=1&&l<=nx)
		    {
		      if(k==i&&l==j)
			{
			  ;
			}
		      else{
			mean5+=image[k][l];
			norm5+=1.0;
		      }
		    }
		}
	    }
	  mean5/=norm5;
	  rms = 0.0;
	  for(k=i-2;k<=i+2;k++)
	    {
	      for(l=j-2;l<=j+2;l++)
		{
		  if(k>=1&&k<=nx&&l>=1&&l<=nx)
		    {
		      if(k==i&&l==j)
			{
			  ;
			}
		      else{
			rms+=pow(image[k][l]-mean5,2.0);
		      }
		    }
		}
	    }
	  rms = pow(rms/(norm5-1.0),0.5);
	  if(pow(pow(image[i][j]-mean3,2.0),0.5)>sigclip*rms)
	    {
	      if(j>1&&j<ny)
		{
		  image1[i][j] = 0.5*image1[i][j-1] + 0.5*image1[i][j+1];
		  image2[i][j] = 0.5*image2[i][j-1] + 0.5*image2[i][j+1];
		  *numfix+=1;
		}
	      else if(j==1)
		{
		  image1[i][j] = image1[i][j+1];
		  image2[i][j] = image2[i][j+1];
		  *numfix+=1;
		}
	      else if(j==ny)
		{
		  image1[i][j] = image1[i][j+1];
		  image2[i][j] = image2[i][j+1];
		  *numfix+=1;
		}
	    }
	}
    }

  return(1);
}


/*radpsfsub02: Given an image, the centroid of a star, a
subtraction radius, and a taper radius, creates a radial
model of the psf out to the taper radius, and subtracts
the whole of this model from the image out to the subtraction
radius, then tapering away the subtraction to zero at the 
taper radius.  The model of the psf is constructed by proceeding
at one-pixel increments in radius out from the central star,
and going around the circle of this radius in one pixel
increments.  At each one-pixel increment, a vector is loaded
with avlen pixel values along the circumference centered
at the current pixel.  This vector is then averaged by
creeping mean averaging with rlev fractional rejection.
The average value is assigned as the psf model at that
radius.  radpsfsub02 performs its psf modeling on
subtracted model of the input image, for which reason
it requires a subtraction image to be input.  It does
not, however, change the input subtraction image.  It
only changes the input target image.  All pixels with
zrad of the center are simply set to zero.*/
int radpsfsub02(float **image1,float **image2,int nx,int ny,float *cen,int subrad,int faderad,int avlen,float rlev,int *sbox,float zrad)
{
  int i,j,k,l,rejn,circnum;
  float *dvec,rad,theta,thetastep,**image3,**image4,**image5,**image6,data;
  float thetacen,*dvec2,x,y,mean1,errn;
  int ix,iy;

  dvec = vector(1,2*avlen+1);
  dvec2 = vector(1,4*avlen);
  image3 = matrix(1,nx,1,ny);
  image4 = matrix(1,nx,1,ny);
  image5 = matrix(1,nx,1,ny);
  image6 = matrix(1,nx,1,ny);

  imzero(image3,nx,ny);
  imzero(image4,nx,ny);
  imzero(image5,nx,ny);
  imzero(image6,nx,ny);

  printf("\n\nPERFORMING RADIAL PSF SUBTRACTION\n\n");
  imcopy01(image1,image3,nx,ny);
  imcopy01(image2,image4,nx,ny);

  specialsub01(image3,nx,ny,sbox,image4);

  for(k=1;k<=2*faderad;k++)
    {
      rad = 0.5*k;
      if(PI*rad<avlen)
	{
	  /*We'll just average the whole circle*/
	  thetastep = PI/(2.0*avlen);
	  for(i=1;i<=4*avlen;i++)
	    {
	      thetacen = (1.0*i-1.0)*thetastep;
	      x = cen[1]+rad*cos(thetacen);
	      y = cen[2]+rad*sin(thetacen);
	      ix = x + 0.5;
	      iy = y + 0.5;
	      if(ix>=1&&ix<=nx&&iy>=1&&iy<=nx)
		{
		  dvec2[i] = image3[ix][iy];
		}
	      else
		{
		  dvec2[i] = 0.0;
		}
	    }
	  rejn = 1.0*(rlev*4.0*avlen);
	  creepvec02(dvec2,4*avlen,rejn,&mean1,&errn);
	  if(rad>faderad)
	    {
	      mean1 = 0.0;
	    }
	  else if(rad<=faderad&&rad>subrad)
	    {
	      mean1*=(1.0*faderad-1.0*rad)/(1.0*faderad - 1.0*subrad);
	    }
	  for(i=1;i<=4*avlen;i++)
	    {
	      thetacen = (1.0*i-1.0)*thetastep;
	      x = cen[1]+rad*cos(thetacen);
	      y = cen[2]+rad*sin(thetacen);
	      ix = x + 0.5;
	      iy = y + 0.5;
	      /*Add value to image5, which holds the psf approximation.
                If values for this point have already been obtained, the
                new value is averaged with the old, and the pixel in
                image6 is increased by one to indicate the addition of
                yet another value.*/
	      if(ix>=1&&ix<=nx&&iy>=1&&iy<=ny)
		{
		  image5[ix][iy] = (image5[ix][iy]*image6[ix][iy] + mean1)/(image6[ix][iy]+1.0);
		  image6[ix][iy]+=1.0;
		}
	    }
	}
      else
	{
	  /*We'll form an arc and carry the arc around*/
	  thetastep = 0.5/rad;
	  circnum = 2.0*PI/thetastep;
	  for(j=1;j<=circnum;j++)
	    {
	      thetacen = 2.0*PI + 1.0*j*thetastep;
	      for(i=1;i<=2*avlen+1;i++)
		{
		  theta = thetacen + (1.0*i-1.0*avlen-1.0)*thetastep;
		  x = cen[1]+rad*cos(theta);
		  y = cen[2]+rad*sin(theta);
		  ix = x + 0.5;
		  iy = y + 0.5;
		  if(ix>=1&&ix<=nx&&iy>=1&&iy<=ny)
		    {
		      dvec[i] = image3[ix][iy];
		    }
		  else
		    {
		      dvec[i] = 0.0;
		    }
		}
	      rejn = 1.0*(rlev*(2.0*avlen+1.0));
	      creepvec02(dvec,2*avlen+1,rejn,&mean1,&errn);
	      if(rad>faderad)
		{
		  mean1 = 0.0;
		}
	      else if(rad<=faderad&&rad>subrad)
		{
		  mean1*=(1.0*faderad-1.0*rad)/(1.0*faderad - 1.0*subrad);
		}
	      x = cen[1]+rad*cos(thetacen);
	      y = cen[2]+rad*sin(thetacen);
	      ix = x + 0.5;
	      iy = y + 0.5;
	      /*Add value to image5, which holds the psf approximation.
                If values for this point have already been obtained, the
                new value is averaged with the old, and the pixel in
                image6 is increased by one to indicate the addition of
                yet another value.*/
	      if(ix>=1&&ix<=nx&&iy>=1&&iy<=ny)
		{
		  image5[ix][iy] = (image5[ix][iy]*image6[ix][iy] + mean1)/(image6[ix][iy]+1.0);
		  image6[ix][iy]+=1.0;
		}
	    }
	}
    }

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  rad = pow(pow(1.0*i-cen[1],2.0) + pow(1.0*j-cen[2],2.0),0.5);
	  if(rad<zrad)
	    {
	      image5[i][j] = image3[i][j];
	    }
	  image1[i][j]-=image5[i][j];
	}
    }

  free_vector(dvec,1,2*avlen+1);
  free_vector(dvec2,1,4*avlen);
  free_matrix(image3,1,nx,1,ny);
  free_matrix(image4,1,nx,1,ny);
  free_matrix(image5,1,nx,1,ny);
  free_matrix(image6,1,nx,1,ny);

  return(1);
}

/*radpsfsub02c: exactly like radpsfsub, but uses specialsub01c, rather
than specialsub01 to subtract the nodded image to get a low-noise
image on which to get the radially averaged psf.  The difference
between specialsub01 and specialsub01c is that the latter uses
pseudocreep01 for box averaging for image scaling, and the former
uses the cruder but faster sigma clip.  Thus radpsfsub02c is
more careful but slower than radpsfsub02*/
int radpsfsub02c(float **image1,float **image2,int nx,int ny,float *cen,int subrad,int faderad,int avlen,float rlev,int *sbox,float zrad)
{
  int i,j,k,l,rejn,circnum;
  float *dvec,rad,theta,thetastep,**image3,**image4,**image5,**image6,data;
  float thetacen,*dvec2,x,y,mean1,errn;
  int ix,iy;

  dvec = vector(1,2*avlen+1);
  dvec2 = vector(1,4*avlen);
  image3 = matrix(1,nx,1,ny);
  image4 = matrix(1,nx,1,ny);
  image5 = matrix(1,nx,1,ny);
  image6 = matrix(1,nx,1,ny);

  imzero(image3,nx,ny);
  imzero(image4,nx,ny);
  imzero(image5,nx,ny);
  imzero(image6,nx,ny);

  printf("\n\nPERFORMING RADIAL PSF SUBTRACTION\n\n");
  imcopy01(image1,image3,nx,ny);
  imcopy01(image2,image4,nx,ny);

  specialsub01c(image3,nx,ny,sbox,image4);

  for(k=1;k<=2*faderad;k++)
    {
      rad = 0.5*k;
      if(PI*rad<avlen)
	{
	  /*We'll just average the whole circle*/
	  thetastep = PI/(2.0*avlen);
	  for(i=1;i<=4*avlen;i++)
	    {
	      thetacen = (1.0*i-1.0)*thetastep;
	      x = cen[1]+rad*cos(thetacen);
	      y = cen[2]+rad*sin(thetacen);
	      ix = x + 0.5;
	      iy = y + 0.5;
	      if(ix>=1&&ix<=nx&&iy>=1&&iy<=nx)
		{
		  dvec2[i] = image3[ix][iy];
		}
	      else
		{
		  dvec2[i] = 0.0;
		}
	    }
	  rejn = 1.0*(rlev*4.0*avlen);
	  creepvec02(dvec2,4*avlen,rejn,&mean1,&errn);
	  if(rad>faderad)
	    {
	      mean1 = 0.0;
	    }
	  else if(rad<=faderad&&rad>subrad)
	    {
	      mean1*=(1.0*faderad-1.0*rad)/(1.0*faderad - 1.0*subrad);
	    }
	  for(i=1;i<=4*avlen;i++)
	    {
	      thetacen = (1.0*i-1.0)*thetastep;
	      x = cen[1]+rad*cos(thetacen);
	      y = cen[2]+rad*sin(thetacen);
	      ix = x + 0.5;
	      iy = y + 0.5;
	      /*Add value to image5, which holds the psf approximation.
                If values for this point have already been obtained, the
                new value is averaged with the old, and the pixel in
                image6 is increased by one to indicate the addition of
                yet another value.*/
	      if(ix>=1&&ix<=nx&&iy>=1&&iy<=ny)
		{
		  image5[ix][iy] = (image5[ix][iy]*image6[ix][iy] + mean1)/(image6[ix][iy]+1.0);
		  image6[ix][iy]+=1.0;
		}
	    }
	}
      else
	{
	  /*We'll form an arc and carry the arc around*/
	  thetastep = 0.5/rad;
	  circnum = 2.0*PI/thetastep;
	  for(j=1;j<=circnum;j++)
	    {
	      thetacen = 2.0*PI + 1.0*j*thetastep;
	      for(i=1;i<=2*avlen+1;i++)
		{
		  theta = thetacen + (1.0*i-1.0*avlen-1.0)*thetastep;
		  x = cen[1]+rad*cos(theta);
		  y = cen[2]+rad*sin(theta);
		  ix = x + 0.5;
		  iy = y + 0.5;
		  if(ix>=1&&ix<=nx&&iy>=1&&iy<=ny)
		    {
		      dvec[i] = image3[ix][iy];
		    }
		  else
		    {
		      dvec[i] = 0.0;
		    }
		}
	      rejn = 1.0*(rlev*(2.0*avlen+1.0));
	      creepvec02(dvec,2*avlen+1,rejn,&mean1,&errn);
	      if(rad>faderad)
		{
		  mean1 = 0.0;
		}
	      else if(rad<=faderad&&rad>subrad)
		{
		  mean1*=(1.0*faderad-1.0*rad)/(1.0*faderad - 1.0*subrad);
		}
	      x = cen[1]+rad*cos(thetacen);
	      y = cen[2]+rad*sin(thetacen);
	      ix = x + 0.5;
	      iy = y + 0.5;
	      /*Add value to image5, which holds the psf approximation.
                If values for this point have already been obtained, the
                new value is averaged with the old, and the pixel in
                image6 is increased by one to indicate the addition of
                yet another value.*/
	      if(ix>=1&&ix<=nx&&iy>=1&&iy<=ny)
		{
		  image5[ix][iy] = (image5[ix][iy]*image6[ix][iy] + mean1)/(image6[ix][iy]+1.0);
		  image6[ix][iy]+=1.0;
		}
	    }
	}
    }

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  rad = pow(pow(1.0*i-cen[1],2.0) + pow(1.0*j-cen[2],2.0),0.5);
	  if(rad<zrad)
	    {
	      image5[i][j] = image3[i][j];
	    }
	  image1[i][j]-=image5[i][j];
	}
    }

  free_vector(dvec,1,2*avlen+1);
  free_vector(dvec2,1,4*avlen);
  free_matrix(image3,1,nx,1,ny);
  free_matrix(image4,1,nx,1,ny);
  free_matrix(image5,1,nx,1,ny);
  free_matrix(image6,1,nx,1,ny);

  return(1);
}


/*simpphot01: a simple subroutine to do aperture photometry with
  sky subtraction about a fixed input center.*/
float simpphot01(float **image,int nx,int ny,float cenx,float ceny,float aprad,float skyrad)
{
  float sky,sum,rad,theta,*skyvec;
  int skynum,i,j,k,hbs,pixct;
  float xp,yp,error,realmean;

  skynum = 2.0*PI*skyrad;
  skyvec = vector(1,skynum);
  /*Calculate sky background*/
  realmean = 0.0;
  for(k=1;k<=skynum;k++)
    {
      theta = 2.0*PI*(1.0*k)/(1.0*skynum);
      xp = cenx + skyrad*cos(theta);
      yp = ceny + skyrad*sin(theta);
      i=xp+0.5;
      j = yp+0.5;
      skyvec[k] = image[i][j];
      realmean+=image[i][j];
    }
  realmean/=(1.0*skynum);
  printf("mean = %f\n",realmean);
  creepvec01(skyvec,skynum,0.5,&sky,&error);


  /*Calculate integrated target flux*/
  hbs = aprad+3.0;
  sum = 0.0;
  pixct = 0;
  for(i=cenx-hbs;i<=cenx+hbs;i++)
    {
      for(j=ceny-hbs;j<=ceny+hbs;j++)
	{
	  rad = pow(pow(1.0*i-cenx,2.0)+pow(1.0*j-ceny,2.0),0.5);
	  if(rad <= aprad)
	    {
	      sum+=image[i][j]-sky;
	      pixct+=1;
	    }
	}
    }
  printf("simpphot finds sky = %f, sum = %f, %d pixels used\n",sky,sum,pixct);
  free_vector(skyvec,1,skynum);
  return(sum);
}

/*simpcen01: a simple subroutine to do a 5-iteration, fixed
radius centroiding with sky subtraction on a star image.
No errors are calculated*/
int simpcen01(float **image,int nx,int ny,float *cenx,float *ceny,float cenrad,float skyradl,float skyradh)
{
  float sky,sum,rad,theta,*skyvec;
  int skynum,i,j,k,hbs,pixct;
  float xp,yp,error,realmean,data;
  float xcen,ycen,xcen2,ycen2;

  skynum = PI*(pow(skyradh,2.0)-pow(skyradl,2.0));
  skynum*=2.0;
  skyvec = vector(1,skynum);

  hbs = 2.0*skyradh;
  skynum = 0;
  xcen = *cenx;
  ycen = *ceny;
  for(i=xcen-hbs;i<=xcen+hbs;i++)
    {
      for(j=ycen-hbs;j<ycen+hbs;j++)
	{
	  rad = pow(pow(1.0*i-xcen,2.0)+pow(1.0*j-ycen,2.0),0.5);
	  if(rad>=skyradl&&rad<=skyradh&&i>=1&&i<=nx&&j>=1&&j<=ny)
	    {
	      skynum+=1;
	      skyvec[skynum] = image[i][j];
	    }
	}
    }

  pseudocreep01(skyvec,skynum,0.5,&sky,&error,&data);

  /*Calculate centroid in 5 iterations*/
  hbs = 2.0*cenrad;
  for(k=1;k<=5;k++)
    {
      sum = xcen2 = ycen2 = 0.0;
      pixct = 0;
      printf("xcen = %f, ycen = %f\n",xcen,ycen);
      for(i=xcen-hbs;i<=xcen+hbs;i++)
	{
	  for(j=ycen-hbs;j<=ycen+hbs;j++)
	    {
	      rad = pow(pow(1.0*i-xcen,2.0)+pow(1.0*j-ycen,2.0),0.5);
	      if(rad <= cenrad&&rad<=skyradh&&i>=1&&i<=nx&&j>=1&&j<=ny)
		{
		  sum+=image[i][j]-sky;
		  xcen2 += (image[i][j]-sky)*(1.0*i);
		  ycen2 += (image[i][j]-sky)*(1.0*j);
		}
	    }
	}
      xcen = xcen2/sum;
      ycen = ycen2/sum;
    }
  *cenx = xcen;
  *ceny = ycen;
  skynum = PI*pow(skyradh,2.0)-PI*pow(skyradl,2.0);
  skynum*=2.0;
  free_vector(skyvec,1,skynum);
  return(1);
}


/*trimimage01: given an input image with dimensions, an output image, and xl,xh,yl,yh for
the good data region, puts a trimmed version of the input image into the output
image.  The calling function is responsible to make sure the output image
has the correct dimensions (xh-xl+1)X(yh-yl+1); if the image is too small
there will simply be a segfault.*/
int trimimage01(float **image1,int nx,int ny,float **image2,int xl,int xh,int yl, int yh)
{
  int i,j;
  for(i=xl;i<=xh;i++)
    {
      for(j=yl;j<=yh;j++)
	{
	  image2[i-xl+1][j-yl+1] = image1[i][j];
	}
    }
  printf("trimmed image to output %d x %d\n",xh-xl+1,yh-yl+1);
}

/*starnsky01: a program for star identification given
an a-priori approximate psf in the form of a radial
gaussian.  It will apply this gaussian template
to an image and produce two new images, one giving the
amplitude of the best fit guassian centered on each
pixel, and the other giving the best-fit sky background
at each pixel.  The only free parameters to the gaussian
fit are the amplitude and sky background, and the
fit is performed by deterministic least square matching
without rejection.*/
int starnsky01(float **image,float **amplim,float **skyim,int nx,int ny, float sigma,float rad)
{
  int i,j,halfbox,k,l;
  float **gaussbox,beta,alpha,pixnum,fsqr,ftimi,fal,ial,radius;

  halfbox = rad + 3;
  gaussbox = matrix(1,2*halfbox+1,1,2*halfbox+1);

  for(i=1;i<=2*halfbox+1;i++)
    {
      for(j=1;j<=2*halfbox+1;j++)
	{
	  gaussbox[i][j] = exp(-0.5*(pow(1.0*halfbox+1.0-1.0*i,2.0)+pow(1.0*halfbox+1.0-1.0*j,2.0))/pow(sigma,2.0));
	}
    }

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  alpha = beta = pixnum = fsqr = ftimi = fal = ial = 0.0;
	  for(k=i-halfbox;k<=i+halfbox;k++)
	    {
	      for(l=j-halfbox;l<=j+halfbox;l++)
		{
		  radius = pow(pow(1.0*k-1.0*i,2.0) + pow(1.0*l-1.0*j,2.0),0.5);
		  if(radius<=rad&&k>=1&&k<=nx&&l>=1&&l<=ny)
		    {
		      fsqr+=pow(gaussbox[k-i+halfbox+1][l-j+halfbox+1],2.0);
		      fal+=gaussbox[k-i+halfbox+1][l-j+halfbox+1];
		      ial+=image[k][l];
		      ftimi+=image[k][l]*gaussbox[k-i+halfbox+1][l-j+halfbox+1];
		      pixnum+=1.0;
		    }
		}
	    }
	  alpha = (pixnum*ftimi - fal*ial)/(pixnum*fsqr - pow(fal,2.0));
	  beta = (ial - alpha*fal)/pixnum;
	  amplim[i][j] = alpha;
	  skyim[i][j] = beta;
	}
    }
  free_matrix(gaussbox,1,2*halfbox+1,1,2*halfbox+1);
  return(1);
}


/*starnsky02: a program for star identification given
an a-priori approximate psf read in from a psf image.  
The center of the psf on the psf image must be given, and
two radii for calculating and subtracting the sky
background.  If either of these radii is zero or
negative, no error will occur but the program will interpret
this to mean that no sky background should be subtracted
from the psf.  The program will apply the psf template
to a science image and produce two new images, one giving the
amplitude of the best fit psf centered on each
pixel, and the other giving the best-fit sky background
at each pixel.  The only free parameters to the
fit are the amplitude and sky background, and the
fit is performed by deterministic least square matching
without rejection.  The psf is normalized in the
sense that the highest pixel is set to one.*/
int starnsky02(float **image,float **amplim,float **skyim,int nx,int ny, float rad,float **psfim, int psfnx,int psfny,int cx,int cy,float skyrad1,float skyrad2)
{
  int i,j,halfbox,k,l,skynum,hcbox;
  float **psfbox,beta,alpha,pixnum,fsqr,ftimi,fal,ial,radius;
  float skylev,*skyvec,r,skyerr,crms,maxpix,norm;

  printf("psfim[cx][cy] = %f\n",psfim[cx][cy]);

  if(skyrad1>0.0 && skyrad2>0.0 && skyrad2 > skyrad1)
    {
      hcbox = skyrad2 + 3;
      /*A sky background should be calculated*/
      skynum = 2.0*PI*pow(skyrad2,2.0);
      skyvec = vector(1,skynum);
      skynum = 0;
      for(i=cx-hcbox;i<=cx+hcbox;i++)
	{
	  for(j=cy-hcbox;j<=cy+hcbox;j++)
	    {
	      r = pow(pow(1.0*i-cx,2.0)+pow(1.0*j-cy,2.0),0.5);
	      if(i>=1&&i<=psfnx&&j>=1&&j<=psfny&&r>skyrad1&&r<skyrad2)
		{
		  skynum+=1;
		  skyvec[skynum] = psfim[i][j];
		  /*printf("skynum = %d\tskyvec = %f\n",skynum,skyvec[skynum]);*/
		}
	    }
	}
      pseudocreep01(skyvec,skynum,0.5,&skylev,&skyerr,&crms);
      printf("Calculating sky background on psf image\n");
      skynum = 2.0*PI*pow(skyrad2,2.0);
      free_vector(skyvec,1,skynum);
    }
  else{
    printf("Sky background on psf image will be set to zero\n");
    skylev = 0.0;
  }
  printf("Sky level on psf image = %f\n",skylev);

  halfbox = rad + 3;
  psfbox = matrix(1,2*halfbox+1,1,2*halfbox+1);

  for(i=1;i<=2*halfbox+1;i++)
    {
      for(j=1;j<=2*halfbox+1;j++)
	{
	  k = cx - halfbox - 1 + i;
	  l = cy - halfbox - 1 + j;
	  if(k>=1&&k<=psfny&&l>=1&&l<=psfnx)
	    {
	      printf("%f\n",psfim[k][l]);
	      psfbox[i][j] = psfim[k][l] - skylev;
	    }
	  else{
	    printf("ERROR: starnksy02 LOOKED FOR PSF OUTSIDE OF PSF IMAGE\n");
	    printf("ABORTING\n");
	    return(0);
	  }
	}
    }

  /*Normalize psf*/
  maxpix = 0.0;
  for(i=1;i<=2*halfbox+1;i++)
    {
      for(j=1;j<=2*halfbox+1;j++)
	{
	  if(psfbox[i][j]>maxpix)
	    {
	      maxpix = psfbox[i][j];
	    }
	}
    }
  for(i=1;i<=2*halfbox+1;i++)
    {
      for(j=1;j<=2*halfbox+1;j++)
	{
	  psfbox[i][j]/=maxpix;
	  printf("%f\n",psfbox[i][j]);
	}
    }


  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  alpha = beta = pixnum = fsqr = ftimi = fal = ial = 0.0;
	  for(k=i-halfbox;k<=i+halfbox;k++)
	    {
	      for(l=j-halfbox;l<=j+halfbox;l++)
		{
		  radius = pow(pow(1.0*k-1.0*i,2.0) + pow(1.0*l-1.0*j,2.0),0.5);
		  if(radius<=rad&&k>=1&&k<=nx&&l>=1&&l<=ny)
		    {
		      fsqr+=pow(psfbox[k-i+halfbox+1][l-j+halfbox+1],2.0);
		      fal+=psfbox[k-i+halfbox+1][l-j+halfbox+1];
		      ial+=image[k][l];
		      ftimi+=image[k][l]*psfbox[k-i+halfbox+1][l-j+halfbox+1];
		      pixnum+=1.0;
		    }
		}
	    }
	  alpha = (pixnum*ftimi - fal*ial)/(pixnum*fsqr - pow(fal,2.0));
	  beta = (ial - alpha*fal)/pixnum;
	  amplim[i][j] = alpha;
	  skyim[i][j] = beta;
	}
    }
  free_matrix(psfbox,1,2*halfbox+1,1,2*halfbox+1);
  return(1);
}

/*starnsky03: Exactly like starnsky02 except that the psf
is normalized in the sense that the sum within a given
large radius maxrad is set to 1.0*/
int starnsky03(float **image,float **amplim,float **skyim,int nx,int ny, float rad,float **psfim, int psfnx,int psfny,int cx,int cy,float skyrad1,float skyrad2,float maxrad)
{
  int i,j,halfbox,k,l,skynum,hcbox,skysubyes;
  float **psfbox,beta,alpha,pixnum,fsqr,ftimi,fal,ial,radius;
  float skylev,*skyvec,r,skyerr,crms,maxpix,norm,*cen,*skyrads;

  cen = vector(1,2);
  skyrads = vector(1,2);
  cen[1] = cx;
  cen[2] = cy;
  skyrads[1] = skyrad1;
  skyrads[2] = skyrad2;

  printf("psfim[cx][cy] = %f\n",psfim[cx][cy]);

  if(skyrad1>0.0 && skyrad2>0.0 && skyrad2 > skyrad1)
    {
      skysubyes = 1;
      hcbox = skyrad2 + 3;
      /*A sky background should be calculated*/
      skynum = 2.0*PI*pow(skyrad2,2.0);
      skyvec = vector(1,skynum);
      skynum = 0;
      for(i=cx-hcbox;i<=cx+hcbox;i++)
	{
	  for(j=cy-hcbox;j<=cy+hcbox;j++)
	    {
	      r = pow(pow(1.0*i-cx,2.0)+pow(1.0*j-cy,2.0),0.5);
	      if(i>=1&&i<=psfnx&&j>=1&&j<=psfny&&r>skyrad1&&r<skyrad2)
		{
		  skynum+=1;
		  skyvec[skynum] = psfim[i][j];
		  /*printf("skynum = %d\tskyvec = %f\n",skynum,skyvec[skynum]);*/
		}
	    }
	}
      pseudocreep01(skyvec,skynum,0.5,&skylev,&skyerr,&crms);
      printf("Calculating sky background on psf image\n");
      skynum = 2.0*PI*pow(skyrad2,2.0);
      free_vector(skyvec,1,skynum);
    }
  else{
    skysubyes = 0;
    printf("Sky background on psf image will be set to zero\n");
    skylev = 0.0;
  }
  printf("Sky level on psf image = %f\n",skylev);

  /*Get normalization for psf image*/
  rphot01(psfim,psfnx,psfny,cen,skyrads,skysubyes,1,maxrad,&norm);

  halfbox = rad + 3;
  psfbox = matrix(1,2*halfbox+1,1,2*halfbox+1);

  for(i=1;i<=2*halfbox+1;i++)
    {
      for(j=1;j<=2*halfbox+1;j++)
	{
	  k = cx - halfbox - 1 + i;
	  l = cy - halfbox - 1 + j;
	  if(k>=1&&k<=psfny&&l>=1&&l<=psfnx)
	    {
	      printf("%f\n",psfim[k][l]);
	      psfbox[i][j] = (psfim[k][l] - skylev)/norm;
	    }
	  else{
	    printf("ERROR: starnksy03 LOOKED FOR PSF OUTSIDE OF PSF IMAGE\n");
	    printf("ABORTING\n");
	    return(0);
	  }
	}
    }

  norm = 0.0;
  for(i=1;i<=2*halfbox+1;i++)
    {
      for(j=1;j<=2*halfbox+1;j++)
	{
	  norm+=psfbox[i][j];
	}
    }
  printf("Normalization of psf over given box is %f\n",norm);
  cen[1] = 1.0*halfbox+1.0;
  cen[2] = 1.0*halfbox+1.0;
  printf("Fitting radius = %f\n",rad);
  rphot01(psfbox,2*halfbox+1,2*halfbox+1,cen,skyrads,0,1,rad,&norm);
  printf("Normalization of psf over fitting radius is %f\n",norm);

  printf("Got nx = %d, ny = %d, psfnx = %d, psfny = %d\n",nx,ny,psfnx,psfny);
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  alpha = beta = pixnum = fsqr = ftimi = fal = ial = 0.0;
	  for(k=i-halfbox;k<=i+halfbox;k++)
	    {
	      for(l=j-halfbox;l<=j+halfbox;l++)
		{
		  radius = pow(pow(1.0*k-1.0*i,2.0) + pow(1.0*l-1.0*j,2.0),0.5);
		  if(radius<=rad&&k>=1&&k<=nx&&l>=1&&l<=ny)
		    {
		      if(i==268&&j==298)
			{
			  printf("psfim = %f\timage = %f\n",psfbox[k-i+halfbox+1][l-j+halfbox+1],image[k][l]);
			}
		      fsqr+=pow(psfbox[k-i+halfbox+1][l-j+halfbox+1],2.0);
		      fal+=psfbox[k-i+halfbox+1][l-j+halfbox+1];
		      ial+=image[k][l];
		      ftimi+=image[k][l]*psfbox[k-i+halfbox+1][l-j+halfbox+1];
		      pixnum+=1.0;
		    }
		}
	    }
	  alpha = (pixnum*ftimi - fal*ial)/(pixnum*fsqr - pow(fal,2.0));
	  beta = (ial - alpha*fal)/pixnum;
	  if(i==268&&j==298)
	    {
	      printf("fsqr = %f\tfal = %f\tial = %f\tftimi = %f\tpixnum = %f\n",fsqr,fal,ial,ftimi,pixnum);
	      printf("alpha = %f\tbeta = %f\n",alpha,beta);
	    }
	  amplim[i][j] = alpha;
	  skyim[i][j] = beta;
	}
    }
  free_matrix(psfbox,1,2*halfbox+1,1,2*halfbox+1);
  free_vector(cen,1,2);
  free_vector(skyrads,1,2);
  return(1);
}



/*boxmedi01: a program to make a median-convolved
version of an input image, that is, a version
made by replacing every pixel in the
image with the median in a 2*bhw+1 x 2*bhw+1 
inclusive box around the pixel.*/
int boxmedi01(float **image1,float **image2,int nx,int ny,int bhw)
{
  int npix,i,j,k,l,halfmark,pmin;
  float *pixvec,smin;

  npix = pow(2*bhw+1,2);
  pixvec = vector(1,npix);

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  npix = 0;
	  for(k=i-bhw;k<=i+bhw;k++)
	    {
	      for(l=j-bhw;l<=j+bhw;l++)
		{
		  if(k>=1&&k<=nx&&l>=1&&l<=ny)
		    {
		      npix+=1;
		      pixvec[npix] = image1[k][l];
		    }
		}
	    }
	  halfmark = (npix+1)/2;
	  dumbsort(pixvec,npix);
	  image2[i][j] = pixvec[halfmark];
	}
    }

  npix = pow(2*bhw+1,2);
  free_vector(pixvec,1,npix);
  return(1);
}

/*dumbsort: a stupid n^2 sort that will always work*/
int dumbsort(float *invec,int np)
{
  float min;
  int i,j,imin;
  for(i=1;i<=np-1;i++)
    {
      min = invec[i];
      imin = i;
      for(j=i+1;j<=np;j++)
	{
	  if(invec[j]<min)
	    {
	      min = invec[j];
	      imin = j;
	    }
	}
      invec[imin] = invec[i];
      invec[i] = min;
    }
  return(1);
}

/*mdumbsort: a stupid n^2 sort of a matrix of nr
rows and nc columns by column csort that will always work*/
int mdumbsort(float **inmat,int nr,int nc,int csort)
{
  float min,*mrow;
  int i,j,imin;
  mrow = vector(1,nc);
  for(i=1;i<=nr-1;i++)
    {
      min = inmat[i][csort];
      imin = i;
      for(j=i+1;j<=nr;j++)
	{
	  if(inmat[j][csort]<min)
	    {
	      min = inmat[j][csort];
	      imin = j;
	    }
	}
      for(j=1;j<=nc;j++)
	{
	  mrow[j] = inmat[i][j];
	}
      for(j=1;j<=nc;j++)
	{
	  inmat[i][j] = inmat[imin][j];
	}
      for(j=1;j<=nc;j++)
	{
	  inmat[imin][j] = mrow[j];
	}
    }
  free_vector(mrow,1,nc);
  return(1);
}

/*ifdumbsort: a stupid n^2 sort of a floating point
vector, with an integer vector of the same length
tied to it.*/
int ifdumbsort(float *fvec,int *ivec,int np)
{
  float min;
  int i,j,imin,ival;
  for(i=1;i<=np-1;i++)
    {
      ival = ivec[i];
      min = fvec[i];
      imin = i;
      for(j=i+1;j<=np;j++)
	{
	  if(fvec[j]<min)
	    {
	      min = fvec[j];
	      ival = ivec[j];
	      imin = j;
	    }
	}
      fvec[imin] = fvec[i];
      fvec[i] = min;
      ivec[imin] = ivec[i];
      ivec[i] = ival;
    }
  return(1);
}


/*vandokkumize01: a program to remove cosmic rays from
an image by Laplacian edge detection using the algorithm
described by Pieter G. van Dokkum in his paper, van Dokkum
2001, PASP, 113, 1420V.  The input parameters are a threshold
describing the rejection of cosmic rays over Poisson noise,
a threshold for rejecting comsic rays over sources, the gain,
and the read noise of the detector.  Pieter van Dokkum
suggests, for well sampled data, the threshold for rejection
over sources should be 2.0, but for undersampled data such
as that from HST WFPC2, it must be 5.0*/
int vandokkumize01(float **image,int nx,int ny,float gain,float readnoise,float nlim,float slim)
{
  float **lbox,**subsampim1,**subsampim2,**noiseim,**lapim,**medim,**fineim,**junkim;
  int i,j,k,l;
  float finscale;

  lbox = matrix(1,3,1,3);
  subsampim1 = matrix(1,nx*VDSUBSAMP,1,ny*VDSUBSAMP);
  subsampim2 = matrix(1,nx*VDSUBSAMP,1,ny*VDSUBSAMP);
  lapim = matrix(1,nx,1,ny);
  noiseim = matrix(1,nx,1,ny);
  medim = matrix(1,nx,1,ny);
  fineim = matrix(1,nx,1,ny);
  junkim = matrix(1,nx,1,ny);

  /*Get factor by which pixels are multiplied.
    This is the factor by which the flux of a
    single cosmic ray on a uniform background
    increases due to the subsampling. 
    Multiple-pixel cosmic rays increase less,
    down to about 1/4 this value, so they are
    not removed as effectively unless multiple
    iterations are run.*/
  finscale = 4.0*VDSUBSAMP;

  /*create laplacian box*/
  lbox[1][1] = 0.0;
  lbox[1][2] = -1.0;
  lbox[1][3] = 0.0;
  lbox[2][1] = -1.0;
  lbox[2][2] = 4.0;
  lbox[2][3] = -1.0;
  lbox[3][1] = 0.0;
  lbox[3][2] = -1.0;
  lbox[3][3] = 0.0;

  /*create sub sampled image*/
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  for(k=1;k<=VDSUBSAMP;k++)
	    {
	      for(l=1;l<=VDSUBSAMP;l++)
		{
		  subsampim1[(i-1)*VDSUBSAMP+k][(j-1)*VDSUBSAMP+l] = image[i][j];
		}
	    }
	}
    }

  /*convolve subsampled image with laplacian box,
    and remove all subzero pixels from result.*/
  for(i=1;i<=nx*VDSUBSAMP;i++)
    {
      for(j=1;j<=ny*VDSUBSAMP;j++)
	{
	  subsampim2[i][j] = 0.0;
	  for(k=i-1;k<=i+1;k++)
	    {
	      for(l=j-1;l<=j+1;l++)
		{
		  if(k>=1&&k<=nx*VDSUBSAMP&&l>=1&&l<=ny*VDSUBSAMP)
		    {
		      subsampim2[i][j]+=subsampim1[k][l]*lbox[k-i+2][l-j+2];
		    }
		}
	    }
	  if(subsampim2[i][j]<0.0)
	    {
	      subsampim2[i][j] = 0.0;
	    }
	}
    }

  /*sum laplacian image back down to original size*/
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  lapim[i][j] = 0.0;
	  for(k=1;k<=VDSUBSAMP;k++)
	    {
	      for(l=1;l<=VDSUBSAMP;l++)
		{
		  lapim[i][j]+=subsampim2[(i-1)*VDSUBSAMP+k][(j-1)*VDSUBSAMP+l];
		}
	    }
	  lapim[i][j]/=finscale;
	}
    }

  printf("writing lapim\n");
  writeim01(nx,ny,"testim01.txt",lapim);

  /*make 5x5 median image*/
  boxmedi01(image,medim,nx,ny,2);

  /*make noise image*/
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  if(medim[i][j]>=0.0)
	    {
	      noiseim[i][j] = pow(gain*medim[i][j] + pow(readnoise,2.0),0.5)/gain;
	    }
	  else{
	    noiseim[i][j] = 1.0;
	  }
	}
    }

  printf("writing noiseim\n");
  writeim01(nx,ny,"testim02.txt",noiseim);

  /*make fine structure image by making
    a 3x3 median image and subtracting from it
    a 7x7 version of itself*/ 
  boxmedi01(image,fineim,nx,ny,1);
  boxmedi01(fineim,junkim,nx,ny,3);
  mathimtim02(fineim,fineim,nx,ny,junkim);

  printf("writing fineim\n");
  writeim01(nx,ny,"testim03.txt",fineim);

  /*make 3x3 median image*/
  boxmedi01(image,medim,nx,ny,2);

  /*identify cosmic rays and replace them with the
  value from the median image*/
  
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  if(lapim[i][j]>nlim*noiseim[i][j]&&lapim[i][j]>slim*fineim[i][j])
	    {
	      image[i][j] = medim[i][j];
	    }
	}
    }

  /*  mathimtim04(lapim,junkim,nx,ny,noiseim);
  writeim01(nx,ny,"noisecut01.txt",junkim);
  printf("noiscut written\n");

  mathimtim04(lapim,junkim,nx,ny,fineim);
  writeim01(nx,ny,"sourcecut01.txt",junkim);
  printf("sourcecut written\n");*/

  /*make a new median image now that most cosmic rays are gone*/
  boxmedi01(image,medim,nx,ny,2);

  /*And iterate again to get rid of any remaining
  scraps of cosmic rays*/
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  if(lapim[i][j]>nlim*noiseim[i][j]&&lapim[i][j]>slim*fineim[i][j])
	    {
	      image[i][j] = medim[i][j];
	    }
	}
    }
  
  free_matrix(subsampim1,1,nx*VDSUBSAMP,1,ny*VDSUBSAMP);
  free_matrix(subsampim2,1,nx*VDSUBSAMP,1,ny*VDSUBSAMP);
  free_matrix(lapim,1,nx,1,ny);
  free_matrix(noiseim,1,nx,1,ny);
  free_matrix(medim,1,nx,1,ny);
  free_matrix(fineim,1,nx,1,ny);
  free_matrix(junkim,1,nx,1,ny);
  free_matrix(lbox,1,3,1,3);
  return(1);
}


/*bigvandokkumize01: Does the same thing as vandokkumize01,
but does it in blocks of blocksizeXblocksize, to avoid overloading
the computer's RAM*/
int bigvandokkumize01(float **image,int nx,int ny,int blocksize,float gain,float readnoise,float nlim,float slim)
{
  float **subim;
  int i,j,k,l,blocknx,blockny;
  int subnx,subny,xstart,ystart,xend,yend;


  blocknx = nx/blocksize;
  blockny = ny/blocksize;
  if(nx-blocknx*blocksize>0)
    {
      blocknx+=1;
    }
  if(ny-blockny*blocksize>0)
    {
      blockny+=1;
    }
  for(k=1;k<=blocknx;k++)
    {
      for(l=1;l<=blockny;l++)
	{
	  printf("bigvandokkumize working on block %d,%d of %d,%d\n",k,l,blocknx,blockny);
	  /*Determine location of sub image in main image
            coordinates, and determine sub image size*/
	  xstart = (k-1)*blocksize+1-BIGVDBORDER;
	  ystart = (l-1)*blocksize+1-BIGVDBORDER;
	  xend = xstart+blocksize-1+2*BIGVDBORDER;
	  yend = ystart+blocksize-1+2*BIGVDBORDER;
	  if(xend>nx) xend=nx;
	  if(yend>ny) yend=ny;
	  if(xstart<1) xstart=1;
	  if(ystart<1) ystart=1;
	  subnx = xend-xstart+1;
	  subny = yend-ystart+1;

	  /*Allocate sub image matrix*/
	  subim = matrix(1,subnx,1,subny);
	  /*Load sub image matrix*/
	  for(i=xstart;i<=xend;i++)
	    {
	      for(j=ystart;j<=yend;j++)
		{
		  subim[i-xstart+1][j-ystart+1] = image[i][j];
		}
	    }
	  /*Run ordinary vandokkumize on sub image*/
	  vandokkumize01(subim,subnx,subny,gain,readnoise,nlim,slim);

	  /*Reset x and y start and end values to neglect image border*/
	  xstart = (k-1)*blocksize+1;
	  ystart = (l-1)*blocksize+1;
	  xend = xstart+blocksize-1;
	  yend = ystart+blocksize-1;
	  if(xend>nx) xend=nx;
	  if(yend>ny) yend=ny;

	  /*Load vandokkumized subimage back into main image*/
	  for(i=xstart;i<=xend;i++)
	    {
	      for(j=ystart;j<=yend;j++)
		{
		  if(xstart!=1&&ystart!=1)
		    {
		      image[i][j] = subim[i-xstart+1+BIGVDBORDER][j-ystart+1+BIGVDBORDER];
		    }
		  else if(xstart==1&&ystart!=1)
		    {
		      image[i][j] = subim[i][j-ystart+1+BIGVDBORDER];
		    }
		  else if(xstart!=1&&ystart==1)
		    {
		      image[i][j] = subim[i-xstart+1+BIGVDBORDER][j];
		    }
		  else if(xstart==1&&ystart==1)
		    {
		      image[i][j] = subim[i][j];
		    }
		}
	    }

	  /*Free sub image matrix*/
	  free_matrix(subim,1,subnx,1,subny);
	}
    }

  return(1);
}


/*meanrms01: a simple program to find the rms
  and mean of a vector*/
int meanrms01(float *vect,int pn,float *mean,float *rms)
{
  float mean1,rms1;
  int i;
  if(pn==1)
    {
      *mean = vect[1];
      *rms = 0.0;
      printf("WARNING: meanrms01 HAS rms = ZERO\n");
      return(1);
    }
  else if(pn>1)
    {
      mean1 = rms1 = 0.0;
      for(i=1;i<=pn;i++)
	{
	  mean1+=vect[i];
	}
      mean1/=(1.0*pn);
      for(i=1;i<=pn;i++)
	{
	  rms1+=pow(mean1-vect[i],2.0);
	}
      rms1 = pow(rms1/(1.0*pn-1.0),0.5);
      *mean = mean1;
      *rms = rms1;
      return(1);
    }
  else{
    printf("ERROR: meanrms01 CALLED WITH BAD pn\n");
    return(0);
  }
}

/*weightmeanrms01: a simple program to find the weighted mean
  and error of the mean given a vector of measured values
  and a vector of errors on these values.  It will also
  calculate the reduced chi-squared value of the result.*/
int weightmeanrms01(float *vect,float *errs,int pn,float *mean,float *meanerror,float *chisq)
{
  float mean1,rms1,norm1,chi1;
  int i;
  if(pn==1)
    {
      printf("WARNING: weightmeanrms01 given only one point\n");
      *mean = vect[1];
      if(errs[1]<0.0)
	{
	  printf("WARNING: weightmeanrms01 recieves negative error value %f!\n",errs[1]);
	  *meanerror = -errs[1];
	}
      else{
	*meanerror = errs[1];
      }
      printf("Chi-squared will be set to -1.0 since meaningful calculation of it wasn't possible.\n");
      *chisq = -1.0;
      return(1);
    }
  else if(pn>1)
    {
      mean1 = norm1 = 0.0;
      for(i=1;i<=pn;i++)
	{
	  if(errs[i]<0.0)
	    {
	      printf("WARNING: weightmeanrms01 receives negative error value %f on point %d\n",errs[i],i);
	    }
	  mean1+=vect[i]/pow(errs[i],2.0);
	  norm1+=1.0/pow(errs[i],2.0);
	}
      mean1/=norm1;
      *meanerror = pow(1.0/norm1,0.5);
      *mean = mean1;
      chi1 = 0.0;
      for(i=1;i<=pn;i++)
	{
	  chi1+=pow((mean1-vect[1])/errs[i],2.0);
	}
      chi1/=(1.0*pn);
      *chisq = chi1;
      return(1);
    }
  else{
    printf("ERROR: weightmeanrms01 CALLED WITH BAD pn\n");
    return(0);
  }
}


/*getchisq01: A very simple program to find the reduced chi-squared
value of a data set, given a vector of data values, a vector
of model values, a vector of errors, and the number of data points*/
float getchisq01(float *data,float *model,float *errors,int np)
{
  float chisq;
  int i;
  if(np<=2)
    {
      printf("ERROR: getchisq01 CALLED WITH 2 OR FEWER POINTS\n");
      printf("CHI-SQUARE = 0.0 WILL BE RETURNED\n");
      return(0.0);
    }
  chisq = 0.0;
  for(i=1;i<=np;i++)
    {
      chisq+=pow((data[i]-model[i])/errors[i],2.0);
    }
  chisq/=((float)np-2.0);
  return(chisq);
}



/*pseudocreep01: Given a vector, its length, and
a rejection factor, carries out a pseudo creeping mean
averaging of the vector and outputs the result.
If fewer than 100 points are to be rejected, pseudocreep01
will call creepmean01 so that it is a real creeping mean
rejection, but if more than 100 points are to be
rejected it will perform iterative sigma-clipping in
an attempt to obtain a result as good as a creeping
mean in much less time.  The program outputs the
mean in output, the approximate error of the mean
in meanerror, and the clipped rms in crms.*/
#define MAXBINS 20 /*Maximum number of times the binary search can
		      run looking for a good rejection amount*/
int pseudocreep01(float *invec,int pnum,float rejfac,float *output,float *meanerror,float *crms)
{
  int rejnum,i,j,nrej,outnow,instill;
  float mean1,mean2,norm,rms,*invec2,*invec3;
  float dev1,data;
  int wpoint,nbadl,nbadh,nbadm,pct,nbinit;
  float sigcutl,sigcuth,sigcutm;

  invec2 = vector(1,pnum);
  invec3 = vector(1,pnum);

  for(i=1;i<=pnum;i++)
    {
      invec2[i] = invec[i];
   }

  if(rejfac>=0.8)
    {
      printf("ERROR: THE pseudocreep01 ALGORITHM IS NOT CONSIDERED\n");
      printf("RELAIBLE FOR A REJECTION FACTOR OF %f\n",rejfac);
      printf("ABORTING\n");
      return(0);
    }

  /*Determine how many entries will be rejected*/
  nrej = rejfac*pnum;

  if(nrej<=PSEUDOCREEPM)
    {
      creepvec01(invec,pnum,rejfac,output,meanerror);
      /**crms = *meanerror*pow(1.0*pnum*(1.0-rejfac),0.5);*/
      *crms = *meanerror;
      free_vector(invec2,1,pnum);
      return(1);
    }
  /*If the code gets here, we must do the full iterative rejection*/
  /*set number of points already rejected to 0*/
  outnow = 0;
  instill = pnum;
  /*printf("%d pixels total; about %d will be rejected\n",pnum,nrej);*/
  while(outnow<0.94*nrej)
    {
      /*attempt to reject approximately 0.1*nrej of the points*/
      sigcutl = 0.00001;
      sigcuth = 100.0;
      meanrms01(invec2,instill,&mean1,&rms);
      /*printf("mean = %f\trms = %f\n",mean1,rms);*/
      nbadl = nbadh = 0;
      for(i=1;i<=instill;i++)
	{
	  dev1 = pow(pow(invec2[i] - mean1,2.0),0.5);
	  if(dev1>sigcutl*rms)
	    {
	      nbadl+=1;
	    }
	  if(dev1>sigcuth*rms)
	    {
	      nbadh+=1;
	    }
	}
      /*printf("sigcutl = %f nbadl = %d sigcuth = %f nbadh = %d\n",sigcutl,nbadl,sigcuth,nbadh);*/
      if(nbadl<0.1*nrej||nbadh>0.1*nrej)
	{
	  printf("ERROR: pseudocreep01 FINDS PSYCHOTIC DISTRIBUTION\n");
	  printf("ABORTING\n");
	  return(0);
	}
      sigcutm = (sigcutl + sigcuth)/2.0;
      nbadm = 0;
      for(i=1;i<=instill;i++)
	{
	  dev1 = pow(pow(invec2[i] - mean1,2.0),0.5);
	  if(dev1>sigcutm*rms) nbadm+=1;
	}
      nbinit = 0;
      while(nbadm<=0.08*nrej||nbadm>=0.12*nrej&&nbinit<MAXBINS)
	{
	  nbinit+=1;
	  if(nbadm>0.1*nrej) 
	    {
	      nbadl = nbadm;
	      sigcutl = sigcutm;
	    }
	  else if(nbadm<0.1*nrej)
	    {
	      nbadh = nbadm;
	      sigcuth = sigcutm;
	    }
	  sigcutm = (sigcutl + sigcuth)/2.0;
	  nbadm = 0;
	  for(i=1;i<=instill;i++)
	    {
	      dev1 = pow(pow(invec2[i] - mean1,2.0),0.5);
	      if(dev1>sigcutm*rms) nbadm+=1;
	    }
	  /*printf("sigcutm = %f nbadm = %d\n",sigcutm,nbadm);*/
	}
      if(nbinit==MAXBINS)
	{
	  /*Probably the binary search did not converge, but
            that's not neccessarily cause for alarm.  Print
            a warning together with the data that's available*/
	  printf("WARNING: pseudocreep binary search did not converge\n");
	  printf("%f %% of the points will be rejected\n",(100.0*nbadm)/(1.0*pnum));
	}
	    
      /*A value for sigcutm that rejects between
        0.08*nrej and 0.12*nrej of the remainin points
        has been found.  Reject these points.*/
      /*printf("sigcutm = %f rejection = %f nrej\n",sigcutm,(1.0*nbadm)/(1.0*nrej));*/
      pct = 0;
      for(i=1;i<=instill;i++)
	{
	  dev1 = pow(pow(invec2[i] - mean1,2.0),0.5);
	  if(dev1<=sigcutm*rms)
	    {
	      pct+=1;
	      invec3[pct] = invec2[i];
	    }
	}
      instill = pct;
      outnow = pnum - instill;
      for(i=1;i<=instill;i++)
	{
	  invec2[i] = invec3[i];
	}
    }

  /*printf("%d points have been rejected, %f percent of the desired number\n",outnow,(100.0*outnow)/(1.0*nrej));*/
  /*printf("The final number of points rejected is the fraction %f of the total\n",(1.0*outnow)/(1.0*pnum));*/
  meanrms01(invec2,instill,&mean1,&rms);
  /*printf("mean1 = %f, rms = %f\n",mean1,rms);*/

  *crms = rms;
  *output = mean1;
  *meanerror = rms/pow(1.0*instill,0.5);

  free_vector(invec2,1,pnum);
  free_vector(invec3,1,pnum);
  return(1);
}


/*starid01: identifies stars on an image produced by starnsky01, by
finding the rms with a sigclip cut using pseudocreep01, then identifying
all local maxima above sigclip*rms.  Produces a star image that has
a value of 1.0 everywhere a star was detected and zero elsewhere.
Returns the count of stars.  The matrix starmat has three columns
and at least starct rows.  In the first two columns are the x,y
position of each star, and in the last column is its amplitude
based on the amplitude image produced by starnsky.  starid01
only finds stars that are at least offstand pixels from
any edge of the image, to insure that good fitting is possible
later.  Also outputs the final rms used in star detection.*/
int starid01(float **image,int nx,int ny,float rejfac,float siglim,float **starim,int *starct,float **starmat,int offstand,float *finrms)
{
  int i,j,k,l,lmax,sct;
  float *bigvec,mean,meanerror,rms,minf;
  bigvec = vector(1,nx*ny);

  imzero(starim,nx,ny);

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  bigvec[(i-1)*ny + j] = image[i][j];
	}
    }
  pseudocreep01(bigvec,nx*ny,rejfac,&mean,&meanerror,&rms);
  *finrms = rms;

  printf("pseudocreep found the rms of the amplitude image to be %f\n",rms);
  printf("siglim = %f, so siglim*rms = %f\n",siglim,siglim*rms);

  sct = 0;
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  lmax = 1;
	  for(k=i-1;k<=i+1;k++)
	    {
	      for(l=j-1;l<=j+1;l++)
		{
		  if(k>=1&&k<=nx&&l>=1&&l<=ny)
		    {
		      if(k==i&&l==j);
		      else if(image[k][l]>=image[i][j]) lmax = 0;
		    }
		}
	    }
	  if(lmax==1&&image[i][j]>siglim*rms&&i>offstand&&i<=nx-offstand&&j>offstand&&j<=ny-offstand)
	    {
	      starim[i][j] = 1.0;
	      sct+=1;
	      starmat[sct][1] = 1.0*i;
	      starmat[sct][2] = 1.0*j;
	      starmat[sct][3] = image[i][j];
	    }
	}
    }
  *starct = sct;

  free_vector(bigvec,1,nx*ny);
  return(1);
}

/*digicoords01: converts hh:mm:ss.ss, dd:mm:ss.ss ra and dec
into radians, or vice-versa, depending upon the sign
of convpar. digicoords01 requires the - sign on hours,
minutes, and seconds when dealing with southern declinations.*/
int digicoords01(float *hmscoords,double *radcoords,int convpar)
{
  if(convpar>=0)
    {
      /*convert hour, minute, second coords to radians*/
      radcoords[1] = hmscoords[1]*PI/12.0+hmscoords[2]*PI/720.0+hmscoords[3]*PI/43200.0;
      radcoords[2] = hmscoords[4]*PI/180.0+hmscoords[5]*PI/10800.0+hmscoords[6]*PI/648000.0;
    }
  else{
    hmscoords[1] = floor(radcoords[1]*12.0/PI);
    hmscoords[2] = floor(radcoords[1]*720.0/PI - 60.0*hmscoords[1]);
    hmscoords[3] = radcoords[1]*43200.0/PI - 3600.0*hmscoords[1] - 60.0*hmscoords[2];
    if(radcoords[2]>=0.0)
      {
	hmscoords[4] = floor(radcoords[2]*180.0/PI);
	hmscoords[5] = floor(radcoords[2]*10800.0/PI - 60.0*hmscoords[4]);
	hmscoords[6] = radcoords[2]*648000.0/PI - 3600.0*hmscoords[4] - 60.0*hmscoords[5];
      }
    else{
	hmscoords[4] = ceil(radcoords[2]*180.0/PI);
	hmscoords[5] = ceil(radcoords[2]*10800.0/PI - 60.0*hmscoords[4]);
	hmscoords[6] = radcoords[2]*648000.0/PI - 3600.0*hmscoords[4] - 60.0*hmscoords[5];
    }
  }
  return(1);
}


/*digicoords02: converts hh:mm:ss.ss, dd:mm:ss.ss ra and dec
into radians, or vice-versa, depending upon the sign
of convpar.  Uses the usual convention that a minus sign on
the dec degrees alone makes the whole declination southerly.*/
int digicoords02(float *hmscoords,double *radcoords,int convpar)
{
  if(convpar>=0)
    {
      /*convert hour, minute, second coords to radians*/
      radcoords[1] = hmscoords[1]*PI/12.0+hmscoords[2]*PI/720.0+hmscoords[3]*PI/43200.0;
      if(hmscoords[4]>0.0||(hmscoords[4]==0.0&&hmscoords[5]>0.0)||(hmscoords[4]==0.0&&hmscoords[5]==0.0&&hmscoords[6]>=0.0))
	{
	  radcoords[2] = hmscoords[4]*PI/180.0+hmscoords[5]*PI/10800.0+hmscoords[6]*PI/648000.0;
	}
      else{
	  radcoords[2] = hmscoords[4]*PI/180.0-hmscoords[5]*PI/10800.0-hmscoords[6]*PI/648000.0;
      }
    }
  else{
    hmscoords[1] = floor(radcoords[1]*12.0/PI);
    hmscoords[2] = floor(radcoords[1]*720.0/PI - 60.0*hmscoords[1]);
    hmscoords[3] = radcoords[1]*43200.0/PI - 3600.0*hmscoords[1] - 60.0*hmscoords[2];
    if(radcoords[2]>=0.0)
      {
	hmscoords[4] = floor(radcoords[2]*180.0/PI);
	hmscoords[5] = floor(radcoords[2]*10800.0/PI - 60.0*hmscoords[4]);
	hmscoords[6] = radcoords[2]*648000.0/PI - 3600.0*hmscoords[4] - 60.0*hmscoords[5];
      }
    else{
      radcoords[2] = -radcoords[2];
      hmscoords[4] = floor(radcoords[2]*180.0/PI);
      hmscoords[5] = floor(radcoords[2]*10800.0/PI - 60.0*hmscoords[4]);
      hmscoords[6] = radcoords[2]*648000.0/PI - 3600.0*hmscoords[4] - 60.0*hmscoords[5];
      hmscoords[4] = -hmscoords[4];
    }
  }
  return(1);
}

/*JDcalc01: given a year, month, day, and hour, minute, and second
UT, calculates the Julian Day.  Only works for dates after Jan 1, 2000
and before Dec 31, 2099*/
int JDcalc01(int *date,int *ut,double *jdout)
{
  int daystojan,yearsbefore;
  int leaps,totaldays;
  float data1,data2;
  /*Calculate number of days up to 00:00 UT, Jan 1,
    of the given year*/
  printf("JDcalc01 received date %d-%d-%d, ut %d:%d:%d\n",date[1],date[2],date[3],ut[1],ut[2],ut[3]);
  daystojan = 0;
  yearsbefore = date[1] - 2000;
  if(yearsbefore<0||date[1]>2099||date[2]<1||date[2]>12||date[3]<1||date[3]>31)
    {
      printf("ERROR: BAD DATE\n");
      printf("ABORTING\n");
      return(0);
    }
  else if(yearsbefore>0)
    {
      /*leaps will always be at least one if yearsbefore>0,
       becuase 2000 itself was a leapyear.  yearsbefore has
       to be 5 before leaps grows to 2, because only then
       will the year be 2005, the first year after the end
       of the leapyear 2004.*/
      leaps = 1 + (yearsbefore-1)/4;
      daystojan = 365*yearsbefore+leaps;
    }
  printf("Years before = %d, leaps = %d, daystojan = %d\n",yearsbefore,leaps,daystojan);
  /*Find out if the current year is a leapyear*/
  data1 = 1.0*yearsbefore/4.0;
  data2 = floor(data1);
  data1-=data2;
  totaldays = daystojan;
  if(data1==0.0)
    {
      /*Then the current year is evenly divisible by 4.0 and is a leap year*/
      printf("This is the %dth month\n",date[2]);
      if(date[2]==1)
	{
	  totaldays+=date[3];
	}
      else if(date[2]==2)
	{
	  totaldays+=date[3]+31;
	}
      else if(date[2]==3)
	{
	  totaldays+=date[3]+60;
	}
      else if(date[2]==4)
	{
	  totaldays+=date[3]+91;
	}
      else if(date[2]==5)
	{
	  totaldays+=date[3]+121;
	}
      else if(date[2]==6)
	{
	  totaldays+=date[3]+152;
	}
      else if(date[2]==7)
	{
	  totaldays+=date[3]+182;
	}
      else if(date[2]==8)
	{
	  totaldays+=date[3]+213;
	}
      else if(date[2]==9)
	{
	  totaldays+=date[3]+244;
	}
      else if(date[2]==10)
	{
	  totaldays+=date[3]+274;
	}
      else if(date[2]==11)
	{
	  totaldays+=date[3]+305;
	}
      else if(date[2]==12)
	{
	  totaldays+=date[3]+335;
	}
    }
  else {
      /*Then the current year is not evenly divisible by 4.0 and is not a leap year*/
      printf("This is the %dth month\n",date[2]);
      if(date[2]==1)
	{
	  totaldays+=date[3];
	}
      else if(date[2]==2)
	{
	  totaldays+=date[3]+31;
	}
      else if(date[2]==3)
	{
	  totaldays+=date[3]+59;
	}
      else if(date[2]==4)
	{
	  totaldays+=date[3]+90;
	}
      else if(date[2]==5)
	{
	  totaldays+=date[3]+120;
	}
      else if(date[2]==6)
	{
	  totaldays+=date[3]+151;
	}
      else if(date[2]==7)
	{
	  totaldays+=date[3]+181;
	}
      else if(date[2]==8)
	{
	  totaldays+=date[3]+212;
	}
      else if(date[2]==9)
	{
	  totaldays+=date[3]+243;
	}
      else if(date[2]==10)
	{
	  totaldays+=date[3]+273;
	}
      else if(date[2]==11)
	{
	  totaldays+=date[3]+304;
	}
      else if(date[2]==12)
	{
	  totaldays+=date[3]+334;
	}
  }
  /*correct for the fact that the day on which the observations
    were made has not yet ended at the time of the observations*/
  totaldays-=1;
  printf("totaldays - daystojan = %d\n",totaldays-daystojan);
  *jdout = 1.0*totaldays + 1.0*ut[1]/24.0 + 1.0*ut[2]/1440.0 + 1.0*ut[3]/86400.0;
  printf("Days after 00:00 UT Jan 1, 2000: %f\n",*jdout);
  *jdout+=2451544.5;
  printf("Julian day: %f\n",*jdout);
  return(1);
}

/*sunxyz01: calculate the X, Y, Z coordinates of the Earth
relative to the Sun, in units of AU, from the number
of days since 00:00 UT Jan 1 2000, using the formulae
in the Astronomical Almanac.  These are allegedly accurate
to about 0.01 degrees in position and therefore I infer about
0.0002 AU.  They will give parallactic correction to the
accuracy of any concievable parallax, and HJD correction
to about 0.09 sec.*/
int sunxyz01(float ndays,float *posvec)
{
  double L,g,lambda,epsilon,R;


  g = 357.528 + 0.9856003*(ndays-0.5);
  L = 280.460 + 0.9856474*(ndays-0.5);

  while(g >= 360.0)
    {
      g-=360.0;
    }
  while(L >= 360.0)
    {
      L-=360.0;
    }
  printf("L, g, %f %f\n",L,g);


  lambda = L + 1.915*sin(g*PI/180.0) + 0.020*sin(g*PI/90.0);
  epsilon = 23.439 - 0.0000004*(ndays-0.5);

  R = 1.00014 - 0.01671*cos(g*PI/180.0) - 0.00014*cos(g*PI/90.0);

  printf("R = %f\n",R);

  posvec[1] = -R*cos(lambda*PI/180.0);
  posvec[2] = -R*cos(epsilon*PI/180.0)*sin(lambda*PI/180.0);
  posvec[3] = -R*sin(epsilon*PI/180.0)*sin(lambda*PI/180.0);

  return(1);
}


/*heliojul01: given the julian day as a double-precision number
and the right ascension and declination in radians 
as components 1 and 2 of a double precision vector,
calculates the heliocentric correction that must be added to
the julian day.  Outputs both the heliocentric julian day as
a double, and the correction as a float.  The calculation
is done using a formula from the Astronomical Almanac.*/
int heliojul01(double julday,double *radcoords,double *hjulday,float *heliocor)
{
  double ndays,hcor,hjd;
  float nd,*posvec;

  posvec = vector(1,3);

  ndays = julday - 2451544.5;
  nd = ndays;
  sunxyz01(nd,posvec);

  /*posvec is in units of AU and the Julian days are, of course,
    days.  The speed of light in AU/day is 173.14.*/

  hcor = (posvec[1]*cos(radcoords[1])*cos(radcoords[2]) + posvec[2]*sin(radcoords[1])*cos(radcoords[2]) + posvec[3]*sin(radcoords[2]))/173.14;

  hjd = julday + (posvec[1]*cos(radcoords[1])*cos(radcoords[2]) + posvec[2]*sin(radcoords[1])*cos(radcoords[2]) + posvec[3]*sin(radcoords[2]))/173.14;

  printf("The correction from JD to HJD was %f seconds\n",hcor*86400.0);

  *hjulday = hjd;
  *heliocor = hcor;

  free_vector(posvec,1,3);
  return(1);
}

/*starposcor01: given the julian day as a double-precision number
and the 2000.0 RA and DEC in radians as components 1 and 2 of a 
double precision vector, the proper motion in declination and
right ascension in units of mas/year with their errors, and the
parallax in units of mas with its error, and the circular error
on the initail 2000.0 position in mas, calculates the current apparent
position of the star in 2000.0 coordinates: that is, having
accounted for proper motion and parallax but not the precision
of the coordinate system.*/
int starposcor01(double julday,double *radcoords,float *propermotion,float *parallax,float *circerr,double *nradcoords, float *ncircerr)
{

  double ndays;
  float nd,*posvec;
  float racorpm,deccorpm,racorpr,deccorpr;
  float pmerr,parerr,ratot,dectot,toterr;

  posvec = vector(1,3);

  ndays = julday - 2451544.5;
  nd = ndays;
  sunxyz01(nd,posvec);

  /*proper motion first*/
  /*proper motion correction to RA*/
  racorpm = propermotion[1]*ndays/(365.2425);
  /*propermotion correction to DEC*/
  deccorpm = propermotion[3]*ndays/(365.2425);
  /*and approximate circular error*/
  pmerr = pow(pow(propermotion[2]*ndays/(365.2425),2.0)+pow(propermotion[4]*ndays/(365.2425),2.0),0.5);

  /*Then parallax*/
  /*RA correction*/
  racorpr = parallax[1]*(posvec[1]*sin(radcoords[1]) - posvec[2]*cos(radcoords[1]));
  /*DEC correction*/
  deccorpr = parallax[1]*(posvec[1]*cos(radcoords[1])*sin(radcoords[2]) + posvec[2]*sin(radcoords[1])*sin(radcoords[2]) - posvec[3]*cos(radcoords[2]));
  /*and approximate circular error*/
  parerr = pow(pow(parallax[2]*(posvec[1]*sin(radcoords[1]) - posvec[2]*cos(radcoords[1])),2.0) + pow(parallax[2]*(posvec[1]*cos(radcoords[1])*sin(radcoords[2]) + posvec[2]*sin(radcoords[1])*sin(radcoords[2]) - posvec[3]*cos(radcoords[2])),2.0),0.5);
  ratot = racorpm + racorpr;
  dectot = deccorpm + deccorpr;
  toterr = pow(pow(pmerr,2.0)+pow(parerr,2.0),0.5);

  printf("The corrections are: proper motion, %f, %f with error %f\n",racorpm,deccorpm,pmerr);
  printf("And parallax, %f, %f with error %f, all in units of mas\n",racorpr,deccorpr,parerr);
  printf("Total thus %f, %f with error %f\n",ratot,dectot,toterr);

  /*206264806.2470 is the number of milli-arcseconds in a radian*/

  nradcoords[1] = radcoords[1] + ratot/(206264806.2470*cos(radcoords[2]));
  nradcoords[2] = radcoords[2] + dectot/206264806.2470;

  *ncircerr = pow(pow(toterr,2.0)+pow((*circerr),2.0),0.5);
  return(1);
}


/*poleswitch01: given a double precision input vector
containing the position in radians of a source on a 
spherical coordinate system, another vector containing
the position of the pole of a new coordinate system
on the old coordinate system, calculates the position
of the point in the new coordinate system, and outputs
this in a third double precision vector.  The desired
RA for the old pole in the new coordinates is also required.
NOTE: the coords must be located in positions 1 and 2
of the double precision vectors, following the NRC
convention, NOT positions 0 and 1.*/
int poleswitch01(double *initpos,double *polepos, double *newpos,double oldpolera)
{
  double x,y,z,xp,yp,zp,thetapole,phipole,theta,phi,thetap,phip;
  int badphip;

  phi = initpos[1];
  theta = initpos[2];
  phipole = polepos[1];
  thetapole = polepos[2];


  z = sin(theta);
  x = cos(theta)*cos(phi-phipole);
  y = cos(theta)*sin(phi-phipole);


  zp = z*sin(thetapole) + x*cos(thetapole);
  xp = x*sin(thetapole) - z*cos(thetapole);
  yp = y;


  thetap = asin(zp);


  if(y==0.0)
    {
      if(x>0.0)
	{
	  phip = 0.0;
	}
      else if(x<0.0)
	{
	  phip = PI;
	}
    }
  else if(y>0.0)
    {
      phip = PI/2.0 - atan(xp/yp);
    }
  else if(y<0.0)
    {
      phip = 3.0*PI/2.0 - atan(xp/yp);
    }

  fflush(stdout);

  phip+=(oldpolera-PI);

  badphip = 0;
  if(phip<0.0||phip>=2.0*PI)
    {
      badphip = 1;
    }
  while(badphip==1)
    {
      if(phip<0.0) phip+=2.0*PI;
      else if(phip>=2.0*PI) phip-=2.0*PI;
      badphip = 0;
      if(phip<0.0||phip>=2.0*PI)
	{
	  badphip = 1;
	}
    }
  newpos[1] = phip;
  newpos[2] = thetap;
  return(1);
}

/*satutest01: given an image and its dimensions, a pixel position,
a saturation threshold satthresh, and a number satmax of pixels less than or equal
to 9, finds out if at least satmax pixels are above satthresh.  If
they are, returns 2, indicating the star is saturated.  If not, returns
1, indicating the star is OK.*/
int satutest01(float **image,int nx,int ny,int cx,int cy,float satthresh,int satmax)
{
  int satnum,i,j;

  if(satmax<1||satmax>9)
    {
      printf("satutest01 ERROR: DISALLOWED PIXEL NUMBER\n");
      return(0);
    }

  satnum = 0;
  for(i=cx-1;i<=cx+1;i++)
    {
      for(j=cy-1;j<=cy+1;j++)
	{
	  if(i>=1&&i<=nx&&j>=1&&j<=ny)
	    {
	      if(image[i][j]>satthresh)
		{
		  satnum+=1;
		}
	    }
	}
    }
  if(satnum>=satmax)
    {
      return(2);
    }
  else{
    return(1);
  }
}

/*celeposget01: given delta_x, delta_y offsets of a source from a reference star,
the radian coordinates of the reference star in double precision with
error, and an astrometric transformation with error, calculates the
position of the source with full spherical geometry, and outputs this
along with the error in provided vectors.  The coordinates are
in radians but the errors are in milli-arcseconds.  All position
errors are circular; no attempt is made to distinguish differing
uncertainties in different directions.  The astrometric transformation
consists of the scale in arcseconds per pixel, then the error of
this scale, and then the quantity parot followed by its error.
parot is in units of degrees and is defined as follows:

       The definition of the rotation part of the astrometric
        calibration in my convention states: 
           Parot is the angle that must be added to the image
           position angle obtained by distpix01 to get the celestial
           position angle. 
        
        The definition of the bezalel01 subroutine distpix01 states:
            Takes in two x,y positions on an images, with
            circular errors, and calculates the separation between them in pixels
            and the celestial position angle in degrees assuming north
            is exactly up and the image is not mirror-reversed.

        So the position angle of true north on an image is 360 - parot
        for that image.  For example, if parot is 10 degrees, and
        distpix01 calculates a position angle of 350 degrees for a given
        star, the true celestial position angle is 350 + 10 = 360 degrees,
        or celestial north.
*/
int celeposget01(float deltax,float deltay,float xyerr,double *radref,float referr,float *astrocal,double *radsource,float *sourcerr)
{
  /*We construct a coordinate system with the reference star at
    the pole and 0h RA at position angle 360 - parot degreess*/
    
  double imcoords[3],rad;
  double polepos[3],oldpolera;
  float dxp,dyp,circerr;


  /*206264.806 is the number of arcseconds in a radian*/
  /*Calculate the declination for the source in the new coordinate system*/
  rad = pow(pow(deltax,2.0)+pow(deltay,2.0),0.5);
  imcoords[2] = 0.5*PI - rad*astrocal[1]/206264.806;

  /*Calculate the right ascension of the source in the new coordinate system*/
  dxp = deltax*cos(astrocal[3]*PI/180.0) - deltay*sin(astrocal[3]*PI/180.0);
  dyp = deltay*cos(astrocal[3]*PI/180.0) + deltax*sin(astrocal[3]*PI/180.0);

  if(rad>0.0)
    {
      if(dxp>=0.0)
	{
	  imcoords[1] = 0.5*PI - asin(dyp/rad);
	}
      else{
	imcoords[1] = 1.5*PI + asin(dyp/rad);
      }
    }
  else{
    imcoords[1]==0.0;
  }


  /*Calculate the error on the source position in milli-arcseconds*/
  /*The components are, the error on the reference position, the error
    on delta_x and delta_y, and the error on the astrometric transformation,
    which has two parts, the error on the scale and the error on the rotation.*/

  circerr = pow(pow(xyerr*1000.0*astrocal[1],2.0) + pow(referr,2.0) + pow(rad*astrocal[2]*1000.0,2.0) + pow(rad*astrocal[1]*astrocal[4]*PI/180.0,2.0),0.5);

  /*Transform the coordinate system with the reference star at the pole
    to a coordinate system with the true pole at the pole.
    The RA of the true pole in the system with the reference star at
    the pole has been carefully set to 0h 0m 0.00000s.  The DEC of the 
    true pole in the system with the reference star at the pole is the
    same as the DEC of the reference star in the system with the
    true pole at the pole.  In the system with the true pole at
    the pole, the RA of the old pole, that is the reference star,
    will of course simply be the true RA of the reference star.*/

  polepos[1] = 0.0;
  polepos[2] = radref[2];
  *sourcerr = circerr;
  poleswitch01(imcoords,polepos,radsource,radref[1]);
  return(1);

}


/*astrocalget01: Given the celestial positions of two
reference stars in radians, the circular errors on these
positions in milli-arcseconds, the difference vector
in their positions (x2-x1,y2-y1) on an image, and the
circular error in the difference vector, calculate
the scale in arcseconds per pixel, the error on the scale,
the value parot = 360 deg - the image position angle
of celetial North in degrees, and the error on parot*/
int astrocalget01(double *refrad1,double *refrad2,float referr1,float referr2,float dx,float dy,float xye,float *astrocal)
{
  double celestialp[3],ncelestialp[3],nrefrad2[3],cdist;
  float *hms1,rad,sigrad,referr,paroterr1,paroterr2,parot;

  /*206264.806 is the number of arcseconds in a radian*/

  printf("In astrocalget01 OK\n");
  fflush(stdout);

  hms1 = vector(1,6);

  /*Create new coordinate system with reference star 1 at the
    pole, and the pole at RA = 0.  Transform the positions
    of the celestial pole and of reference star 2 into
    this coordinate system.*/

  celestialp[1] = 0.0;
  celestialp[2] = 0.5*PI;
  digicoords01(hms1,refrad1,-1);
  printf("astrocalget receives ref 1 at %.0f:%.0f:%.4f %.0f:%.0f:%.3f\n",hms1[1],hms1[2],hms1[3],hms1[4],hms1[5],hms1[6]);
  fflush(stdout);
  poleswitch01(celestialp,refrad1,ncelestialp,0.0);
  digicoords01(hms1,ncelestialp,-1);
  printf("position of NCP in new coordinates is %.0f:%.0f:%.4f %.0f:%.0f:%.3f\n",hms1[1],hms1[2],hms1[3],hms1[4],hms1[5],hms1[6]);
  poleswitch01(refrad2,refrad1,nrefrad2,0.0);
  printf("position angle of ref star 2 measured CW from NCP is %f\n",180.0*nrefrad2[1]/PI);
  digicoords01(hms1,nrefrad2,-1);
  printf("position of refstar 2 in new coordinates is %.0f:%.0f:%.4f %.0f:%.0f:%.3f\n",hms1[1],hms1[2],hms1[3],hms1[4],hms1[5],hms1[6]);

  /*Get scale in arcsec/pixel*/
  /*get celestial distance between stars in arcseconds*/
  cdist = 0.5*PI - nrefrad2[2];
  cdist*=206264.806;
  /*get image distance between stars in pixels*/
  rad = pow(pow(dx,2.0)+pow(dy,2.0),0.5);
  if(rad<=0.0)
    {
      printf("ERROR: astrocalget01 FINDS DISTANCE BETWEEN THE TWO STARS TO BE ZERO!\n");
      printf("ABORTING\n");
      return(0);
    }
  /*get scale*/
  astrocal[1] = cdist/rad;
  /*get difference vector error in mas*/
  sigrad = xye*astrocal[1]*1000.0;
  /*get error on distance between reference stars in mas*/
  referr = pow(pow(referr1,2.0)+pow(referr2,2.0),0.5);
  /*get total error on scale*/
  astrocal[2] = astrocal[1]*pow(pow(sigrad,2.0)+pow(referr,2.0),0.5)/(1000.0*cdist);

  /*Get parot in degrees*/
  /*Find the angle of the line from ref 1 to ref 2 on the image,
    measuring from straight up clockwise around, as RA is measured
    from the north celestial pole*/
  if(dx>=0.0)
    {
      parot = 0.5*PI - asin(dy/rad);
    }
  else{
    parot = 1.5*PI + asin(dy/rad);
  }
  printf("Position angle of ref2 from ref1 on image is %f\n",180.0*parot/PI);
  /*Find the error on this angle*/
  paroterr1 = xye/rad;
  /*The angle between the line from ref 1 to ref 2 and the
    line from ref 1 toward true celestial north is simply nrefrad2[1]*/
  /*The error on this angle will be:*/
  paroterr2 = referr/(1000.0*cdist);
  /*so the total error on parot will be:*/
  astrocal[4] = 180.0*pow(pow(paroterr1,2.0)+pow(paroterr2,2.0),0.5)/PI;
  /*parot is the position angle of celestial North measured clockwise
    from straight up on the image, or 360.0 deg minus the position
    angle of celetial North measured counter-clockwise from straight
    up, which is the usual way of measuring position angles.

    However, both quantities we have now are measured clockwise from
    straight up on the image.  The variable parot currently holds the
    postion angle of the ref1 - ref2 line measured in this way, while
    nrefrad2[1] holds the position angle of ref2 measured clockwise from
    the position angle of celestial North.  This is the same as saying,
    however, that nrefrad2[1] holds the position angle of celestial North
    measured COUNTER-clockwise from ref2.  Thus parot should be
    the current variable parot MINUS nrefrad2[1].  Since the value
    of the variable parot at present is guaranteed to be between 0.0 and 2PI,
    and the value of nrefrad2[1] is guaranteed likewise, to insure
    the resulting final parot value is in this range it will only be
    necessary to see if parot is negative, and if it is to add 2PI*/

  parot = parot - nrefrad2[1];
  if(parot<0.0)
    {
      astrocal[3] = 360.0 + 180.0*parot/PI;
    }
  else{
    astrocal[3] = 180.0*parot/PI;
  }

  free_vector(hms1,1,6);
  return(1);
}

/*imposget01: Given the coordinates in radians of a star, the
  coordinates of a reference star, the position of the reference
  star on an image, and an astrometric calibration, finds and
  outputs the position of the star on this image.  findonim01
  is to be used to search a catalog of image data made
  by one of the starcat programs for a specific star.  findonim01
  will make it possible after reading in initial information
  on an image to predict the location of a star of interest on
  that image, after which it will be possible to test to see
  if the location lies within the actual image, and finally
  see if a source matching the location has been measured.*/
int imposget01(double *starcoords,double *refcoords,float refxim,float refyim,float *astrocal,float *starxim,float *staryim)
{

  double nstarcoords[3],cdist;
  float *hms1,theta,dy,dx;

  /*Transform the star position to a coordinate system
    where the reference is at the pole and true north
    is at 0h RA*/
  poleswitch01(starcoords,refcoords,nstarcoords,0.0);

  /*Now nstarcoords[1] is the position angle of the star
    measured clockwise around the reference from North.
    astrocal[3] holds the position angle of North measured
    clockwise from straight up on the image.  We want
    to know the position the star will have on the image.
    We will calculate the position angle the star will have
    on the image, measured clockwise around from straight up*/

  theta = astrocal[3]*PI/180.0+nstarcoords[1];
  printf("Position angle of star measured CW from North: %f\n",nstarcoords[1]*180.0/PI);
  printf("Position angle of North measred CW from up: %f\n",astrocal[3]);
  printf("Therefore theta = %f\n",theta*180.0/PI);
  if(theta>=2.0*PI)
    {
      theta-=2.0*PI;
    }
  printf("Corrected, theta = %f\n",theta*180.0/PI);
  cdist = (0.5*PI-nstarcoords[2])*206264.806/astrocal[1]; /*dist from star to ref in pixels*/
  printf("Pixels from ref to star:%f\n",cdist);
  dx = cdist*sin(theta);
  dy = cdist*cos(theta);
  printf("pixel vector from ref to star: %f,%f\n",dx,dy);
  dx+=refxim;
  dy+=refyim;
  printf("Image position of star thus: %f,%f\n",dx,dy);
  *starxim = dx;
  *staryim = dy;
  return(1);
}

/*rdistget01: given the position of two celestial sources in double precision
  radian coordinates, get the distance between them in arcseconds*/
float rdistget01(double *star1,double *star2)
{
  float dist;
  double nstar2[3];
  poleswitch01(star2,star1,nstar2,0.0);
  dist = 0.5*PI - nstar2[2];
  dist*=206264.806;
  return(dist);
}

/*rpadistget01: given the position of two celestial sources in double precision
  radian coordinates, and the errors on these positions in milli-arcseconds,
  find the distance between them in arcseconds, the error on this distance
  in arcseconds, the pa of the second star from the first in degrees, and
  the error on this pa*/
int rpadistget01(double *star1,double *star2,float err1,float err2,float *dist,float *disterr,float *pa,float *paerr)
{
  float dis,dise,p,pae;
  double nstar2[3];
  poleswitch01(star2,star1,nstar2,0.0);
  dis = 0.5*PI - nstar2[2];
  dis*=206264.806;
  dise = pow(pow(err1,2.0)+pow(err2,2.0),0.5)/1000.0;
  p = 2.0*PI - nstar2[1];
  pae = dise/dis;
  p*=(180.0/PI);
  pae*=(180.0/PI);
  *dist = dis;
  *disterr = dise;
  *pa = p;
  *paerr = pae;
  return(1);
}

/*creepimstat01: given an image and xl,xh,yl,yh for a box
on the image, and a rejection factor, performs pseudo-creeping mean
rejection and outputs the resulting mean and rms.
The calling function is responsible to insure that the
box lies entirely within the image; otherwise creepimstat01
will simply segfault.*/
int creepimstat01(float **image,int xl,int xh,int yl,int yh,float rejfac,float *mean,float *rms)
{
  float *squarvec,data;
  int pnum,i,j,k;

  pnum = (xh-xl+1)*(yh-yl+1);
  squarvec = vector(1,pnum);
  k = 0;
  for(i=xl;i<=xh;i++)
    {
      for(j=yl;j<=yh;j++)
	{
	  k+=1;
	  squarvec[k] = image[i][j];
	}
    }
  pseudocreep01(squarvec,pnum,rejfac,mean,&data,rms);
  free_vector(squarvec,1,pnum);
  return(1);
}


/*creeperr01: Given a vector of measurements,
a vector of errors on those measurements, the number
of entries in the vector, and
a rejection factor, carries out creeping mean
averaging of the vector and outputs the result.
Does not consider the errors except in a final
calculation of the error of the final mean.
Also calculates the reduced chi-squared value
of the final mean.  Note that since the mean
is not weighted the reduced chi-square should
not usually be expected to be 1.0*/
int creeperr01(float *invec,float *inerr,int pnum,float rejfac,float *mean,float *meanerror,float *chisq)
{
  int rejnum,i,j,nrej;
  float mean1,mean2,norm,rms,*invec2,*inerr2;
  float sval,maxerr,meanerr1,chi1,serr;
  int wpoint;

  invec2 = vector(1,pnum);
  inerr2 = vector(1,pnum);

  for(i=1;i<=pnum;i++)
    {
      invec2[i] = invec[i];
      inerr2[i] = inerr[i];
   }

  /*Determine how many entries will be rejected*/
  rejnum = rejfac*pnum;

  if(rejnum>=pnum)
    {
      printf("Warning: you have asked creeperr01 to\n");
      printf("reject all of your points!\nAll but one will be rejected.\n");
      rejnum = pnum-1;
    }

  /*If the answer is zero let it work as an ordinary average*/
  if(rejnum<=0)
    {
      printf("Warning: creeperr01 is not rejecting any points\n");
      meanrms01(invec2,pnum,&mean1,&rms);
      *mean = mean1;
      rms = chi1 = 0.0;
      for(i=1;i<=pnum;i++)
	{
	  rms+=pow(inerr2[i]/(1.0*pnum),2.0);
	  chi1+=pow((mean1-invec2[i])/inerr2[i],2.0);
	}
      rms = pow(rms,0.5);
      chi1/=(1.0*pnum);
      *meanerror = rms;
      *chisq = chi1;
      if(pnum==1)
	{
	  printf("Warning: creeperr01 called with only one point!\n");
	}
    }
  else{
    /*Now for the full code*/
    for(nrej=0;nrej<=rejnum;nrej++)
      {
	/*calculate mean*/
	meanrms01(invec2,pnum-nrej,&mean1,&rms);
	/*If this is not the last time around,
          reject a point.*/
	if(nrej<rejnum)
	  {
	    maxerr = fabs(invec2[1]-mean1);
	    wpoint = 1;
	    for(i=2;i<=pnum-nrej;i++)
	      {
		if(fabs(invec2[i]-mean1)>maxerr)
		  {
		    maxerr = fabs(invec2[i]-mean1);
		    wpoint = i;
		  }
	      }
	    /*Switch the worst point to the end of the
	      vector, which will be missed on the next step.*/
	    sval = invec2[wpoint];
	    invec2[wpoint] = invec2[pnum-nrej];
	    invec2[pnum-nrej] = sval;
	    serr = inerr2[wpoint];
	    inerr2[wpoint] = inerr2[pnum-nrej];
	    inerr2[pnum-nrej] = serr;
	  }
	else{
	  /*This is the last time around.
            Calculate the error of the mean, and the chi-squared value.*/
	  rms = chi1 = 0.0;
	  for(i=1;i<=pnum-nrej;i++)
	    {
	      rms+=pow(inerr2[i]/(1.0*pnum-1.0*nrej),2.0);
	      chi1+=pow((mean1-invec2[i])/inerr2[i],2.0);
	    }
	  rms = pow(rms,0.5);
	  chi1/=(1.0*pnum-1.0*nrej);
	  *meanerror = rms;
	  *chisq = chi1;
	  *mean = mean1;
	  if(pnum-nrej==1)
	    {
	      printf("Warning: creeperr01 has rejected all but one point\n");
	    }
	}
      }
  }

  free_vector(invec2,1,pnum);
  free_vector(inerr2,1,pnum);
  return(1);
}


/*creeperr02: Like creeperr01, but performs
weighted averaging.  The bad points are still 
rejected on the basis of largest absoute 
deviation from the mean, which
is now a weighted mean.*/
int creeperr02(float *invec,float *inerr,int pnum,float rejfac,float *mean,float *meanerror,float *chisq)
{
  int rejnum,i,j,nrej;
  float mean1,mean2,norm,rms,*invec2,*inerr2;
  float sval,maxerr,meanerr1,chi1,serr;
  int wpoint;

  invec2 = vector(1,pnum);
  inerr2 = vector(1,pnum);

  for(i=1;i<=pnum;i++)
    {
      invec2[i] = invec[i];
      inerr2[i] = inerr[i];
   }

  /*Determine how many entries will be rejected*/
  rejnum = rejfac*pnum;

  if(rejnum>=pnum)
    {
      printf("Warning: you have asked creeperr02 to\n");
      printf("reject all of your points!\nAll but one will be rejected.\n");
      rejnum = pnum-1;
    }

  /*If the answer is zero let it work as an ordinary average*/
  if(rejnum<=0)
    {
      if(pnum==1)
	{
	  printf("Warning: creeperr02 called with only one point!\n");
	}
      printf("Warning: creeperr02 is not rejecting any points\n");
      weightmeanrms01(invec2,inerr2,pnum,mean,meanerror,chisq);
    }
  else{
    /*Now for the full code*/
    for(nrej=0;nrej<=rejnum;nrej++)
      {
	/*calculate mean*/
	weightmeanrms01(invec2,inerr2,pnum-nrej,&mean1,&meanerr1,&chi1);
	/*If this is not the last time around,
          reject a point.*/
	if(nrej<rejnum)
	  {
	    maxerr = fabs(invec2[1]-mean1);
	    wpoint = 1;
	    for(i=2;i<=pnum-nrej;i++)
	      {
		if(fabs(invec2[i]-mean1)>maxerr)
		  {
		    maxerr = fabs(invec2[i]-mean1);
		    wpoint = i;
		  }
	      }
	    /*Switch the worst point to the end of the
	      vector, which will be missed on the next step.*/
	    sval = invec2[wpoint];
	    invec2[wpoint] = invec2[pnum-nrej];
	    invec2[pnum-nrej] = sval;
	    serr = inerr2[wpoint];
	    inerr2[wpoint] = inerr2[pnum-nrej];
	    inerr2[pnum-nrej] = serr;
	  }
	else{
	  /*This is the last time around.
            Output the values to the calling function*/
	  *meanerror = meanerr1;
	  *chisq = chi1;
	  *mean = mean1;
	  if(pnum-nrej==1)
	    {
	      printf("Warning: creeperr02 has rejected all but one point\n");
	    }
	}
      }
  }

  free_vector(invec2,1,pnum);
  free_vector(inerr2,1,pnum);
  return(1);
}

/*creeperr03: Like creeperr02, but
rejects the points based on largest
deviation from the weighted mean RELATIVE
to their errors, not based on largest
absolute deviation from the weighted mean.*/
int creeperr03(float *invec,float *inerr,int pnum,float rejfac,float *mean,float *meanerror,float *chisq)
{
  int rejnum,i,j,nrej;
  float mean1,mean2,norm,rms,*invec2,*inerr2;
  float sval,maxerr,meanerr1,chi1,serr;
  int wpoint;

  invec2 = vector(1,pnum);
  inerr2 = vector(1,pnum);

  for(i=1;i<=pnum;i++)
    {
      invec2[i] = invec[i];
      inerr2[i] = inerr[i];
   }

  /*Determine how many entries will be rejected*/
  rejnum = rejfac*pnum;

  if(rejnum>=pnum)
    {
      printf("Warning: you have asked creeperr03 to\n");
      printf("reject all of your points!\nAll but one will be rejected.\n");
      rejnum = pnum-1;
    }

  /*If the answer is zero let it work as an ordinary average*/
  if(rejnum<=0)
    {
      if(pnum==1)
	{
	  printf("Warning: creeperr03 called with only one point!\n");
	}
      printf("Warning: creeperr03 is not rejecting any points\n");
      weightmeanrms01(invec2,inerr2,pnum,mean,meanerror,chisq);
    }
  else{
    /*Now for the full code*/
    for(nrej=0;nrej<=rejnum;nrej++)
      {
	/*calculate mean*/
	weightmeanrms01(invec2,inerr2,pnum-nrej,&mean1,&meanerr1,&chi1);
	/*If this is not the last time around,
          reject a point.*/
	if(nrej<rejnum)
	  {
	    maxerr = fabs(invec2[1]-mean1)/fabs(inerr2[1]);
	    wpoint = 1;
	    for(i=2;i<=pnum-nrej;i++)
	      {
		if(fabs(invec2[i]-mean1)/fabs(inerr2[i])>maxerr)
		  {
		    maxerr = fabs(invec2[i]-mean1)/fabs(inerr2[i]);
		    wpoint = i;
		  }
	      }
	    /*Switch the worst point to the end of the
	      vector, which will be missed on the next step.*/
	    sval = invec2[wpoint];
	    invec2[wpoint] = invec2[pnum-nrej];
	    invec2[pnum-nrej] = sval;
	    serr = inerr2[wpoint];
	    inerr2[wpoint] = inerr2[pnum-nrej];
	    inerr2[pnum-nrej] = serr;
	  }
	else{
	  /*This is the last time around.
            Output the values to the calling function*/
	  *meanerror = meanerr1;
	  *chisq = chi1;
	  *mean = mean1;
	  if(pnum-nrej==1)
	    {
	      printf("Warning: creeperr03 has rejected all but one point\n");
	    }
	}
      }
  }

  free_vector(invec2,1,pnum);
  free_vector(inerr2,1,pnum);
  return(1);
}



/*wsinlinfit01: a program to make a weighted fit of data to a 
sinusoid of fixed period and fixed angular phase,
but variable zero point a and amplitude b.
values of a, siga, b, sigb, and the chi-square of the fit
will be returned.  This program can easily be modified to
fit data to do an analogous 2-parameter fit to ANY other
defined function.  Only a few lines in
the initial summation sequence, and one in the chi-square
calculation would need to be changed.*/
int wsinlinfit01(float periodt,float phaset,float *x,float *y,float *yerr,int np,float *a,float *siga,float *b,float *sigb,float *chisquare)
{
  float yal,xal,nsum,ytx,xsq,fita,fitb,fitsiga,fitsigb,fitchi;
  int i;
  float delta;

  yal = xal = nsum = ytx = xsq = 0.0;
  for(i=1;i<np;i++)
    {
      nsum+=1.0/pow(yerr[i],2.0);
      yal+=y[i]/pow(yerr[i],2.0);
      xal+=sin(x[i]*2.0*PI/periodt + phaset)/pow(yerr[i],2.0);
      ytx+=y[i]*sin(x[i]*2.0*PI/periodt + phaset)/pow(yerr[i],2.0);
      xsq+=pow(sin(x[i]*2.0*PI/periodt + phaset),2.0)/pow(yerr[i],2.0);
    }
  delta = (nsum*xsq - pow(xal,2.0));
  fitb = (ytx*nsum - xal*yal)/delta;
  fita = (xsq*yal - ytx*xal)/delta;
  fitsigb = pow((pow(nsum,2.0)*xsq + pow(xal,2.0)*nsum)/pow(delta,2.0),0.5);
  fitsiga = pow((pow(xsq,2.0)*nsum + pow(xal,2.0)*xsq)/pow(delta,2.0),0.5);
  fitchi = 0.0;
  for(i=1;i<=np;i++)
    {
      fitchi+=pow((fita+fitb*sin(x[i]*2.0*PI/periodt + phaset) - y[i])/yerr[i],2.0);
    }
  if(np>2)
    {
      fitchi/=(1.0*np - 2.0);
    }
  else{
    printf("WARNING: wsinlinfit01 RECIEVED TOO FEW POINTS\nTO CALCULATE A MEANINGFUL CHI-SQUARE VALUE\n");
    fitchi = -1.0;
  }
  *a = fita;
  *b = fitb;
  *siga = fitsiga;
  *sigb = fitsigb;
  *chisquare = fitchi;
  return(1);
}

/*photmag01: A simple program to give the magnitude
of a star, given the exposure time on the image,
the airmass of the image, the counts on the image,
the value of atmospheric tau and sigma tau, a reference
magnitude and a reference airmass, and the number
of counts per second for a star at this magnitude
and airmass, and the sigma on this count number.
The calculated uncertainty depends only on
calibration error, not on any error in the
measured counts from the target.  It is assumed
that the latter error will be calculated outside
the program based on an rms of many measurements
of the star, and added in quadrature to the 
calibration error.*/
int photomag01(float exposure,float airmass,float starcounts,float tau,float sigtau,float refair,float refmag,float counts,float sigcounts,float *mag,float *magerr)
{
  float magnitude,magnerr;
  magnitude = refmag - 2.5*log10(starcounts*exp((airmass-refair)*tau)/(exposure*counts));
  magnerr = pow(pow(sigcounts/counts,2.0)+pow((airmass-refair)*sigtau,2.0),0.5)/EFOLDMAG;
  *mag = magnitude;
  *magerr = magnerr;
  return(1);
}

/*lineskip01: Given a pointer to a file and a number of lines,
skips that many lines and returns the number of lines.  Prints an error
message and returns 0 if the end of the file is encountered*/
int lineskip01(FILE *fp1,int lnum)
{
  int c,i;
  for(i=1;i<=lnum;i++)
    {
      c = 0;
      while(c!='\n')
	{
	  c = getc(fp1);
	  if(c==EOF)
	    {
	      printf("Script file read error returned by lineskip: check script file!\n");
	      return(0);
	    }
	}
    }
  return(lnum);
}

/*lineskip02: Given a pointer to a file and an integer,
reads characters from the file until a character cooresponding
to that integer is reached.  For example, if it is called as
lineskip02(fp1,'%'), it will read characters from the file
until it reaches the first % and then return.*/
int lineskip02(FILE *fp1,int stopchar)
{
  int c;
  c = 0;
  while(c!=stopchar)
    {
      c = getc(fp1);
      if(c==EOF)
	{
	  printf("lineskip02 hit end of file: check script file!\n");
	  return(0);
	}
    }
  return(1);
}


/*celtoalt01: converts declination and hour angle of a celestial
object to altitude and azimuth, given the latitude of the observatory.
Also calculates the parallactic angle.  Requires declination in decimal
degrees and hour angle in decimal hours, positive to the west.  The
parallactic angle is defined as the celestial position angle of the
zenith-pointing vector from the source.  Returns altitude, azimuth,
and parallactic angle in decimal degrees.*/
int celtoalt01(float dec,float ha,float lat,float *alt,float *az,float *pa)
{

  float decrad,harad,latrad,altrad,azrad,parad;
  float z,x,y,zp,xp,yp,xd,yd;
  double initpos[3],polepos[3],newpos[3],oldpolera;

  decrad = dec*PI/180.0;
  harad = ha*PI/12.0;
  latrad = lat*PI/180.0;

  z = sin(decrad);
  x = -cos(decrad)*cos(harad);
  y = cos(decrad)*sin(harad);

  zp = z*sin(latrad)-x*cos(latrad);
  xp = x*sin(latrad)+z*cos(latrad);
  yp = y;

  altrad = asin(zp);
  if(yp>0.0)
    {
      azrad = 1.5*PI + atan(xp/yp);
    }
  else if(yp<0.0)
    {
      azrad = 0.5*PI + atan(xp/yp);
    }
  else if(yp==0.0)
    {
      if(xp>=0.0)
	{
	  azrad = 0.0;
	}
      else if(xp<0.0)
	{
	  azrad = PI;
	}
    }


  /*poleswitch01: given a double precision input vector
  containing the position in radians of a source on a 
  spherical coordinate system, another vector containing
  the position of the pole of a new coordinate system
  on the old coordinate system, calculates the position
  of the point in the new coordinate system, and outputs
  this in a third double precision vector.  The desired
  RA for the old pole in the new coordinates is also required.*/

  /*Make polepos the position of the star in the celestial
  coordinate system.  Since we don't have actual RA, we rotate
  the coordinate system so that the zenith is at 0h RA.*/
  polepos[1] = -harad;
  if(polepos[1]<0.0)
    {
      polepos[1]+=2.0*PI;
    }
  polepos[2] = decrad;

  /*Make initpos the position of the zenith*/
  initpos[1] = 0.0;
  initpos[2] = latrad;

  /*Perform pole switch.  Set the true north celestial pole
    to 0h RA in the new system*/

  oldpolera = 0.0;
  poleswitch01(initpos,polepos,newpos,oldpolera);

  parad = 2.0*PI-newpos[1];

  *alt = 180.0*altrad/PI;
  *az = 180.0*azrad/PI;
  *pa = 180.0*parad/PI;

  return(1);
}

/*getsidet01: given the date in the form of an integer vector
holding the year, month, and day, and the ut in the form
of an integer vector holding the hour, minute, and second, and
the longitude in decimal degrees (negative to the west), 
find the local mean sidereal time using the formula 
given in the 2005 Astronomical Almanac, and the 
subroutine JDcalc01.  The local sidereal time is 
returned in decimal hours.*/
int getsidet01(int *date,int *ut,float lon,float *lmst)
{
  double jdout,tu,gmst;
  int notgood,*utnew;
  float jdoff;

  utnew = ivector(1,3);

  utnew[1] = 0;
  utnew[2] = 0;
  utnew[3] = 0;

  JDcalc01(date,utnew,&jdout);
  jdoff = jdout-2451545.0;
  printf("jdout-2451545 = %f\n",jdoff);

  tu = (jdout - 2451545.0)/36525.0;

  gmst = 24110.54841 + 8640184.812866*tu + 0.093104*tu*tu - 6.2e-6*tu*tu*tu;

  /*This formula from the Almanac gives the gmst in seconds.
    However, if it is not 2005 the formula probably gives a gmst
    of more than 24 or less than 0 hours.  We will fix this last,
    after everything else that may put gmst out of range
    has already happened*/

  /*Convert gmst from seconds to hours*/
  gmst/=3600.0;

  printf("getsidet01: GMST = %f",gmst);

  /*Add the current ut, scaled by the sidereal to solar period conversion*/
  /*Note: at this point it stops being gmst*/
  gmst += (1.0*ut[1]+1.0*ut[2]/60.0+1.0*ut[3]/3600.0)*1.0027379094;
  printf("\t%f",gmst);

  /*Add the longitude, converted to hours*/
  gmst += lon/15.0;
  printf("\t%f",gmst);

  /*Get value between 0.0 and 24.0 hours*/
  notgood = 1;
  if(gmst>=0.0&&gmst<24.0)
    {
      notgood=0;
    }

  while(notgood==1)
    {
      if(gmst<0.0)
	{
	  gmst+=24.0;
	}
      else if(gmst>=24.0)
	{
	  gmst-=24.0;
	}
      if(gmst>=0.0&&gmst<24.0)
	{
	  notgood=0;
	}
    }
  printf("\t%f\n",gmst);

  *lmst = gmst;

  free_ivector(utnew,1,3);
  return(1);
}

/*mirrorflip01: given an input image and an integer, mirror-flips
the image left-to-right if the integer is 1 and top-to-bottom
if the integer is 2.  Otherwise does nothing.*/
int mirrorflip01(float **image,int nx,int ny,int choicepar)
{
  float **image2;
  int i,j;

  image2 = matrix(1,nx,1,ny);

  if(choicepar==1)
    {
      for(i=1;i<=nx;i++)
	{
	  for(j=1;j<=ny;j++)
	    {
	      image2[i][j] = image[nx+1-i][j];
	    }
	}
      for(i=1;i<=nx;i++)
	{
	  for(j=1;j<=ny;j++)
	    {
	      image[i][j] = image2[i][j];
	    }
	}
    }
  else if(choicepar == 2)
    {
      for(i=1;i<=nx;i++)
	{
	  for(j=1;j<=ny;j++)
	    {
	      image2[i][j] = image[i][ny+1-j];
	    }
	}
      for(i=1;i<=nx;i++)
	{
	  for(j=1;j<=ny;j++)
	    {
	      image[i][j] = image2[i][j];
	    }
	}
    }

  free_matrix(image2,1,nx,1,ny);
  return(1);
}

/*annucounts01: given an input image x and y coordinates
of a point, and inner and outer radii
for an annulus, find the mean counts in the annulus 
centered on the point using pseudocreep01*/
float annucounts01(float **image,int nx,int ny,float x1,float y1,float rad1,float rad2)
{
  int i,j,bhw,sgct;
  float rad,mean,rms,meanerror,*dvec;

  if(rad1>=rad2)
    {
      printf("ERROR: annucounts01 recieves bad radii\n");
      printf("ABORTING\n");
      return(-1.0e30);
    }

  bhw = rad2 + 5;

  dvec = vector(1,4*bhw*bhw);

  sgct = 0;
  for(i=x1-bhw;i<=x1+bhw;i++)
    {
      for(j=y1-bhw;j<=y1+bhw;j++)
	{
	  rad = pow(pow(1.0*i-x1,2.0)+pow(1.0*j-y1,2.0),0.5);
	  if(rad>=rad1&&rad<=rad2&&i>=1&&i<=nx&&j>=1&&j<=ny)
	    {
	      sgct+=1;
	      dvec[sgct] = image[i][j];
	    }
	}
    }
  pseudocreep01(dvec,sgct,CANRLEV,&mean,&meanerror,&rms);
  free_vector(dvec,1,4*bhw*bhw);
  return(mean);
}

/*subpsftemp01: Subtract a psf template from an image, with subtraction
  out to a radius of psftsubrad, using scaling in an annulus determined
  by annucounts01.  Pixels at radii less than zrad will simply be set to zero.*/
int subpsftemp01(float **image,float **psfim,int nx,int ny,float x1,float y1,float rad1,float rad2,float psftsubrad,float zrad,float faderad)
{
  float **image1,meanpsf,meanim,rad;
  int i,j;

  image1 = matrix(1,nx,1,ny);

  imcopy01(psfim,image1,nx,ny);

  meanpsf = annucounts01(image1,nx,ny,x1,y1,rad1,rad2);
  meanim = annucounts01(image,nx,ny,x1,y1,rad1,rad2);

  mathimc03(image1,image1,nx,ny,meanim/meanpsf);

  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  if(image[i][j]!=0.0)
	    {
	      rad = pow(pow(1.0*i-x1,2.0)+pow(1.0*j-y1,2.0),0.5);
	      if(rad<zrad)
		{
		  image[i][j] = 0.0;
		}
	      else if(rad<=psftsubrad)
		{
		  image[i][j]-=image1[i][j];
		}
	      else if(rad>psftsubrad&&rad&&rad<=faderad)
		{
		  image[i][j]-=image1[i][j]*(faderad-rad)/(faderad-psftsubrad);
		}
	    }
	  else
	    {
	      /*This pixel is zero on the science image*/
	      /*this means it is outside the valid data*/
	      /*region, and should be left zero, not given*/
	      /*a spurious nonzero value by subtracting the*/
	      /*psf model from it.  Do nothing*/
	      image[i][j] = 0.0;
	    }
	}
    }

  free_matrix(image1,1,nx,1,ny);

  return(1);
}



/*subpsftemp02: Subtract a psf template from an image.  
Pixels at radius less than rad1 will simply be set to
zero.  Pixels at radii between rad1 and rad2 will have have a scaled
version of the psf template subtracted from them.  The scaling will be
by annular regions of width 5 pixels centered on the radius of the
pixel under consideration, except in the case of pixels within two
pixels outside of rad1 or inside of rad2, in which cases the scaling
will be by annular region of 5 pixels width beginning at rad1 or ending
at rad2.  For pixels between rad2 and rad3,  scaling will be by
the average of scalings obtained between rad1 and rad2.  Between
rad3 and rad4 subtraction will be by a scaled version of a 3x3
smoothed version of the template.  Between rad4 and rad5
subtraction will fade linearly to zero.  The parameter
secsubscale is a fudge factor that allows one to increase
or decrease the nominal subtraction scaling.  It was developed
originally to deal with situations in which, when subtracting
the primary using a scaled version of the secondary was attempted,
the secondary seemed to get scaled up too high.  For normal
use it can be set to 1.0.*/
int subpsftemp02(float **image,float **psfim,int nx,int ny,float x1,float y1,float rad1,float rad2,float rad3,float rad4,float rad5,float secsubscale)
{
  float **image1,meanpsf,meanim,rad;
  int i,j,scalerings,scalecirc,cx,cy,bhw,*scalenumvec;
  float **scalemat,*scalevec1,*scalevec2;
  int sgct,irad,d1,d2,k,l;
  float data1,data2,avscale,radb;
  FILE *fp1;

  scalerings = rad2-rad1;
  rad2 = rad1+(float)scalerings;
  scalecirc = 4.0*(PI*rad2);

  image1 = matrix(1,nx,1,ny);
  scalemat  = matrix(1,scalerings,1,scalecirc);
  scalevec1 = vector(1,scalerings);
  scalevec2 = vector(1,scalerings);
  scalenumvec = ivector(1,scalerings);

  imcopy01(psfim,image1,nx,ny);

  /*zero scalenumvec*/
  for(i=1;i<=scalerings;i++)
    {
      scalenumvec[i] = 0;
    }

  /*zero scalemat*/
  for(i=1;i<=scalerings;i++)
    {
      for(j=1;j<=scalecirc;j++)
	{
	  scalemat[i][j] = 0.0;
	}
    }

  /*Get scaling rings for science image*/
  cx = x1;
  cy = y1;
  bhw = rad2+5;

  for(i=cx-bhw;i<=cx+bhw;i++)
    {
      for(j=cy-bhw;j<=cy+bhw;j++)
	{
	  if(i>=1&&i<=nx&&j>=1&&j<=nx)
	    {
	      if(image[i][j]!=0.0)
		{
		  rad = pow(pow((float)i-x1,2.0)+pow((float)j-y1,2.0),0.5);
		  rad -= rad1;
		  rad += 1.0;
		  irad = rad;
		  if(irad>=1&&irad<=scalerings)
		    {
		      scalenumvec[irad]+=1;
		      scalemat[irad][scalenumvec[irad]] = image[i][j];
		    }
		}
	    }
	}
    }

  /*Average scaling rings for science image*/
  for(i=1;i<=scalerings;i++)
    {
      if(scalenumvec[i]>1)
	{
	  creepvec01(scalemat[i],scalenumvec[i],0.5,&data1,&data2);
	  scalevec1[i] = data1;
	}
      else
	{
	  scalevec1[i] = 0;
	}
    }

  /*zero scalenumvec*/
  for(i=1;i<=scalerings;i++)
    {
      scalenumvec[i] = 0;
    }

  /*zero scalemat*/
  for(i=1;i<=scalerings;i++)
    {
      for(j=1;j<=scalecirc;j++)
	{
	  scalemat[i][j] = 0.0;
	}
    }

  /*Get scaling rings for psf image*/
  cx = x1;
  cy = y1;
  bhw = rad2+5;

  for(i=cx-bhw;i<=cx+bhw;i++)
    {
      for(j=cy-bhw;j<=cy+bhw;j++)
	{
	  if(i>=1&&i<=nx&&j>=1&&j<=nx)
	    {
	      if(image[i][j]!=0.0)
		{
		  rad = pow(pow((float)i-x1,2.0)+pow((float)j-y1,2.0),0.5);
		  rad -= rad1;
		  rad += 1.0;
		  irad = rad;
		  if(irad>=1&&irad<=scalerings)
		    {
		      scalenumvec[irad]+=1;
		      scalemat[irad][scalenumvec[irad]] = psfim[i][j];
		    }
		}
	    }
	}
    }

  /*Average scaling rings for science image*/
  for(i=1;i<=scalerings;i++)
    {
      if(scalenumvec[i]>1)
	{
	  creepvec01(scalemat[i],scalenumvec[i],0.5,&data1,&data2);
	  scalevec2[i] = data1;
	}
      else
	{
	  scalevec2[i] = 0;
	}
    }

  /*Get scalings, ring by ring, in scalevec1*/
  for(i=1;i<=scalerings;i++)
    {
      if(scalevec2[i]>0.0)
	{
	  scalevec1[i]/=scalevec2[i];
	}
      else
	{
	  scalevec1[i] = 0.0;
	}
    }

  /*copy smoothed version of scalevec1 into scalevec2*/
  for(i=1;i<=scalerings;i++)
    {
      d1 = i-2;
      d2 = i+2;
      if(d1<1)
	{
	  d1 = 1;
	  d2 = 5;
	}
      else if(d2>scalerings)
	{
	  d2 = scalerings;
	  d1 = scalerings-4;
	}
      data1 = 0.0;
      for(j=d1;j<=d2;j++)
	{
	  data1+=scalevec1[j];
	}
      scalevec2[i] = data1/5.0;
    }

  avscale = scalevec2[scalerings];

  printf("\n\n\nWriting file spt02junk01\n\n\n");
  fp1 = fopen("spt02junk01","w");
  for(i=1;i<=scalerings;i++)
    {
      printf("%f\t%f\n",rad1-0.5+(float)i,scalevec2[i]);
      fprintf(fp1,"%f\t%f\n",rad1-0.5+(float)i,scalevec2[i]);
    }
  for(i=scalerings+1;i<=scalerings+10;i++)
    {
      printf("%f\t%f\n",rad1-0.5+(float)i,avscale);
      fprintf(fp1,"%f\t%f\n",rad1-0.5+(float)i,avscale);
    }
  fclose(fp1);

  /*Make 3x3 smoothed version of psf template*/
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  data1 = 0.0;
	  data2 = 0.0;
	  for(k=i-1;k<=i+1;k++)
	    {
	      for(l=j-1;l<=j+1;l++)
		{
		  if(k>=1&&k<=nx&&l>=1&&l<=ny)
		    {
		      if(psfim[k][l]!=0.0)
			{
			  data1+=1.0;
			  data2+=psfim[k][l];
			}
		    }
		}
	    }
	  if(data1>0.0)
	    {
	      image1[i][j] = data2/data1;
	    }
	  else
	    {
	      image1[i][j] = 0.0;
	    }
	}
    }



  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  rad = pow(pow((float)i-x1,2.0)+pow((float)j-y1,2.0),0.5);
	  if(rad<=rad1)
	    {
	      image[i][j] = 0.0;
	    }
	  else if(rad>rad1&&rad<rad2)
	    {
	      radb = rad-rad1;
	      radb += 1.0;
	      irad = radb;
	      if(irad<1)
		{
		  irad = 1;
		}
	      else if(irad>scalerings)
		{
		  irad = scalerings;
		}
	      image[i][j]-=psfim[i][j]*scalevec2[irad]*secsubscale;
	    }
	  else if(rad>=rad2&&rad<=rad3&&rad<=rad4)
	    {
	      image[i][j]-=psfim[i][j]*avscale*secsubscale;
	    }
	  else if(rad>rad3&&rad<=rad4)
	    {
	      image[i][j]-=image1[i][j]*avscale*secsubscale;
	    }
	  else if(rad>rad4&&rad<=rad3&&rad<=rad5)
	    {
	      image[i][j]-=psfim[i][j]*avscale*secsubscale*(rad5-rad)/(rad5-rad4);
	    }
	  else if(rad>rad4&&rad>rad3&&rad<=rad5)
	    {
	      image[i][j]-=image1[i][j]*avscale*secsubscale*(rad5-rad)/(rad5-rad4);
	    }
	}
    }

  free_matrix(image1,1,nx,1,ny);
  free_matrix(scalemat,1,scalerings,1,scalecirc);
  free_vector(scalevec1,1,scalerings);
  free_vector(scalevec2,1,scalerings);
  free_ivector(scalenumvec,1,scalerings);

  return(1);
}


/*brightfind01: A crude routine for quickly identifying the brightest
object in an image.  It will sum a 3x3 box, and take the 0.4 rejection
creeping mean combine of this box, finding the brightness of the core
of the stellar psf if the box is centered on a star.  It will also take 
the values of the eight pixels at the corners of a 2*shiftout+1 square 
box centered on the pixel under consideration, and find the 0.4 creeping 
mean rejection of these eight values, obtaining the brightness of the
halo of a stellar psf if the pixel is centered on a star.  It will
average together the core and halo brightnesses.  From this average
it will subtract the 0.4 rejection creeping mean combine of the eight 
pixels that are at the corners and the side-centers of a box of dimensions 
2*skydist x 2*skydist centered on the 3x3 box, where skydist is supposed
to be large enough that these pixels are only sampling the sky*/

float brightfind01(float **image,int nx,int ny,int x,int y,int skydist,int shiftout)
{
  float *cvec1,mean1,mean2,rms;
  int i,j,sgct;

  cvec1 = vector(1,9);

  /*measure core brightness*/
  sgct = 0;
  for(i=x-1;i<=x+1;i++)
    {
      for(j=y-1;j<=y+1;j++)
	{
	  if(i>=1&&i<=nx&&j>=1&&j<=ny)
	    {
	      sgct+=1;
	      cvec1[sgct] = image[i][j];
	    }
	}
    }
  creepvec01(cvec1,sgct,0.4,&mean1,&rms);

  /*measure halo brightness*/
  sgct = 0;
  i = x+shiftout;
  j = y;
  if(i>=1&&i<=nx&&j>=1&&j<=ny)
    {
      sgct+=1;
      cvec1[sgct] = image[i][j];
    }
  i = x-shiftout;
  j = y;
  if(i>=1&&i<=nx&&j>=1&&j<=ny)
    {
      sgct+=1;
      cvec1[sgct] = image[i][j];
    }
  i = x;
  j = y+shiftout;
  if(i>=1&&i<=nx&&j>=1&&j<=ny)
    {
      sgct+=1;
      cvec1[sgct] = image[i][j];
    }
  i = x;
  j = y-shiftout;
  if(i>=1&&i<=nx&&j>=1&&j<=ny)
    {
      sgct+=1;
      cvec1[sgct] = image[i][j];
    }
  i = x+shiftout;
  j = y+shiftout;
  if(i>=1&&i<=nx&&j>=1&&j<=ny)
    {
      sgct+=1;
      cvec1[sgct] = image[i][j];
    }
  i = x+shiftout;
  j = y-shiftout;
  if(i>=1&&i<=nx&&j>=1&&j<=ny)
    {
      sgct+=1;
      cvec1[sgct] = image[i][j];
    }
  i = x-shiftout;
  j = y+shiftout;
  if(i>=1&&i<=nx&&j>=1&&j<=ny)
    {
      sgct+=1;
      cvec1[sgct] = image[i][j];
    }
  i = x-shiftout;
  j = y-shiftout;
  if(i>=1&&i<=nx&&j>=1&&j<=ny)
    {
      sgct+=1;
      cvec1[sgct] = image[i][j];
    }
  creepvec01(cvec1,sgct,0.4,&mean2,&rms);

  /*Average together halo brightness and core brightness*/
  mean1 = 0.5*mean1+0.5*mean2;

  /*Get sky brightness*/
  sgct = 0;
  i = x+skydist;
  j = y;
  if(i>=1&&i<=nx&&j>=1&&j<=ny)
    {
      sgct+=1;
      cvec1[sgct] = image[i][j];
    }
  i = x-skydist;
  j = y;
  if(i>=1&&i<=nx&&j>=1&&j<=ny)
    {
      sgct+=1;
      cvec1[sgct] = image[i][j];
    }
  i = x;
  j = y+skydist;
  if(i>=1&&i<=nx&&j>=1&&j<=ny)
    {
      sgct+=1;
      cvec1[sgct] = image[i][j];
    }
  i = x;
  j = y-skydist;
  if(i>=1&&i<=nx&&j>=1&&j<=ny)
    {
      sgct+=1;
      cvec1[sgct] = image[i][j];
    }
  i = x+skydist;
  j = y+skydist;
  if(i>=1&&i<=nx&&j>=1&&j<=ny)
    {
      sgct+=1;
      cvec1[sgct] = image[i][j];
    }
  i = x+skydist;
  j = y-skydist;
  if(i>=1&&i<=nx&&j>=1&&j<=ny)
    {
      sgct+=1;
      cvec1[sgct] = image[i][j];
    }
  i = x-skydist;
  j = y+skydist;
  if(i>=1&&i<=nx&&j>=1&&j<=ny)
    {
      sgct+=1;
      cvec1[sgct] = image[i][j];
    }
  i = x-skydist;
  j = y-skydist;
  if(i>=1&&i<=nx&&j>=1&&j<=ny)
    {
      sgct+=1;
      cvec1[sgct] = image[i][j];
    }

  creepvec01(cvec1,sgct,0.4,&mean2,&rms);

  free_vector(cvec1,1,9);
  return(mean1-mean2);
}




/*pairferr01: A program to find the error of an input psf fit to
a double star pair.  It will take in an image from which it can
obtain the psf, the dimensions of this image, the exact location
of the psf star on this image, the image to be fit, the dimensions
of this image, the exact location of the photocenter of the binary
pair on this image, the seperation, brightness ratio, and image
position angle to be fit, and the radius within which the fitting
should be done.  It will then create two small images with the
psf star trimmed out in their centers, shift and scale them to
have the proper position angle and to overlay the image with the
double star perfectly, and then add them together.  It will then
scale their sum to match the total flux from the double star
within the aperture, and find and return the mean absolute fitting
error.  If skysubchoose = 1 it will perform sky subtraction
between skyrad1 and skyrad2; otherwise the skylevel will be
assumed to be zero.  Ratiostar is the ratio of the brighter
star to the fainter.*/
float pairferr01(float **psfimage,int psfnx,int psfny,float **fitimage,int fitnx,int fitny,float *cenpsf,float *cenfit,float sep,float pa,float ratiostar,float fitrad,float *skyrads,int skysubchoose)
{

  int bhw,nx,ny,i,j,icpx,icpy,icfx,icfy,psfoutrange;
  float **postim1,**postim2,psfbright,pairbright,shiftpx,shiftpy;
  float skylev,skyerr,shiftfx,shiftsx,shiftsy;
  float shiftrad,*cenrads,*fcenpos1,postbright;
  int *cenpos1,fitoutrange;
  float sumerr,radius1,radius2,xsec,ysec,xpri,ypri,norm;

  /*get box half-width and postage stamp image dimensions*/
  bhw = fitrad + sep + 5.0;
  nx = ny = 2*bhw+1;

  postim1 = matrix(1,nx,1,ny);
  postim2 = matrix(1,nx,1,ny);
  cenpos1 = ivector(1,2);
  fcenpos1 = vector(1,2);
  cenrads = vector(1,3);

  for(i=1;i<=3;i++)
    {
      cenrads[i] = fitrad+sep;
    }

  /*trim out postage stamp images*/
  icpx = cenpsf[1]+0.5;
  icpy = cenpsf[2]+0.5;
  icfx = cenfit[1]+0.5;
  icfy = cenfit[2]+0.5;

  psfoutrange = 0;
  for(i=icpx-bhw;i<=icpx+bhw;i++)
    {
      for(j=icpy-bhw;j<=icpy+bhw;j++)
	{
	  if(i>=1&&i<=psfnx&&j>=1&&j<=psfny)
	    {
	      postim1[i-icpx+bhw+1][j-icpy+bhw+1] = psfimage[i][j];
	    }
	  else
	    {
	      postim1[i-icpx+bhw+1][j-icpy+bhw+1] = 0.0;
	      psfoutrange = 1;
	    }
	}
    }
  if(psfoutrange==1)
    {
      printf("WARNING: pairferr01 GETS PSF TRIM BOX PARTLY OUT OF IMAGE\n");
      printf("PROCESSING WILL CONTINUE BUT SOMETHING MAY BE WRONG\n");
    }

  /*Get integrated brightness of fitting target and psf image over fitting
    area.  If sky subtraction is in use, these will be sky-subtracted*/

  rphot01(psfimage,psfnx,psfny,cenpsf,skyrads,skysubchoose,1,fitrad+sep,&psfbright);
  rphot01(fitimage,fitnx,fitny,cenfit,skyrads,skysubchoose,1,fitrad+sep,&pairbright);

  /*printf("The brightness of the psf star is %f\n",psfbright);
    printf("The combined brightness of the double is %f\n",pairbright);*/

  /*Perform sky subtraction on the psf image if requested*/
  if(skysubchoose==1)
    {
      skyfind02(psfimage,psfnx,psfny,skyrads,&skylev,&skyerr,cenpsf);
      for(i=1;i<=nx;i++)
	{
	  for(j=1;j<=ny;j++)
	    {
	      postim1[i][j]-=skylev;
	    }
	}
    }

  /*Copy psf image*/
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  postim2[i][j]=postim1[i][j];
	}
    }

  /*The center of the postage stamp images corresponds to
    pixel icpx,icpy.  To shift the center-of-light in the
    postage stamp image to overlay this pixel we need
    to shift the light by icpx-cenpsf[1], icpy-cenpsf[2].
    The center of the box we consider on the fit image
    is icfx,icfy.  To shift the center of the light on
    the postage stamp image from its own center to overlay
    the true fit center cenfit[1],cenfit[2], we must shift
    the light a further amount cenfit[1]-icfx, cenfit[2]-icfy.
    The rest is position angle, seperation, and trigonometry*/

  /*Secondary image shifts*/
  shiftrad = sep*ratiostar/(1.0+ratiostar);
  shiftsx = -shiftrad*sin(pa*PI/180.0) + (1.0*icpx-cenpsf[1]) + (cenfit[1]-1.0*icfx);
  shiftsy = shiftrad*cos(pa*PI/180.0) + (1.0*icpy-cenpsf[2]) + (cenfit[2]-1.0*icfy);

  /*Primary image shifts*/
  shiftrad = sep*1.0/(1.0+ratiostar);
  shiftpx = shiftrad*sin(pa*PI/180.0) + (1.0*icpx-cenpsf[1]) + (cenfit[1]-1.0*icfx);
  shiftpy = -shiftrad*cos(pa*PI/180.0) + (1.0*icpy-cenpsf[2]) + (cenfit[2]-1.0*icfy);

  /*shift primary image*/
  shift01(postim1,nx,ny,shiftpx,shiftpy);

  /*shift secondary image*/
  shift01(postim2,nx,ny,shiftsx,shiftsy);

  /*scale primary image*/
  mathimc03(postim1,postim1,nx,ny,(pairbright/psfbright)*ratiostar/(1.0+ratiostar));

  /*scale secondary image*/
  mathimc03(postim2,postim2,nx,ny,(pairbright/psfbright)*1.0/(1.0+ratiostar));

  /*Add images together*/
  mathimtim01(postim1,postim1,nx,ny,postim2);

  writeim01(nx,ny,"postim1.txt",postim1);

  /*Examine centroid of postage stamp image*/
  cenpos1[1] = cenpos1[2] = bhw+1;
  rcentroid01(postim1,nx,ny,cenpos1,cenrads,fcenpos1,3,skyrads,0,1);
  rphot01(postim1,nx,ny,fcenpos1,skyrads,0,1,fitrad+sep,&postbright);
  fcenpos1[1]+=(1.0*icfx-1.0*bhw-1.0);
  fcenpos1[2]+=(1.0*icfy-1.0*bhw-1.0);

  /*printf("Centroid of true image:\t%f %f\n",cenfit[1],cenfit[2]);
    printf("Centroid of model image:\t%f %f\n",fcenpos1[1],fcenpos1[2]);*/

  /*Examine flux of postage stamp image*/
  /*  printf("Flux of true image:\t%f\n",pairbright);
      printf("Flux of model image:\t%f\n",postbright);*/

  /*Scale postage stamp image to exactly match true brightness*/
  mathimc03(postim1,postim1,nx,ny,pairbright/postbright);

  /*Get sum absolute error*/
  fitoutrange = 0;
  sumerr = norm = 0.0;
  for(i=icfx-bhw;i<=icfx+bhw;i++)
    {
      for(j=icfy-bhw;j<=icfy+bhw;j++)
	{
	  if(i>=1&&i<=fitnx&&j>=1&&j<=fitny)
	    {  
	      /*position of primary overlay on image to be fit*/
	      shiftrad = sep*1.0/(1.0+ratiostar);
	      xpri = cenfit[1]+shiftrad*sin(pa*PI/180.0);
	      ypri = cenfit[2]-shiftrad*cos(pa*PI/180.0);

	      /*position of secondary overlay on image to be fit*/
	      shiftrad = sep*ratiostar/(1.0+ratiostar);
	      xsec = cenfit[1]-shiftrad*sin(pa*PI/180.0);
	      ysec = cenfit[2]+shiftrad*cos(pa*PI/180.0);

	      radius1 = pow(pow(1.0*i-xpri,2.0)+pow(1.0*j-ypri,2.0),0.5);
	      radius2 = pow(pow(1.0*i-xsec,2.0)+pow(1.0*j-ysec,2.0),0.5);
	      if(radius1<=fitrad||radius2<=fitrad)
		{
		  norm+=1.0;
		  sumerr+=fabs(postim1[i-icfx+bhw+1][j-icfy+bhw+1]-fitimage[i][j]);
		}
	    }
	  else
	    {
	      fitoutrange = 1;
	    }
	}
    }

  sumerr/=norm;

  if(psfoutrange==1)
    {
      printf("WARNING: pairferr01 GETS FITTING BOX PARTLY OUT OF IMAGE\n");
      printf("PROCESSING WILL CONTINUE BUT SOMETHING MAY BE WRONG\n");
    }


  free_matrix(postim1,1,nx,1,ny);
  free_matrix(postim2,1,nx,1,ny);
  free_ivector(cenpos1,1,2);
  free_vector(fcenpos1,1,2);
  free_vector(cenrads,1,3);

  return(sumerr);
}


/*spline, splint, splie2, and splin2: Numerical Recipes in C bicubic
spline routines.  Please note well that, unlike the rest of bezalel01.c,
these routines are not written by Ari Heinze, and are not his intellectual
property.  On the contrary, they are the intellectual property of the
authors of Numerical Recipes in C, as indicated in the copyright
notices below.  They are included here so that they need not be
individually compiled for bezalel01.c routines that use them,
namely shift02, rotate02, and rotateshift02.  To use the full
2D bicubic spline on an image, use splie2 and splin2.  To understand
how to make the call, look at the parameter list for splie2:
void splie2(float x1a[], float x2a[], float **ya, int m, int n, float **y2a).
x1a is a vector holding the x values of every column: 1,2,3,...nx.
x2a is a vector holding the y values of every row: 1,2,3,...ny.
Note that these are floating point vectors.  m = nx and n = ny.
ya is the image matrix, and y2a is the blackbox-NRC-magic-ie-I-don't-
have-to-understand-it output.  After calling splie2 with this prescription,
you call splin2 EVERY TIME YOU WANT A VALUE AT A SPECIFIC POINT.  The
parameter list looks like this: void splin2(float x1a[], float x2a[], float **ya, 
float **y2a, int m, int n,float x1, float x2, float *y).  The variables
all have the same definitions as for splie2, BUT MAKE SURE YOU DON'T
CHANGE y2a BETWEEN CALLING splie2 AND CALLING splin2.  Then x1, x2 are
simply the x, y coords of the point at which you want an interpolated
value, and y is the value that will be returned.  See shift02, rotate02,
and rotateshift02 for examples of how this works in practice.*/

#define NRANSI
void spline(float x[], float y[], int n, float yp1, float ypn, float y2[])
{
	int i,k;
	float p,qn,sig,un,*u;

	u=vector(1,n-1);
	if (yp1 > 0.99e30)
		y2[1]=u[1]=0.0;
	else {
		y2[1] = -0.5;
		u[1]=(3.0/(x[2]-x[1]))*((y[2]-y[1])/(x[2]-x[1])-yp1);
	}
	for (i=2;i<=n-1;i++) {
		sig=(x[i]-x[i-1])/(x[i+1]-x[i-1]);
		p=sig*y2[i-1]+2.0;
		y2[i]=(sig-1.0)/p;
		u[i]=(y[i+1]-y[i])/(x[i+1]-x[i]) - (y[i]-y[i-1])/(x[i]-x[i-1]);
		u[i]=(6.0*u[i]/(x[i+1]-x[i-1])-sig*u[i-1])/p;
	}
	if (ypn > 0.99e30)
		qn=un=0.0;
	else {
		qn=0.5;
		un=(3.0/(x[n]-x[n-1]))*(ypn-(y[n]-y[n-1])/(x[n]-x[n-1]));
	}
	y2[n]=(un-qn*u[n-1])/(qn*y2[n-1]+1.0);
	for (k=n-1;k>=1;k--)
		y2[k]=y2[k]*y2[k+1]+u[k];
	free_vector(u,1,n-1);
}
#undef NRANSI
/* (C) Copr. 1986-92 Numerical Recipes Software sO>$1"n26@129. */


void splint(float xa[], float ya[], float y2a[], int n, float x, float *y)
{
	void nrerror(char error_text[]);
	int klo,khi,k;
	float h,b,a;

	klo=1;
	khi=n;
	while (khi-klo > 1) {
		k=(khi+klo) >> 1;
		if (xa[k] > x) khi=k;
		else klo=k;
	}
	h=xa[khi]-xa[klo];
	if (h == 0.0) nrerror("Bad xa input to routine splint");
	a=(xa[khi]-x)/h;
	b=(x-xa[klo])/h;
	*y=a*ya[klo]+b*ya[khi]+((a*a*a-a)*y2a[klo]+(b*b*b-b)*y2a[khi])*(h*h)/6.0;
}
/* (C) Copr. 1986-92 Numerical Recipes Software sO>$1"n26@129. */


void splie2(float x1a[], float x2a[], float **ya, int m, int n, float **y2a)
{
	void spline(float x[], float y[], int n, float yp1, float ypn, float y2[]);
	int j;

	for (j=1;j<=m;j++)
		spline(x2a,ya[j],n,1.0e30,1.0e30,y2a[j]);
}
/* (C) Copr. 1986-92 Numerical Recipes Software sO>$1"n26@129. */

#define NRANSI

void splin2(float x1a[], float x2a[], float **ya, float **y2a, int m, int n,float x1, float x2, float *y)
{
	void spline(float x[], float y[], int n, float yp1, float ypn, float y2[]);
	void splint(float xa[], float ya[], float y2a[], int n, float x, float *y);
	int j;
	float *ytmp,*yytmp;

	ytmp=vector(1,m);
	yytmp=vector(1,m);
	for (j=1;j<=m;j++)
		splint(x2a,ya[j],y2a[j],n,x2,&yytmp[j]);
	spline(x1a,yytmp,m,1.0e30,1.0e30,ytmp);
	splint(x1a,yytmp,ytmp,m,x1,y);
	free_vector(yytmp,1,m);
	free_vector(ytmp,1,m);
}
#undef NRANSI
/* (C) Copr. 1986-92 Numerical Recipes Software sO>$1"n26@129. */


/*bestradfind01: given an input psf image, center, minumum and maximum
radii, and radius step size, finds the photometric brightness of the
psf at all radii between minrad and maxrad, with resolution steprad,
and returns in bestrad the radius that maximizes the ratio of integrated
light to the square root of the number of pixels.  This is the optimal radius
for background-limited detection of sources with the given psf, provided
the background noise is gaussian.  This is because the uncertainty
due to gaussian noise in a given aperture scales as the square root
of the number of pixels.  Thus the aperture radius that has the highest ratio of
flux(r)/n^(1/2) for a given psf gives the highest signal-to-noise.  Bestradfind01
will also return in fluxrat the ratio of the flux within the
aperture at the optimal aperture to the flux within the aperture
at the maximum aperture.  If the maximum aperture is chosen so
as to include practically all the light, this will give a good
indication of the efficiency of the given aperture.  If skysubyes
is one, uses sky subtraction with the inner and outer radii
given in skyrads*/
int bestradfind01(float **psfim,int nx,int ny,float *cen,float minrad,float maxrad,float steprad,float *bestrad,float *fluxrat,int skysubyes,float *skyrads)
{
  int i,j,k,l,bhs;
  float rad,radbest,flux,ratio,bestratio;
  float bestflux,highflux,numin,radius;

  bestratio = 0.0;

  for(rad=minrad;rad<=maxrad;rad+=steprad)
    {
      rphot01(psfim,nx,ny,cen,skyrads,skysubyes,1,rad,&flux);

      bhs = rad + 3.0;
      numin = 0.0;
      i = j = 100;
      for(k=i-bhs;k<=i+bhs;k++)
	{
	  for(l=j-bhs;l<=j+bhs;l++)
	    {
	      radius = pow(pow(1.0*l-1.0*j,2.0)+pow(1.0*i-1.0*k,2.0),0.5);
	      if(radius<=rad)
		{
		  numin+=1.0;
		}
	    }
	}

      ratio = flux/pow(numin,0.5);

      if(ratio>=bestratio)
	{
	  bestratio = ratio;
	  radbest = rad;
	  bestflux = flux;
	}
      printf("bestradfind01:\trad: %f\tflux: %f\tratio: %f\n",rad,flux,ratio);
    }

  rphot01(psfim,nx,ny,cen,skyrads,skysubyes,1,maxrad,&highflux);

  printf("best radius: %f\nbest flux: %f\nbest flux/highest flux: %f\n",radbest,bestflux,bestflux/highflux);
  *bestrad = radbest;
  *fluxrat = bestflux/highflux;

  return(1);
}


/*blockoutreg01: creat an image which is 1.0 everywhere except
on an arbitrary number of input-specified regions, which include
circnum circles, boxnum rectangular boxes, and sectornum sectors
of annuli, in which the image will be zero.  It may then be
multiplied times an existing image to block out some areas with zeros.
The boxnum x 4 matrix boxes contains the beginning x, ending x, 
beginning y, and ending y values for boxnum rectangular boxes 
that are to be set to zero.  The circnum x 3 matrix circles contains 
the x center, y center, and radius of circnum circles,within which 
all pixels are to be set to zero.  The sectornum x 6 matrix sectors 
contains the x center, y center, and inner radius, outer radius, 
minumum theta, and maximum theta of sectornum annular sectors 
within which all pixels are to be set to zero.  Theta is measured 
in degrees in the mathematical convention, counterclockwise from 
the +x axis.  If a sector that spans theta = 0 is desired, it must 
be given as two sectors, one starting at zero and another ending 
at 360.0.*/
int blockoutreg01(float **image,int nx,int ny,int boxnum,int circnum,int sectornum,int **boxes,float **circles,float **sectors)
{
  int i,j,k,cx,cy,bhw;
  float rad,theta;

  /*Initialize image with 1.0 everywhere*/
  for(i=1;i<=nx;i++)
    {
      for(j=1;j<=ny;j++)
	{
	  image[i][j] = 1.0;
	}
    }

  /*zero boxes*/
  for(k=1;k<=boxnum;k++)
    {
      /*the boxnum x 4 matrix boxes contains the
        beginning x, ending x, beginning y, and ending y
        values for boxnum rectangular boxes that are to
        be set to zero*/
      for(i=boxes[k][1];i<=boxes[k][2];i++)
	{
	  for(j=boxes[k][3];j<=boxes[k][4];j++)
	    {
	      if(i>=1&&i<=nx&&j>=1&&j<=ny)
		{
		  image[i][j] = 0.0;
		}
	    }
	}
    }

  /*zero circles.*/
  for(k=1;k<=circnum;k++)
    {
      /*The circnum x 3 matrix circles contains the
        x center, y center, and radius of circnum circles,
        within which all pixels are to be set to zero*/
      cx = circles[k][1];
      cy = circles[k][2];
      bhw = circles[k][3] + 3.0;
      for(i=cx-bhw;i<=cx+bhw;i++)
	{
	  for(j=cy-bhw;j<=cy+bhw;j++)
	    {
	      if(i>=1&&i<=nx&&j>=1&&j<=ny)
		{
		  rad = pow(pow((float)i-circles[k][1],2.0) + pow((float)j-circles[k][2],2.0),0.5);
		  if(rad<=circles[k][3])
		    {
		      image[i][j] = 0.0;
		    }
		}
	    }
	}
    }

  /*zero sectors.*/
  for(k=1;k<=sectornum;k++)
    {
      /*The sectornum x 6 matrix sectors contains the
        x center, y center, and inner radius, outer radius,
        minumum theta, and maximum theta of sectornum
        annular sectors within which all pixels are to
        be set to zero.  theta is measured in the mathematical
        convention, counterclockwise from the +x axis.  If
        a sector that spans theta = 0 is desired, it must
        be given as two sectors, one starting at zero and
        another ending at 360.0.*/
      cx = sectors[k][1];
      cy = sectors[k][2];

      bhw = sectors[k][4] + 3.0;
      for(i=cx-bhw;i<=cx+bhw;i++)
	{
	  for(j=cy-bhw;j<=cy+bhw;j++)
	    {
	      if(i>=1&&i<=nx&&j>=1&&j<=ny)
		{
		  rad = pow(pow((float)i-sectors[k][1],2.0) + pow((float)j-sectors[k][2],2.0),0.5);
		  if((float)j-sectors[k][2]>0.0)
		    {
		      theta = 90.0 - 180.0*atan(((float)i-sectors[k][1])/((float)j-sectors[k][2]))/PI;
		    }
		  else if((float)j-sectors[k][2]<0.0)
		    {
		      theta = 270.0 - 180.0*atan(((float)i-sectors[k][1])/((float)j-sectors[k][2]))/PI;
		    }
		  else if((float)j-sectors[k][2]==0.0)
		    {
		      if((float)i-sectors[k][1]>=0.0)
			{
			  theta = 0.0;
			}
		      else
			{
			  theta = 180.0;
			}
		    }
      
		  if(rad>=sectors[k][3]&&rad<=sectors[k][4]&&theta>=sectors[k][5]&&theta<=sectors[k][6])
		    {
		      image[i][j] = 0.0;
		    }
		}
	    }
	}
    }

  return(1);
}


/*baraffemint01: a program to take in an L' band
magnitude, an age in Gyr, a distance in pc, and a file of L' band
absolute magnitudes of substellar objects from Baraffe 
et al 2003.  It will first use a power law interpolation
with an exponent of pwrexp in age to find the absolute
magnitude of a range of planets at the input age.
It will then use the given distance to calculate the
absolute magnitude corresponding to the input apparent
magnitude.  It will then use linear interpolation to
find the exact mass to which the input magnitude
corresponds.  Visual investigation suggests that
the most natural curves are obtained when pwrexp is
about 0.7.  Although curves for M-band brightnesses
have not been investigated, they probably have about
the same optimal power law, and this program should
handle them equally well.  It is required that the input
file have age columns for 0.1, 0.5, 1.0, 5.0, and 10.0 Gyr,
and exactly 25 rows, with the first row containing useless
string data*/
int baraffemint01(float mag,float age,float dist,char *filename,float *outmass,float pwrexp)
{
  float *massvec,**magmat,*magvec,*agevec;
  float newmag;
  int i,j,c,jlow;
  FILE *fp1;

  /*Check for age within limits*/
  if(age<0.1)
    {
      printf("ERROR: baraffemint01 GIVEN AGE BELOW MINIMUM LIMIT!\n");
      printf("ABORTING\n");
      fflush(stdout);
      return(0);
    }
  if(age>10.0)
    {
      printf("ERROR: baraffemint01 GIVEN AGE ABOVE MAXIMUM LIMIT!\n");
      printf("ABORTING\n");
      fflush(stdout);
      return(0);
    }

  massvec = vector(1,24);
  magmat = matrix(1,5,1,24);
  magvec = vector(1,24);
  agevec = vector(1,5);

  agevec[1] = 0.1;
  agevec[2] = 0.5;
  agevec[3] = 1.0;
  agevec[4] = 5.0;
  agevec[5] = 10.0;

  fp1 = fopen(filename,"r");

  /*skip first line*/
  c = '0';
  while(c!='\n')
    {
      c = getc(fp1);
      fflush(stdout);
    }

  /*for next 24 lines, read one mass value and 5 brightness values*/
  for(i=1;i<=24;i++)
    {
      fscanf(fp1,"%f",massvec+i);
      for(j=1;j<=5;j++)
	{
	  fscanf(fp1,"%f",magmat[j]+i);
	}
    }
  fclose(fp1);

  /*Construct age-interpolated magnitude vector*/

  for(j=1;j<=4;j++)
    {
      if(age>=agevec[j]&&age<=agevec[j+1])
	{
	  jlow = j;
	}
    }

  printf("\n\n\nAGE-DEPENDENT MASS VECTOR\n");

  for(i=1;i<=24;i++)
    {
      magvec[i] = magmat[jlow][i] + (magmat[jlow+1][i]-magmat[jlow][i])*pow((age-agevec[jlow]),pwrexp)/pow((agevec[jlow+1]-agevec[jlow]),pwrexp);
      printf("%f\t%f\n",massvec[i],magvec[i]);
    }
  printf("\n\n\n");

  /*Change input apparent magnitude into an absolute magnitude*/
  newmag = mag + 2.0*log(10.0/dist)/EFOLDMAG;
  printf("mag = %f\tnewmag = %f\t",mag,newmag);

  /*Check for valid magnitude*/
  if(newmag>magvec[1]||newmag<magvec[24])
    {
      printf("ERROR: MAGNITUDE SUPPLIED TO baraffemint01 IS OUT OF RANGE!\n");
      printf("ABORTING!\n");
      fflush(stdout);
      return(0);
    }

  /*Find true mass based on input magnitude*/
  for(j=1;j<=23;j++)
    {
      if(newmag<=magvec[j]&&newmag>=magvec[j+1])
	{
	  jlow = j;
	}
    }
  *outmass = massvec[jlow] + (massvec[jlow+1]-massvec[jlow])*(newmag-magvec[jlow])/(magvec[jlow+1]-magvec[jlow]);
  printf("outmass = %f\n",*outmass);

  free_vector(massvec,1,24);
  free_matrix(magmat,1,5,1,24);
  free_vector(magvec,1,24);
  free_vector(agevec,1,5);
  return(1);
}

/*baraffemint02: The reverse process to baraffemint01.
Given distance and age of a star, and mass of an orbiting
planet, calculate the apparent L' magnitude of the planet,
using exactly the same input file of Baraffe magnitudes
as baraffemint01.  Mass is in Jupiter masses, age in
Gyr, and distance in pc.*/
int baraffemint02(float mass,float age,float dist,char *filename,float *outmag,float pwrexp)
{
  float *massvec,**magmat,*magvec,*agevec;
  float newmag;
  int i,j,c,jlow;
  FILE *fp1;

  /*Check for age within limits*/
  if(age<0.1)
    {
      printf("ERROR: baraffemint01 GIVEN AGE BELOW MINIMUM LIMIT!\n");
      printf("ABORTING\n");
      fflush(stdout);
      return(0);
    }
  if(age>10.0)
    {
      printf("ERROR: baraffemint01 GIVEN AGE ABOVE MAXIMUM LIMIT!\n");
      printf("ABORTING\n");
      fflush(stdout);
      return(0);
    }


  massvec = vector(1,24);
  magmat = matrix(1,5,1,24);
  magvec = vector(1,24);
  agevec = vector(1,5);


  agevec[1] = 0.1;
  agevec[2] = 0.5;
  agevec[3] = 1.0;
  agevec[4] = 5.0;
  agevec[5] = 10.0;


  fp1 = fopen(filename,"r");

  /*skip first line*/
  c = '0';
  while(c!='\n')
    {
      c = getc(fp1);
      fflush(stdout);
    }

  /*for next 24 lines, read one mass value and 5 brightness values*/
  for(i=1;i<=24;i++)
    {
      fscanf(fp1,"%f",massvec+i);
      for(j=1;j<=5;j++)
	{
	  fscanf(fp1,"%f",magmat[j]+i);
	}
    }
  fclose(fp1);

  /*Construct age-interpolated magnitude vector*/

  for(j=1;j<=4;j++)
    {
      if(age>=agevec[j]&&age<=agevec[j+1])
	{
	  jlow = j;
	}
    }


  for(i=1;i<=24;i++)
    {
      magvec[i] = magmat[jlow][i] + (magmat[jlow+1][i]-magmat[jlow][i])*pow((age-agevec[jlow]),pwrexp)/pow((agevec[jlow+1]-agevec[jlow]),pwrexp);
    }

  /*Change absolute magnitudes in age-dependent magnitude
    vector into apparent magnitudes at the appropriate distance.*/
  for(i=1;i<=24;i++)
    {
      magvec[i]+=2*log(dist/10.0)/EFOLDMAG;
    }

  /*Find true magnitude based on input mass*/
  jlow = 0;
  for(j=1;j<=23;j++)
    {
      if(mass>=massvec[j]&&mass<=massvec[j+1])
	{
	  jlow = j;
	}
    }
  if(jlow==0)
    {
      printf("ERROR: mass out of range.  ABORTING!\n");
      return(0);
    }
  *outmag = magvec[jlow] + (magvec[jlow+1]-magvec[jlow])*(mass-massvec[jlow])/(massvec[jlow+1]-massvec[jlow]);
  printf("outmag = %f\n",*outmag);

  free_vector(massvec,1,24);
  free_matrix(magmat,1,5,1,24);
  free_vector(magvec,1,24);
  free_vector(agevec,1,5);
  return(1);
}



/*headerpatch01: patches fits headers that were made by
Clio with Query AO off when it should have been on. 
Such headers do not contain the UT keyword that is
needed by legolas04.c to run properly.  They do, however,
contain a DATE keyword that usually has the correct
UT to sufficient precision for proper parallactic rotation.
headerpatch reads the DATE keyword and uses the time given
there, plus a fudge value, to reconstruct a UT entry that
is just the minimum needed to get legolas04 to run.
utfudge is a 3-element integer vector supposed to contain
the hours, minutes, and seconds that must be added to
the DATE ut to get the correct UT.*/
int headerpatch01(char *imname,int *utfudge)
{
  fitsfile *fptr;
  int status,  nfound, anynull,ii,jj,i;
  long naxes[2];
  long npixels;
  long fpixel[2];
  float nullval,**image2;
  char dateval[800],newutstr[10];
  int nowpos,colpos,uth,utm,uts,utfound,c;
  int tensplace,onesplace;
  float ut;

  printf("headerpatch01 here OK\n");
  fflush(stdout);

  status = 0;

  /*Obtain FITS file pointer*/
  if(fits_open_file(&fptr,imname,READWRITE, &status))
    {
       fits_report_error(stderr, status); /* print error report */
      printf("headerpatch error on fits open\n");
      fflush(stdout);
       exit( status );    /* terminate the program, returning error status */
    }

  printf("Opened fits file in headerpatch01 OK\n");
  fflush(stdout);
  if(fits_read_card(fptr,"DATE",dateval,&status))
    {
       fits_report_error(stderr, status); /* print error report */
      printf("headerpatch01 error on fits read\n");
      fflush(stdout);
       exit( status );    /* terminate the program, returning error status */
    }

  /*find the first colon in the long string*/
  utfound = nowpos = 0;
  c = 'A';
  while(utfound == 0&&c!='\0')
    {
      c = dateval[nowpos];
      if(c==':')
	{
	  utfound = 1;
	  colpos = nowpos;
	}
      nowpos+=1;
    }

  if(c!='\0')
    {
      uth = (dateval[colpos-2]-'0')*10 + (dateval[colpos-1]-'0');
      utm = (dateval[colpos+1]-'0')*10 + (dateval[colpos+2]-'0');
      uts = (dateval[colpos+4]-'0')*10 + (dateval[colpos+5]-'0');

      uts+=utfudge[3];
      if(uts<0)
	{
	  uts+=60;
	  utm-=1;
	}
      else if(uts>=60)
	{
	  uts-=60;
	  utm+=1;
	}
      utm+=utfudge[2];
      if(utm<0)
	{
	  utm+=60;
	  uth-=1;
	}
      else if(utm>=60)
	{
	  utm-=60;
	  uth+=1;
	}
      uth+=utfudge[1];
      if(uth<0)
	{
	  uth+=24;
	}
      else if(uth>=24)
	{
	  uth-=24;
	}

      tensplace = uth/10;
      onesplace = uth - tensplace*10;
      newutstr[0] = '0'+tensplace;
      newutstr[1] = '0'+onesplace;
      newutstr[2] = ':';
      tensplace = utm/10;
      onesplace = utm - tensplace*10;
      newutstr[3] = '0'+tensplace;
      newutstr[4] = '0'+onesplace;
      newutstr[5] = ':';
      tensplace = uts/10;
      onesplace = uts - tensplace*10;
      newutstr[6] = '0'+tensplace;
      newutstr[7] = '0'+onesplace;
      newutstr[8] = '\0';

      printf("headerpatch01 finds UT = %s\n",newutstr);
      if(fits_write_key(fptr,TSTRING,"UT",newutstr,"UT fudged by headerpatch01",&status))
	{
	  fits_report_error(stderr, status); /* print error report */
	  printf("headerpatch01 error on fits write\n");
	  fflush(stdout);
	  exit( status );    /* terminate the program, returning error status */
	}
      fits_close_file(fptr,&status);
      return(1);
    }
   
  printf("ERROR: DATE KEYWORD NOT FOUND BY headerpatch01\n");

  fits_close_file(fptr,&status);
  return(0);
}

/*powerlaw01: A program to generate a random variable which is
a power law of exponent alpha, normalized bewteen min and max,
using the nrc random number function ran1.  There are no
restrictions on the value of alpha.  The random number seed
idum should be negative.*/

int powerlaw01(float alpha,float min,float max,long *idum,float *output)
{
  double norm,maxx,minx;
  double outp,alph,expon,xexpon;

  if(alpha>-1.0)
    {
      alph = alpha;
      expon = 1.0/(alph+1.0);
      xexpon = alph+1.0;
      minx = pow(min,xexpon);
      maxx = pow(max,xexpon);
      norm = maxx-minx;
      outp = pow(minx+norm*ran1(idum),expon);
    }
  else if(alpha==-1.0)
    {
      minx = log(min);
      maxx = log(max);
      norm = maxx-minx;
      outp = exp(minx + norm*ran1(idum));
    }
  else if(alpha<-1.0)
    {
      alph = alpha;
      expon = 1.0/(alph+1.0);
      xexpon = alph+1.0;
      maxx = pow(min,xexpon);
      minx = pow(max,xexpon);
      norm = maxx-minx;
      outp = pow(minx+norm*ran1(idum),expon);
    }
  else
    {
      printf("The Universe has gone mad.  ABORTING!\n");
      return(0);
    }
  *output = outp;
  return(1);
}

#define IA 16807
#define IM 2147483647
#define AM (1.0/IM)
#define IQ 127773
#define IR 2836
#define NTAB 32
#define NDIV (1+(IM-1)/NTAB)
#define EPS 1.2e-7
#define RNMX (1.0-EPS)

float ran1(long *idum)
{
	int j;
	long k;
	static long iy=0;
	static long iv[NTAB];
	float temp;

	if (*idum <= 0 || !iy) {
		if (-(*idum) < 1) *idum=1;
		else *idum = -(*idum);
		for (j=NTAB+7;j>=0;j--) {
			k=(*idum)/IQ;
			*idum=IA*(*idum-k*IQ)-IR*k;
			if (*idum < 0) *idum += IM;
			if (j < NTAB) iv[j] = *idum;
		}
		iy=iv[0];
	}
	k=(*idum)/IQ;
	*idum=IA*(*idum-k*IQ)-IR*k;
	if (*idum < 0) *idum += IM;
	j=iy/NDIV;
	iy=iv[j];
	iv[j] = *idum;
	if ((temp=AM*iy) > RNMX) return RNMX;
	else return temp;
}
#undef IA
#undef IM
#undef AM
#undef IQ
#undef IR
#undef NTAB
#undef NDIV
#undef EPS
#undef RNMX
/* (C) Copr. 1986-92 Numerical Recipes Software sO>$1"n26@129. */

/*minmaxmed01: A program to find the min,max,and median value
  of a vector given the vector itself and its length as input*/
int minmaxmed01(float *invec,int pnum,float *min,float *max, float *med)
{
  int medp;
  sort(pnum,invec);
  *min = invec[1];
  *max = invec[pnum];
  if(pnum>1)
    {
      medp = pnum/2;
      *med = invec[medp];
    }
  else
    {
      *med = invec[1];
    }
  return(1);
}


/*sharpstar01: A program to find the sharpness of a stellar
image (or any image).  An accurate center for the image is
assumed given.  The program calculates the ratio of the
integral over flux*radius^2 to the integral over flux,
within in aperture of given radius.  It converts this
ratio to a guassian sigma, assuming the image is a
radially symmetric assumption.  If the image is
dramatically non guassian, or the computed centroid
is wrong, the result will, of course, not have a
clear meaning.  However, it should in general imply
the image is very blurry, i.e. useless.  The program was
originally written for use in lucky imaging, so the
fact that for messed up images it gives very blurry
but otherwise not very meaningful values is just fine:
those images will be rejected, as they should be.
In fact, in the general case it is a good measure of
the blurriness of an image, even if the image is not
at all gaussian.  The only caveat is that the radius
of the integration aperture must be chosen so it
includes most of the object's flux.  If desired,
an annular sky mean is calculated and subtracted
from the gaussian fit.  Setting either anrad1
or anrad2 to 0.0 causes the program to assume a
sky background of zero.*/
int sharpstar01(int nx,int ny,float **image,float aprad,float *outsig,float cenx,float ceny,float anrad1,float anrad2)
{
  int bhw,i,j,cx,cy,goodap;
  float rad,skyval;
  double norm,momsum;

  bhw = aprad + 3.0;

  cx = cenx+0.5;
  cy = ceny+0.5;

  if(anrad1!=0.0&&anrad2!=0.0)
    {
      if(anrad2>=anrad1)
	{
	  skyval = annucounts01(image,nx,ny,cenx,ceny,anrad1,anrad2);
	}
      else
	{
	  printf("ERROR: the inner edge of the annulus is given as\n");
	  printf("further out than the outer edge!!\n");
	  printf("Processing will continue with sky value set to zero\n");
	  printf("but something may have gone wrong.\n");
	  skyval = 0.0;
	}
    }
  else
    {
      skyval = 0.0;
    }
  momsum = norm = 0.0;
  goodap = 1;
  for(i=cx-bhw;i<=cx+bhw;i++)
    {
      for(j=cy-bhw;j<=cy+bhw;j++)
	{
	  rad = pow(pow((float)i-cenx,2.0)+pow((float)j-ceny,2.0),0.5);
	  if(rad<=aprad)
	    {
	      if(i>=1&&i<=nx&&j>=1&&j<=ny)
		{
		  norm+=(image[i][j]-skyval);
		  momsum+=(image[i][j]-skyval)*pow(rad,2.0);
		}
	      else
		{
		  goodap = 0;
		}
	    }
	}
    }
  if(goodap==0)
    {
      printf("WARNING: PART OF THE SHARPNESS DETERMINATION\n");
      printf("APERTURE WAS OFF THE IMAGE.  PROCESSING WILL\n");
      printf("CONTINUE BUT THE SHARPNESS RESULT MAY BE BAD!\n");
    }

  *outsig = pow(0.5*momsum/norm,0.5);

  return(1);
}

/*sharpstar02: Exactly like sharpstar01, but convolves the image
with a template image before finding the sharpness.  This
is supposed to allow one to accurately evaluate the sharpness
of saturated images, and may get unsaturated ones more
accurately too.  NOTE: it is assumed that the center
of the psf on the template image is located at the exact
center of the pixel nearest cenx,ceny.*/
int sharpstar02(int nx,int ny,float **image,float **tempim,float aprad,float *outsig,float cenx,float ceny,float anrad1,float anrad2)
{
  int bhw,i,j,k,l,cx,cy,goodtrim;
  float rad,skyvalim,skyvaltemp;
  double norm;
  float **trimim,**trimtemp,**convim;

  bhw = 2*aprad + 5;

  trimim = matrix(1,2*bhw+1,1,2*bhw+1);
  trimtemp = matrix(1,2*bhw+1,1,2*bhw+1);
  convim = matrix(1,2*bhw+1,1,2*bhw+1);

  cx = cenx+0.5;
  cy = ceny+0.5;

  /*Get sky values for template and science image*/

  if(anrad1!=0.0&&anrad2!=0.0)
    {
      if(anrad2>=anrad1)
	{
	  skyvaltemp = annucounts01(tempim,nx,ny,cenx,ceny,anrad1,anrad2);
	  skyvalim = annucounts01(image,nx,ny,cenx,ceny,anrad1,anrad2);
	}
      else
	{
	  printf("ERROR: the inner edge of the annulus is given as\n");
	  printf("further out than the outer edge!!\n");
	  printf("Processing will continue with sky value set to zero\n");
	  printf("but something may have gone wrong.\n");
	  skyvaltemp = skyvalim = 0.0;
	}
    }
  else
    {
      skyvaltemp = skyvalim = 0.0;
    }

  /*Trim out subimages from the science image and the template image*/
  goodtrim = 1;
  for(i=cx-bhw;i<=cx+bhw;i++)
    {
      for(j=cy-bhw;j<=cy+bhw;j++)
	{
	  if(i>=1&&i<=nx&&j>=1&&j<=ny)
	    {
	      trimim[i-cx+bhw+1][j-cy+bhw+1] = image[i][j] - skyvalim;
	      trimtemp[i-cx+bhw+1][j-cy+bhw+1] = tempim[i][j] - skyvaltemp;
	    }
	  else
	    {
	      goodtrim=0;
	      trimim[i-cx+bhw+1][j-cy+bhw+1] = 0.0;
	      trimtemp[i-cx+bhw+1][j-cy+bhw+1] = 0.0;
	    }
	}
    }
  /*Normalize the trimmed template image*/
  norm = 0.0;
  for(i=1;i<=2*bhw+1;i++)
    {
      for(j=1;j<=2*bhw+1;j++)
	{
	  norm+=trimtemp[i][j];
	}
    }
  /*
  for(i=1;i<=2*bhw+1;i++)
    {
      for(j=1;j<=2*bhw+1;j++)
	{
	  trimtemp[i][j]/=norm;
	}
    }
  */
  if(goodtrim==0)
    {
      printf("WARNING: sharpstar02 TRIM IMAGES PARTLY OUSIDE THE\n");
      printf("INPUT IMAGE.  PROCESSING WILL CONTINUE BUT THIS MAY\n");
      printf("INDICATE A PROBLEM.\n");
    }

  for(i=1;i<=2*bhw+1;i++)
    {
      for(j=1;j<=2*bhw+1;j++)
	{
	  convim[i][j] = 0.0;
	  for(k=i-bhw;k<=i+bhw;k++)
	    {
	      for(l=j-bhw;l<=j+bhw;l++)
		{
		  if(k>=1&&k<=2*bhw+1&&l>=1&&l<=2*bhw+1)
		    {
		      convim[i][j]+=trimim[k][l]*trimtemp[k-i+bhw+1][l-j+bhw+1];
		    }
		}
	    }
	}
    }

  writeim01(2*bhw+1,2*bhw+1,"trimim01.fits",trimim);
  writeim01(2*bhw+1,2*bhw+1,"trimtemp01.fits",trimtemp);
  writeim01(2*bhw+1,2*bhw+1,"convim01.fits",convim);

  /*Call sharpstar01 on the convolved image, without sky subtraction*/
  sharpstar01(2*bhw+1,2*bhw+1,convim,aprad,outsig,cenx-(float)cx+(float)bhw+1.0,ceny-(float)cy+(float)bhw+1.0,0.0,0.0);

  free_matrix(trimim,1,2*bhw+1,1,2*bhw+1);
  free_matrix(trimtemp,1,2*bhw+1,1,2*bhw+1);
  free_matrix(convim,1,2*bhw+1,1,2*bhw+1);

  return(1);
}

/*sharpstar03: Intended to serve the same purpose as sharpstar01 and 02,
but in a very different way.  Rather than calculating a real sharpness,
simply calculates the normalized difference between the image and the
template over the radius aprad, and returns this in outsig.  What I mean
by the normalized difference is the volume between the surface defined
by the tempim psf and that defined by the image psf, when both have been
normalized to an integrated flux of 1.0.*/
int sharpstar03(int nx,int ny,float **image,float **tempim,float aprad,float *outsig,float cenx,float ceny,float anrad1,float anrad2)
{
  int bhw,i,j,cx,cy,goodap;
  float rad,skyvalim,skyvaltemp;
  double norm1,norm2,normerr;

  bhw = aprad + 3.0;

  cx = cenx+0.5;
  cy = ceny+0.5;

  /*Get sky values for template and science image*/

  if(anrad1!=0.0&&anrad2!=0.0)
    {
      if(anrad2>=anrad1)
	{
	  skyvaltemp = annucounts01(tempim,nx,ny,cenx,ceny,anrad1,anrad2);
	  skyvalim = annucounts01(image,nx,ny,cenx,ceny,anrad1,anrad2);
	}
      else
	{
	  printf("ERROR: the inner edge of the annulus is given as\n");
	  printf("further out than the outer edge!!\n");
	  printf("Processing will continue with sky value set to zero\n");
	  printf("but something may have gone wrong.\n");
	  skyvaltemp = skyvalim = 0.0;
	}
    }
  else
    {
      skyvaltemp = skyvalim = 0.0;
    }

  /*Get the image normalizations*/
  norm1 = norm2 = 0.0;
  goodap = 1;
  for(i=cx-bhw;i<=cx+bhw;i++)
    {
      for(j=cy-bhw;j<=cy+bhw;j++)
	{
	  rad = pow(pow((float)i-cenx,2.0)+pow((float)j-ceny,2.0),0.5);
	  if(rad<=aprad)
	    {
	      if(i>=1&&i<=nx&&j>=1&&j<=ny)
		{
		  norm1+=(image[i][j]-skyvalim);
		  norm2+=(tempim[i][j]-skyvaltemp);		  
		}
	      else
		{
		  goodap = 0;
		}
	    }
	}
    }
  if(goodap==0)
    {
      printf("WARNING: PART OF THE SHARPNESS DETERMINATION\n");
      printf("APERTURE WAS OFF THE IMAGE.  PROCESSING WILL\n");
      printf("CONTINUE BUT THE SHARPNESS RESULT MAY BE BAD!\n");
    }

  /*Find the error between the two images*/
  normerr = 0.0;
  for(i=cx-bhw;i<=cx+bhw;i++)
    {
      for(j=cy-bhw;j<=cy+bhw;j++)
	{
	  rad = pow(pow((float)i-cenx,2.0)+pow((float)j-ceny,2.0),0.5);
	  if(rad<=aprad)
	    {
	      if(i>=1&&i<=nx&&j>=1&&j<=ny)
		{
		  normerr+=fabs((image[i][j]-skyvalim)/norm1 - (tempim[i][j]-skyvaltemp)/norm2);
		}
	      else
		{
		  goodap = 0;
		}
	    }
	}
    }



  *outsig = normerr;

  return(1);
}



/*paprecess01: A program to take in a date and a J2000.0
celestial position, and find the difference between the 
direction from that position to the J2000.0 North
Celestial Pole, and the direction from that position to
the epoch of date North Celestial Pole.  The answer will
be output in the sense of a clockwise rotation in
degrees required to get J2000.0 North up, provided
epoch of date North is currently up.  If the answer is
negative, it will, of course, imply that a counterclockwise
rotation is needed.  Since celestial position angles
are measured North to East in sky coordinates, they
increase counterclockwise.  Thus if this program is
used to find a correction to a position of a double star
the following signs apply:  If the old position angle
is in epoch of date coordinates, the J2000.0 position
angle may be obtained by SUBTRACTING the output of this
program from the epoch of date position angle.  To convert
a J2000.0 position angle to epoch of date coordinates,
ADD the output of this program to the J2000.0 position
angle to get the epoch of date coordinates.
     The variable ndays is the number of days since
00:00 UT Jan 1 2000, rounded to the nearest integer.
Coordinates ra0 and dec0 are expected in decimal
radians.*/

int paprecess01(int ndays,double ra0,double dec0,float *thetaout)
{
  float decd,decm,decs,rah,ram,ras,dechold,rahold;
  float poledec,polera;
  int precesscon;
  double initpos[3],polepos[3],newpos[3];
  double thetar;
  float thetarad,thetadeg,thetamin,thetasec;

  /*STEP 1: FIND THE J2000.0 COORDS OF THE EPOCH
    OF DATE POLE*/

  /*precess01: Given J2000.0 RA and DEC in radians, and the 
  integer number of days it has been since 00:00 UT on 
  Jan 1, 2000.  If precesscon is 1, precesses RA and DEC 
  to the epoch of date using formulae from the 2007 
  Astronomical Almanac, and outputs these values in radians.
  If precesscon is -1, deprecesses the input ra and dec
  from the epoch of data to J2000.0.*/
  precesscon = -1;
  precess01(PI/2.0,1.0,ndays,&poledec,&polera,precesscon);

  /*Disply poledec and polera in sexegesimal form*/
  dechold = poledec*180.0/PI;
  rahold = polera*12.0/PI;
  decd = (int)dechold;
  decm = (int)(60.0*dechold - 60.0*decd);
  decs = 3600.0*dechold - 3600.0*decd - 60.0*decm; 
  rah = (int)rahold;
  ram = (int)(60.0*rahold - 60.0*rah);
  ras = 3600.0*rahold - 3600.0*rah - 60.0*ram; 

  printf("The J2000.0 coordinates of the epoch of date pole are:\n");
  printf("%f, %f, or\n",dechold,rahold);
  printf("%.0f:%.0f:%.4f, %.0f:%.0f:%.3f\n",decd,decm,decs,rah,ram,ras);

  /*STEP 2: PERFORM A POLE-SWITCH OPERATION.  A POLE
    SWITCH OPERATION IS PERFORMED *ON* A SET OF COORDINATES,
    TRANSLATING THEM *TO* A SYSTEM WITH A NEW POLE.
    THE RA OF THE OLD POLE IN THE NEW SYSTEM MUST
    ALSO BE SPECIFIED.  HERE, WE PERFORM THE POLE
    SWITCH *ON* THE J2000.0 COORDS OF THE EPOCH OF
    DATE POLE, TRANSLATING THEM *TO* A NEW COORDINATE
    SYSTEM IN WHICH THE *LOCATION OF THE TARGET OBJECT*
    IS THE NEW POLE, AND THE RA OF THE J2000.0 POLE
    IS EXACTLY ZERO.  THE RA OF THE EPOCH OF DATE
    POLE THEN GIVES THE DESIRED ROTATION.*/

  /*poleswitch01: given a double precision input vector
  containing the position in radians of a source on a 
  spherical coordinate system, another vector containing
  the position of the pole of a new coordinate system
  on the old coordinate system, calculates the position
  of the point in the new coordinate system, and outputs
  this in a third double precision vector.  The desired
  RA for the old pole in the new coordinates is also required.
  NOTE: the coords must be located in positions 1 and 2
  of the double precision vectors, following the NRC
  convention, NOT positions 0 and 1.*/
  initpos[1] = polera;
  initpos[2] = poledec;
  polepos[1] = ra0;
  polepos[2] = dec0;
  poleswitch01(initpos,polepos,newpos,0.0);
  if(newpos[1]<=PI)
    {
      thetar = newpos[1];
    }
  else
    {
      thetar = newpos[1]-2.0*PI;
    }
  thetarad = thetar;
  thetadeg = thetarad*180.0/PI;
  thetamin = thetadeg*60.0;
  thetasec = thetamin*60.0;
  printf("the required rotation is: %f radians,\n",thetarad);
  printf("%f degrees, %f arcmin, or %f arcsec.\n",thetadeg,thetamin,thetasec);
  *thetaout = thetadeg;
  return(1);
}



/*paprecess02: DOES THE SAME THING AS paprecess01,
BUT DOES IT A DIFFERENT WAY AS A CHECK.
A program to take in a date and a J2000.0
celestial position, and find the difference between the 
direction from that position to the J2000.0 North
Celestial Pole, and the direction from that position to
the epoch of date North Celestial Pole.  The answer will
be output in the sense of a clockwise rotation in
degrees required to get J2000.0 North up, provided
epoch of date North is currently up.  If the answer is
negative, it will, of course, imply that a counterclockwise
rotation is needed.  Since celestial position angles
are measured North to East in sky coordinates, they
increase counterclockwise.  Thus if this program is
used to find a correction to a position of a double star
the following signs apply:  If the old position angle
is in epoch of date coordinates, the J2000.0 position
angle may be obtained by SUBTRACTING the output of this
program from the epoch of date position angle.  To convert
a J2000.0 position angle to epoch of date coordinates,
ADD the output of this program to the J2000.0 position
angle to get the epoch of date coordinates.
     The variable ndays is the number of days since
00:00 UT Jan 1 2000, rounded to the nearest integer.
Coordinates ra0 and dec0 are expected in decimal
radians.*/

int paprecess02(int ndays,double ra0,double dec0,float *thetaout)
{
  float decd,decm,decs,rah,ram,ras,dechold,rahold;
  float poledec,polera;
  int precesscon;
  double initpos[3],polepos[3],newpos[3];
  double thetar;
  float thetarad,thetadeg,thetamin,thetasec;
  float dec1,dec2,ra1,ra2;
  double dec3,ra3;

  dec1 = dec0;
  ra1 = ra0;

  /*FIND THE EPOCH OF DATE COORDS OF THE TARGET OBJECT*/
  precesscon = 1;
  precess01(dec1,ra1,ndays,&dec2,&ra2,precesscon);

  /*STEP 1: FIND THE EPOCH OF DATE COORDS OF THE 
    J2000.0 POLE*/

  /*precess01: Given J2000.0 RA and DEC in radians, and the 
  integer number of days it has been since 00:00 UT on 
  Jan 1, 2000.  If precesscon is 1, precesses RA and DEC 
  to the epoch of date using formulae from the 2007 
  Astronomical Almanac, and outputs these values in radians.
  If precesscon is -1, deprecesses the input ra and dec
  from the epoch of data to J2000.0.*/
  precesscon = 1;
  precess01(PI/2.0,1.0,ndays,&poledec,&polera,precesscon);

  /*Disply poledec and polera in sexegesimal form*/
  dechold = poledec*180.0/PI;
  rahold = polera*12.0/PI;
  decd = (int)dechold;
  decm = (int)(60.0*dechold - 60.0*decd);
  decs = 3600.0*dechold - 3600.0*decd - 60.0*decm; 
  rah = (int)rahold;
  ram = (int)(60.0*rahold - 60.0*rah);
  ras = 3600.0*rahold - 3600.0*rah - 60.0*ram; 

  printf("The epoch of date coordinates of the J2000.0 pole are:\n");
  printf("%f, %f, or\n",dechold,rahold);
  printf("%.0f:%.0f:%.4f, %.0f:%.0f:%.3f\n",decd,decm,decs,rah,ram,ras);

  /*STEP 2: PERFORM A POLE-SWITCH OPERATION.  A POLE
    SWITCH OPERATION IS PERFORMED *ON* A SET OF COORDINATES,
    TRANSLATING THEM *TO* A SYSTEM WITH A NEW POLE.
    THE RA OF THE OLD POLE IN THE NEW SYSTEM MUST
    ALSO BE SPECIFIED.  HERE, WE PERFORM THE POLE
    SWITCH *ON* THE EPOCH OF DATE COORDS OF THE
    J2000.0 POLE, TRANSLATING THEM *TO* A NEW COORDINATE
    SYSTEM IN WHICH THE *LOCATION OF THE TARGET OBJECT*
    IS THE NEW POLE, AND THE RA OF THE EPOCH OF DATE POLE
    IS EXACTLY ZERO.  THE RA OF THE J2000.0
    POLE THEN GIVES THE DESIRED ROTATION.*/

  /*poleswitch01: given a double precision input vector
  containing the position in radians of a source on a 
  spherical coordinate system, another vector containing
  the position of the pole of a new coordinate system
  on the old coordinate system, calculates the position
  of the point in the new coordinate system, and outputs
  this in a third double precision vector.  The desired
  RA for the old pole in the new coordinates is also required.
  NOTE: the coords must be located in positions 1 and 2
  of the double precision vectors, following the NRC
  convention, NOT positions 0 and 1.*/
  initpos[1] = polera;
  initpos[2] = poledec;
  polepos[1] = ra2;
  polepos[2] = dec2;
  poleswitch01(initpos,polepos,newpos,0.0);
  if(newpos[1]<=PI)
    {
      thetar = newpos[1];
    }
  else
    {
      thetar = newpos[1]-2.0*PI;
    }
  thetar*=-1.0;
  thetarad = thetar;
  thetadeg = thetarad*180.0/PI;
  thetamin = thetadeg*60.0;
  thetasec = thetamin*60.0;
  printf("the required rotation is: %f radians,\n",thetarad);
  printf("%f degrees, %f arcmin, or %f arcsec.\n",thetadeg,thetamin,thetasec);
  *thetaout = thetadeg;
  return(1);
}

/*propermotion01: Given input J2000.0 celestial coords in
radians, and proper motion according to the Simbad
convention, milliarcseconds per year in RA and then DEC,
positive east and north, and the number of days since
00:00 UT Jan1, 2000, rounded to the nearest integer,
calculates the new J2000.0 position after proper motion.*/
int propermotion01(double ra1,double dec1,float pmra,float pmdec,int ndays,double *ra2,double *dec2)
{
  float pmpa;
  double pmpolera,pmpoledec,initpos[3],polepos[3],newpos[3];
  double oldpolera;

  /*First, calculate the celestial position angle of
    the proper motion in radians*/

  if(pmra>0.0)
    {
      pmpa = PI/2.0 - atan(pmdec/pmra);
    }
  else if(pmra<0.0)
    {
      pmpa = 3.0*PI/2.0 - atan(pmdec/pmra);
    }
  else if(pmra==0.0)
    {
      if(pmdec>=0.0)
	{
	  pmpa = 0.0;
	}
      else
	{
	  pmpa = PI;
	}
    }
  else
    {
      printf("LOGICALLY IMPOSSIBLE CASE IN propermotion01!\n");
      printf("ABORTING\n");
      return(0);
    }

  /*Next, find out what this is in RA if the pole is moved
    to the target object with the old pole at 00:00 RA.*/
  pmpolera = 2.0*PI - pmpa;

  /*Next, consider this system whose pole is the J2000.0
    location of the target object, with the J2000.0 pole 
    at 00:00 RA.  The position of the proper motioned
    target object in this coordinate system is RA = pmpolera,
    and declination = PI/2.0 - the total magnitude of
    the proper motion since J2000.0.  Find this declination*/

  pmpoledec = PI/2.0 - pow(pow((double)pmra*(double)ndays/365.2425,2.0) + pow((double)pmdec*(double)ndays/365.2425,2.0),0.5)/(1000.0*ASECPRAD);

  /*NOW: Use poleswitch01 to transform these coordinates back
    to J2000.0 coords.  The position of the J2000.0 pole in
    these coordinates is 00:00 RA, declination the same as
    the un-propermotioned declination of the target object.
    The RA of the old pole is, of course, just the
    un-propermotioned J2000.0 RA of the target object.*/

  /*poleswitch01: given a double precision input vector
  containing the position in radians of a source on a 
  spherical coordinate system, another vector containing
  the position of the pole of a new coordinate system
  on the old coordinate system, calculates the position
  of the point in the new coordinate system, and outputs
  this in a third double precision vector.  The desired
  RA for the old pole in the new coordinates is also required.
  NOTE: the coords must be located in positions 1 and 2
  of the double precision vectors, following the NRC
  convention, NOT positions 0 and 1.*/
  initpos[1] = pmpolera;
  initpos[2] = pmpoledec;
  polepos[1] = 0.0;
  polepos[2] = dec1;
  oldpolera = ra1;
  poleswitch01(initpos,polepos,newpos,oldpolera);

  *ra2 = newpos[1];
  *dec2 = newpos[2];

  return(1);
}

/*manyapphot01: A program to carry out photometry of a
list of standard stars on a list of images using many
different apertures, and output the resulting photometry
in the imnum X starnum*apnum matrix photvalmat.  The
formal (ie photon-noise limited) errors will be stored
in the matrix photerrmat.  As input, the program
requires the image dimensions nx and ny, the number
of images imnum, the number of stars starnum, the number 
of apertures apnum, the number of centroiding iterations 
itnum, a matrix starposvec of dimensions starnum X 2 
giving the positions of every star on the first image, a matrix
refposvec of length imnum X 2 giving the position of
the first star on every image, a vector apvec of length
apnum giving the radius for each photometric aperture,
a vector cenradvec of length itnum giving the radius 
for each centroiding iteration, a vector skyrads of
length 2 giving the radius of  and a file listing the 
image names, one per line.  The gain and readnoise of the
CCD are also required for the calculation of the formal
error.  The gain is expected to be in electrons/ADU,
and the readnois in electrons.*/
int manyapphot01(int nx,int ny,int imnum,int starnum,int apnum,int itnum,int **starposvec,int **refposvec,float *apvec,float *cenradvec,float *skyrads,char *imlistfile,float gain,float readnoise,float **photvalmat,float **photerrmat)
{
  FILE *fp1;
  char imname[NML];
  float **offsetmat,**image,prix,priy;
  int creepmeanyes,skysubyes,i,j,k;
  float *outcoords,**imstarpos,*skyvec,data1;
  int *incoords;
  float skyerr,skynoise,rnnoise,photnoise;
  float nphotpix,nskypix;


  image = matrix(1,nx,1,ny);
  offsetmat = matrix(1,starnum,1,2);
  /*offsetmat will hold the floating point offsets of each star
    from the first reference star*/
  outcoords = vector(1,2);
  incoords = ivector(1,2);
  /*imstarpos will hold the exact coords of each
    star on a given image*/
  imstarpos = matrix(1,starnum,1,2);
  skyvec = vector(1,starnum);

  /*Read the first image name from the image list file*/
  fp1 = fopen(imlistfile,"r");
  fscanf(fp1,"%s",imname);
  printf("The first image is called %s\n",imname);
  fclose(fp1);

  /*Read this image into a matrix*/
  readim01(nx,ny,imname,image);

  /*Get coords for primary reference star on image 1*/
  skysubyes = creepmeanyes = 1;
  rcentroid01(image,nx,ny,starposvec[1],cenradvec,outcoords,itnum,skyrads,skysubyes,creepmeanyes);
  prix = outcoords[1];
  priy = outcoords[2];
  offsetmat[1][1] = offsetmat[1][2] = 0.0;

  for(i=2;i<=starnum;i++)
    {
      /*Get the coordinates of star i on image 1*/
      skysubyes = creepmeanyes = 1;
      rcentroid01(image,nx,ny,starposvec[i],cenradvec,outcoords,itnum,skyrads,skysubyes,creepmeanyes);

      /*Find the offset of star i from star 1, the
        primary reference star.*/
      offsetmat[i][1] = outcoords[1] - prix;
      offsetmat[i][2] = outcoords[2] - priy;
    }

  /*Go through all the images and do photometry*/
  fp1 = fopen(imlistfile,"r");
  for(i=1;i<=imnum;i++)
    {
      fscanf(fp1,"%s",imname);
      printf("Image %d is called %s\n",i,imname);
      readim01(nx,ny,imname,image);

      /*Get the coords of the primary reference star
        on this image.*/
      skysubyes = creepmeanyes = 1;
      rcentroid01(image,nx,ny,refposvec[i],cenradvec,imstarpos[1],itnum,skyrads,skysubyes,creepmeanyes);
      /*imstarpos[1] now holds the coords of the primary reference
        star on this image*/
      for(j=2;j<=starnum;j++)
	{
	  /*Use the primary reference star coords and the
	    offset matrix to get approx coords for star j*/
	  incoords[1] = imstarpos[1][1]+offsetmat[j][1];
	  incoords[2] = imstarpos[1][2]+offsetmat[j][2];
	  /*Use these approx coords with rcentroid01 to get
            exact coords.  The exact coords for star j will
            be stored in imstarpos[j]*/
	  skysubyes = creepmeanyes = 1;
	  rcentroid01(image,nx,ny,incoords,cenradvec,imstarpos[j],itnum,skyrads,skysubyes,creepmeanyes);
	}
      /*Get the sky brightness around each star*/
      for(j=1;j<=starnum;j++)
	{
	  skyfind02(image,nx,ny,skyrads,skyvec+j,&data1,imstarpos[j]);
	}
      /*Get the photometry and photometric uncertainty for
        every star and every aperture on this image*/
      for(j=1;j<=starnum;j++)
	{
	  for(k=1;k<=apnum;k++)
	    {
	      skysubyes = creepmeanyes = 1;
	      rphot01(image,nx,ny,imstarpos[j],skyrads,skysubyes,creepmeanyes,apvec[k],&data1);
	      photvalmat[i][(j-1)*apnum+k] = data1;
	      /*Now get the errors.  First, photon noise from the star*/
	      /*skyerr,skynoise,rnnoise,photnoise*/
	      photnoise = pow(data1/gain,0.5);
	      /*second, error on the sky background*/
	      /*This calculation will include both readnoise
                and the fact that half the sky pixels have
                been rejected in the creeping mean*/
	      nskypix = 0.5*PI*(pow(skyrads[2],2.0) - pow(skyrads[1],2.0));
	      skyerr = pow((skyvec[j]+pow(readnoise,2.0)/gain)/(gain*nskypix),0.5);
	      /*This skyerr is now the error on the average sky
                value output by skyfind02.*/
	      /*Now, the skynoise.  This is noise from the
                sky background that gets included in the photometric
                aperture.*/
	      nphotpix = PI*pow(apvec[k],2.0);
	      skynoise = pow(skyvec[j]*nphotpix/gain,0.5);
	      /*Finally, the readnoise within the photometry aperture*/
	      rnnoise = readnoise*pow(nphotpix,0.5)/gain;
	      /*The final photometric error is simply the sum
                in quadrature of all of these terms*/
	      photerrmat[i][(j-1)*apnum+k] = pow(pow(photnoise,2.0)+pow(skyerr*nphotpix,2.)+pow(skynoise,2.0)+pow(rnnoise,2.0),0.5);
	    }
	}
    }
  fclose(fp1);


  free_matrix(image,1,nx,1,ny);
  free_matrix(offsetmat,1,starnum,1,2);
  free_vector(outcoords,1,2);
  free_ivector(incoords,1,2);
  free_matrix(imstarpos,1,starnum,1,2);
  free_vector(skyvec,1,starnum);

  return(1);
}





/*manyapmtarg01: like manyapphot01, but expects only
a single object, possibly a moving target like an asteroid
or Kuiper belt object*/
int manyapmtarg01(int nx,int ny,int imnum,int apnum,int itnum,int **targposvec,float *apvec,float *cenradvec,float *skyrads,char *imlistfile,float gain,float readnoise,float **targphotmat,float **targerrmat)
{
  FILE *fp1;
  char imname[NML];
  float **image;
  int creepmeanyes,skysubyes,i,k;
  float *outcoords,skyval,data1;
  int *incoords;
  float skyerr,skynoise,rnnoise,photnoise;
  float nphotpix,nskypix;


  image = matrix(1,nx,1,ny);
  outcoords = vector(1,2);
  incoords = ivector(1,2);

  /*Go through all the images and do photometry*/
  fp1 = fopen(imlistfile,"r");
  for(i=1;i<=imnum;i++)
    {
      fscanf(fp1,"%s",imname);
      printf("Image %d is called %s\n",i,imname);
      readim01(nx,ny,imname,image);

      /*Get the exact coords of the target on this image.*/
      skysubyes = creepmeanyes = 1;
      rcentroid01(image,nx,ny,targposvec[i],cenradvec,outcoords,itnum,skyrads,skysubyes,creepmeanyes);
      /*Get the sky brightness around the target.*/
      skyfind02(image,nx,ny,skyrads,&skyval,&data1,outcoords);

      /*Get the photometry and photometric uncertainty for
        the target for every image.*/
      for(k=1;k<=apnum;k++)
	{
	  skysubyes = creepmeanyes = 1;
	  rphot01(image,nx,ny,outcoords,skyrads,skysubyes,creepmeanyes,apvec[k],&data1);
	  targphotmat[i][k] = data1;
	  /*Now get the errors.  First, photon noise from the star*/
	  /*skyerr,skynoise,rnnoise,photnoise*/
	  photnoise = pow(data1/gain,0.5);
	  /*second, error on the sky background*/
	  /*This calculation will include both readnoise
            and the fact that half the sky pixels have
            been rejected in the creeping mean*/
	  nskypix = 0.5*PI*(pow(skyrads[2],2.0) - pow(skyrads[1],2.0));
	  skyerr = pow((skyval+pow(readnoise,2.0)/gain)/(gain*nskypix),0.5);
	  /*This skyerr is now the error on the average sky
            value output by skyfind02.*/
	  /*Now, the skynoise.  This is noise from the
            sky background that gets included in the photometric
            aperture.*/
	  nphotpix = PI*pow(apvec[k],2.0);
	  skynoise = pow(skyval*nphotpix/gain,0.5);
	  /*Finally, the readnoise within the photometry aperture*/
	  rnnoise = readnoise*pow(nphotpix,0.5)/gain;
	  /*The final photometric error is simply the sum
            in quadrature of all of these terms*/
	  targerrmat[i][k] = pow(pow(photnoise,2.0)+pow(skyerr*nphotpix,2.)+pow(skynoise,2.0)+pow(rnnoise,2.0),0.5);
	}
    }
  fclose(fp1);

  free_matrix(image,1,nx,1,ny);
  free_vector(outcoords,1,2);
  free_ivector(incoords,1,2);

  return(1);
}
