Index: /branches/eam_branches/ipp-20220316/Ohana/src/opihi/cmd.data/imspline_apply.c
===================================================================
--- /branches/eam_branches/ipp-20220316/Ohana/src/opihi/cmd.data/imspline_apply.c	(revision 42360)
+++ /branches/eam_branches/ipp-20220316/Ohana/src/opihi/cmd.data/imspline_apply.c	(revision 42361)
@@ -77,5 +77,5 @@
       Tx1[i] = spline_apply_flt (Tyc, Ty1, Ty2, Ny, y);
     }
-    spline_construct_flt (Txc, Tx1, Nx, Tx2);
+    spline_construct_flt (Txc, Tx1, Nx, Tx2, NAN, NAN);
 
     /* apply x-dir spline to new image */
Index: /branches/eam_branches/ipp-20220316/Ohana/src/opihi/cmd.data/imspline_construct.c
===================================================================
--- /branches/eam_branches/ipp-20220316/Ohana/src/opihi/cmd.data/imspline_construct.c	(revision 42360)
+++ /branches/eam_branches/ipp-20220316/Ohana/src/opihi/cmd.data/imspline_construct.c	(revision 42361)
@@ -55,5 +55,5 @@
     }
   
-    spline_construct_flt (Tx, Ty, Ny, Ty2);
+    spline_construct_flt (Tx, Ty, Ny, Ty2, NAN, NAN);
   
     /* copy derivatives to output buffer */
Index: /branches/eam_branches/ipp-20220316/Ohana/src/opihi/cmd.data/spline_commands.c
===================================================================
--- /branches/eam_branches/ipp-20220316/Ohana/src/opihi/cmd.data/spline_commands.c	(revision 42360)
+++ /branches/eam_branches/ipp-20220316/Ohana/src/opihi/cmd.data/spline_commands.c	(revision 42361)
@@ -15,6 +15,19 @@
 int spline_create (int argc, char **argv) {
 
-  int i;
+  int i, N;
   Vector *xvec, *yvec;
+
+  double dyLower = NAN;
+  double dyUpper = NAN;
+  if ((N = get_argument (argc, argv, "-dyLower"))) {
+    remove_argument (N, &argc, argv);
+    dyLower = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-dyUpper"))) {
+    remove_argument (N, &argc, argv);
+    dyUpper = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
 
   if (argc != 4) {
@@ -43,5 +56,5 @@
   }    
 
-  spline_construct_dbl (myspline->xk, myspline->yk, myspline->Nknots, myspline->y2);
+  spline_construct_dbl (myspline->xk, myspline->yk, myspline->Nknots, myspline->y2, dyLower, dyUpper);
   return TRUE;
 }
Index: /branches/eam_branches/ipp-20220316/Ohana/src/opihi/cmd.data/threshold.c
===================================================================
--- /branches/eam_branches/ipp-20220316/Ohana/src/opihi/cmd.data/threshold.c	(revision 42360)
+++ /branches/eam_branches/ipp-20220316/Ohana/src/opihi/cmd.data/threshold.c	(revision 42361)
@@ -1,3 +1,16 @@
 # include "data.h"
+
+int QUIET = FALSE;
+
+void _threshold_set_values (double value, int Nbin, double level, int thresherr) {
+
+  set_variable ("threshval", value);
+  set_int_variable ("threshbin", Nbin);
+  set_variable ("threshold", level);
+  set_int_variable ("thresherr", thresherr);
+
+  if (!QUIET) gprint (GP_LOG, "theshold %f (bin %d is %f)\n", level, Nbin, value);
+  return;
+}
 
 int threshold (int argc, char **argv) {
@@ -6,7 +19,16 @@
   Vector *vecx, *vecy;
 
-  int QUIET = FALSE;
   if ((N = get_argument (argc, argv, "-q"))) {
     QUIET = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  int SATURATE = FALSE;
+  if ((N = get_argument (argc, argv, "-saturate"))) {
+    SATURATE = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-sat"))) {
+    SATURATE = TRUE;
     remove_argument (N, &argc, argv);
   }
@@ -95,24 +117,22 @@
     // this algorithm assumes vecy[BinMax] > threshold, vecy[BinMin] < threshold
     if (vecy[0].elements.Flt[BinMin] > value) {
-      if (!QUIET) gprint (GP_ERR, "ERROR: all values above threshold\n");
-      set_int_variable ("threshbin", BinMin);
-      set_variable ("threshval", vecy[0].elements.Flt[BinMin]);
-      set_variable ("threshold", vecx[0].elements.Flt[BinMin]);
-      set_int_variable ("thresherr", 1);
-      if (!QUIET) gprint (GP_LOG, "theshold %f (bin %d is %f)\n",
-			  vecx[0].elements.Flt[BinMin], BinMin,
-			  vecy[0].elements.Flt[BinMin]);
-      return TRUE;
+      if (SATURATE) {
+	_threshold_set_values (vecy[0].elements.Flt[BinMin], BinMin, vecx[0].elements.Flt[BinMin], 1);
+	return TRUE;
+      } else {
+	gprint (GP_ERR, "ERROR: all values above threshold\n");
+	_threshold_set_values (NAN, -1, NAN, 1);
+	return FALSE;
+      }
     }
     if (vecy[0].elements.Flt[BinMax] < value) {
-      if (!QUIET) gprint (GP_ERR, "ERROR: all values below threshold\n");
-      set_int_variable ("threshbin", BinMax);
-      set_variable ("threshval", vecy[0].elements.Flt[BinMax]);
-      set_variable ("threshold", vecx[0].elements.Flt[BinMax]);
-      set_int_variable ("thresherr", 1);
-      if (!QUIET) gprint (GP_LOG, "theshold %f (bin %d is %f)\n",
-			  vecx[0].elements.Flt[BinMax], BinMax,
-			  vecy[0].elements.Flt[BinMax]);
-      return TRUE;
+      if (SATURATE) {
+	_threshold_set_values (vecy[0].elements.Flt[BinMax], BinMax, vecx[0].elements.Flt[BinMax], 1);
+	return TRUE;
+      } else {
+	gprint (GP_ERR, "ERROR: all values below threshold\n");
+	_threshold_set_values (NAN, -1, NAN, 1);
+	return FALSE;
+      }
     }
     while (Nhi - Nlo > 10) {
@@ -136,24 +156,22 @@
     // this algorithm assumes vecy[BinMin] > threshold, vecy[BinMax] < threshold
     if (vecy[0].elements.Flt[BinMin] < value) {
-      if (!QUIET) gprint (GP_ERR, "ERROR: all values below threshold\n");
-      set_int_variable ("threshbin", BinMin);
-      set_variable ("threshval", vecy[0].elements.Flt[BinMin]);
-      set_variable ("threshold", vecx[0].elements.Flt[BinMin]);
-      set_int_variable ("thresherr", 1);
-      if (!QUIET) gprint (GP_LOG, "theshold %f (bin %d is %f)\n",
-			  vecx[0].elements.Flt[BinMin], BinMin,
-			  vecy[0].elements.Flt[BinMin]);
-      return TRUE;
+      if (SATURATE) {
+	_threshold_set_values (vecy[0].elements.Flt[BinMin], BinMin, vecx[0].elements.Flt[BinMin], 1);
+	return TRUE;
+      } else {
+	gprint (GP_ERR, "ERROR: all values below threshold\n");
+	_threshold_set_values (NAN, -1, NAN, 1);
+	return FALSE;
+      }
     }
     if (vecy[0].elements.Flt[BinMax] > value) {
-      if (!QUIET) gprint (GP_ERR, "ERROR: all values above threshold\n");
-      set_int_variable ("threshbin", BinMax);
-      set_variable ("threshval", vecy[0].elements.Flt[BinMax]);
-      set_variable ("threshold", vecx[0].elements.Flt[BinMax]);
-      set_int_variable ("thresherr", 1);
-      if (!QUIET) gprint (GP_LOG, "theshold %f (bin %d is %f)\n",
-			  vecx[0].elements.Flt[BinMax], BinMax,
-			  vecy[0].elements.Flt[BinMax]);
-      return TRUE;
+      if (SATURATE) {
+	_threshold_set_values (vecy[0].elements.Flt[BinMax], BinMax, vecx[0].elements.Flt[BinMax], 1);
+	return TRUE;
+      } else {
+	gprint (GP_ERR, "ERROR: all values above threshold\n");
+	_threshold_set_values (NAN, -1, NAN, 1);
+	return FALSE;
+      }
     }
     while (Nhi - Nlo > 10) {
@@ -202,11 +220,5 @@
   }
 
-  set_variable ("threshval", y1);
-  set_variable ("threshold", Xvalue);
-  set_int_variable ("threshbin", Nhi);
-  set_int_variable ("thresherr", 0);
-
-  if (!QUIET) gprint (GP_LOG, "theshold %f (bin %d is %f)\n", Xvalue, Nhi, y1);
-
+  _threshold_set_values (y1, Nhi, Xvalue, 0);
   return (TRUE);
 }
Index: /branches/eam_branches/ipp-20220316/Ohana/src/opihi/include/data.h
===================================================================
--- /branches/eam_branches/ipp-20220316/Ohana/src/opihi/include/data.h	(revision 42360)
+++ /branches/eam_branches/ipp-20220316/Ohana/src/opihi/include/data.h	(revision 42361)
@@ -133,7 +133,7 @@
 
 /* in spline.c */
-void spline_construct_flt (float *x, float *y, int N, float *y2);
+void spline_construct_flt (float *x, float *y, int N, float *y2, float dyLower, float dyUpper);
 float spline_apply_flt (float *x, float *y, float *y2, int N, float X);
-void spline_construct_dbl (opihi_flt *x, opihi_flt *y, int N, opihi_flt *y2);
+void spline_construct_dbl (opihi_flt *x, opihi_flt *y, int N, opihi_flt *y2, opihi_flt dyLower, opihi_flt dyUpper);
 opihi_flt spline_apply_dbl (opihi_flt *x, opihi_flt *y, opihi_flt *y2, int N, opihi_flt X);
 
Index: /branches/eam_branches/ipp-20220316/Ohana/src/opihi/lib.data/spline.c
===================================================================
--- /branches/eam_branches/ipp-20220316/Ohana/src/opihi/lib.data/spline.c	(revision 42360)
+++ /branches/eam_branches/ipp-20220316/Ohana/src/opihi/lib.data/spline.c	(revision 42361)
@@ -2,5 +2,5 @@
 
 /* construct the natural spline for x, y in y2 */
-void spline_construct_flt (float *x, float *y, int N, float *y2) {
+void spline_construct_flt (float *x, float *y, int N, float *y2, float dyLower, float dyUpper) {
 
   int i;
@@ -67,5 +67,5 @@
 
 /* construct the natural spline for x, y in y2 */
-void spline_construct_dbl (opihi_flt *x, opihi_flt *y, int N, opihi_flt *y2) {
+void spline_construct_dbl (opihi_flt *x, opihi_flt *y, int N, opihi_flt *y2, opihi_flt dyLower, opihi_flt dyUpper) {
 
   int i;
@@ -77,5 +77,10 @@
   ALLOCATE (tmp, opihi_flt, N);
 
-  y2[0] = tmp[0] = 0.0;
+  if (isnan(dyLower)) {
+    y2[0] = tmp[0] = 0.0;
+  } else {
+    y2[0] = -0.5;
+    tmp[0]   = (3.0/(x[1]-x[0])) * ((y[1]-y[0])/(x[1]-x[0]) - dyLower);
+  }
   
   for (i = 1; i < N-1; i++) {
@@ -86,8 +91,16 @@
     tmp[i] = (6.0 * tmp[i] / (x[i+1] - x[i-1]) - dx*tmp[i-1]) / dy;
   }
+
+  if (isfinite(dyUpper)) {
+    opihi_flt qn = 0.5;
+    tmp[N-1] = (3.0/(x[N-1]-x[N-2])) * (dyUpper - (y[N-1]-y[N-2])/(x[N-1]-x[N-2]));
+    y2[N-1] = (tmp[N-1] - (qn * tmp[N-2])) / ((qn * y2[N-2]) + 1.0);
+  } else {
+    y2[N-1] = 0;
+  }
   
-  y2[N-1] = 0;
-  for (i = N-2; i >= 1; i--)
+  for (i = N-2; i >= 0; i--) {
     y2[i] = y2[i]*y2[i+1] + tmp[i];
+  }
 
   free (tmp);
Index: /branches/eam_branches/ipp-20220316/Ohana/src/opihi/lib.shell/parse.c
===================================================================
--- /branches/eam_branches/ipp-20220316/Ohana/src/opihi/lib.shell/parse.c	(revision 42360)
+++ /branches/eam_branches/ipp-20220316/Ohana/src/opihi/lib.shell/parse.c	(revision 42361)
@@ -124,4 +124,5 @@
       free (B);
 
+      // XXX make this error output conditional
       if (filestatus) gprint (GP_ERR, "warning: exit status of command %d\n", filestatus);
       set_int_variable ("EXECSTATUS", filestatus);
Index: /branches/eam_branches/ipp-20220316/Ohana/src/opihi/lib.shell/stack_math.c
===================================================================
--- /branches/eam_branches/ipp-20220316/Ohana/src/opihi/lib.shell/stack_math.c	(revision 42360)
+++ /branches/eam_branches/ipp-20220316/Ohana/src/opihi/lib.shell/stack_math.c	(revision 42361)
@@ -1619,4 +1619,12 @@
   OUT[0].vector = InitVector ();
   OUT[0].type = ST_VECTOR_TMP; /*** <<--- says this is a temporary matrix ***/
+
+  if (V1->vector->type == OPIHI_STR) {
+    ResetVector (OUT->vector, V1->vector->type, V1->vector->Nelements);
+    for (i = 0; i < V1->vector->Nelements; i++) {
+      OUT->vector->elements.Str[i] = strcreate (V1->vector->elements.Str[i]);
+    }
+    goto escape;
+  }
 
 # define V_FUNC(OP,FTYPE) {						\
