Index: trunk/ippScripts/scripts/stack_skycell.pl
===================================================================
--- trunk/ippScripts/scripts/stack_skycell.pl	(revision 30633)
+++ trunk/ippScripts/scripts/stack_skycell.pl	(revision 30636)
@@ -172,5 +172,9 @@
 my $photometry = metadataLookupBool($recipe, 'PHOTOMETRY'); # perform photometry?
 my $output_nocomp = metadataLookupBool($recipe, 'OUTPUT.NOCOMP'); # change filerules to produced uncompressed output images
-
+my $output_logflux = metadataLookupBool($recipe, 'OUTPUT.LOGFLUX'); # change filerules to produce logflux compressed output images.
+
+if ($output_nocomp and $output_logflux) {
+    &my_die("Unable to not compress and logflux compress simultaneously. Check config.",$stack_id, $PS_EXIT_CONFIG_ERROR);
+}
 
 # Generate MDC file with the inputs
@@ -252,4 +256,12 @@
         $command .= " -F PPSTACK.UNCONV.EXPWT PPSTACK.UNCONV.EXPWT.NOCOMP";
     }
+    if ($output_logflux) {
+	$command .= " -R PPSTACK.OUTPUT FITS.TYPE COMP_STACK "; # Just this one output component?
+	$command .= " -R PPSTACK.OUTPUT.VARIANCE FITS.TYPE COMP_STACK "; 
+	$command .= " -R PPSTACK.OUTPUT.EXPWT FITS.TYPE COMP_STACK ";
+	$command .= " -R PPSTACK.UNCONV FITS.TYPE COMP_STACK ";
+	$command .= " -R PPSTACK.UNCONV.VARIANCE FITS.TYPE COMP_STACK ";
+	$command .= " -R PPSTACK.UNCONV.EXPWT FITS.TYPE COMP_STACK ";
+    }
     $command .= " -threads $threads" if defined $threads;
     $command .= " -debug-stack" if defined $debug;
Index: trunk/ippconfig/gpc1/ppStack.config
===================================================================
--- trunk/ippconfig/gpc1/ppStack.config	(revision 30633)
+++ trunk/ippconfig/gpc1/ppStack.config	(revision 30636)
@@ -20,3 +20,19 @@
 PS1_REFERENCE METADATA
     OUTPUT.NOCOMP   BOOL    TRUE
+    OUTPUT.LOGFLUX  BOOL    FALSE
 END
+
+STACK_DEEP    METADATA
+    OUTPUT.NOCOMP   BOOL    TRUE
+    OUTPUT.LOGFLUX  BOOL    FALSE
+END
+
+STACK_NIGHTLY  METADATA
+    OUTPUT.NOCOMP   BOOL    FALSE
+    OUTPUT.LOGFLUX  BOOL    FALSE
+END
+
+STACK_THREEPI  METADATA
+    OUTPUT.NOCOMP   BOOL    FALSE
+    OUTPUT.LOGFLUX  BOOL    TRUE
+END
Index: trunk/ippconfig/recipes/fitstypes.mdc
===================================================================
--- trunk/ippconfig/recipes/fitstypes.mdc	(revision 30633)
+++ trunk/ippconfig/recipes/fitstypes.mdc	(revision 30636)
@@ -98,4 +98,16 @@
 	NOISE		S32	8
 END
+# Compressed log flux image for stacks.
+COMP_STACK     METADATA
+        BITPIX          S32     16
+        SCALING         STR     LOG_STDEV_POSITIVE
+        STDEV.BITS      S32     4
+        STDEV.NUM       F32     10
+	COMPRESSION     STR     RICE
+	TILE.X		S32	0
+	TILE.Y		S32	1
+	TILE.Z		S32	1
+	NOISE		S32	8
+END
 
 # Compressed exposure image
Index: trunk/ippconfig/recipes/ppStack.config
===================================================================
--- trunk/ippconfig/recipes/ppStack.config	(revision 30633)
+++ trunk/ippconfig/recipes/ppStack.config	(revision 30636)
@@ -112,2 +112,14 @@
         PHOTOMETRY          BOOL  FALSE           # Do basic photometry?
 END
+
+
+# 
+
+STACK_DEEP    METADATA
+END
+
+STACK_NIGHTLY  METADATA
+END
+
+STACK_THREEPI  METADATA
+END
Index: trunk/ippconfig/recipes/reductionClasses.mdc
===================================================================
--- trunk/ippconfig/recipes/reductionClasses.mdc	(revision 30633)
+++ trunk/ippconfig/recipes/reductionClasses.mdc	(revision 30636)
@@ -192,4 +192,26 @@
 	JPEG_BIN1	STR	PPIMAGE_J1
 	JPEG_BIN2	STR	PPIMAGE_J2
+END
+
+# reduction classes for different stacks
+# regular stacks
+NIGHTLY_STACK         METADATA
+      STACK_PPSTACK   STR      STACK_NIGHTLY
+      STACK_PPSUB     STR      STACK
+      STACK_PSPHOT    STR      STACK
+END
+
+# deep stacks
+DEEP_STACK            METADATA
+      STACK_PPSTACK   STR      STACK_DEEP
+      STACK_PPSUB     STR      STACK
+      STACK_PSPHOT    STR      STACK
+END
+
+# three pi stacks
+THREEPI_STACK         METADATA
+      STACK_PPSTACK   STR      STACK_THREEPI
+      STACK_PPSUB     STR      STACK
+      STACK_PSPHOT    STR      STACK
 END
 
Index: trunk/psLib/src/fits/psFits.h
===================================================================
--- trunk/psLib/src/fits/psFits.h	(revision 30633)
+++ trunk/psLib/src/fits/psFits.h	(revision 30636)
@@ -50,5 +50,10 @@
     PS_FITS_SCALE_STDEV_NEGATIVE,       ///< Auto-scale to sample stdev, place mean at upper limit
     PS_FITS_SCALE_STDEV_BOTH,           ///< Auto-scale to sample stdev, place mean at middle
-    PS_FITS_SCALE_MANUAL                ///< Manual scaling (use specified BSCALE and BZERO)
+    PS_FITS_SCALE_MANUAL,                ///< Manual scaling (use specified BSCALE and BZERO)
+    PS_FITS_SCALE_LOG_RANGE,            ///< Take logarithm, Auto-scale to preserve dynamic range
+    PS_FITS_SCALE_LOG_STDEV_POSITIVE,   ///< Take logarithm, Auto-scale to sample stdev, place mean at lower limit
+    PS_FITS_SCALE_LOG_STDEV_NEGATIVE,   ///< Take logarithm, Auto-scale to sample stdev, place mean at upper limit
+    PS_FITS_SCALE_LOG_STDEV_BOTH,       ///< Take logarithm, Auto-scale to sample stdev, place mean at middle
+    PS_FITS_SCALE_LOG_MANUAL            ///< Manual scaling (use specified BSCALE, BZERO, and BOFFSET)
 } psFitsScaling;
 
@@ -66,4 +71,5 @@
     bool fuzz;                          ///< Fuzz the values when quantising floating-point values?
     double bscale, bzero;               ///< Manually specified BSCALE and BZERO (for SCALE_MANUAL)
+    double boffset;                     ///< Manually specified BOFFSET (for SCALE_MANUAL)
     double mean, stdev;                 ///< Mean and standard deviation of image
     int stdevBits;                      ///< Number of bits to sample a standard deviation (for SCALE_STDEV_*)
Index: trunk/psLib/src/fits/psFitsImage.c
===================================================================
--- trunk/psLib/src/fits/psFitsImage.c	(revision 30633)
+++ trunk/psLib/src/fits/psFitsImage.c	(revision 30636)
@@ -54,4 +54,5 @@
     int fitsDatatype;                   // cfitsio data type
     int psDatatype;                     // psLib data type
+    bool is_logscaled;                  // is this image log scaled using BOFFSET?
 } p_psFitsReadInfo;
 
@@ -128,5 +129,5 @@
 
     // Check scale and zero
-    double bscale = 0.0, bzero = 0.0;    // Scale and zero point
+    double bscale = 0.0, bzero = 0.0, boffset = NAN;    // Scale and zero point
     if (fits_read_key_dbl(fits->fd, "BSCALE", &bscale, NULL, &status) && status != KEY_NO_EXIST) {
         psFitsError(status, true, "Unable to read header.");
@@ -137,4 +138,18 @@
         psFitsError(status, true, "Unable to read header.");
         goto bad;
+    }
+    status = 0;
+    if (fits_read_key_dbl(fits->fd, "BOFFSET", &boffset, NULL, &status) && status != KEY_NO_EXIST) {
+        psFitsError(status, true, "Unable to read header.");
+        goto bad;
+    }
+    if (status == KEY_NO_EXIST) {
+      info->is_logscaled = false;
+    }
+    else if (isfinite(boffset)) {
+      info->is_logscaled = true;
+    }
+    else {
+      info->is_logscaled = false;
     }
     status = 0;
@@ -246,4 +261,5 @@
 static psImage *imageToDiskRepresentation(double *bscale, // Scaling applied
                                           double *bzero, // Zero point applied
+					  double *boffset, // Log offset applied
                                           long *blank, // Blank value (integer data)
                                           psFitsFloat *floatType, // Type of custom floating-point
@@ -258,4 +274,5 @@
     psAssert(bscale, "impossible");
     psAssert(bzero, "impossible");
+    psAssert(boffset, "impossible");
     psAssert(floatType, "impossible");
     psAssert(fits, "impossible");
@@ -305,5 +322,5 @@
         if (newScaleZero) {
             // Choose an appropriate BSCALE and BZERO
-            if (!psFitsScaleDetermine(bscale, bzero, blank, image, mask, maskVal, fits)) {
+ 	  if (!psFitsScaleDetermine(bscale, bzero, boffset, blank, image, mask, maskVal, fits)) {
                 // We can't have the write dying for this reason --- try to save it somehow!
                 psWarning("Unable to determine BSCALE and BZERO for image --- refusing to quantise.");
@@ -331,5 +348,5 @@
         }
 
-        return psFitsScaleForDisk(image, fits, *bscale, *bzero, rng);
+        return psFitsScaleForDisk(image, fits, *bscale, *bzero, *boffset, rng);
     }
 
@@ -459,9 +476,18 @@
         return NULL;
     }
-    psFree(info);
 
     if (floatType != PS_FITS_FLOAT_NONE) {
         outImage = psFitsFloatImageFromDisk(outImage, inImage, floatType);
     }
+
+    // Need to apply BOFFSET if info->is_logscaled is true
+    if (info->is_logscaled) {
+      double boffset;
+      int status;
+      fits_read_key_dbl(fits->fd, "BOFFSET", &boffset, NULL, &status);
+      outImage = psFitsScaleFromDisk(outImage,boffset);
+    }
+    psFree(info);
+
     psFree(inImage);
 
@@ -572,7 +598,8 @@
 
     double bscale = NAN, bzero = NAN;   // Scale and zero point to put in header
+    double boffset = NAN;               // Log offset to put into header.
     long blank = 0;                     // Blank (undefined) value for image
     psFitsFloat floatType;              // Custom floating-point convention type
-    psImage *diskImage = imageToDiskRepresentation(&bscale, &bzero, &blank, &floatType, fits, image,
+    psImage *diskImage = imageToDiskRepresentation(&bscale, &bzero, &boffset, &blank, &floatType, fits, image,
                                                    mask, maskVal, NULL, true); // Image to write out
     if (!diskImage) {
@@ -610,4 +637,16 @@
 
     psFitsOptions *options = fits->options; // FITS I/O options
+/*     if (options) { */
+/*       if (options->scaling == PS_FITS_SCALE_LOG_RANGE) { */
+/* 	fprintf(stderr,"it has the scaling I expect\n"); */
+/*       } */
+/*       else { */
+/* 	fprintf(stderr,"it does nto have the scaling I expect\n"); */
+/*       } */
+/*     } */
+/*     else { */
+/*       fprintf(stderr,"options is null, apparently? \n"); */
+/*     } */
+     
     psAssert(!useRequestedScale || !options || bitPix == options->bitpix || options->bitpix == 0,
              "Something's not consistent");
@@ -651,4 +690,15 @@
     }
 
+    // Remove any BOFFSET values that exist in the header if we are not using that scaling anymore
+    if (options&&(!((options->scaling == PS_FITS_SCALE_LOG_RANGE)||
+		    (options->scaling == PS_FITS_SCALE_LOG_MANUAL)||
+		   (options->scaling == PS_FITS_SCALE_LOG_STDEV_POSITIVE)||
+		   (options->scaling == PS_FITS_SCALE_LOG_STDEV_NEGATIVE)||
+		   (options->scaling == PS_FITS_SCALE_LOG_STDEV_BOTH)))) {
+      if (psMetadataLookup(header,"BOFFSET")) {
+	psMetadataRemoveKey(header,"BOFFSET");
+      }
+    }	
+
     // write the header, if any.
     if (header && !psFitsWriteHeaderImage(fits, header, createPHU)) {
@@ -668,4 +718,12 @@
         fits_write_key_dbl(fits->fd, "BSCALE", bscale, 12,
                            "Scaling: TRUE = BZERO + BSCALE * DISK", &status);
+	if (options&&(((options->scaling == PS_FITS_SCALE_LOG_RANGE)||
+		       (options->scaling == PS_FITS_SCALE_LOG_MANUAL)||
+		       (options->scaling == PS_FITS_SCALE_LOG_STDEV_POSITIVE)||
+		       (options->scaling == PS_FITS_SCALE_LOG_STDEV_NEGATIVE)||
+		       (options->scaling == PS_FITS_SCALE_LOG_STDEV_BOTH)))) {
+	  fits_write_key_dbl(fits->fd, "BOFFSET", boffset, 12,
+			     "Scaling: TRUE = BZERO + BSCALE * 10**(DISK) + BOFFSET)", &status);
+	}	
         if (psFitsError(status, true, "Could not write BSCALE/BZERO headers to file.")) {
             success = false;
@@ -769,7 +827,8 @@
     bool success = true;                // Successful update?
     double bscale = NAN, bzero = NAN;   // Scale and zero point to put in header
+    double boffset = NAN;               // Log offset to put in header
     long blank = 0;                     // Blank (undefined) value for image
     psFitsFloat floatType;              // Custom floating-point convention type
-    psImage *diskImage = imageToDiskRepresentation(&bscale, &bzero, &blank, &floatType, fits, input,
+    psImage *diskImage = imageToDiskRepresentation(&bscale, &bzero, &boffset, &blank, &floatType, fits, input,
                                                    mask, maskVal, NULL, false); // Image to write out
     if (!diskImage) {
Index: trunk/psLib/src/fits/psFitsScale.c
===================================================================
--- trunk/psLib/src/fits/psFitsScale.c	(revision 30633)
+++ trunk/psLib/src/fits/psFitsScale.c	(revision 30636)
@@ -100,4 +100,5 @@
 }
 
+    
 // Determine appropriate BSCALE and BZERO for an image, mapping the standard deviation to the nominated number
 // of bits
@@ -212,4 +213,5 @@
     switch (options->scaling) {
       case PS_FITS_SCALE_STDEV_POSITIVE:
+      case PS_FITS_SCALE_LOG_STDEV_POSITIVE:
         // Put (mean - N sigma) at the lowest possible value: predominantly positive images
         imageVal = mean - options->stdevNum * stdev;
@@ -217,4 +219,5 @@
         break;
       case PS_FITS_SCALE_STDEV_NEGATIVE:
+      case PS_FITS_SCALE_LOG_STDEV_NEGATIVE:
         // Put (mean + N sigma) at the highest possible value: predominantly negative images
         imageVal = mean + options->stdevNum * stdev;
@@ -222,4 +225,5 @@
         break;
       case PS_FITS_SCALE_STDEV_BOTH:
+      case PS_FITS_SCALE_LOG_STDEV_BOTH:
         // Put mean right in the middle: images with an equal abundance of positive and negative values
         imageVal = mean;
@@ -237,13 +241,230 @@
 }
 
+
+static bool logscaleStdev(double *bscale, // Scaling, to return
+			  double *bzero, // Zero point, to return
+			  double *boffset, // Log offset, to return
+			  const psImage *image, // Image to scale
+			  const psImage *mask, // Mask image
+			  psImageMaskType maskVal, // Value to mask
+			  const psFitsOptions *options // FITS options
+    )
+{
+    psAssert(bscale, "impossible");
+    psAssert(bzero, "impossible");
+    psAssert(boffset, "impossible");
+    psAssert(image, "impossible");
+    psAssert(options, "impossible");
+
+    psTrace("psLib.fits", 3, "Scaling image by logarithm statistics");
+    int numCols = image->numCols, numRows = image->numRows; // Size of image
+
+    psImage *copy;
+    
+    *boffset = 99e99;
+
+    // Make a copy of the image to pass to get the scaling parameters
+
+    switch (image->type.type) {
+    case PS_TYPE_F32:
+      copy = psImageCopy(NULL,image,PS_TYPE_F32);
+      break;
+    case PS_TYPE_F64:
+      copy = psImageCopy(NULL,image,PS_TYPE_F64);
+      break;
+    default:
+      psError(PS_ERR_UNKNOWN, true, "Target type is not a float: %d", image->type.type);
+      return NULL;
+      break;
+    }
+    
+    // Determine the minimum value on this image.
+    switch (image->type.type) {
+    case PS_TYPE_F32: 
+      for (int y = 0; y < numRows; y++) {
+	for (int x = 0; x < numCols; x++) {
+	  psF32 value = image->data.F32[y][x];
+	  if (isfinite(value)) {
+	    if (value < *boffset) {
+	      *boffset = value;
+	    }
+	  }
+	}
+      }
+      break;
+    case PS_TYPE_F64:
+      for (int y = 0; y < numRows; y++) {
+	for (int x = 0; x < numCols; x++) {
+	  psF64 value = image->data.F64[y][x];
+	  if (isfinite(value)) {
+	    if (value < *boffset) {
+	      *boffset = value;
+	    }
+	  }
+	}
+      }
+      break;
+    default:
+      psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Target type is not a float: %d",image->type.type);
+      return NULL;
+      break;
+    }
+    // We only need to offset images that go negative.
+    if (*boffset > 0.0) {
+      *boffset = 0.0;
+    }
+    // Write offset to header
+    // How?
+    //    psMetadataAddF32(header,PS_LIST_TAIL,"LOGZERO",0,"Flux offset subtracted before taking logarithm.",offset);
+    // Take the logarithm of the image, applying the offset
+    switch (image->type.type) {
+    case PS_TYPE_F32: 
+      for (int y = 0; y < numRows; y++) {
+	for (int x = 0; x < numCols; x++) {
+/* 	  if (x == 2331 && y == 2843) { */
+/* 	    fprintf(stderr,"psFS32: %d %d %g %g %g\n",x,y,offset,image->data.F32[y][x],log10(image->data.F32[y][x] - offset)); */
+/* 	  } */
+	  copy->data.F32[y][x] = (log10( image->data.F32[y][x] - *boffset));
+	}
+      }
+      break;
+    case PS_TYPE_F64:
+	for (int y = 0; y < numRows; y++) {
+	  for (int x = 0; x < numCols; x++) {
+	    //	    fprintf(stderr,"psFS64: %d %d %g %g %g\n",x,y,offset,image->data.F64[y][x],log10(image->data.F64[y][x] - offset));
+	    copy->data.F64[y][x] = (log10( image->data.F64[y][x] - *boffset));
+	  }
+	}
+      break;
+    default:
+      psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Target type is not a float: %d",image->type.type);
+      return NULL;
+      break;
+    }
+      
+    // Do regular scaling on the logarithm image
+    if (!scaleStdev(bscale, bzero, copy, mask, maskVal, options)) {
+      psError(PS_ERR_UNKNOWN, false, "Unable to set BSCALE and BZERO from stdev");
+      return false;
+    }
+    psFree(copy);
+    return true;
+}
+
+static bool logscaleRange(double *bscale, // Scaling, to return
+			  double *bzero, // Zero point, to return
+			  double *boffset, // Log offset, to return
+			  const psImage *image, // Image to scale
+			  const psFitsOptions *options // FITS options
+    )
+{
+    psAssert(bscale, "impossible");
+    psAssert(bzero, "impossible");
+    psAssert(boffset, "impossible");
+    psAssert(image, "impossible");
+    psAssert(options, "impossible");
+
+    psTrace("psLib.fits", 3, "Scaling image by logarithm statistics");
+    int numCols = image->numCols, numRows = image->numRows; // Size of image
+
+    psImage *copy;
+    
+    *boffset = 99e99;
+
+    // Make a copy of the image to pass to get the scaling parameters
+
+    switch (image->type.type) {
+    case PS_TYPE_F32:
+      copy = psImageCopy(NULL,image,PS_TYPE_F32);
+      break;
+    case PS_TYPE_F64:
+      copy = psImageCopy(NULL,image,PS_TYPE_F64);
+      break;
+    default:
+      psError(PS_ERR_UNKNOWN, true, "Target type is not a float: %d", image->type.type);
+      return NULL;
+      break;
+    }
+    
+    // Determine the minimum value on this image.
+    switch (image->type.type) {
+    case PS_TYPE_F32: 
+      for (int y = 0; y < numRows; y++) {
+	for (int x = 0; x < numCols; x++) {
+	  psF32 value = image->data.F32[y][x];
+	  if (!isfinite(value)) {
+	    if (value < *boffset) {
+	      *boffset = value;
+	    }
+	  }
+	}
+      }
+      break;
+    case PS_TYPE_F64:
+      for (int y = 0; y < numRows; y++) {
+	for (int x = 0; x < numCols; x++) {
+	  psF64 value = image->data.F64[y][x];
+	  if (!isfinite(value)) {
+	    if (value < *boffset) {
+	      *boffset = value;
+	    }
+	  }
+	}
+      }
+      break;
+    default:
+      psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Target type is not a float: %d",image->type.type);
+      return NULL;
+      break;
+    }
+    // We only need to offset images that go negative.
+    if (*boffset > 0.0) {
+      *boffset = 0.0;
+    }
+    // Write offset to header
+    // How?
+    //    psMetadataAddF32(header,PS_LIST_TAIL,"LOGZERO",0,"Flux offset subtracted before taking logarithm.",offset);
+    // Take the logarithm of the image, applying the offset
+    switch (image->type.type) {
+    case PS_TYPE_F32: 
+      for (int y = 0; y < numRows; y++) {
+	for (int x = 0; x < numCols; x++) {
+	  copy->data.F32[y][x] = (log10( image->data.F32[y][x] - *boffset));
+	}
+      }
+      break;
+    case PS_TYPE_F64:
+	for (int y = 0; y < numRows; y++) {
+	  for (int x = 0; x < numCols; x++) {
+	    copy->data.F64[y][x] = (log10( image->data.F64[y][x] - *boffset));
+	  }
+	}
+      break;
+    default:
+      psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Target type is not a float: %d",image->type.type);
+      return NULL;
+      break;
+    }
+      
+    // Do regular scaling on the logarithm image
+    if (!scaleRange(bscale, bzero, copy, options)) {
+      psError(PS_ERR_UNKNOWN, false, "Unable to set BSCALE and BZERO from stdev");
+      return false;
+    }
+    psFree(copy);
+    return true;
+}
+
+
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
 // Public functions
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-bool psFitsScaleDetermine(double *bscale, double *bzero, long *blank, const psImage *image,
+bool psFitsScaleDetermine(double *bscale, double *bzero, double *boffset, long *blank, const psImage *image,
                           const psImage *mask, psImageMaskType maskVal, const psFits *fits)
 {
     PS_ASSERT_PTR_NON_NULL(bscale, false);
     PS_ASSERT_PTR_NON_NULL(bzero, false);
+    PS_ASSERT_PTR_NON_NULL(boffset, false);
     PS_ASSERT_PTR_NON_NULL(blank, false);
     PS_ASSERT_IMAGE_NON_NULL(image, false);
@@ -256,4 +477,5 @@
     *bscale = NAN;
     *bzero = NAN;
+    *boffset = 0;
     *blank = 0;
 
@@ -299,7 +521,26 @@
         }
         break;
+    case PS_FITS_SCALE_LOG_RANGE:
+      if (!logscaleRange(bscale,bzero,boffset,image,options)) {
+	psError(PS_ERR_UNKNOWN, false, "Unable to set BSCALE and BZERO from range");
+	return false;
+      }
+      break;
+    case PS_FITS_SCALE_LOG_STDEV_POSITIVE:
+    case PS_FITS_SCALE_LOG_STDEV_NEGATIVE:
+    case PS_FITS_SCALE_LOG_STDEV_BOTH:
+      if (!logscaleStdev(bscale, bzero,boffset, image, mask, maskVal, options)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to set BSCALE and BZERO from stdev");
+            return false;
+        }
+        break;
       case PS_FITS_SCALE_MANUAL:
         *bscale = options->bscale;
         *bzero = options->bzero;
+        break;
+      case PS_FITS_SCALE_LOG_MANUAL:
+        *bscale = options->bscale;
+        *bzero = options->bzero;
+	*boffset = options->boffset;
         break;
       default:
@@ -316,10 +557,11 @@
 
 
-    psTrace("psLib.fits", 3, "BSCALE = %.10lf, BZERO = %.10lf, BLANK = %ld\n", *bscale, *bzero, *blank);
+    psTrace("psLib.fits", 3, "BSCALE = %.10lf, BZERO = %.10lf, BOFFSET = %.10lf, BLANK = %ld\n",
+	    *bscale, *bzero, *boffset, *blank);
     return true;
 }
 
 
-psImage *psFitsScaleForDisk(const psImage *image, const psFits *fits, double bscale, double bzero,
+psImage *psFitsScaleForDisk(const psImage *image, const psFits *fits, double bscale, double bzero, double boffset,
                             psRandom *rng)
 {
@@ -377,5 +619,15 @@
         for (int y = 0; y < numRows; y++) { \
             for (int x = 0; x < numCols; x++) { \
-                ps##INTYPE value = (IN)->data.INTYPE[y][x]; \
+	      ps##INTYPE value; \
+	      if ((options->scaling == PS_FITS_SCALE_LOG_RANGE)||	\
+		(options->scaling == PS_FITS_SCALE_LOG_MANUAL)||        \
+		  (options->scaling == PS_FITS_SCALE_LOG_STDEV_POSITIVE)|| \
+		  (options->scaling == PS_FITS_SCALE_LOG_STDEV_NEGATIVE)|| \
+		  (options->scaling == PS_FITS_SCALE_LOG_STDEV_BOTH)) {	\
+  		value = log10( (IN)->data.INTYPE[y][x] - boffset ); \
+	      }								\
+		else { \
+		  value = (IN)->data.INTYPE[y][x];	\
+		}					    \
                 if (!isfinite(value)) { \
                     /* This choice of "max" for non-finite pixels is mainly cosmetic --- it has to be */ \
@@ -423,16 +675,11 @@
 
 
-#if 0
+
 // This function to apply BSCALE and BZERO to an image read immediately from disk should not be necessary at
 // the present time, since cfitsio should apply the scaling itself in the process of reading.  However, we may
 // later desire it (e.g., if we ever make our own FITS implementation).
-psImage *psFitsScaleFromDisk(psFits *fits, psImage *image)
+psImage *psFitsScaleFromDisk(const psImage *image, double boffset)
 {
     PS_ASSERT_IMAGE_NON_NULL(image, NULL);
-
-    if (bscale == 0.0) {
-        // BSCALE = 0 means don't apply anything
-        return psMemIncrRefCounter(image);
-    }
 
     psElemType inType = image->type.type; // Type for input image
@@ -471,5 +718,5 @@
       for (int y = 0; y < numRows; y++) { \
           for (int x = 0; x < numCols; x++) { \
-              out->data.OUTTYPE[y][x] = image->data.INTYPE[y][x] * bscale + bzero; \
+	    out->data.OUTTYPE[y][x] = pow(10,image->data.INTYPE[y][x]) + boffset;; \
           } \
       } \
@@ -505,7 +752,4 @@
     return out;
 }
-#endif
-
-
 
 psFitsScaling psFitsScalingFromString(const char *string)
@@ -517,4 +761,9 @@
     if (strcasecmp(string, "STDEV_NEGATIVE") == 0) return PS_FITS_SCALE_STDEV_NEGATIVE;
     if (strcasecmp(string, "STDEV_BOTH") == 0)     return PS_FITS_SCALE_STDEV_BOTH;
+    if (strcasecmp(string, "LOG_RANGE") == 0)      return PS_FITS_SCALE_LOG_RANGE;
+    if (strcasecmp(string, "LOG_MANUAL") == 0)      return PS_FITS_SCALE_LOG_MANUAL;
+    if (strcasecmp(string, "LOG_STDEV_POSITIVE") == 0) return PS_FITS_SCALE_LOG_STDEV_POSITIVE;
+    if (strcasecmp(string, "LOG_STDEV_NEGATIVE") == 0) return PS_FITS_SCALE_LOG_STDEV_NEGATIVE;
+    if (strcasecmp(string, "LOG_STDEV_BOTH") == 0) return PS_FITS_SCALE_LOG_STDEV_BOTH;
     if (strcasecmp(string, "MANUAL") == 0)         return PS_FITS_SCALE_MANUAL;
 
Index: trunk/psLib/src/fits/psFitsScale.h
===================================================================
--- trunk/psLib/src/fits/psFitsScale.h	(revision 30633)
+++ trunk/psLib/src/fits/psFitsScale.h	(revision 30636)
@@ -10,4 +10,5 @@
 bool psFitsScaleDetermine(double *bscale, ///< Scaling, to return
                           double *bzero, ///< Zero point, to return
+			  double *boffset, ///< Log offset, to return
                           long *blank,  ///< Blank value, to return
                           const psImage *image, ///< Image to scale
@@ -27,7 +28,10 @@
                             double bscale, ///< Scaling
                             double bzero, ///< Zero point
+			    double boffset, ///< Log offset
                             psRandom *rng ///< Random number generator (for the "fuzz"), or NULL
     );
-
+psImage *psFitsScaleFromDisk(const psImage *image, ///< Image to to unapply BOFFSET
+			     double boffset        ///< Log offset
+			     );
 /// Interpret a string as a scaling method
 psFitsScaling psFitsScalingFromString(const char *string ///< String to interpret
Index: trunk/psModules/src/camera/pmFPAfileDefine.c
===================================================================
--- trunk/psModules/src/camera/pmFPAfileDefine.c	(revision 30633)
+++ trunk/psModules/src/camera/pmFPAfileDefine.c	(revision 30636)
@@ -282,8 +282,11 @@
               case PS_FITS_SCALE_NONE:
               case PS_FITS_SCALE_RANGE:
+	      case PS_FITS_SCALE_LOG_RANGE:
                 // No options required
                 break;
               case PS_FITS_SCALE_STDEV_POSITIVE:
               case PS_FITS_SCALE_STDEV_NEGATIVE:
+	      case PS_FITS_SCALE_LOG_STDEV_POSITIVE:
+  	      case PS_FITS_SCALE_LOG_STDEV_NEGATIVE:
                 options->stdevNum = parseOptionFloat(scheme, "STDEV.NUM", source); // Padding to edge
                 if (!isfinite(options->stdevNum)) {
@@ -295,4 +298,5 @@
                 // Flow through
               case PS_FITS_SCALE_STDEV_BOTH:
+	      case PS_FITS_SCALE_LOG_STDEV_BOTH:
                 options->stdevBits = parseOptionInt(scheme, "STDEV.BITS", source, 0); // Bits for stdev
                 if (options->stdevBits <= 0) {
@@ -308,4 +312,9 @@
                 options->bzero = parseOptionDouble(scheme, "BZERO", source); // Zero point
                 break;
+	    case PS_FITS_SCALE_LOG_MANUAL:
+	      options->bscale = parseOptionDouble(scheme, "BSCALE", source); // Scaling
+	      options->bzero = parseOptionDouble(scheme, "BZERO", source); // Zero point
+	      options->boffset = parseOptionDouble(scheme, "BOFFSET", source); // Log offset
+	      break;	      
               default:
                 psAbort("Should never get here.");
Index: trunk/psModules/src/config/pmConfig.c
===================================================================
--- trunk/psModules/src/config/pmConfig.c	(revision 30633)
+++ trunk/psModules/src/config/pmConfig.c	(revision 30636)
@@ -897,4 +897,71 @@
             psMetadataAddMetadata(filerules, PS_LIST_TAIL, old, PS_META_REPLACE,
                                   "Original replaced by -F option", newRule);
+        }
+        psFree(camerasIter);
+    }
+
+    // Look for command-line options for files to replace
+    while ((argNum = psArgumentGet(*argc, argv, "-R")) > 0) {
+        psArgumentRemove(argNum, argc, argv);
+        if (argNum + 2 >= *argc) {
+            psError(PM_ERR_CONFIG, true,
+                    "Filerule element switch (-R) provided without filerule element and value.");
+            psFree(config);
+            return NULL;
+        }
+
+        const char *rulename = argv[argNum]; // The filerule, to be modified
+        psArgumentRemove(argNum, argc, argv);
+        const char *element  = argv[argNum]; // The element, to be modified
+        psArgumentRemove(argNum, argc, argv);
+	const char *value    = argv[argNum]; // The value, to be set
+	psArgumentRemove(argNum, argc, argv);
+
+        psMetadata *cameras = psMetadataLookupMetadata(NULL, config->system, "CAMERAS"); // List of cameras
+        if (!cameras) {
+            psError(PM_ERR_CONFIG, false, "Unable to find CAMERAS in the site configuration.\n");
+            return false;
+        }
+
+        psMetadataIterator *camerasIter = psMetadataIteratorAlloc(cameras, PS_LIST_HEAD, NULL); // Iterator
+        psMetadataItem *cameraItem;     // Item from iteration
+        while ((cameraItem = psMetadataGetAndIncrement(camerasIter))) {
+            // Silently ignore problems --- they will be caught later, because if the user wants the nominated
+            // file and it's not available for that camera, then they will know.
+
+            if (cameraItem->type != PS_DATA_METADATA) {
+                psTrace("psModules.config", 2,
+                        "Entry %s in CAMERAS is not of type METADATA --- ignored.", cameraItem->name);
+                continue;
+            }
+            psMetadata *camera = cameraItem->data.md; // Camera configuration
+
+            psMetadata *newRule = pmConfigFileRule(config, camera, rulename); // The rule of interest
+            if (!newRule) {
+                psTrace("psModules.config", 2,
+                        "Unable to find filerule %s in camera %s --- ignored.", rulename, cameraItem->name);
+                continue;
+            }
+
+            // By calling pmConfigFileRule, we've assured that the FILERULES is now a metadata
+            psMetadata *filerules = psMetadataLookupMetadata(NULL, camera, "FILERULES"); // File rules
+            if (!filerules) {
+                psTrace("psModules.config", 2,
+                        "Can't find FILERULES of type METADATA in camera %s --- ignored.", cameraItem->name);
+                continue;
+            }
+
+	    // Convert newRule to have the element value requested.
+	    if (!psMetadataLookupStr(NULL,newRule,element)) {
+	      psTrace("psModules.config", 2,
+		      "Unable to find filerule element %s in filerule %s in camera %s --- ignored.",
+		      element,rulename,cameraItem->name);
+	      continue;
+	    }
+	    psMetadataAddStr(newRule, PS_LIST_TAIL, element, PS_META_REPLACE,
+			     "Original replaced by -R option", value);
+	    
+            psMetadataAddMetadata(filerules, PS_LIST_TAIL, rulename, PS_META_REPLACE,
+                                  "Original replaced by -R option", newRule);
         }
         psFree(camerasIter);
