Index: trunk/psastro/src/psastroModelAnalysis.c
===================================================================
--- trunk/psastro/src/psastroModelAnalysis.c	(revision 19314)
+++ trunk/psastro/src/psastroModelAnalysis.c	(revision 19386)
@@ -14,4 +14,7 @@
     pmFPAfile *output = psMetadataLookupPtr (&status, config->files, "PSASTRO.OUT.MODEL");
     if (!status) psAbort ("Can't find output pmFPAfile PSASTRO.OUT.MODEL");
+
+    char *outroot = psMetadataLookupStr (&status, config->arguments, "OUTPUT");
+    if (!status || !outroot) psAbort ("Can't find outroot on config->arguments");
 
     // physical pixel scale in microns per pixel
@@ -58,4 +61,14 @@
     output->fpa = NULL;
 
+    char filename[256];
+    snprintf (filename, 256, "%s.bore", outroot);
+    FILE *outfile = fopen (filename, "w");
+    if (!outfile) {
+        psError(PSASTRO_ERR_ARGUMENTS, true, "cannot open %s for output", filename);
+	return false;
+    }
+
+    float posBoundary = 0.0;
+
     // extract the relevant measured and reported values from the reference chip
     for (int i = 0; i < files->n; i++) {
@@ -80,13 +93,20 @@
 
 	// we have two measurements of the posangle (may be parity flipped to different quadrants)
+	// atan2 returns values in the range 0-2pi
+	// all posZero values should be clustered in some region, but we need to flip over the 0,360 boundary correctly.
+	// push all to one side or the other
 	float posangle = PM_DEG_RAD * atan2 (chip->toFPA->y->coeff[1][0], chip->toFPA->x->coeff[1][0]);
 	posZero->data.F32[n] = POSANGLE - posangle;
-	while (posZero->data.F32[n] > 360.0) posZero->data.F32[n] -= 360.0;
-	while (posZero->data.F32[n] <   0.0) posZero->data.F32[n] += 360.0;
+	if (n == 0) {
+	    posBoundary = posZero->data.F32[n] + 180.0;
+	} else {
+	    while (posZero->data.F32[n] > posBoundary) posZero->data.F32[n] -= 360.0;
+	    while (posZero->data.F32[n] < posBoundary - 360.0) posZero->data.F32[n] += 360.0;
+	}
 
 	Po->data.F32[n] = POSANGLE * PM_RAD_DEG; // reported position angle
 	Xo->data.F32[n] = chip->fromFPA->x->coeff[0][0]; // reported boresite x position in ref chip coordinates
 	Yo->data.F32[n] = chip->fromFPA->y->coeff[0][0]; // reported boresite y position in ref chip coordinates
-	fprintf (stderr, "%d : %f %f : %f = %f - %f\n", i, Xo->data.F32[n], Yo->data.F32[n], posZero->data.F32[n], POSANGLE, posangle);
+	fprintf (outfile, "%d : %f %f : %f = %f - %f\n", i, Xo->data.F32[n], Yo->data.F32[n], posZero->data.F32[n], POSANGLE, posangle);
 	n ++;
     }
@@ -100,9 +120,11 @@
     psVectorStats (stats, posZero, NULL, NULL, 0);
 
-    fprintf (stderr, "pos zero %f +/- %f\n", stats->sampleMedian, stats->sampleStdev);
+    fprintf (outfile, "# pos zero %f +/- %f\n", stats->sampleMedian, stats->sampleStdev);
     psMetadataAddF32 (output->fpa->concepts, PS_LIST_TAIL, "FPA.POS_ZERO", PS_META_REPLACE, "offset between obs and meas posangle", stats->sampleMedian); 
+    fclose (outfile);
 
-    psVector *params = psastroModelFitBoresite (Xo, Yo, Po);
+    psVector *params = psastroModelFitBoresite (Xo, Yo, Po, outroot);
     if (params->n != 6) psAbort ("error");
+
 
     psMetadataAddF32 (output->fpa->concepts, PS_LIST_TAIL, "FPA.BORE.X0", PS_META_REPLACE, "boresite parameter", params->data.F32[PAR_X0]); 
Index: trunk/psastro/src/psastroMosaicAstrom.c
===================================================================
--- trunk/psastro/src/psastroMosaicAstrom.c	(revision 19314)
+++ trunk/psastro/src/psastroMosaicAstrom.c	(revision 19386)
@@ -2,11 +2,14 @@
 # define NONLIN_TOL 0.001 /* tolerance in pixels */
 
-bool psastroMosaicFit (pmFPA *fpa, psMetadata *recipe, int pass);
+bool psastroMosaicFit (pmFPA *fpa, psMetadata *recipe, const char *rootname, int pass);
 
 // XXX require this fpa to have multiple chip extensions and a PHU?
 bool psastroMosaicAstrom (pmConfig *config) {
 
+    bool status;
+    char filename[256];
+
     // select the current recipe
-    psMetadata *recipe  = psMetadataLookupPtr (NULL, config->recipes, PSASTRO_RECIPE);
+    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSASTRO_RECIPE);
     if (!recipe) {
 	psError(PSASTRO_ERR_CONFIG, false, "Can't find PSASTRO recipe!\n");
@@ -36,8 +39,11 @@
     # endif
 
-    if (!psastroMosaicFit (fpa, recipe, 0)) return false;
-    if (!psastroMosaicFit (fpa, recipe, 1)) return false;
-    if (!psastroMosaicFit (fpa, recipe, 2)) return false;
-    if (!psastroMosaicFit (fpa, recipe, 3)) return false;
+    char *outroot = psMetadataLookupStr (&status, config->arguments, "OUTPUT");
+    if (!status || !outroot) psAbort ("Can't find outroot on config->arguments");
+
+    if (!psastroMosaicFit (fpa, recipe, outroot, 0)) return false;
+    if (!psastroMosaicFit (fpa, recipe, outroot, 1)) return false;
+    if (!psastroMosaicFit (fpa, recipe, outroot, 2)) return false;
+    if (!psastroMosaicFit (fpa, recipe, outroot, 3)) return false;
 
     // now fit the chips under the common distortion with higher-order terms
@@ -51,5 +57,8 @@
 	return false;
     }
-    if (psTraceGetLevel("psastro.dump") > 0) { psastroDumpMatches (fpa, "match.10.dat"); }
+    if (psTraceGetLevel("psastro.dump") > 0) { 
+	snprintf (filename, 256, "%s.10.dat", outroot);
+	psastroDumpMatches (fpa, filename); 
+    }
 
     // save WCS and analysis metadata in update header.
@@ -84,7 +93,7 @@
 // 2: match 6,7
 // 3: match 8,9
-bool psastroMosaicFit (pmFPA *fpa, psMetadata *recipe, int pass) {
+bool psastroMosaicFit (pmFPA *fpa, psMetadata *recipe, const char *rootname, int pass) {
 
-    char filename[16];
+    char filename[256];
 
     // given the existing per-chip astrometry, determine matches between raw and ref stars
@@ -95,5 +104,8 @@
     }
 
-    if ((pass == 0) && (psTraceGetLevel("psastro.dump.psastroMosaicAstrom") > 0)) { psastroDumpMatches (fpa, "match.0.dat"); }
+    if ((pass == 0) && (psTraceGetLevel("psastro.dump.psastroMosaicAstrom") > 0)) { 
+	snprintf (filename, 256, "%s.0.dat", rootname);
+	psastroDumpMatches (fpa, filename); 
+    }
 
     // fitted chips will follow the local plate-scale, hiding the distortion
@@ -105,5 +117,8 @@
     }
 
-    if ((pass == 0) && (psTraceGetLevel("psastro.dump.psastroMosaicAstrom") > 0)) { psastroDumpMatches (fpa, "match.1.dat"); }
+    if ((pass == 0) && (psTraceGetLevel("psastro.dump.psastroMosaicAstrom") > 0)) { 
+	snprintf (filename, 256, "%s.1.dat", rootname);
+	psastroDumpMatches (fpa, filename); 
+    }
 
     // fit the distortion by fitting its gradient
@@ -115,5 +130,5 @@
     }
 
-    snprintf (filename, 16, "match.%d.dat", 2*pass + 2);
+    snprintf (filename, 256, "%s.%d.dat", rootname, 2*pass + 2);
     if (psTraceGetLevel("psastro.dump.psastroMosaicAstrom") > 0) { psastroDumpMatches (fpa, filename); }
     
@@ -124,5 +139,5 @@
     }
 
-    snprintf (filename, 16, "match.%d.dat", 2*pass + 3);
+    snprintf (filename, 256, "%s.%d.dat", rootname, 2*pass + 3);
     if (psTraceGetLevel("psastro.dump.psastroMosaicAstrom") > 0) { psastroDumpMatches (fpa, filename); }
 
