/** @file  pmFringeStats.h
 *
 *  @brief Measure Fringe statistics and apply correction
 *
 *  @author Eugene Magnier, IfA
 *
 *  @version $Revision: 1.7 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2006-07-12 04:44:01 $
 *
 *  Copyright 2004 IfA, University of Hawaii
 */

# ifndef PM_FRINGE_STATS
# define PM_FRINGE_STATS

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// pmFringeRegions
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

/** Structure to hold the fringe measurement regions.
 */
typedef struct
{
    psU32 nRequested;   // number of fringe points selected
    psU32 nAccepted;   // number of fringe points not masked
    psU32 dX;    // median box half-width
    psU32 dY;    // median box half-height
    psU32 nX;    // large-scale smoothing in x (col)
    psU32 nY;    // large-scale smoothing in y (row)
    psVector *x;    // fringe point coordinates (col)
    psVector *y;    // fringe point coordinates (row)
    psVector *mask;   // fringe point on/off mask
}
pmFringeRegions;

/// Allocate fringe regions
pmFringeRegions *pmFringeRegionsAlloc (
    int nPts,     // number of points to create
    int dX,     // half-width of fringe boxes
    int dY,     // half-height of fringe boxes
    int nX,     // smoothing scale in x
    int nY    // smoothing scale in y
);

// Generate the fringe points
bool pmFringeRegionsCreatePoints(pmFringeRegions *fringe, // Fringe regions
                                 const psImage *image, // Image for the regions (defines the size)
                                 psRandom *random // Random number generator
                                );

// Write the regions to a FITS file
bool pmFringeRegionsWriteFits(psFits *fits, // Output FITS file
                              psMetadata *header, // Header to write, or NULL
                              const pmFringeRegions *regions, // Regions to write
                              const char *extname // Extension name, or NULL
                             );

// Read the regions from a FITS file
pmFringeRegions *pmFringeRegionsReadFits(psMetadata *header, // Header to read, or NULL
        const psFits *fits, // Input FITS file
        const char *extname // Extension name, or NULL
                                        );



//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// pmFringeStats
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

/** Structure to hold the fringe measurements for a particular image
 */
typedef struct
{
    pmFringeRegions *regions;           // Fringe regions
    psVector *f;    // fringe point median
    psVector *df;   // fringe point stdev
}
pmFringeStats;

/// Allocate fringe statistics
pmFringeStats *pmFringeStatsAlloc(pmFringeRegions *regions // The fringe regions which will be measured
                                 );

/** Measure the fringe stats for an image
 *
 *  Given an input image and a fringe stats structure, measure the statistics for each of the fringe points on
 *  the image.  If the fringe vectors are NULL, new vectors are created.
 *
 *  XXX should the structure carry the image dimensions for validation?
 *
 *  @return  bool: True or false for success or failure
 */
pmFringeStats *pmFringeStatsMeasure(
    pmFringeRegions *fringe,            ///< fringe regions
    pmReadout *readout,                 ///< measure fringes on this readout
    psMaskType maskVal                  ///< Mask value for statistics
);

// Write the fringe stats for an image to a FITS table
bool pmFringeStatsWriteFits(psFits *fits, // FITS file to which to write
                            psMetadata *header, // Header to write, or NULL
                            const pmFringeStats *fringe, // Fringe statistics to be written
                            const char *extname // Extension name for table
                           );

// Read the fringe stats for an image from a FITS table
pmFringeStats *pmFringeStatsReadFits(psMetadata *header, // Header to read, or NULL
                                     const psFits *fits, // FITS file from which to read
                                     const char *extname, // Extension name to read
                                     pmFringeRegions *regions // Corresponding regions for fringe measurements
                                    );

// Concatenate the fringe stats for several readouts into a single fringe stats.  The idea is that each
// readout of each chip should be measured separately (so as to avoid any gaps, as in the case for GPC), but
// then perform the fit to all the readouts belonging to a chip.  To do so, we need to concatenate.
pmFringeStats *pmFringeStatsConcatenate(const psArray *fringes, // Array of pmFringeStats for the readouts
                                        const psVector *x0, // Offset in x for the readout
                                        const psVector *y0 // Offset in y for the readout
                                       );

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// pmFringeScale
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

/** the pmFringeScale structure defines the relationship between two fringe measurements
 */
typedef struct
{
    int nFringeFrames;
    psVector *coeff;
    psVector *coeffErr;
}
pmFringeScale;

/** Determine the scales for the fringe correction
 *
 * Given an input fringe measurement, and an array of template fringe measurements, measure the contribution
 * of each of the templates to the input.  Rejection is performed on the fringe regions, to weed out stars
 * etc.
 *
 * @return pmFringeScale*
 */
pmFringeScale *pmFringeScaleMeasure(pmFringeStats *science, // Fringe measurements from science image
                                    psArray *fringes, // Array of fringe measurements from templates
                                    float rej, // Rejection threshold (in standard deviations)
                                    unsigned int nIter, // Maximum number of iterations
                                    float keepFrac // Minimum fraction of regions to keep
                                   );

/// Allocate fringe scales
pmFringeScale *pmFringeScaleAlloc(int nFringeFrames // Number of fringe frames
                                 );


//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Fringe correction
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

/** Fringe correct the science image
 *
 *  Given a science image, a set of fringe stats and a matched set of fringe images, correct the science image
 *  for the fringe images.
 *
 *  @return  psImage: summed fringe image
 */
psImage *pmFringeCorrect(pmReadout *in, // place info about results here
                         pmFringeRegions *fringes, // The fringe regions used
                         psArray *fringeImages, // fringe images to use in correction
                         psArray *fringeStats, // fringe stats to use in correction
                         psMaskType maskVal, // Value to mask
                         float rej,     // Rejection threshold, for pmFringeScaleMeasure
                         unsigned int nIter, // Maximum number of iterations, for pmFringeScaleMeasure
                         float keepFrac // Minimum fraction of regions to keep, for pmFringeScaleMeasure
                        );


# endif
