Index: trunk/psphot/src/psphotOutput.c
===================================================================
--- trunk/psphot/src/psphotOutput.c	(revision 5986)
+++ trunk/psphot/src/psphotOutput.c	(revision 5993)
@@ -14,7 +14,11 @@
 
     if (residImage != NULL) psphotSaveImage (imdata->header, imdata->image, residImage);
-    if (psfFile != NULL) psphotWritePSF (psf, psfFile);
     psphotSamplePSFs (config, psf, imdata->image);
 
+    if (psfFile != NULL) {
+	psMetadata *psfData = pmPSFtoMD (NULL, psf);
+	psMetadataConfigWrite (psfData, psfFile);
+	psFree (psfData);
+    }
     if (outputFile == NULL) {
 	psLogMsg ("output", 3, "no data output file selected");
@@ -166,21 +170,8 @@
     float ZERO_POINT = psMetadataLookupF32 (&status, config, "ZERO_POINT");
     if (!status) ZERO_POINT = 25.0;
-    char *PHOTCODE = psMetadataLookupPtr (&status, config, "PHOTCODE");
 
     // write necessary information to output header
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "NSTARS",   PS_DATA_S32 | PS_META_REPLACE, "NUMBER OF STARS",     sources->n);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "ZERO_PT",  PS_DATA_F32 | PS_META_REPLACE, "zero point",          ZERO_POINT);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   psf->ApResid);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", psf->dApResid);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "ap residual scatter", psf->nApResid);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "NPSFSTAR", PS_DATA_S32 | PS_META_REPLACE, "ap residual scatter", psf->nPSFstars);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "SKYBIAS",  PS_DATA_F32 | PS_META_REPLACE, "aperture sky bias",   psf->skyBias);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "SKYSAT",   PS_DATA_F32 | PS_META_REPLACE, "aperture sky bias",   psf->skySat);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "PHOTCODE", PS_DATA_STRING | PS_META_REPLACE, "photometry code",     PHOTCODE);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "FWHM_X",   PS_DATA_F32 | PS_META_REPLACE, "PSF FWHM X",          0.0);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "FWHM_Y",   PS_DATA_F32 | PS_META_REPLACE, "PSF FWHM Y",          0.0);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "ANGLE",    PS_DATA_F32 | PS_META_REPLACE, "PSF ANGLE",           0.0);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "FSATUR",   PS_DATA_F32 | PS_META_REPLACE, "SATURATION MAG",      0.0);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "FLIMIT",   PS_DATA_F32 | PS_META_REPLACE, "COMPLETENESS MAG",    0.0);
+    psphotUpdateHeader (imdata->header, config);
+    psMetadataAdd (imdata->header, PS_LIST_TAIL, "NSTARS",   PS_DATA_S32 | PS_META_REPLACE, "NUMBER OF STARS", sources->n);
 
     // create file, write-out header
@@ -227,9 +218,9 @@
 	psLineAdd (line, "%2d ",   type);
 	psLineAdd (line, "%3.1f ", lsky);
-	psLineAdd (line, "%6.3f ", 99.999);    // should be 'Mgal
+	psLineAdd (line, "%6.3f ", 99.999); // should be 'Mgal
 	psLineAdd (line, "%6.3f ", PS_MIN (99.999, source->apMag + ZERO_POINT)); 
-	psLineAdd (line, "%6.2f ", PAR[4]);  // should be 'FHWM x'
-	psLineAdd (line, "%6.2f ", PAR[5]);  // should be 'FHWM y'
-	psLineAdd (line, "%5.1f\n", 0);   // should be theta
+	psLineAdd (line, "%6.2f ", PAR[4]); // should be 'FHWM x'
+	psLineAdd (line, "%6.2f ", PAR[5]); // should be 'FHWM y'
+	psLineAdd (line, "%5.1f\n", 0);	// should be theta
 	fwrite (line->line, 1, line->Nline, f);
     }
@@ -256,23 +247,7 @@
     float RADIUS = psMetadataLookupF32 (&status, config, "AP_RADIUS");
     float ZERO_POINT = psMetadataLookupF32 (&status, config, "ZERO_POINT");
-    char *PHOTCODE = psMetadataLookupPtr (&status, config, "PHOTCODE");
 
     // write necessary information to output header
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "NSTARS",   PS_DATA_S32 | PS_META_REPLACE, "NUMBER OF STARS",     sources->n);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "ZERO_PT",  PS_DATA_F32 | PS_META_REPLACE, "zero point",          ZERO_POINT);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   psf->ApResid);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "dAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", psf->dApResid);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "SKYBIAS",  PS_DATA_F32 | PS_META_REPLACE, "aperture sky bias",   psf->skyBias);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "PHOTCODE", PS_DATA_STRING | PS_META_REPLACE, "photometry code",     PHOTCODE);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "FWHM_X",   PS_DATA_F32 | PS_META_REPLACE, "PSF FWHM X",          0.0);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "FWHM_Y",   PS_DATA_F32 | PS_META_REPLACE, "PSF FWHM Y",          0.0);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "ANGLE",    PS_DATA_F32 | PS_META_REPLACE, "PSF ANGLE",           0.0);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "FSATUR",   PS_DATA_F32 | PS_META_REPLACE, "SATURATION MAG",      0.0);
-    psMetadataAdd (imdata->header, PS_LIST_TAIL, "FLIMIT",   PS_DATA_F32 | PS_META_REPLACE, "COMPLETENESS MAG",    0.0);
-
-    // set NAXIS to 0
-    mdi = psMetadataLookup (imdata->header, "NAXIS");
-    mdi->data.S32 = 0;
-    mdi->type = PS_DATA_S32;
+    psphotUpdateHeader (imdata->header, config);
 
     table = psArrayAlloc (sources->n);
@@ -299,10 +274,10 @@
 	psMetadataAdd (row, PS_LIST_TAIL, "MAG_GAL", PS_DATA_F32, "", type);
 	psMetadataAdd (row, PS_LIST_TAIL, "MAG_AP",  PS_DATA_F32, "", lsky);
-	psMetadataAdd (row, PS_LIST_TAIL, "LOG_SKY", PS_DATA_F32, "", 32.0);    // should be 'Mgal'
+	psMetadataAdd (row, PS_LIST_TAIL, "LOG_SKY", PS_DATA_F32, "", 32.0);
 	psMetadataAdd (row, PS_LIST_TAIL, "FWHM_X",  PS_DATA_F32, "", source->apMag + ZERO_POINT); 
-	psMetadataAdd (row, PS_LIST_TAIL, "FWHM_Y",  PS_DATA_F32, "", PAR[4]);  // should be 'FHWM x'
-	psMetadataAdd (row, PS_LIST_TAIL, "THETA",   PS_DATA_F32, "", PAR[5]);  // should be 'FHWM y'
-	psMetadataAdd (row, PS_LIST_TAIL, "DOPHOT",  PS_TYPE_S32, "", 0);   // should be theta
-	// psMetadataAdd (header, PS_LIST_HEAD, "DUMMY",   PS_DATA_STRING, "", NULL);
+	psMetadataAdd (row, PS_LIST_TAIL, "FWHM_Y",  PS_DATA_F32, "", PAR[4]);
+	psMetadataAdd (row, PS_LIST_TAIL, "THETA",   PS_DATA_F32, "", PAR[5]);
+	psMetadataAdd (row, PS_LIST_TAIL, "DOPHOT",  PS_DATA_STRING, "", "0");
+	psMetadataAdd (row, PS_LIST_TAIL, "DUMMY",   PS_DATA_STRING, "", "123");
     
 	psArrayAdd (table, 100, row);
@@ -310,28 +285,21 @@
     }
 
-    // psAbort ("psphotOutput", "FITS table output not finished");
-
-    // psImage *image = psImageAlloc (1, 1, PS_TYPE_F32);
-    // XXX missing: theader = psFitsHeaderFromTable (NULL, table, "SMPFILE");
-    // psFitsWriteImage (fits, imdata->header, image, 0);
-
+    // write the correct number of sources in the header
+    psMetadataAdd (imdata->header, PS_LIST_TAIL, "NSTARS", PS_DATA_S32 | PS_META_REPLACE, "NUMBER OF STARS", table->n);
+    psMetadataAdd (imdata->header, PS_LIST_TAIL, "EXTEND", PS_DATA_BOOL | PS_META_REPLACE, "this file has extensions", true);
+
+    // set NAXIS to 0 (we don't write out the data array)
+    mdi = psMetadataLookup (imdata->header, "NAXIS");
+    mdi->data.S32 = 0;
+    mdi->type = PS_DATA_S32;
+
+    // create the basic table header
     theader = psMetadataAlloc ();
     psMetadataAdd (theader, PS_LIST_HEAD, "EXTNAME", PS_DATA_STRING, "extension name", "SMPFILE");
 
-    psImage *image;
-
-    image = psImageAlloc (512, 512, PS_DATA_F32);
-    for (int j = 0; j < 512; j++) {
-	for (int i = 0; i < 512; i++) {
-	    image->data.F32[j][i] = i;
-	}
-    }
-
+    // write out the header and table
     psFits *fits = psFitsOpen (filename, "w");
-    // psFitsWriteHeader (imdata->header, fits);
-    // psFitsWriteTable (fits, theader, table);
-
-    psFitsWriteImage (fits, NULL, image, 0);
-    psFitsWriteTable (fits, NULL, table);
+    psFitsWriteHeader (imdata->header, fits);
+    psFitsWriteTable (fits, theader, table);
     psFitsClose (fits);
 
@@ -348,6 +316,6 @@
     pmModelWritePSFs (sources, config, name, psf);
 
-    sprintf (name, "%s.flt.dat", filename);
-    pmModelWriteFLTs (sources, name);
+    sprintf (name, "%s.ext.dat", filename);
+    pmModelWriteEXTs (sources, name);
 
     sprintf (name, "%s.nul.dat", filename);
@@ -417,5 +385,5 @@
 
 // dump the sources to an output file
-bool pmModelWriteFLTs (psArray *sources, char *filename) {
+bool pmModelWriteEXTs (psArray *sources, char *filename) {
 
     double dPos, dMag;
@@ -427,5 +395,5 @@
     f = fopen (filename, "w");
     if (f == NULL) {
-	psLogMsg ("pmModelWriteFLTs", 3, "can't open output file for moments%s\n", filename);
+	psLogMsg ("pmModelWriteEXTs", 3, "can't open output file for moments%s\n", filename);
 	return false;
     }
@@ -435,5 +403,5 @@
 	pmSource *source = (pmSource *) sources->data[i];
 
-	if (source->type != PM_SOURCE_GALAXY) continue;
+	if (source->type != PM_SOURCE_EXTENDED) continue;
 	model = pmSourceMagnitudes (source, NULL, 0.0);
 	if (model == NULL) continue;
@@ -491,7 +459,7 @@
 	source = sources->data[i];
 
-	// skip these sources (in PSF or FLT)
+	// skip these sources (in PSF or EXT)
 	if (source->type == PM_SOURCE_STAR) continue;
-	if (source->type == PM_SOURCE_GALAXY) continue;
+	if (source->type == PM_SOURCE_EXTENDED) continue;
 	    
 	if (source->moments == NULL) {
@@ -580,5 +548,5 @@
 	return (1);
 
-      case PM_SOURCE_GALAXY:
+      case PM_SOURCE_EXTENDED:
 	return (2);
 
@@ -597,5 +565,5 @@
 }
 
-psImage *pmModelPSFatXY (psImage *image, pmModel *modelFLT, pmPSF *psf, int x, int y, int dx, int dy) {
+psImage *pmModelPSFatXY (psImage *image, pmModel *modelEXT, pmPSF *psf, int x, int y, int dx, int dy) {
 
     psRegion region = {x - dx, x + dx, y - dy, y + dy};
@@ -603,7 +571,7 @@
     psImage *sample = psImageCopy (NULL, view, PS_TYPE_F32);
     psImageInit (sample, 0);
-    modelFLT->params->data.F32[2] = x;
-    modelFLT->params->data.F32[3] = y;
-    pmModel *modelPSF = pmModelFromPSF (modelFLT, psf);
+    modelEXT->params->data.F32[2] = x;
+    modelEXT->params->data.F32[3] = y;
+    pmModel *modelPSF = pmModelFromPSF (modelEXT, psf);
     pmSourceAddModel (sample, NULL, modelPSF, false, false);
     psFree (modelPSF);
@@ -625,300 +593,23 @@
     if (output[0] == 0) return false;
 
-    pmModel *modelFLT = pmModelAlloc (psf->type);
-    modelFLT->params->data.F32[0] = 0;
-    modelFLT->params->data.F32[1] = 1;
+    pmModel *modelEXT = pmModelAlloc (psf->type);
+    modelEXT->params->data.F32[0] = 0;
+    modelEXT->params->data.F32[1] = 1;
 
     psFits *fits = psFitsOpen (output, "w");
 
-    sample = pmModelPSFatXY (image, modelFLT, psf, 25, 25, 25, 25);
+    sample = pmModelPSFatXY (image, modelEXT, psf, 25, 25, 25, 25);
     psFitsWriteImage (fits, NULL, sample, 0);
-    sample = pmModelPSFatXY (image, modelFLT, psf, image->numCols - 25, image->numRows - 25, 25, 25);
+    sample = pmModelPSFatXY (image, modelEXT, psf, image->numCols - 25, image->numRows - 25, 25, 25);
     psFitsWriteImage (fits, NULL, sample, 0);
-    sample = pmModelPSFatXY (image, modelFLT, psf, image->numCols - 25, 25, 25, 25);
+    sample = pmModelPSFatXY (image, modelEXT, psf, image->numCols - 25, 25, 25, 25);
     psFitsWriteImage (fits, NULL, sample, 0);
-    sample = pmModelPSFatXY (image, modelFLT, psf, 25, image->numRows - 25, 25, 25);
+    sample = pmModelPSFatXY (image, modelEXT, psf, 25, image->numRows - 25, 25, 25);
     psFitsWriteImage (fits, NULL, sample, 0);
-    sample = pmModelPSFatXY (image, modelFLT, psf, image->numCols / 2, image->numRows / 2, 25, 25);
+    sample = pmModelPSFatXY (image, modelEXT, psf, image->numCols / 2, image->numRows / 2, 25, 25);
     psFitsWriteImage (fits, NULL, sample, 0);
 
     psFitsClose (fits);
     return (TRUE);
-}
-
-psPolynomial2D *psPolynomial2DfromMD (psMetadata *folder) {
-
-    bool status;
-    char keyword[80];
-
-    // get polynomial orders
-    // XXX add status failures tests
-    int nXorder = psMetadataLookupS32 (&status, folder, "NORDER_X");
-    int nYorder = psMetadataLookupS32 (&status, folder, "NORDER_Y");
-
-    psPolynomial2D *poly = psPolynomial2DAlloc (nXorder, nYorder, PS_POLYNOMIAL_ORD);
-
-    for (int nx = 0; nx < poly->nX + 1; nx++) {
-	for (int ny = 0; ny < poly->nY + 1; ny++) {
-	    sprintf (keyword, "VAL_X%02d_Y%02d", nx, ny);
-	    poly->coeff[nx][ny] = psMetadataLookupF32 (&status, folder, keyword);
-	    if (!status) poly->mask[nx][ny] = 1;
-
-	    sprintf (keyword, "ERR_X%02d_Y%02d", nx, ny);
-	    poly->coeffErr[nx][ny] = psMetadataLookupF32 (&status, folder, keyword);
-	}
-    }
-    return (poly);
-}
-
-psPolynomial3D *psPolynomial3DfromMD (psMetadata *folder) {
-
-    bool status;
-    char keyword[80];
-
-    // get polynomial orders
-    // XXX add status failures tests
-    int nXorder = psMetadataLookupS32 (&status, folder, "NORDER_X");
-    int nYorder = psMetadataLookupS32 (&status, folder, "NORDER_Y");
-    int nZorder = psMetadataLookupS32 (&status, folder, "NORDER_Z");
-
-    psPolynomial3D *poly = psPolynomial3DAlloc (nXorder, nYorder, nZorder, PS_POLYNOMIAL_ORD);
-
-    for (int nx = 0; nx < poly->nX + 1; nx++) {
-	for (int ny = 0; ny < poly->nY + 1; ny++) {
-	    for (int nz = 0; nz < poly->nZ + 1; nz++) {
-		sprintf (keyword, "VAL_X%02d_Y%02d_Z%02d", nx, ny, nz);
-		poly->coeff[nx][ny][nz] = psMetadataLookupF32 (&status, folder, keyword);
-		if (!status) poly->mask[nx][ny][nz] = 1;
-
-		sprintf (keyword, "ERR_X%02d_Y%02d_Z%02d", nx, ny, nz);
-		poly->coeffErr[nx][ny][nz] = psMetadataLookupF32 (&status, folder, keyword);
-	    }
-	}
-    }
-    return (poly);
-}
-
-psPolynomial4D *psPolynomial4DfromMD (psMetadata *folder) {
-
-    bool status;
-    char keyword[80];
-
-    // get polynomial orders
-    // XXX add status failures tests
-    int nXorder = psMetadataLookupS32 (&status, folder, "NORDER_X");
-    int nYorder = psMetadataLookupS32 (&status, folder, "NORDER_Y");
-    int nZorder = psMetadataLookupS32 (&status, folder, "NORDER_Z");
-    int nTorder = psMetadataLookupS32 (&status, folder, "NORDER_T");
-
-    psPolynomial4D *poly = psPolynomial4DAlloc (nXorder, nYorder, nZorder, nTorder, PS_POLYNOMIAL_ORD);
-
-    for (int nx = 0; nx < poly->nX + 1; nx++) {
-	for (int ny = 0; ny < poly->nY + 1; ny++) {
-	    for (int nz = 0; nz < poly->nZ + 1; nz++) {
-		for (int nt = 0; nt < poly->nT + 1; nt++) {
-		    sprintf (keyword, "VAL_X%02d_Y%02d_Z%02d_T%02d", nx, ny, nz, nt);
-		    poly->coeff[nx][ny][nz][nt] = psMetadataLookupF32 (&status, folder, keyword);
-		    if (!status) poly->mask[nx][ny][nz][nt] = 1;
-		    
-		    sprintf (keyword, "ERR_X%02d_Y%02d_Z%02d_T%02d", nx, ny, nz, nt);
-		    poly->coeffErr[nx][ny][nz][nt] = psMetadataLookupF32 (&status, folder, keyword);
-		}
-	    }
-	}
-    }
-    return (poly);
-}
-
-// XXX : these may need F64, or %g format for output
-bool psPolynomial2DtoMD (psMetadata *md, psPolynomial2D *poly, char *format, ...) {
-
-    int Nbyte;
-    char tmp;
-    char *root;
-    va_list argp;  
-
-    va_start (argp, format);
-    Nbyte = vsnprintf (&tmp, 0, format, argp);
-    va_end (argp);
-
-    if (!Nbyte) return false;
-
-    va_start (argp, format);
-    root = (char *) psAlloc (Nbyte + 1);
-    memset (root, 0, Nbyte + 1);
-    vsnprintf (root, Nbyte + 1, format, argp);
-    va_end (argp);
-
-    psMetadata *folder = psMetadataAlloc ();
-    psMetadataAdd (md, PS_LIST_TAIL, root, PS_DATA_METADATA, "folder for 2D polynomial", folder);
-    psFree (root);
-
-    // specify the polynomial orders
-    psMetadataAdd (folder, PS_LIST_TAIL, "NORDER_X", PS_DATA_S32, "number of x orders", poly->nX);
-    psMetadataAdd (folder, PS_LIST_TAIL, "NORDER_Y", PS_DATA_S32, "number of y orders", poly->nY);
-
-    // place polynomial entries on folder
-    for (int nx = 0; nx < poly->nX + 1; nx++) {
-	for (int ny = 0; ny < poly->nY + 1; ny++) {
-	    if (poly->mask[nx][ny]) continue;
-	    psMetadataAdd (folder, PS_LIST_TAIL, "VAL_X%02d_Y%02d", PS_DATA_F32, "polynomial coefficient", poly->coeff[nx][ny], nx, ny);
-	    psMetadataAdd (folder, PS_LIST_TAIL, "ERR_X%02d_Y%02d", PS_DATA_F32, "polynomial coefficient error", poly->coeffErr[nx][ny], nx, ny);
-	}
-    }
-    return true;
-}
-
-bool psPolynomial3DtoMD (psMetadata *md, psPolynomial3D *poly, char *format, ...) {
-
-    int Nbyte;
-    char tmp;
-    char *root;
-    va_list argp;  
-
-    va_start (argp, format);
-    Nbyte = vsnprintf (&tmp, 0, format, argp);
-    va_end (argp);
-
-    if (!Nbyte) return false;
-
-    va_start (argp, format);
-    root = (char *) psAlloc (Nbyte + 1);
-    memset (root, 0, Nbyte + 1);
-    vsnprintf (root, Nbyte + 1, format, argp);
-    va_end (argp);
-
-    psMetadata *folder = psMetadataAlloc ();
-    psMetadataAdd (md, PS_LIST_TAIL, root, PS_DATA_METADATA, "folder for 3D polynomial", folder);
-    psFree (root);
-
-    // specify the polynomial orders
-    psMetadataAdd (folder, PS_LIST_TAIL, "NORDER_X", PS_DATA_S32, "number of x orders", poly->nX);
-    psMetadataAdd (folder, PS_LIST_TAIL, "NORDER_Y", PS_DATA_S32, "number of y orders", poly->nY);
-    psMetadataAdd (folder, PS_LIST_TAIL, "NORDER_Z", PS_DATA_S32, "number of z orders", poly->nZ);
-
-    // place polynomial entries on folder
-    for (int nx = 0; nx < poly->nX + 1; nx++) {
-	for (int ny = 0; ny < poly->nY + 1; ny++) {
-	    for (int nz = 0; nz < poly->nZ + 1; nz++) {
-		if (poly->mask[nx][ny][nz]) continue;
-		psMetadataAdd (folder, PS_LIST_TAIL, "VAL_X%02d_Y%02d_Z%02d", PS_DATA_F32, "polynomial coefficient", poly->coeff[nx][ny][nz], nx, ny, nz);
-		psMetadataAdd (folder, PS_LIST_TAIL, "ERR_X%02d_Y%02d_Z%02d", PS_DATA_F32, "polynomial coeffficient error", poly->coeffErr[nx][ny][nz], nx, ny, nz);
-	    }
-	}
-    }
-    return true;
-}
-
-bool psPolynomial4DtoMD (psMetadata *md, psPolynomial4D *poly, char *format, ...) {
-
-    int Nbyte;
-    char tmp;
-    char *root;
-    va_list argp;  
-
-    va_start (argp, format);
-    Nbyte = vsnprintf (&tmp, 0, format, argp);
-    va_end (argp);
-
-    if (!Nbyte) return false;
-
-    va_start (argp, format);
-    root = (char *) psAlloc (Nbyte + 1);
-    memset (root, 0, Nbyte + 1);
-    vsnprintf (root, Nbyte + 1, format, argp);
-    va_end (argp);
-
-    psMetadata *folder = psMetadataAlloc ();
-    psMetadataAdd (md, PS_LIST_TAIL, root, PS_DATA_METADATA, "folder for 4D polynomial", folder);
-    psFree (root);
-
-    // specify the polynomial orders
-    psMetadataAdd (folder, PS_LIST_TAIL, "NORDER_X", PS_DATA_S32, "number of x orders", poly->nX);
-    psMetadataAdd (folder, PS_LIST_TAIL, "NORDER_Y", PS_DATA_S32, "number of y orders", poly->nY);
-    psMetadataAdd (folder, PS_LIST_TAIL, "NORDER_Z", PS_DATA_S32, "number of z orders", poly->nZ);
-    psMetadataAdd (folder, PS_LIST_TAIL, "NORDER_T", PS_DATA_S32, "number of z orders", poly->nT);
-
-    // place polynomial entries on folder
-    for (int nx = 0; nx < poly->nX + 1; nx++) {
-	for (int ny = 0; ny < poly->nY + 1; ny++) {
-	    for (int nz = 0; nz < poly->nZ + 1; nz++) {
-		for (int nt = 0; nt < poly->nT + 1; nt++) {
-		    if (poly->mask[nx][ny][nz][nt]) continue;
-		    psMetadataAdd (folder, PS_LIST_TAIL, "VAL_X%02d_Y%02d_Z%02d_T%02d", PS_DATA_F32, "polynomial coefficient", poly->coeff[nx][ny][nz][nt], nx, ny, nz, nt);
-		    psMetadataAdd (folder, PS_LIST_TAIL, "ERR_X%02d_Y%02d_Z%02d_T%02d", PS_DATA_F32, "polynomial coeffficient error", poly->coeffErr[nx][ny][nz][nt], nx, ny, nz, nt);
-		}
-	    }
-	}
-    }
-    return true;
-}
-
-bool psphotWritePSF (pmPSF *psf, char *filename) {
-
-    psMetadata *psfdata = psMetadataAlloc ();
-
-    char *modelName = pmModelGetType (psf->type);
-    psMetadataAdd (psfdata, PS_LIST_TAIL, "PSF_MODEL_NAME", PS_DATA_STRING, "PSF model name", modelName);
-
-    int nPar = pmModelParameterCount (psf->type)    ;
-    psMetadataAdd (psfdata, PS_LIST_TAIL, "PSF_MODEL_NPAR", PS_DATA_S32, "PSF model parameter count", nPar);
-
-    for (int i = 0; i < nPar - 4; i++) {
-	psPolynomial2D *poly = psf->params->data[i];
-	psPolynomial2DtoMD (psfdata, poly, "PSF_PAR%02d", i);
-    }
-    psPolynomial4DtoMD (psfdata, psf->ApTrend, "APTREND");
-
-    psMetadataAdd (psfdata, PS_LIST_TAIL, "PSF_AP_RESID", PS_DATA_F32, "aperture residual", psf->ApResid);
-    psMetadataAdd (psfdata, PS_LIST_TAIL, "PSF_dAP_RESID", PS_DATA_F32, "aperture residual scatter", psf->dApResid);
-    psMetadataAdd (psfdata, PS_LIST_TAIL, "PSF_SKY_BIAS", PS_DATA_F32, "sky bias level", psf->skyBias);
-
-    psMetadataAdd (psfdata, PS_LIST_TAIL, "PSF_CHISQ", PS_DATA_F32, "chi-square for fit", psf->chisq);
-    psMetadataAdd (psfdata, PS_LIST_TAIL, "PSF_NSTARS", PS_DATA_S32, "number of stars used to measure PSF", psf->nPSFstars);
-    
-    psMetadataConfigWrite (psfdata, filename);
-    psFree (psfdata);
-
-    return true;
-}
-
-pmPSF *psphotReadPSF (char *filename) {
-
-    bool status;
-    unsigned int Nfail;
-    char keyword[80];
-
-    psMetadata *psfdata = psMetadataConfigParse (NULL, &Nfail, filename, FALSE);
-
-    char *modelName = psMetadataLookupPtr (&status, psfdata, "PSF_MODEL_NAME");
-    pmModelType type = pmModelSetType (modelName);
-
-    pmPSF *psf = pmPSFAlloc (type);
-
-    int nPar = psMetadataLookupS32 (&status, psfdata, "PSF_MODEL_NPAR");
-    if (nPar != pmModelParameterCount (psf->type)) psAbort ("read PSF" , "mismatch model par count");
-
-    for (int i = 0; i < nPar - 4; i++) {
-	sprintf (keyword, "PSF_PAR%02d", i);
-	psMetadata *folder = psMetadataLookupPtr (&status, psfdata, keyword);
-	psPolynomial2D *poly = psPolynomial2DfromMD (folder);
-	psFree (psf->params->data[i]);
-	psf->params->data[i] = poly;
-    }
-    sprintf (keyword, "APTREND");
-    psMetadata *folder = psMetadataLookupPtr (&status, psfdata, keyword);
-    psPolynomial4D *poly = psPolynomial4DfromMD (folder);
-    psFree (psf->ApTrend);
-    psf->ApTrend = poly;
-
-    psf->ApResid = psMetadataLookupF32 (&status, psfdata, "PSF_AP_RESID");
-    psf->dApResid = psMetadataLookupF32 (&status, psfdata, "PSF_dAP_RESID");
-    psf->skyBias = psMetadataLookupF32 (&status, psfdata, "PSF_SKY_BIAS");
-
-    psf->chisq = psMetadataLookupF32 (&status, psfdata, "PSF_CHISQ");
-    psf->nPSFstars = psMetadataLookupS32 (&status, psfdata, "PSF_NSTARS");
-
-    psFree (psfdata);
-    return (psf);
 }
 
@@ -937,2 +628,31 @@
     return true;
 }
+
+bool psphotUpdateHeader (psMetadata *header, psMetadata *config) {
+
+    // write necessary information to output header
+    psMetadataItemTransfer (header, config, "NSTARS");
+    psMetadataItemTransfer (header, config, "ZERO_PT");
+    psMetadataItemTransfer (header, config, "APMIFIT");
+    psMetadataItemTransfer (header, config, "dAPMIFIT");
+    psMetadataItemTransfer (header, config, "SKYBIAS");
+    psMetadataItemTransfer (header, config, "PHOTCODE");
+    
+    // write necessary information to output header
+    psMetadataItemTransfer (header, config, "NPSFSTAR");
+    psMetadataItemTransfer (header, config, "SKYBIAS");
+    psMetadataItemTransfer (header, config, "SKYSAT");
+    psMetadataItemTransfer (header, config, "APMIFIT");
+    psMetadataItemTransfer (header, config, "DAPMIFIT");
+    psMetadataItemTransfer (header, config, "NAPMIFIT");
+    psMetadataItemTransfer (header, config, "APLOSS");
+
+    // XXX these need to be defined from elsewhere
+    psMetadataAdd (header, PS_LIST_TAIL, "FWHM_X",   PS_DATA_F32 | PS_META_REPLACE, "PSF FWHM X",          0.0);
+    psMetadataAdd (header, PS_LIST_TAIL, "FWHM_Y",   PS_DATA_F32 | PS_META_REPLACE, "PSF FWHM Y",          0.0);
+    psMetadataAdd (header, PS_LIST_TAIL, "ANGLE",    PS_DATA_F32 | PS_META_REPLACE, "PSF ANGLE",           0.0);
+    psMetadataAdd (header, PS_LIST_TAIL, "FSATUR",   PS_DATA_F32 | PS_META_REPLACE, "SATURATION MAG",      0.0);
+    psMetadataAdd (header, PS_LIST_TAIL, "FLIMIT",   PS_DATA_F32 | PS_META_REPLACE, "COMPLETENESS MAG",    0.0);
+
+    return true;
+}
