Index: trunk/ippconfig/gpc1/format_mef.config
===================================================================
--- trunk/ippconfig/gpc1/format_mef.config	(revision 26963)
+++ trunk/ippconfig/gpc1/format_mef.config	(revision 26964)
@@ -179,4 +179,5 @@
 	FPA.AZ		STR	AZ
 	FPA.TEMP	STR	DETTEM
+	FPA.ZP		STR	MAG_ZP
 	CHIP.ID         STR	DETECTOR
 	CELL.XBIN	STR	CCDSUM
Index: trunk/ippconfig/gpc1/format_relphot.config
===================================================================
--- trunk/ippconfig/gpc1/format_relphot.config	(revision 26963)
+++ trunk/ippconfig/gpc1/format_relphot.config	(revision 26964)
@@ -116,4 +116,5 @@
 	FPA.AZ		STR	AZ
 	FPA.TEMP	STR	DETTEM
+	FPA.ZP		STR	MAG_ZP
 	CHIP.ID         STR	DETECTOR
 	CELL.XBIN	STR	CCDSUM
Index: trunk/psModules/src/concepts/pmConcepts.c
===================================================================
--- trunk/psModules/src/concepts/pmConcepts.c	(revision 26963)
+++ trunk/psModules/src/concepts/pmConcepts.c	(revision 26964)
@@ -292,5 +292,5 @@
         conceptRegisterF32("FPA.FOCUS", "Telescope focus", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
         conceptRegisterF32("FPA.AIRMASS", "Airmass at boresight", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
-	// XXX p_pmConceptParse_FPA_FILTER -> p_pmConceptParse_FPA_FILTERID (and Format as well)?
+        // XXX p_pmConceptParse_FPA_FILTER -> p_pmConceptParse_FPA_FILTERID (and Format as well)?
         conceptRegisterStr("FPA.FILTERID", "Filter used (parsed, abstract name)", p_pmConceptParse_FPA_FILTER, p_pmConceptFormat_FPA_FILTER, NULL, false, PM_FPA_LEVEL_FPA);
         conceptRegisterStr("FPA.FILTER", "Filter used (instrument name)", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
@@ -334,7 +334,8 @@
         conceptRegisterF32("FPA.TELTEMP.EXTRA", "Telescope Temperatures: extra", p_pmConceptParse_TELTEMPS, NULL, NULL, false, PM_FPA_LEVEL_FPA);
         conceptRegisterF32("FPA.PON.TIME", "Power On Time", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
-	conceptRegisterS32("FPA.BURNTOOL.APPLIED", "[T=applied] Burn streaks applied to image data", p_pmConceptParse_BTOOLAPP,p_pmConceptFormat_BTOOLAPP,NULL,false,PM_FPA_LEVEL_FPA);
-	//	conceptRegisterBool("FPA.BURNTOOL.APPLIED", "Status of burntool processing", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterS32("FPA.BURNTOOL.APPLIED", "[T=applied] Burn streaks applied to image data", p_pmConceptParse_BTOOLAPP,p_pmConceptFormat_BTOOLAPP,NULL,false,PM_FPA_LEVEL_FPA);
+        //      conceptRegisterBool("FPA.BURNTOOL.APPLIED", "Status of burntool processing", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
         conceptRegisterF32("FPA.EXPOSURE", "Exposure time (sec)", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+        conceptRegisterF32("FPA.ZP", "Magnitude zero point", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
     }
     if (!conceptsChip) {
Index: trunk/psModules/src/concepts/pmConceptsAverage.c
===================================================================
--- trunk/psModules/src/concepts/pmConceptsAverage.c	(revision 26963)
+++ trunk/psModules/src/concepts/pmConceptsAverage.c	(revision 26964)
@@ -36,4 +36,5 @@
 
     double time      = 0.0;             // Time of observation
+    double zp        = 0.0;             // Zero point
     psTimeType timeSys = 0;             // Time system
     char *filter     = NULL;            // Filter
@@ -63,4 +64,7 @@
         psTimeConvert(fpaTime, PS_TIME_TAI);
         time       += psTimeToMJD(fpaTime);
+
+        zp += psMetadataLookupF32(NULL, fpa->concepts, "FPA.ZP");
+
         if (num == 1) {
             timeSys = psMetadataLookupS32(NULL, fpa->concepts, "FPA.TIMESYS");
@@ -85,4 +89,5 @@
 
     time /= (double)num;
+    zp /= (double)num;
 
     MD_UPDATE(target->concepts, "FPA.TIMESYS", S32, timeSys);
@@ -92,4 +97,5 @@
     MD_UPDATE_STR(target->concepts, "FPA.INSTRUMENT", instrument);
     MD_UPDATE_STR(target->concepts, "FPA.DETECTOR", detector);
+    MD_UPDATE(target->concepts, "FPA.ZP", F32, zp);
 
     // FPA.TIME needs special care
Index: trunk/psModules/src/objects/pmSourceIO_CMF_PS1_V1.c
===================================================================
--- trunk/psModules/src/objects/pmSourceIO_CMF_PS1_V1.c	(revision 26963)
+++ trunk/psModules/src/objects/pmSourceIO_CMF_PS1_V1.c	(revision 26964)
@@ -69,9 +69,12 @@
     float magOffset = NAN;
     float exptime   = psMetadataLookupF32 (&status1, fpa->concepts, "FPA.EXPOSURE");
-    float zeropt    = psMetadataLookupF32 (&status2, imageHeader, "ZPT_OBS");
-    float zeroptErr = psMetadataLookupF32 (&status2, imageHeader, "ZPT_ERR");
+    float zeropt    = psMetadataLookupF32(&status2, fpa->concepts, "FPA.ZP");
+    if (!isfinite(zeropt)) {
+        zeropt    = psMetadataLookupF32 (&status2, imageHeader, "ZPT_OBS");
+    }
     if (status1 && status2 && (exptime > 0.0)) {
         magOffset = zeropt + 2.5*log10(exptime);
     }
+    float zeroptErr = psMetadataLookupF32 (&status2, imageHeader, "ZPT_ERR");
 
     // if the sequence is defined, write these in seq order; otherwise
@@ -477,5 +480,5 @@
         }
 
-# endif	
+# endif
         psArrayAdd (table, 100, row);
         psFree (row);
Index: trunk/psModules/src/objects/pmSourceIO_CMF_PS1_V2.c
===================================================================
--- trunk/psModules/src/objects/pmSourceIO_CMF_PS1_V2.c	(revision 26963)
+++ trunk/psModules/src/objects/pmSourceIO_CMF_PS1_V2.c	(revision 26964)
@@ -69,9 +69,12 @@
     float magOffset = NAN;
     float exptime   = psMetadataLookupF32 (&status1, fpa->concepts, "FPA.EXPOSURE");
-    float zeropt    = psMetadataLookupF32 (&status2, imageHeader, "ZPT_OBS");
-    float zeroptErr = psMetadataLookupF32 (&status2, imageHeader, "ZPT_ERR");
+    float zeropt    = psMetadataLookupF32(&status2, fpa->concepts, "FPA.ZP");
+    if (!isfinite(zeropt)) {
+        zeropt    = psMetadataLookupF32 (&status2, imageHeader, "ZPT_OBS");
+    }
     if (status1 && status2 && (exptime > 0.0)) {
         magOffset = zeropt + 2.5*log10(exptime);
     }
+    float zeroptErr = psMetadataLookupF32 (&status2, imageHeader, "ZPT_ERR");
 
     // if the sequence is defined, write these in seq order; otherwise
Index: trunk/psastro/src/psastroZeroPoint.c
===================================================================
--- trunk/psastro/src/psastroZeroPoint.c	(revision 26963)
+++ trunk/psastro/src/psastroZeroPoint.c	(revision 26964)
@@ -1,5 +1,5 @@
 /** @file psastroMosaicZeroPoint.c
  *
- *  @brief 
+ *  @brief
  *
  *  @ingroup libpsastro
@@ -24,6 +24,6 @@
     psMetadata *recipe  = psMetadataLookupPtr (NULL, config->recipes, PSASTRO_RECIPE);
     if (!recipe) {
-	psError(PSASTRO_ERR_CONFIG, false, "Can't find PSASTRO recipe!\n");
-	return false;
+        psError(PSASTRO_ERR_CONFIG, false, "Can't find PSASTRO recipe!\n");
+        return false;
     }
 
@@ -34,6 +34,6 @@
     pmFPAfile *input = psMetadataLookupPtr (NULL, config->files, "PSASTRO.INPUT");
     if (!input) {
-	psError(PSASTRO_ERR_CONFIG, false, "Can't find input data!\n");
-	return false;
+        psError(PSASTRO_ERR_CONFIG, false, "Can't find input data!\n");
+        return false;
     }
     pmFPA *fpa = input->fpa;
@@ -55,6 +55,6 @@
     // really error-out here?  or just skip?
     if (!psastroZeroPointFromRecipe (&zeropt, &exptime, NULL, fpa, recipe)) {
-	psLogMsg ("psastro", PS_LOG_INFO, "failed to load zeropt data from recipe");
-	return false;
+        psLogMsg ("psastro", PS_LOG_INFO, "failed to load zeropt data from recipe");
+        return false;
     }
 
@@ -67,40 +67,43 @@
         psTrace ("psastro", 4, "Chip %d: %x %x\n", view->chip, chip->file_exists, chip->process);
         if (!chip->process || !chip->file_exists) { continue; }
-	if (!chip->toFPA) { continue; }
-
-	while ((cell = pmFPAviewNextCell (view, fpa, 1)) != NULL) {
+        if (!chip->toFPA) { continue; }
+
+        while ((cell = pmFPAviewNextCell (view, fpa, 1)) != NULL) {
             psTrace ("psastro", 4, "Cell %d: %x %x\n", view->cell, cell->file_exists, cell->process);
             if (!cell->process || !cell->file_exists) { continue; }
 
-	    // process each of the readouts
-	    // XXX there can only be one readout per chip, right?
-	    while ((readout = pmFPAviewNextReadout (view, fpa, 1)) != NULL) {
-		if (! readout->data_exists) { continue; }
-
-		// calculate dMag for the matched stars
-		dMag = psastroZeroPointReadoutAccum (dMag, readout, exptime);
-
-		if (!byExposure) {
-		    // calculate dMag for the matched stars just for this readout (well, chip)
-		    psMetadata *header = psMetadataLookupMetadata (&status, readout->analysis, "PSASTRO.HEADER");
-		    psastroZeroPointAnalysis (header, dMag, zeropt, recipe);
-		    psFree (dMag);
-		    dMag = NULL;
-		}
-	    }
-	}
+            // process each of the readouts
+            // XXX there can only be one readout per chip, right?
+            while ((readout = pmFPAviewNextReadout (view, fpa, 1)) != NULL) {
+                if (! readout->data_exists) { continue; }
+
+                // calculate dMag for the matched stars
+                dMag = psastroZeroPointReadoutAccum (dMag, readout, exptime);
+
+                if (!byExposure) {
+                    // calculate dMag for the matched stars just for this readout (well, chip)
+                    psMetadata *header = psMetadataLookupMetadata (&status, readout->analysis, "PSASTRO.HEADER");
+                    psastroZeroPointAnalysis (header, dMag, zeropt, recipe);
+                    psFree (dMag);
+                    dMag = NULL;
+                }
+            }
+        }
     }
 
     if (byExposure) {
-	psMetadata *header = psMetadataLookupMetadata (&status, fpa->analysis, "PSASTRO.HEADER");
-	if (!header) {
-	  header = psMetadataAlloc ();
-	  psMetadataAddMetadata (fpa->analysis, PS_LIST_TAIL, "PSASTRO.HEADER",  PS_META_REPLACE, "psastro header stats", header);
-	  psFree (header);
-	}
-	psastroZeroPointAnalysis (header, dMag, zeropt, recipe);
-	psFree (dMag);
-	dMag = NULL;
-    }
+        psMetadata *header = psMetadataLookupMetadata (&status, fpa->analysis, "PSASTRO.HEADER");
+        if (!header) {
+          header = psMetadataAlloc ();
+          psMetadataAddMetadata (fpa->analysis, PS_LIST_TAIL, "PSASTRO.HEADER",  PS_META_REPLACE, "psastro header stats", header);
+          psFree (header);
+        }
+        psastroZeroPointAnalysis (header, dMag, zeropt, recipe);
+        psFree (dMag);
+        dMag = NULL;
+    }
+
+    psMetadataItem *item = psMetadataLookup(fpa->concepts, "FPA.ZP");
+    item->data.F32 = zeropt;
 
     psFree (view);
@@ -127,5 +130,5 @@
 
     if (!dMag) {
-	dMag  = psVectorAllocEmpty (100, PS_TYPE_F32);
+        dMag  = psVectorAllocEmpty (100, PS_TYPE_F32);
     }
 
@@ -164,17 +167,17 @@
     psStats *stats = NULL;
     if (useMean) {
-	// stats structure and mask for use in measuring the clipping statistic
-	// this analysis has too few data points to use the robust median method
-	stats = psStatsAlloc (PS_STAT_CLIPPED_MEAN | PS_STAT_CLIPPED_STDEV);
-	if (!psVectorStats (stats, dMag, NULL, NULL, 0)) {
-	    psError(PS_ERR_UNKNOWN, false, "failure to measure zero point by mean");
-	    return false;
-	}
+        // stats structure and mask for use in measuring the clipping statistic
+        // this analysis has too few data points to use the robust median method
+        stats = psStatsAlloc (PS_STAT_CLIPPED_MEAN | PS_STAT_CLIPPED_STDEV);
+        if (!psVectorStats (stats, dMag, NULL, NULL, 0)) {
+            psError(PS_ERR_UNKNOWN, false, "failure to measure zero point by mean");
+            return false;
+        }
     } else {
-	stats = psastroStatsPercentile (dMag, recipe);
-	if (!stats) {
-	    psError(PS_ERR_UNKNOWN, false, "failure to measure zero point by edge");
-	    return false;
-	}
+        stats = psastroStatsPercentile (dMag, recipe);
+        if (!stats) {
+            psError(PS_ERR_UNKNOWN, false, "failure to measure zero point by edge");
+            return false;
+        }
     }
     fprintf (stderr, "zero point %f +/- %f using %ld stars; transparency %f\n", stats->clippedMean, stats->clippedStdev, dMag->n, zeropt - stats->clippedMean);
@@ -243,5 +246,5 @@
     // search for the 'blue' edge of the dMag distribution:
     // the distribution is not a normal population, but instead has a broad range with fairly hard edges.
-    // construct a histogram and look for the 
+    // construct a histogram and look for the
 
     bool status;
@@ -256,5 +259,5 @@
     float min = NAN, max = NAN;         // Mimimum and maximum values
 
-    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS);  
+    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS);
 
     // Get the minimum and maximum values
@@ -267,12 +270,12 @@
     // If all data points have the same value, then we set the appropriate members of stats and return.
     if (fabs(max - min) <= FLT_EPSILON) {
-	stats->clippedMean = min;
-	stats->clippedStdev = NAN;
-	stats->results |= PS_STAT_CLIPPED_MEAN;
-	stats->results |= PS_STAT_CLIPPED_STDEV;
-	return stats;
-    }
-    
-    // Define the histogram bin size.  
+        stats->clippedMean = min;
+        stats->clippedStdev = NAN;
+        stats->results |= PS_STAT_CLIPPED_MEAN;
+        stats->results |= PS_STAT_CLIPPED_STDEV;
+        return stats;
+    }
+
+    // Define the histogram bin size.
     float binSize = MAG_RESOLUTION;
     long numBins = (max - min) / binSize; // Number of bins
@@ -293,17 +296,17 @@
     float S2 = 0.0;
     for (int i = 0; i < edgeSample; i++) {
-	
-	// generate the subset vector
-	for (long i = 0; i < nSubset; i++) {
-	    double frnd = psRandomUniform(rng);
-	    int entry = PS_MIN(myVector->n - 1, PS_MAX(0, myVector->n * frnd));
-
-	    subset->data.F32[i] = myVector->data.F32[entry];
-	}
-
-	float value = psastroStatsPercentileValue (histogram, cumulative, subset, edgeFraction);
-
-	Sum += value;
-	S2 += value*value;
+
+        // generate the subset vector
+        for (long i = 0; i < nSubset; i++) {
+            double frnd = psRandomUniform(rng);
+            int entry = PS_MIN(myVector->n - 1, PS_MAX(0, myVector->n * frnd));
+
+            subset->data.F32[i] = myVector->data.F32[entry];
+        }
+
+        float value = psastroStatsPercentileValue (histogram, cumulative, subset, edgeFraction);
+
+        Sum += value;
+        S2 += value*value;
     }
     psTrace("psastro", 6, "subset stats: Sum: %f, S2: %f, Npts: %d\n", Sum, S2, edgeSample);
@@ -345,10 +348,10 @@
     psVectorInit (histogram->nums, 0);
     if (!psVectorHistogram(histogram, myVector, NULL, NULL, 0)) {
-	// if psVectorHistogram returns false, we have a programming error
-	psAbort ("Unable to generate histogram for psastroZeroPointAnalysis");
+        // if psVectorHistogram returns false, we have a programming error
+        psAbort ("Unable to generate histogram for psastroZeroPointAnalysis");
     }
     if (psTraceGetLevel("psastro") >= 8) {
-	PS_VECTOR_PRINT_F32(histogram->bounds);
-	PS_VECTOR_PRINT_F32(histogram->nums);
+        PS_VECTOR_PRINT_F32(histogram->bounds);
+        PS_VECTOR_PRINT_F32(histogram->nums);
     }
 
@@ -357,10 +360,10 @@
     cumulative->nums->data.F32[0] = histogram->nums->data.F32[0];
     for (long i = 1; i < histogram->nums->n; i++) {
-	cumulative->nums->data.F32[i] = cumulative->nums->data.F32[i-1] + histogram->nums->data.F32[i];
-	cumulative->bounds->data.F32[i-1] = histogram->bounds->data.F32[i];
+        cumulative->nums->data.F32[i] = cumulative->nums->data.F32[i-1] + histogram->nums->data.F32[i];
+        cumulative->bounds->data.F32[i-1] = histogram->bounds->data.F32[i];
     }
     if (psTraceGetLevel("psastro") >= 8) {
-	PS_VECTOR_PRINT_F32(cumulative->bounds);
-	PS_VECTOR_PRINT_F32(cumulative->nums);
+        PS_VECTOR_PRINT_F32(cumulative->bounds);
+        PS_VECTOR_PRINT_F32(cumulative->nums);
     }
 
@@ -403,36 +406,36 @@
     if (item->type != PS_DATA_METADATA_MULTI) ESCAPE ("PHOTCODE.DATA not a multi");
 
-    // PHOTCODE.DATA is a multi of metadata items 
+    // PHOTCODE.DATA is a multi of metadata items
     psListIterator *iter = psListIteratorAlloc(item->data.list, PS_LIST_HEAD, false);
 
     psMetadataItem *refItem = NULL;
     while ((refItem = psListGetAndIncrement (iter))) {
-	if (refItem->type != PS_DATA_METADATA) ESCAPE ("PHOTCODE.DATA entry is not a metadata folder");
-    
-	char *refFilter = psMetadataLookupStr (&status, refItem->data.md, "FILTER");
-	if (!status) {
-	    // psLogMsg ("psastro", PS_LOG_INFO, "a PHOTCODE.DATA recipe folder is missing FILTER");
-	    continue;
-	}
-
-	// does this entry match the current filter?
-	if (strcmp (refFilter, filter)) continue;
-
-	psLogMsg ("psastro", PS_LOG_DETAIL, "PHOTCODE.DATA found for filter %s", filter);
-
-	*zeropt = psMetadataLookupF32 (&status, refItem->data.md, "ZEROPT");
-	if (!status) {
-	    psLogMsg ("psastro", PS_LOG_INFO, "a PHOTCODE.DATA recipe folder is missing ZEROPT");
-	    continue;
-	}
-	if (ghostMaxMag) {
-	    *ghostMaxMag = psMetadataLookupF32 (&status, refItem->data.md, "GHOST_MAX_MAG");
-	    if (!status) {
-		psLogMsg ("psastro", PS_LOG_INFO, "a PHOTCODE.DATA recipe folder is missing GHOST_MAX_MAG");
-		continue;
-	    }
-	}
-	psFree (iter);
-	return true;
+        if (refItem->type != PS_DATA_METADATA) ESCAPE ("PHOTCODE.DATA entry is not a metadata folder");
+
+        char *refFilter = psMetadataLookupStr (&status, refItem->data.md, "FILTER");
+        if (!status) {
+            // psLogMsg ("psastro", PS_LOG_INFO, "a PHOTCODE.DATA recipe folder is missing FILTER");
+            continue;
+        }
+
+        // does this entry match the current filter?
+        if (strcmp (refFilter, filter)) continue;
+
+        psLogMsg ("psastro", PS_LOG_DETAIL, "PHOTCODE.DATA found for filter %s", filter);
+
+        *zeropt = psMetadataLookupF32 (&status, refItem->data.md, "ZEROPT");
+        if (!status) {
+            psLogMsg ("psastro", PS_LOG_INFO, "a PHOTCODE.DATA recipe folder is missing ZEROPT");
+            continue;
+        }
+        if (ghostMaxMag) {
+            *ghostMaxMag = psMetadataLookupF32 (&status, refItem->data.md, "GHOST_MAX_MAG");
+            if (!status) {
+                psLogMsg ("psastro", PS_LOG_INFO, "a PHOTCODE.DATA recipe folder is missing GHOST_MAX_MAG");
+                continue;
+            }
+        }
+        psFree (iter);
+        return true;
     }
     psFree (iter);
Index: trunk/pswarp/src/pswarpLoop.c
===================================================================
--- trunk/pswarp/src/pswarpLoop.c	(revision 26963)
+++ trunk/pswarp/src/pswarpLoop.c	(revision 26964)
@@ -367,4 +367,10 @@
     }
 
+    // Update ZP from the astrometry
+    {
+        psMetadataItem *item = psMetadataLookup(outFPA->concepts, "FPA.ZP");
+        item->data.F32 = psMetadataLookupF32(NULL, astrom->fpa->concepts, "FPA.ZP");
+    }
+
     pmHDU *hdu = outFPA->hdu;           ///< HDU for the output warped image
 
