Index: trunk/Ohana/src/opihi/cmd.data/vstats.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/vstats.c	(revision 38441)
+++ trunk/Ohana/src/opihi/cmd.data/vstats.c	(revision 41891)
@@ -48,6 +48,8 @@
   }
 
-  if (argc != 2) {
-    gprint (GP_ERR, "USAGE: vstat (vector) [-ignore value] [-q] [-quiet] [-iter Niter] [-sigma-clip Nsigma]\n");
+  int valid = (argc == 2);
+  valid |= (argc > 3) && !strcmp (argv[2], "where");
+  if (!valid) {
+    gprint (GP_ERR, "USAGE: vstat (vector) [-ignore value] [-q] [-quiet] [-iter Niter] [-sigma-clip Nsigma] [where (logical expression)]\n");
     gprint (GP_ERR, "  default is 1 iteration without sigma clipping or 3 with sigma clipping\n");
     return (FALSE);
@@ -58,21 +60,48 @@
   /* we need two passes, one for max, min, mean, sum, one for median, stdev, etc */
 
-  // set a good / bad mask
+  // tvec is used for logical test (truth vector)
+  Vector *tvec = NULL;
+  if (argc > 3) {
+    int size;
+    char *out = dvomath (argc - 3, &argv[3], &size, 1);
+    if (out == NULL) {
+      print_error ();
+      return FALSE;
+    }
+    if ((tvec = SelectVector (out, OLDVECTOR, TRUE)) == NULL) {
+      gprint (GP_ERR, " invalid logic result\n");
+      DeleteNamedVector (out);
+      free (out);
+      return (FALSE);
+    }
+    if (tvec->Nelements != vec->Nelements) {
+      gprint (GP_ERR, "logical vector does not match in length\n");
+      return FALSE;
+    }
+  }
+
+  // set a good / bad mask (mask == 1 means 'bad')
   ALLOCATE (mask, char, vec[0].Nelements);
   if (vec[0].type == OPIHI_FLT) {
     opihi_flt *X = vec[0].elements.Flt;
     for (i = 0; i < vec[0].Nelements; i++, X++) {
-      mask[i] = 1;
-      if (!finite (*X)) continue;
-      if (Ignore && (*X == IgnoreValue)) continue;
-      mask[i] = 0;
+      mask[i] = 0; // do not mask unless we have a reason below
+      if (tvec) {
+	// note the logical vector is 0 == bad (ignore) while mask[i] has the opposite sense (0 is good)
+	mask[i] = (tvec->type == OPIHI_FLT) ? (tvec->elements.Flt[i] == 0.0) : (tvec->elements.Int[i] == 0);
+      }
+      if (!finite (*X)) { mask[i] = 1; }
+      if (Ignore && (*X == IgnoreValue)) { mask[i] = 1; }
     }      
   } else {
     opihi_int *X = vec[0].elements.Int;
     for (i = 0; i < vec[0].Nelements; i++, X++) {
-      mask[i] = 1;
-      if (!finite (*X)) continue;
-      if (Ignore && (*X == IgnoreValue)) continue;
-      mask[i] = 0;
+      mask[i] = 0; // do not mask unless we have a reason below
+      if (tvec) {
+	// note the logical vector is 0 == bad (ignore) while mask[i] has the opposite sense (0 is good)
+	mask[i] = (tvec->type == OPIHI_FLT) ? (tvec->elements.Flt[i] == 0.0) : (tvec->elements.Int[i] == 0);
+      }
+      if (!finite (*X)) { mask[i] = 1; }
+      if (Ignore && (*X == IgnoreValue)) { mask[i] = 1; }
     }      
   }
