Index: trunk/psModules/src/objects/Makefile.am
===================================================================
--- trunk/psModules/src/objects/Makefile.am	(revision 10611)
+++ trunk/psModules/src/objects/Makefile.am	(revision 10827)
@@ -19,4 +19,7 @@
      pmSourceIO_SX.c \
      pmSourceIO_RAW.c \
+     pmSourcePlots.c \
+     pmSourcePlotPSFModel.c \
+     pmSourcePlotMoments.c \
      pmPSF.c \
      pmPSF_IO.c \
@@ -41,4 +44,5 @@
      pmSourcePhotometry.h \
      pmSourceIO.h \
+     pmSourcePlots.h \
      pmPSF.h \
      pmPSF_IO.h \
Index: trunk/psModules/src/objects/pmSourcePlotMoments.c
===================================================================
--- trunk/psModules/src/objects/pmSourcePlotMoments.c	(revision 10827)
+++ trunk/psModules/src/objects/pmSourcePlotMoments.c	(revision 10827)
@@ -0,0 +1,163 @@
+/** @file  pmSourcePlot.c
+ *
+ * This file contains functions to write source plots
+ *
+ *  @author EAM, IfA
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-12-23 04:00:30 $
+ *
+ *  Copyright 2006 IfA, University of Hawaii
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <pslib.h>
+
+#include "pmHDU.h"
+#include "pmFPA.h"
+#include "pmFPAfile.h"
+#include "pmFPAview.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmGrowthCurve.h"
+#include "pmModel.h"
+#include "pmPSF.h"
+#include "pmSource.h"
+#include "pmSourcePlots.h"
+#include "pmKapaPlots.h"
+
+// this variable is defined in psmodules.h if ohana-config is found
+# if (HAVE_KAPA)
+    # include <kapa.h>
+
+    // plot the sx, sy moments plane (faint and bright sources)
+    bool pmSourcePlotMoments (const pmFPAview *view, pmFPAfile *file, pmConfig *config, pmSourcePlotLayout *layout)
+{
+
+    Graphdata graphdata;
+    KapaSection section;
+
+    psLogMsg ("psphot", 3, "creating moments plot");
+
+    // find the currently selected readout
+    pmReadout  *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT");
+
+    psArray *sources = psMetadataLookupPtr (NULL, readout->analysis, "PSPHOT.SOURCES");
+    if (sources == NULL)
+        return false;
+
+    int kapa = pmKapaOpen (true);
+    if (kapa == -1) {
+        psError(PS_ERR_UNKNOWN, true, "failure to open kapa");
+        return false;
+    }
+
+    // moments plot subplots are square
+    int DX = 1000;
+    int dx = DX / layout->nX;
+    int dy = dx;
+    int DY = dy * layout->nY;
+
+    // XXX make the aspect-ratio match the image
+    if (layout->i == 0) {
+        KapaResize (kapa, DX, DY);
+    }
+
+    KapaInitGraph (&graphdata);
+    section.dx = dx / (float) DX;
+    section.dy = dy / (float) DY;
+    section.x = layout->iX * section.dx;
+    section.y = layout->iY * section.dy;
+    section.name = NULL;
+    psStringAppend (&section.name, "a%d", layout->i);
+    KapaSetSection (kapa, &section);
+    psFree (section.name);
+
+    // examine sources to set data range
+    graphdata.xmin = -0.05;
+    graphdata.ymin = -0.05;
+    graphdata.xmax = +2.05;
+    graphdata.ymax = +2.05;
+    KapaSetLimits (kapa, &graphdata);
+
+    KapaSetFont (kapa, "helvetica", 14);
+    KapaBox (kapa, &graphdata);
+    KapaSendLabel (kapa, "&ss&h_x| (pixels)", KAPA_LABEL_XM);
+    KapaSendLabel (kapa, "&ss&h_y| (pixels)", KAPA_LABEL_YM);
+
+    psVector *xBright = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+    psVector *yBright = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+    psVector *xFaint  = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+    psVector *yFaint  = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+
+    // construct the vectors
+    int nB = 0;
+    int nF = 0;
+    for (int i = 0; i < sources->n; i++) {
+        pmSource *source = sources->data[i];
+        if (source->moments == NULL)
+            continue;
+
+        xFaint->data.F32[nF] = source->moments->Sx;
+        yFaint->data.F32[nF] = source->moments->Sy;
+        nF++;
+
+        // XXX make this a user-defined cutoff
+        if (source->moments->SN < 50)
+            continue;
+
+        xBright->data.F32[nB] = source->moments->Sx;
+        yBright->data.F32[nB] = source->moments->Sy;
+        nB++;
+    }
+    xFaint->n = nF;
+    yFaint->n = nF;
+
+    xBright->n = nB;
+    yBright->n = nB;
+
+    graphdata.color = KapaColorByName ("black");
+    graphdata.ptype = 0;
+    graphdata.size = 0.3;
+    graphdata.style = 2;
+    KapaPrepPlot (kapa, nF, &graphdata);
+    KapaPlotVector (kapa, nF, xFaint->data.F32);
+    KapaPlotVector (kapa, nF, yFaint->data.F32);
+
+    graphdata.color = KapaColorByName ("red");
+    graphdata.ptype = 2;
+    graphdata.size = 0.5;
+    graphdata.style = 2;
+    KapaPrepPlot (kapa, nB, &graphdata);
+    KapaPlotVector (kapa, nB, xBright->data.F32);
+    KapaPlotVector (kapa, nB, yBright->data.F32);
+
+    if (layout->i == layout->nTotal - 1) {
+        psLogMsg ("psphot", 3, "saving plot to %s", file->filename);
+        KapaPNG (kapa, file->filename);
+    }
+
+    psFree (xBright);
+    psFree (yBright);
+    psFree (xFaint);
+    psFree (yFaint);
+
+    return true;
+}
+
+
+# else
+
+    bool psphotPlotMoments (pmConfig *config, pmFPAview *view, psArray *sources)
+{
+    psLogMsg ("psphot", 3, "skipping moments plot");
+    return true;
+}
+
+# endif
Index: trunk/psModules/src/objects/pmSourcePlotPSFModel.c
===================================================================
--- trunk/psModules/src/objects/pmSourcePlotPSFModel.c	(revision 10827)
+++ trunk/psModules/src/objects/pmSourcePlotPSFModel.c	(revision 10827)
@@ -0,0 +1,229 @@
+/** @file  pmSourcePlot.c
+ *
+ * This file contains functions to write source plots
+ *
+ *  @author EAM, IfA
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-12-23 04:00:30 $
+ *
+ *  Copyright 2006 IfA, University of Hawaii
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <pslib.h>
+
+#include "pmHDU.h"
+#include "pmFPA.h"
+#include "pmFPAfile.h"
+#include "pmFPAview.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmGrowthCurve.h"
+#include "pmModel.h"
+#include "pmPSF.h"
+#include "pmSource.h"
+#include "pmSourcePlots.h"
+#include "pmKapaPlots.h"
+
+// this variable is defined in psmodules.h if ohana-config is found
+# if (HAVE_KAPA)
+    # include <kapa.h>
+
+    // plot the sx, sy, sxy as vector field,
+    // plot the PSF measured sx, sy, sxy as vector field
+    // pull the sources from the config / file?
+    bool pmSourcePlotPSFModel (const pmFPAview *view, pmFPAfile *file, pmConfig *config, pmSourcePlotLayout *layout)
+{
+
+    Graphdata graphdata;
+    KapaSection section;
+
+    psLogMsg ("psphot", 3, "creating psf model plot");
+
+    // find the currently selected readout
+    pmReadout  *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT");
+
+    psArray *sources = psMetadataLookupPtr (NULL, readout->analysis, "PSPHOT.SOURCES");
+    if (sources == NULL)
+        return false;
+
+    int kapa = pmKapaOpen (true);
+    if (kapa == -1) {
+        psError(PS_ERR_UNKNOWN, true, "failure to open kapa");
+        return false;
+    }
+
+    int DX = 1000;
+    float dx = DX / layout->nX;
+    float dy = dx * layout->aspectRatio;
+    int DY = dy * layout->nY;
+
+    // XXX make the aspect-ratio match the image
+    if (layout->i == 0) {
+        KapaResize (kapa, DX, DY);
+    }
+
+    KapaInitGraph (&graphdata);
+    section.dx = dx / DX;
+    section.dy = dy / DY;
+    section.x = layout->iX * section.dx;
+    section.y = layout->iY * section.dy;
+    section.name = NULL;
+    psStringAppend (&section.name, "a%d", layout->i);
+    KapaSetSection (kapa, &section);
+    psFree (section.name);
+
+    psVector *xMNT = psVectorAllocEmpty (2*sources->n, PS_TYPE_F32);
+    psVector *yMNT = psVectorAllocEmpty (2*sources->n, PS_TYPE_F32);
+    psVector *xPSF = psVectorAllocEmpty (2*sources->n, PS_TYPE_F32);
+    psVector *yPSF = psVectorAllocEmpty (2*sources->n, PS_TYPE_F32);
+    psVector *xMIN = psVectorAllocEmpty (2*sources->n, PS_TYPE_F32);
+    psVector *yMIN = psVectorAllocEmpty (2*sources->n, PS_TYPE_F32);
+
+    // construct the plot vectors
+    int nMNT = 0;
+    int nPSF = 0;
+    int nMIN = 0;
+    dx = 0;
+    dy = 0;
+    float scale = 10;
+    for (int i = 0; i < sources->n; i++) {
+        pmSource *source = sources->data[i];
+        if (source->moments == NULL)
+            continue;
+        if (source->moments->SN < 25)
+            continue;
+        if (source->type != PM_SOURCE_TYPE_STAR)
+            continue;
+
+        pmModel *model = source->modelPSF;
+        if (model == NULL)
+            continue;
+
+        psF32 *PAR = model->params->data.F32;
+
+        psEllipseMoments moments;
+        moments.x2 = source->moments->Sx;
+        moments.y2 = source->moments->Sy;
+        moments.xy = source->moments->Sxy;
+
+        psEllipseShape shape;
+        shape.sx  = PAR[PM_PAR_SXX] / sqrt(2.0);
+        shape.sy  = PAR[PM_PAR_SYY] / sqrt(2.0);
+        shape.sxy = PAR[PM_PAR_SXY];
+
+        // force the axis ratio to be < 20.0
+        psEllipseAxes axes_mnt = psEllipseMomentsToAxes (moments, 20.0);
+        psEllipseAxes axes_psf = psEllipseShapeToAxes (shape, 20.0);
+
+        // moments major axis
+        dx = scale*axes_mnt.major*cos(axes_mnt.theta);
+        dy = scale*axes_mnt.major*sin(axes_mnt.theta);
+        xMNT->data.F32[nMNT] = PAR[PM_PAR_XPOS] - dx;
+        yMNT->data.F32[nMNT] = PAR[PM_PAR_YPOS] - dy;
+        nMNT++;
+        xMNT->data.F32[nMNT] = PAR[PM_PAR_XPOS] + dx;
+        yMNT->data.F32[nMNT] = PAR[PM_PAR_YPOS] + dy;
+        nMNT++;
+
+        // psf major axis
+        dx = scale*axes_psf.major*cos(axes_psf.theta);
+        dy = scale*axes_psf.major*sin(axes_psf.theta);
+        xPSF->data.F32[nPSF] = PAR[PM_PAR_XPOS] - dx;
+        yPSF->data.F32[nPSF] = PAR[PM_PAR_YPOS] - dy;
+        nPSF++;
+        xPSF->data.F32[nPSF] = PAR[PM_PAR_XPOS] + dx;
+        yPSF->data.F32[nPSF] = PAR[PM_PAR_YPOS] + dy;
+        nPSF++;
+
+        // minor axis (to show size)
+        dy = +scale*axes_psf.minor*cos(axes_psf.theta);
+        dx = -scale*axes_psf.minor*sin(axes_psf.theta);
+        xMIN->data.F32[nMIN] = PAR[PM_PAR_XPOS] - dx;
+        yMIN->data.F32[nMIN] = PAR[PM_PAR_YPOS] - dy;
+        nMIN++;
+        xMIN->data.F32[nMIN] = PAR[PM_PAR_XPOS] + dx;
+        yMIN->data.F32[nMIN] = PAR[PM_PAR_YPOS] + dy;
+        nMIN++;
+
+        graphdata.xmin = PS_MIN(graphdata.xmin, PAR[PM_PAR_XPOS]);
+        graphdata.xmax = PS_MAX(graphdata.xmax, PAR[PM_PAR_XPOS]);
+        graphdata.ymin = PS_MIN(graphdata.ymin, PAR[PM_PAR_YPOS]);
+        graphdata.ymax = PS_MAX(graphdata.ymax, PAR[PM_PAR_YPOS]);
+    }
+    xMNT->n = yMNT->n = nMNT;
+    xPSF->n = yPSF->n = nPSF;
+    xMIN->n = yMIN->n = nMIN;
+
+    float range;
+    range = graphdata.xmax - graphdata.xmin;
+    graphdata.xmax += 0.05*range;
+    graphdata.xmin -= 0.05*range;
+    range = graphdata.ymax - graphdata.ymin;
+    graphdata.ymax += 0.05*range;
+    graphdata.ymin -= 0.05*range;
+
+    // XXX set the plot range to match the image
+    KapaSetLimits (kapa, &graphdata);
+
+    KapaSetFont (kapa, "helvetica", 14);
+    KapaBox (kapa, &graphdata);
+    KapaSendLabel (kapa, "x (pixels)", KAPA_LABEL_XM);
+    KapaSendLabel (kapa, "y (pixels)", KAPA_LABEL_YM);
+    KapaSendLabel (kapa, "vector is major axis (scaled by 20) : black are moments, blue are psf model, red is psf minor axis", KAPA_LABEL_XP);
+
+    graphdata.color = KapaColorByName ("black");
+    graphdata.ptype = 100;
+    graphdata.size = 0.3;
+    graphdata.style = 2;
+    KapaPrepPlot (kapa, nMNT, &graphdata);
+    KapaPlotVector (kapa, nMNT, xMNT->data.F32);
+    KapaPlotVector (kapa, nMNT, yMNT->data.F32);
+
+    graphdata.color = KapaColorByName ("blue");
+    graphdata.ptype = 100;
+    graphdata.size = 0.5;
+    graphdata.style = 2;
+    KapaPrepPlot (kapa, nPSF, &graphdata);
+    KapaPlotVector (kapa, nPSF, xPSF->data.F32);
+    KapaPlotVector (kapa, nPSF, yPSF->data.F32);
+
+    graphdata.color = KapaColorByName ("red");
+    graphdata.ptype = 100;
+    graphdata.size = 0.5;
+    graphdata.style = 2;
+    KapaPrepPlot (kapa, nMIN, &graphdata);
+    KapaPlotVector (kapa, nMIN, xMIN->data.F32);
+    KapaPlotVector (kapa, nMIN, yMIN->data.F32);
+
+    if (layout->i == layout->nTotal - 1) {
+        psLogMsg ("psphot", 3, "saving plot to %s", file->filename);
+        KapaPNG (kapa, file->filename);
+    }
+
+    psFree (xMNT);
+    psFree (yMNT);
+    psFree (xPSF);
+    psFree (yPSF);
+    psFree (xMIN);
+    psFree (yMIN);
+
+    return true;
+}
+
+# else
+
+    bool psphotPlotPSFModel (pmConfig *config, pmFPAview *view, psArray *sources)
+{
+    psLogMsg ("psphot", 3, "skipping psf model plot");
+    return true;
+}
+
+# endif
Index: trunk/psModules/src/objects/pmSourcePlots.c
===================================================================
--- trunk/psModules/src/objects/pmSourcePlots.c	(revision 10827)
+++ trunk/psModules/src/objects/pmSourcePlots.c	(revision 10827)
@@ -0,0 +1,160 @@
+/** @file  pmSourcePlot.c
+ *
+ * This file contains functions to write source plots
+ *
+ *  @author EAM, IfA
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-12-23 04:00:30 $
+ *
+ *  Copyright 2006 IfA, University of Hawaii
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <pslib.h>
+
+#include "pmHDU.h"
+#include "pmFPA.h"
+#include "pmFPAfile.h"
+#include "pmFPAview.h"
+#include "pmSourcePlots.h"
+
+// this function is called for the specific plotting program at the fileLevel
+// fileLevel must be >= chip
+bool pmFPAviewWriteSourcePlot(const pmFPAview *view, pmFPAfile *file, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(view, false);
+    PS_ASSERT_PTR_NON_NULL(file, false);
+
+    if ((view->readout != -1) || (view->cell != -1)) {
+        psError(PS_ERR_UNKNOWN, true, "source plots must have fileLevel >= chip");
+        return false;
+    }
+
+    pmFPA *fpa = file->fpa;
+
+    if (view->chip == -1) {
+        pmFPAWriteSourcePlot (fpa, view, file, config, NULL);
+        return true;
+    }
+
+    pmChipWriteSourcePlot (fpa, view, file, config, NULL);
+    return true;
+}
+
+// read in all chip-level SourcePlot files for this FPA
+bool pmFPAWriteSourcePlot (pmFPA *fpa, const pmFPAview *view, pmFPAfile *file, pmConfig *config, pmSourcePlotLayout *layout)
+{
+    PS_ASSERT_PTR_NON_NULL(fpa, false);
+    PS_ASSERT_PTR_NON_NULL(view, false);
+    PS_ASSERT_PTR_NON_NULL(file, false);
+
+    // if the layout is not defined, this level is the top level being plotted
+    // determine the plot layout
+    if (!layout) {
+        layout = pmSourcePlotLayoutAlloc ();
+        // XXX temporary hardwired values for essence?
+        layout->nX = 4;
+        layout->nY = 2;
+        layout->aspectRatio = 2.0;
+        // count the number of chips and their layout (xrange, yrange, axis ratio)
+        for (int i = 0; i < fpa->chips->n; i++) {
+            pmChip *chip = fpa->chips->data[i];
+            if (chip->data_exists) {
+                layout->nTotal ++;
+            }
+        }
+    }
+
+    pmFPAview *chipView = pmFPAviewAlloc(0);
+
+    while (pmFPAviewNextChip (chipView, fpa, 1) != NULL) {
+        pmChipWriteSourcePlot (fpa, chipView, file, config, layout);
+        layout->i ++;
+        layout->iX ++;
+        if (layout->iX == layout->nX) {
+            layout->iY++;
+            layout->iX = 0;
+        }
+    }
+    psFree (chipView);
+    psFree (layout);
+    return true;
+}
+
+// read in all cell-level SourcePlot files for this chip
+bool pmChipWriteSourcePlot (pmFPA *fpa, const pmFPAview *view, pmFPAfile *file, pmConfig *config, pmSourcePlotLayout *layout)
+{
+    PS_ASSERT_PTR_NON_NULL(view, false);
+    PS_ASSERT_PTR_NON_NULL(file, false);
+
+    // if the layout is not defined, this level is the top level being plotted
+    // determine the plot layout (always single chip)
+    if (!layout) {
+        layout = pmSourcePlotLayoutAlloc ();
+        layout->nTotal = 1;
+    } else {
+        psMemIncrRefCounter (layout);
+    }
+
+    pmFPAview *newView = pmFPAviewAlloc(0);
+    newView->chip = view->chip;
+
+    while (pmFPAviewNextCell (newView, fpa, 1) != NULL) {
+        while (pmFPAviewNextReadout (newView, fpa, 1) != NULL) {
+
+            if (!strcmp (file->name, "SOURCE.PLOT.PSFMODEL")) {
+                pmSourcePlotPSFModel (newView, file, config, layout);
+            }
+            if (!strcmp (file->name, "SOURCE.PLOT.MOMENTS")) {
+                pmSourcePlotMoments (newView, file, config, layout);
+            }
+        }
+    }
+    psFree (newView);
+    psFree (layout);
+    return true;
+}
+
+static void pmSourcePlotLayoutFree(pmSourcePlotLayout *layout)
+{
+    return;
+}
+
+pmSourcePlotLayout *pmSourcePlotLayoutAlloc()
+{
+    pmSourcePlotLayout *layout = (pmSourcePlotLayout *)psAlloc(sizeof(pmSourcePlotLayout));
+    psMemSetDeallocator(layout, (psFreeFunc)pmSourcePlotLayoutFree );
+
+    layout->nX = layout->nY = layout->nTotal = 0;
+    layout->iX = layout->iY = layout->i  =  0;
+    layout->aspectRatio = 1.0;
+    return (layout);
+}
+
+/* we have three types of plots to produce (maybe more?)
+ * for each plot, we need to supply the following information:
+ *     - what are overall dimensions?
+ *     - what is the relative position of this element?
+ *     - what are the dimensions of this element?
+ *     - create a new page for this element?
+ 
+ * the answers to these questions come from slightly different locations
+ * for the different types of plots:
+ 
+ *  1) focal-plane layout based plots: 
+ *     - dimensions depend on fileLevel
+ 
+ *  2) multi-row plots: 
+ *     - dimensions depend on total number of rows
+ 
+ *  2) multi-page plots: 
+ *     - dimensions depend on total number of rows
+ */
+
Index: trunk/psModules/src/objects/pmSourcePlots.h
===================================================================
--- trunk/psModules/src/objects/pmSourcePlots.h	(revision 10827)
+++ trunk/psModules/src/objects/pmSourcePlots.h	(revision 10827)
@@ -0,0 +1,40 @@
+/** @file  pmSourcePlots.h
+*
+*  @brief functions to create plots illustrating source properties
+*
+*  @ingroup none
+*
+*  @author EAM, IfA
+*
+*  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2006-12-23 04:00:30 $
+*
+*  Copyright 2006 Institute for Astronomy, University of Hawaii
+*/
+
+#ifndef PM_SOURCE_PLOTS_H
+#define PM_SOURCE_PLOTS_H
+
+typedef struct
+{
+    int nX;
+    int nY;
+    int nTotal;
+    int iX;
+    int iY;
+    int i;
+    float aspectRatio;
+}
+pmSourcePlotLayout;
+
+// typedef bool (*pmSourcePlotFunction)(pmConfig *config, pmFPAview *view, pmSourcePlotLayout *layout);
+
+pmSourcePlotLayout *pmSourcePlotLayoutAlloc();
+
+bool pmFPAviewWriteSourcePlot(const pmFPAview *view, pmFPAfile *file, pmConfig *config);
+bool pmFPAWriteSourcePlot (pmFPA *fpa, const pmFPAview *view, pmFPAfile *file, pmConfig *config, pmSourcePlotLayout *layout);
+bool pmChipWriteSourcePlot (pmFPA *fpa, const pmFPAview *view, pmFPAfile *file, pmConfig *config, pmSourcePlotLayout *layout);
+bool pmSourcePlotPSFModel (const pmFPAview *view, pmFPAfile *file, pmConfig *config, pmSourcePlotLayout *layout);
+bool pmSourcePlotMoments (const pmFPAview *view, pmFPAfile *file, pmConfig *config, pmSourcePlotLayout *layout);
+
+#endif // PM_SOURCE_PLOTS_H
