Index: /branches/eam_branches/ipp-20150112/Ohana/src/opihi/cmd.astro/cdhistogram.c
===================================================================
--- /branches/eam_branches/ipp-20150112/Ohana/src/opihi/cmd.astro/cdhistogram.c	(revision 37900)
+++ /branches/eam_branches/ipp-20150112/Ohana/src/opihi/cmd.astro/cdhistogram.c	(revision 37901)
@@ -2,5 +2,4 @@
 
 # define CHECKVAL(ARG) if (!isfinite(ARG)) { gprint (GP_ERR, "illegal value for %s: %f\n", #ARG, ARG); return (FALSE); }
-enum {IS_DOT, IS_SQUARE, IS_CIRCLE, IS_GAUSS};
 
 int cdhistogram (int argc, char **argv) {
Index: /branches/eam_branches/ipp-20150112/Ohana/src/opihi/cmd.data/Makefile
===================================================================
--- /branches/eam_branches/ipp-20150112/Ohana/src/opihi/cmd.data/Makefile	(revision 37900)
+++ /branches/eam_branches/ipp-20150112/Ohana/src/opihi/cmd.data/Makefile	(revision 37901)
@@ -61,4 +61,5 @@
 $(SRC)/ungridify.$(ARCH).o     \
 $(SRC)/histogram.$(ARCH).o	\
+$(SRC)/tdhistogram.$(ARCH).o	\
 $(SRC)/hermitian1d.$(ARCH).o	\
 $(SRC)/hermitian2d.$(ARCH).o	\
@@ -131,4 +132,5 @@
 $(SRC)/imspline_apply.$(ARCH).o	\
 $(SRC)/imspline_construct.$(ARCH).o \
+$(SRC)/squash3d.$(ARCH).o	   \
 $(SRC)/imstats.$(ARCH).o	   \
 $(SRC)/style.$(ARCH).o		   \
Index: /branches/eam_branches/ipp-20150112/Ohana/src/opihi/cmd.data/init.c
===================================================================
--- /branches/eam_branches/ipp-20150112/Ohana/src/opihi/cmd.data/init.c	(revision 37900)
+++ /branches/eam_branches/ipp-20150112/Ohana/src/opihi/cmd.data/init.c	(revision 37901)
@@ -51,4 +51,5 @@
 int ungridify        PROTO((int, char **));
 int histogram        PROTO((int, char **));
+int tdhistogram      PROTO((int, char **));
 int hermitian1d      PROTO((int, char **));
 int hermitian2d      PROTO((int, char **));
@@ -118,4 +119,5 @@
 int imspline_apply   PROTO((int, char **));
 int imspline_construct PROTO((int, char **));
+int squash3d         PROTO((int, char **));
 int stats            PROTO((int, char **));
 int imstats          PROTO((int, char **));
@@ -218,4 +220,5 @@
   {1, "header",       header,           "print image header"},
   {1, "histogram",    histogram,        "generate histogram from vector"},
+  {1, "tdhistogram",  tdhistogram,      "generate 2D histogram image from vector set"},
   {1, "hermitian1d",  hermitian1d,      "generate 1-D Hermitian Polynomial"},
   {1, "hermitian2d",  hermitian2d,      "generate 2-D Hermitian Polynomial"},
@@ -291,4 +294,5 @@
   {1, "imspline.apply", imspline_apply, "apply spline fit to generate an image"},
   {1, "imspline.const", imspline_construct, "create spline 2nd deriv. terms"},
+  {1, "squash3d",     squash3d,         "squash 3d buffer to 2d"},
   {1, "stats",        imstats,          "statistics on a portion of an image"},
   {1, "style",        style,            "set the style for graph plots"},
Index: /branches/eam_branches/ipp-20150112/Ohana/src/opihi/cmd.data/read_vectors.c
===================================================================
--- /branches/eam_branches/ipp-20150112/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 37900)
+++ /branches/eam_branches/ipp-20150112/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 37901)
@@ -372,4 +372,10 @@
   }
 
+  int VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    remove_argument (N, &argc, argv);
+    VERBOSE = TRUE;
+  }
+
   int start = 0;
   int Nrows = -1; // -1 : read entire table
@@ -399,5 +405,6 @@
   // }
 
-  if (argc < 2) ESCAPE ("USAGE: read -fits extension [-extnum] [-keyword key] name name ...\n");
+  if ((argc < 2) && !getSizes) ESCAPE ("USAGE: read -fits extension [-extnum] [-keyword key] name name ...\n");
+  if ((argc != 1) && getSizes) ESCAPE ("USAGE: read -sizes -fits extension [-extnum] (does not read data values)\n");
 
   if (f == NULL) ESCAPE ("file not found\n");
@@ -436,5 +443,9 @@
     if (start >= header.Naxis[1]) ESCAPE ("invalid range: start >= Ny (%d)\n", header.Naxis[1]);
     if (Nrows < 0) ESCAPE ("invalid range: Nrows < 0\n");
-    if (start + Nrows > header.Naxis[1]) ESCAPE ("invalid range: start + Nrows > Ny (%d)\n", header.Naxis[1]);
+
+    // just a warning:
+    if (start + Nrows > header.Naxis[1]) {
+      if (VERBOSE) gprint (GP_ERR, "NOTE: reading last block will return only %d rows\n", header.Naxis[1] - start);
+    }
 
     // Ny = 100, start = 0, Nrows = -1 -> Nrows => 100
@@ -472,4 +483,11 @@
       }
 
+      if (getSizes) {
+	read_table_sizes (&header);
+	if (CCDKeyword != NULL) free (CCDKeyword); 
+	gfits_free_header (&header); 
+	return TRUE;
+      }
+
       if (Nrows == -1) {
 	Nrows = header.Naxis[1] - start;
@@ -478,5 +496,9 @@
       if (start >= header.Naxis[1]) ESCAPE ("invalid range: start >= Ny (%d)\n", header.Naxis[1]);
       if (Nrows < 0) ESCAPE ("invalid range: Nrows < 0\n");
-      if (start + Nrows > header.Naxis[1]) ESCAPE ("invalid range: start + Nrows > Ny (%d)\n", header.Naxis[1]);
+
+      // just a warning:
+      if (start + Nrows > header.Naxis[1]) {
+	if (VERBOSE) gprint (GP_ERR, "NOTE: reading last block will return only %d rows\n", header.Naxis[1] - start);
+      }
 
       if (!gfits_fread_ftable_range (f, padIfShort, &table, start, Nrows)) ESCAPE ("error reading table for extension %d\n", Nextend);
@@ -603,5 +625,5 @@
 
   set_int_variable ("table:Nx", header->Naxis[0]);
-  set_int_variable ("table:Nx", header->Naxis[0]);
+  set_int_variable ("table:Ny", header->Naxis[1]);
   set_int_variable ("table:Nfields", Nfields);
 
Index: /branches/eam_branches/ipp-20150112/Ohana/src/opihi/cmd.data/squash3d.c
===================================================================
--- /branches/eam_branches/ipp-20150112/Ohana/src/opihi/cmd.data/squash3d.c	(revision 37901)
+++ /branches/eam_branches/ipp-20150112/Ohana/src/opihi/cmd.data/squash3d.c	(revision 37901)
@@ -0,0 +1,113 @@
+# include "data.h"
+
+enum {SQUASH_NONE, SQUASH_X, SQUASH_Y, SQUASH_Z};
+
+int squash3d (int argc, char **argv) {
+  
+  int ox, oy, oz;
+  Buffer *src;
+  Buffer *tgt;
+
+  if (argc != 4) {
+    gprint (GP_ERR, "USAGE: squash3d <3d> <2d> (dir)\n");
+    gprint (GP_ERR, " dir: x -> squash in x-dir, y -> squash in y-dir, z -> squash in z-dir\n");
+    return (FALSE);
+  }
+
+  int dir = SQUASH_NONE;
+  if (!strcasecmp (argv[3], "x")) dir = SQUASH_X;
+  if (!strcasecmp (argv[3], "y")) dir = SQUASH_Y;
+  if (!strcasecmp (argv[3], "z")) dir = SQUASH_Z;
+  if (!dir) {
+    gprint (GP_ERR, "invalid direction %s\n", argv[3]);
+    return FALSE;
+  }
+
+  if ((src = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if (src[0].matrix.Naxes < 3) {
+    gprint (GP_ERR, "buffer is not 3D\n");
+    return FALSE;
+  }
+
+  float *iBuf  = (float *) src[0].matrix.buffer;
+
+  if ((tgt = SelectBuffer (argv[2], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+  gfits_free_matrix (&tgt[0].matrix);
+  gfits_free_header (&tgt[0].header);
+
+  switch (dir) {
+    case SQUASH_X:
+      {     
+	int iNx = src[0].matrix.Naxis[0];
+	int iNy = src[0].matrix.Naxis[1];
+	int iNz = src[0].matrix.Naxis[2];
+
+	// output is Nz,Ny
+	int oNx = iNz;
+	int oNy = iNy;
+	CreateBuffer (tgt, oNx, oNy, -32, 0.0, 1.0);
+	float *oBuf  = (float *) tgt[0].matrix.buffer;
+
+	for (ox = 0; ox < oNx; ox ++) {
+	  for (oy = 0; oy < oNy; oy ++) {
+	    float val = 0.0;
+	    for (oz = 0; oz < iNx; oz ++) { // src x is tgt z
+	      val += iBuf[oz + oy*iNx + ox*iNx*iNy];
+	    }
+	    oBuf[ox + oy*oNx] = val;
+	  }
+	}
+      }
+      break;
+      
+    case SQUASH_Y:
+      {     
+	int iNx = src[0].matrix.Naxis[0];
+	int iNy = src[0].matrix.Naxis[1];
+	int iNz = src[0].matrix.Naxis[2];
+
+	// output is Nx,Nz
+	int oNx = iNx;
+	int oNy = iNz;
+	CreateBuffer (tgt, oNx, oNy, -32, 0.0, 1.0);
+	float *oBuf  = (float *) tgt[0].matrix.buffer;
+
+	for (ox = 0; ox < oNx; ox ++) {
+	  for (oy = 0; oy < oNy; oy ++) { // src z is tgt y
+	    float val = 0.0;
+	    for (oz = 0; oz < iNy; oz ++) {
+	      val += iBuf[ox + oz*iNx + oy*iNx*iNy];
+	    }
+	    oBuf[ox + oy*oNx] = val;
+	  }
+	}
+      }
+      break;
+      
+    case SQUASH_Z:
+      {     
+	int iNx = src[0].matrix.Naxis[0];
+	int iNy = src[0].matrix.Naxis[1];
+	int iNz = src[0].matrix.Naxis[2];
+
+	// output is Nx,Ny
+	int oNx = iNx;
+	int oNy = iNy;
+	CreateBuffer (tgt, oNx, oNy, -32, 0.0, 1.0);
+	float *oBuf  = (float *) tgt[0].matrix.buffer;
+
+	for (ox = 0; ox < oNx; ox ++) {
+	  for (oy = 0; oy < oNy; oy ++) {
+	    float val = 0.0;
+	    for (oz = 0; oz < iNz; oz ++) {
+	      val += iBuf[ox + oy*iNx + oz*iNx*iNy];
+	    }
+	    oBuf[ox + oy*oNx] = val;
+	  }
+	}
+      }
+      break;
+  }
+
+  return (TRUE);
+}
Index: /branches/eam_branches/ipp-20150112/Ohana/src/opihi/cmd.data/tdhistogram.c
===================================================================
--- /branches/eam_branches/ipp-20150112/Ohana/src/opihi/cmd.data/tdhistogram.c	(revision 37901)
+++ /branches/eam_branches/ipp-20150112/Ohana/src/opihi/cmd.data/tdhistogram.c	(revision 37901)
@@ -0,0 +1,176 @@
+# include "data.h"
+
+# define CHECKVAL(ARG) if (!isfinite(ARG)) { gprint (GP_ERR, "illegal value for %s: %f\n", #ARG, ARG); return (FALSE); }
+
+int tdhistogram (int argc, char **argv) {
+
+  int i, Nx, Ny, Nz, N;
+  float *val;
+  Buffer *bf;
+  Vector *vx, *vy, *vz, *range;
+  opihi_flt *x, *y, *z;
+
+  int reuse = FALSE;
+  if ((N = get_argument (argc, argv, "-reuse"))) {
+    remove_argument (N, &argc, argv);
+    reuse = TRUE;
+  }
+
+  range = NULL;
+  if ((N = get_argument (argc, argv, "-range"))) {
+    remove_argument (N, &argc, argv);
+    if ((range = SelectVector (argv[N], ANYVECTOR, TRUE)) == NULL) return (FALSE);    
+    remove_argument (N, &argc, argv);
+  }
+
+  double dx = NAN;
+  if ((N = get_argument (argc, argv, "-dx"))) {
+    remove_argument (N, &argc, argv);
+    dx = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  double dy = NAN;
+  if ((N = get_argument (argc, argv, "-dy"))) {
+    remove_argument (N, &argc, argv);
+    dy = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  double dz = NAN;
+  if ((N = get_argument (argc, argv, "-dz"))) {
+    remove_argument (N, &argc, argv);
+    dz = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  int valid = (!reuse && (argc == 11)) || (reuse && (argc == 5));
+  if (!valid) {
+    gprint (GP_ERR, "USAGE: tdhistogram buffer x y z (Xmin) (Xmax) (Ymin) (Ymax) (Zmin) (Zmax) [-dx dx] [-dy dy] [-dz dz]\n");
+    gprint (GP_ERR, "   OR: tdhistogram buffer x y z -reuse\n");
+    gprint (GP_ERR, " output buffer is 3D\n");
+    return (FALSE);
+  }
+  
+  if ((bf = SelectBuffer (argv[1], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((vx = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vy = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vz = SelectVector (argv[4], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (vx[0].Nelements != vy[0].Nelements) return (FALSE);
+  if (vx[0].Nelements != vz[0].Nelements) return (FALSE);
+
+  double Xmin, Xmax, Ymin, Ymax, Zmin, Zmax;
+
+  if (!reuse) {
+    Xmin = atof(argv[5]);
+    Xmax = atof(argv[6]);
+    if (!isfinite(dx)) {
+      Nx = 100;
+      dx = (Xmax - Xmin) / (Nx - 1);
+    } else {
+      Nx = (Xmax - Xmin) / dx + 1;
+    }
+    if (dx < 0) {
+      gprint (GP_ERR, "invalid value for delta: %f\n", dx);
+      return (FALSE);
+    }
+    Ymin = atof(argv[7]);
+    Ymax = atof(argv[8]);
+    if (!isfinite(dy)) {
+      Ny = 100;
+      dy = (Ymax - Ymin) / (Ny - 1);
+    } else {
+      Ny = (Ymax - Ymin) / dy + 1;
+    }
+    if (dy < 0) {
+      gprint (GP_ERR, "invalid value for delta: %f\n", dy);
+      return (FALSE);
+    }
+    Zmin = atof(argv[9]);
+    Zmax = atof(argv[10]);
+    if (!isfinite(dz)) {
+      Nz = 100;
+      dz = (Zmax - Zmin) / (Nz - 1);
+    } else {
+      Nz = (Zmax - Zmin) / dz + 1;
+    }
+    if (dz < 0) {
+      gprint (GP_ERR, "invalid value for delta: %f\n", dz);
+      return (FALSE);
+    }
+
+    if (Nz > 1000) {
+      gprint (GP_ERR, "warning: delta of %f will result in %d histogram bins\n", dz, Nz);
+      return (FALSE);
+    }
+  } else {
+    gfits_scan (&bf[0].header, "XMIN", "%lf", 1, &Xmin);
+    gfits_scan (&bf[0].header, "XMAX", "%lf", 1, &Xmax);
+    gfits_scan (&bf[0].header, "XDEL", "%lf", 1, &dx);
+    gfits_scan (&bf[0].header, "YMIN", "%lf", 1, &Ymin);
+    gfits_scan (&bf[0].header, "YMAX", "%lf", 1, &Ymax);
+    gfits_scan (&bf[0].header, "YDEL", "%lf", 1, &dy);
+    gfits_scan (&bf[0].header, "ZMIN", "%lf", 1, &Zmin);
+    gfits_scan (&bf[0].header, "ZMAX", "%lf", 1, &Zmax);
+    gfits_scan (&bf[0].header, "ZDEL", "%lf", 1, &dz);
+    Nx = bf[0].header.Naxis[0];
+    Ny = bf[0].header.Naxis[1];
+    Nz = bf[0].header.Naxis[2];
+  }
+
+  REQUIRE_VECTOR_FLT (vx, FALSE); 
+  REQUIRE_VECTOR_FLT (vy, FALSE); 
+  REQUIRE_VECTOR_FLT (vz, FALSE); 
+
+  CHECKVAL(Xmin);
+  CHECKVAL(Xmax);
+  CHECKVAL(dx);
+
+  CHECKVAL(Ymin);
+  CHECKVAL(Ymax);
+  CHECKVAL(dy);
+
+  if (range) {
+    ResetVector (range, OPIHI_FLT, Nz);
+    for (i = 0; i < range[0].Nelements; i++) {
+      range[0].elements.Flt[i] = Zmin + i*dz;
+    }
+  }
+
+  if (!reuse) {
+    gfits_free_matrix (&bf[0].matrix);
+    gfits_free_header (&bf[0].header);
+    CreateBuffer3D (bf, Nx, Ny, Nz, -32, 0.0, 1.0);
+    strcpy (bf[0].file, "(empty)");
+
+    gfits_modify (&bf[0].header, "XMIN", "%lf", 1, Xmin);
+    gfits_modify (&bf[0].header, "XMAX", "%lf", 1, Xmax);
+    gfits_modify (&bf[0].header, "XDEL", "%lf", 1, dx);
+    gfits_modify (&bf[0].header, "YMIN", "%lf", 1, Ymin);
+    gfits_modify (&bf[0].header, "YMAX", "%lf", 1, Ymax);
+    gfits_modify (&bf[0].header, "YDEL", "%lf", 1, dy);
+    gfits_modify (&bf[0].header, "ZMIN", "%lf", 1, Zmin);
+    gfits_modify (&bf[0].header, "ZMAX", "%lf", 1, Zmax);
+    gfits_modify (&bf[0].header, "ZDEL", "%lf", 1, dz);
+  }
+  
+  x = vx[0].elements.Flt;
+  y = vy[0].elements.Flt;
+  z = vz[0].elements.Flt;
+
+  val = (float *) bf[0].matrix.buffer;
+
+  for (i = 0; i < vx[0].Nelements; i++, x++, y++, z++) {
+    int Xb = (*x - Xmin) / dx;
+    int Yb = (*y - Ymin) / dy;
+    int Zb = (*z - Zmin) / dz;
+
+    if (Xb >= Nx) continue;
+    if (Yb >= Ny) continue;
+    if (Zb >= Nz) continue;
+    if (Xb < 0) continue;
+    if (Yb < 0) continue;
+    if (Zb < 0) continue;
+    val[Xb + Yb*Nx + Zb*Nx*Ny] ++;
+  }
+  return (TRUE);
+}
