Index: trunk/Ohana/src/opihi/cmd.astro/specpairfit.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.astro/specpairfit.c	(revision 39557)
+++ trunk/Ohana/src/opihi/cmd.astro/specpairfit.c	(revision 39558)
@@ -19,25 +19,56 @@
   CastVector (window, OPIHI_INT);
 
-  // minimize (flux1 - flux2*alpha) in window defined by mask
+  // minimize (flux2 - flux1*A - B) in window defined by mask
   // note that the mask is a SELECTION mask not an EXCLUSION mask
 
-  double F12 = 0.0; 
-  double F22 = 0.0;
+  double R = 0.0, F1 = 0.0, F11 = 0.0, F12 = 0.0, F2 = 0.0;
   for (i = 0; i < flux1->Nelements; i++) {
-    if ((mask & window->elements.Int[i]) == 0) continue;
+    // if ((mask & window->elements.Int[i]) == 0) continue;
     double weight = 1.0 / (SQ(dflux1->elements.Flt[i]) + SQ(dflux2->elements.Flt[i]));
+    R   += weight;
+    F1  += flux1->elements.Flt[i] * weight;
+    F2  += flux2->elements.Flt[i] * weight;
+    F11 += flux1->elements.Flt[i] * flux1->elements.Flt[i] * weight;
     F12 += flux1->elements.Flt[i] * flux2->elements.Flt[i] * weight;
-    F22 += flux2->elements.Flt[i] * flux2->elements.Flt[i] * weight;
   }
 
-  double Ao = F12 / F22;
-  double dA = sqrt(1.0 / F22);
+  int nterm = 2;
+  double **b = NULL, **c = NULL;
+  ALLOCATE (b, double *, nterm);
+  ALLOCATE (c, double *, nterm);
+  for (i = 0; i < nterm; i++) {
+    ALLOCATE (c[i], double, nterm);
+    ALLOCATE (b[i], double, 1);
+  }
+  c[0][0] = F11;
+  c[1][0] = c[0][1] = F1;
+  c[1][1] = R;
 
-  int Ndof = -1; // 1 parameter fit
+  b[0][0] = F12;
+  b[1][0] = F2;
+
+  if (!dgaussjordan (c, b, nterm, 1)) {
+    gprint (GP_ERR, "failed to fit data : ill-conditioned matrix\n");
+    goto escape;
+  }
+
+  double Ao = b[0][0];
+  double dA = sqrt(c[0][0]);
+  double Bo = b[1][0];
+  double dB = sqrt(c[1][1]);
+
+  for (i = 0; i < nterm; i++) {
+    free (b[i]);
+    free (c[i]);
+  }
+  free (b);
+  free (c);
+
+  int Ndof = -2; // 2 parameter fit
   double chisq = 0.0;
   for (i = 0; i < flux1->Nelements; i++) {
     if ((mask & window->elements.Int[i]) == 0) continue;
     double weight = 1.0 / (SQ(dflux1->elements.Flt[i]) + SQ(dflux2->elements.Flt[i]));
-    chisq += SQ(flux1->elements.Flt[i] - Ao * flux2->elements.Flt[i]) * weight;
+    chisq += SQ(flux1->elements.Flt[i] - Ao * flux2->elements.Flt[i] - Bo) * weight;
     Ndof ++;
   }
@@ -45,7 +76,10 @@
   double chisqNu = chisq / Ndof;
 
+  // fprintf (stderr, "R: %f, F1: %f, F11: %f, F2: %f, F12: %f\n", R, F1, F11, F2, F12);
   // fprintf (stderr, "Ao: %f +/- %f, chisq: %f, chisq_nu : %f for %d dof\n", Ao, dA, chisq, chisqNu, Ndof);
   set_variable ("Ao", Ao);
   set_variable ("dA", dA);
+  set_variable ("Bo", Bo);
+  set_variable ("dB", dB);
   set_variable ("Xv", chisqNu);
   set_variable ("Nd", Ndof);
Index: trunk/Ohana/src/opihi/cmd.astro/transform.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.astro/transform.c	(revision 39557)
+++ trunk/Ohana/src/opihi/cmd.astro/transform.c	(revision 39558)
@@ -53,4 +53,5 @@
 	  X = x; Y = y;
 	  if ((X > -1) && (X < Nx) && (Y > -1) && (Y < Ny)) {
+	    if (!isfinite(*Vin)) continue;
 	    Vout[X + Y*Nx] += *Vin;
 	    Sout[X + Y*Nx] ++;
Index: trunk/Ohana/src/opihi/cmd.data/Makefile
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/Makefile	(revision 39557)
+++ trunk/Ohana/src/opihi/cmd.data/Makefile	(revision 39558)
@@ -149,4 +149,5 @@
 $(SRC)/tvcontour.$(ARCH).o	   \
 $(SRC)/tvgrid.$(ARCH).o	           \
+$(SRC)/type.$(ARCH).o		   \
 $(SRC)/uniq.$(ARCH).o		   \
 $(SRC)/unsign.$(ARCH).o	           \
Index: trunk/Ohana/src/opihi/cmd.data/init.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/init.c	(revision 39557)
+++ trunk/Ohana/src/opihi/cmd.data/init.c	(revision 39558)
@@ -137,4 +137,5 @@
 int tvcontour        PROTO((int, char **));
 int tvgrid           PROTO((int, char **));
+int opihi_type             PROTO((int, char **));
 int uniq             PROTO((int, char **));
 int unsign           PROTO((int, char **));
@@ -314,4 +315,5 @@
   {1, "tvcontour",    tvcontour,        "send contour to image overlay"},
   {1, "tvgrid",       tvgrid,           "RA/DEC grid on an image"},
+  {1, "type",         opihi_type,       "get scalar/vector/matrix type information"},
   {1, "ungridify",    ungridify,        "convert image region to vector triplet"},
   {1, "uniq",         uniq,             "create a uniq vector subset from a vector"},
Index: trunk/Ohana/src/opihi/cmd.data/type.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/type.c	(revision 39558)
+++ trunk/Ohana/src/opihi/cmd.data/type.c	(revision 39558)
@@ -0,0 +1,56 @@
+# include "data.h"
+
+int opihi_type (int argc, char **argv) {
+  
+  int N;
+
+  int SCALAR = FALSE;
+  if ((N = get_argument (argc, argv, "-scalar"))) {
+    SCALAR = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  char *varName = NULL;
+  if ((N = get_argument (argc, argv, "-var"))) {
+    remove_argument (N, &argc, argv);
+    varName = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 2) goto usage;
+
+  char result[16]; memset (result, 0, 16);
+
+  if (SCALAR) {
+    if (IsScalar (argv[1])) {
+      strcpy (result, "found");
+    } else {
+      strcpy (result, "none");
+    }
+    goto got_result;
+  }
+
+  Vector *vec = NULL;
+  Buffer *buf = NULL;
+  if ((vec = SelectVector (argv[1], OLDVECTOR, FALSE)) != NULL) {
+    if (vec->type == OPIHI_FLT) { strcpy (result, "float"); goto got_result; }
+    if (vec->type == OPIHI_INT) { strcpy (result, "int");   goto got_result; }
+    myAbort ("impossible");
+  }
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, FALSE)) != NULL) { strcpy (result, "matrix"); goto got_result; }
+  strcpy (result, "none");
+
+got_result:
+  if (varName) {
+    set_str_variable (varName, result);
+  } else {
+    gprint (GP_LOG, "%s\n", result);
+  }
+  return TRUE;
+
+usage:
+  gprint (GP_ERR, "SYNTAX: type (vector/buffer) [-var value] [-scalar]\n");
+  gprint (GP_ERR, "  returns 'none', 'float', 'int' for vector types, 'matrix' for buffer / image / matrix\n");
+  gprint (GP_ERR, "  returns 'none', 'found' for scalar types if -scalar is selected\n");
+  return (FALSE);
+}
Index: trunk/Ohana/src/opihi/lib.shell/VariableOps.c
===================================================================
--- trunk/Ohana/src/opihi/lib.shell/VariableOps.c	(revision 39557)
+++ trunk/Ohana/src/opihi/lib.shell/VariableOps.c	(revision 39558)
@@ -197,4 +197,6 @@
 
 /* return TRUE / FALSE if name is an existant variable */
+// XXX is this function better than IsScalar?
+# if (0) 
 int get_variable_exists (char *name) {
   
@@ -205,4 +207,5 @@
   return (FALSE);
 }
+# endif
 
 float get_variable_default (char *name, float dvalue) {
Index: trunk/Ohana/src/opihi/lib.shell/convert_to_RPN.c
===================================================================
--- trunk/Ohana/src/opihi/lib.shell/convert_to_RPN.c	(revision 39557)
+++ trunk/Ohana/src/opihi/lib.shell/convert_to_RPN.c	(revision 39558)
@@ -76,5 +76,6 @@
     if (!strcmp (argv[i], "max"))    { type = ST_BINARY; strcpy (argv[i], "U"); goto gotit; }
     if (!strcmp (argv[i], "min"))    { type = ST_BINARY; strcpy (argv[i], "D"); goto gotit; }
-    if (!strcmp (argv[i], "atan2"))  { type = ST_BINARY; goto gotit; }
+    if (!strcmp (argv[i], "atan2"))  { type = ST_BINARY; strcpy (argv[i], "a"); goto gotit; }
+    if (!strcmp (argv[i], "datan2")) { type = ST_BINARY; strcpy (argv[i], "d"); goto gotit; }
     if (!strcmp (argv[i], ","))      { type = ST_COMMA; goto gotit; }
 
Index: trunk/Ohana/src/opihi/lib.shell/stack_math.c
===================================================================
--- trunk/Ohana/src/opihi/lib.shell/stack_math.c	(revision 39557)
+++ trunk/Ohana/src/opihi/lib.shell/stack_math.c	(revision 39558)
@@ -343,5 +343,6 @@
     case '^': VV_FUNC(ST_SCALAR_FLT, pow (*M1, *M2));
     case '@': VV_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (*M1, *M2));
-    case 'a': VV_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (*M1, *M2));
+    case 'd': VV_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (*M1, *M2));
+    case 'a': VV_FUNC(ST_SCALAR_FLT,         atan2 (*M1, *M2));
     case 'D': VV_FUNC(ST_SCALAR_INT, MIN (*M1, *M2));
     case 'U': VV_FUNC(ST_SCALAR_INT, MAX (*M1, *M2));
@@ -454,5 +455,6 @@
     case '^': SV_FUNC(ST_SCALAR_FLT, pow (M1, *M2));
     case '@': SV_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (M1, *M2));
-    case 'a': SV_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (M1, *M2));
+    case 'd': SV_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (M1, *M2));
+    case 'a': SV_FUNC(ST_SCALAR_FLT,         atan2 (M1, *M2));
     case 'D': SV_FUNC(ST_SCALAR_INT, MIN (M1, *M2));
     case 'U': SV_FUNC(ST_SCALAR_INT, MAX (M1, *M2));
@@ -561,5 +563,6 @@
     case '^': VS_FUNC(ST_SCALAR_FLT, pow (*M1, M2));
     case '@': VS_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (*M1, M2));
-    case 'a': VS_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (*M1, M2));
+    case 'd': VS_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (*M1, M2));
+    case 'a': VS_FUNC(ST_SCALAR_FLT,         atan2 (*M1, M2));
     case 'D': VS_FUNC(ST_SCALAR_INT, MIN (*M1, M2));
     case 'U': VS_FUNC(ST_SCALAR_INT, MAX (*M1, M2));
@@ -652,5 +655,6 @@
     case '^': MV_FUNC(pow (*M1, *M2));
     case '@': MV_FUNC(DEG_RAD*atan2 (*M1, *M2));
-    case 'a': MV_FUNC(DEG_RAD*atan2 (*M1, *M2));
+    case 'd': MV_FUNC(DEG_RAD*atan2 (*M1, *M2));
+    case 'a': MV_FUNC(        atan2 (*M1, *M2));
     case 'D': MV_FUNC(MIN (*M1, *M2));
     case 'U': MV_FUNC(MAX (*M1, *M2));
@@ -745,5 +749,6 @@
     case '^': VM_FUNC(pow (*M1, *M2));
     case '@': VM_FUNC(DEG_RAD*atan2 (*M1, *M2));
-    case 'a': VM_FUNC(DEG_RAD*atan2 (*M1, *M2));
+    case 'd': VM_FUNC(DEG_RAD*atan2 (*M1, *M2));
+    case 'a': VM_FUNC(        atan2 (*M1, *M2));
     case 'D': VM_FUNC(MIN (*M1, *M2));
     case 'U': VM_FUNC(MAX (*M1, *M2));
@@ -825,5 +830,6 @@
     case '^': MM_FUNC(pow (*M1, *M2));
     case '@': MM_FUNC(DEG_RAD*atan2 (*M1, *M2));
-    case 'a': MM_FUNC(DEG_RAD*atan2 (*M1, *M2));
+    case 'd': MM_FUNC(DEG_RAD*atan2 (*M1, *M2));
+    case 'a': MM_FUNC(        atan2 (*M1, *M2));
     case 'D': MM_FUNC(MIN (*M1, *M2));
     case 'U': MM_FUNC(MAX (*M1, *M2));
@@ -910,5 +916,6 @@
     case '^': MS_FUNC(pow (*M1, M2));
     case '@': MS_FUNC(DEG_RAD*atan2 (*M1, M2));
-    case 'a': MS_FUNC(DEG_RAD*atan2 (*M1, M2));
+    case 'd': MS_FUNC(DEG_RAD*atan2 (*M1, M2));
+    case 'a': MS_FUNC(        atan2 (*M1, M2));
     case 'D': MS_FUNC(MIN (*M1, M2));
     case 'U': MS_FUNC(MAX (*M1, M2));
@@ -986,5 +993,6 @@
     case '^': SM_FUNC(pow (M1, *M2));
     case '@': SM_FUNC(DEG_RAD*atan2 (M1, *M2));
-    case 'a': SM_FUNC(DEG_RAD*atan2 (M1, *M2));
+    case 'd': SM_FUNC(DEG_RAD*atan2 (M1, *M2));
+    case 'a': SM_FUNC(        atan2 (M1, *M2));
     case 'D': SM_FUNC(MIN (M1, *M2));
     case 'U': SM_FUNC(MAX (M1, *M2));
@@ -1068,5 +1076,6 @@
     case '^': SS_FUNC(ST_SCALAR_FLT, pow (M1, M2));
     case '@': SS_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (M1, M2));
-    case 'a': SS_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (M1, M2));
+    case 'd': SS_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (M1, M2));
+    case 'a': SS_FUNC(ST_SCALAR_FLT,         atan2 (M1, M2));
     case 'D': SS_FUNC(ST_SCALAR_INT, MIN (M1, M2));
     case 'U': SS_FUNC(ST_SCALAR_INT, MAX (M1, M2));
