Index: /trunk/ppSim/src/Makefile.am
===================================================================
--- /trunk/ppSim/src/Makefile.am	(revision 16499)
+++ /trunk/ppSim/src/Makefile.am	(revision 16500)
@@ -1,3 +1,3 @@
-bin_PROGRAMS = ppSim
+bin_PROGRAMS = ppSim ppSimSequence
 
 ppSim_CPPFLAGS = $(PSLIB_CFLAGS) $(PSMODULE_CFLAGS) $(PSASTRO_CFLAGS) $(ppSim_CFLAGS)
@@ -26,6 +26,16 @@
 	ppSimBadPixels.c
 
+ppSimSequence_CPPFLAGS = $(PSLIB_CFLAGS) $(PSMODULE_CFLAGS) $(PSASTRO_CFLAGS) $(ppSim_CFLAGS)
+ppSimSequence_LDFLAGS = $(PSLIB_LIBS) $(PSMODULE_LIBS) $(PSASTRO_LIBS)
+ppSimSequence_SOURCES = \
+	ppSimSequence.c		\
+	ppSimSequenceBias.c	\
+	ppSimSequenceDark.c	\
+	ppSimSequenceFlat.c	\
+	ppSimSequenceObject.c
+
 noinst_HEADERS = \
-	ppSim.h
+	ppSim.h \
+	ppSimSequence.h
 
 
Index: /trunk/ppSim/src/ppSimSequence.h
===================================================================
--- /trunk/ppSim/src/ppSimSequence.h	(revision 16500)
+++ /trunk/ppSim/src/ppSimSequence.h	(revision 16500)
@@ -0,0 +1,19 @@
+#ifndef PP_SIM_SEQUENCE_H
+#define PP_SIM_SEQUENCE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <strings.h>
+#include <pslib.h>
+#include <psmodules.h>
+#include <psastro.h>
+
+bool ppSimSequenceBias 	 (FILE *simfile, FILE *inject, psMetadata *sequence, int nSeq, psRandom *rng, const char *path, const char *basename, const char *injectCommand);
+bool ppSimSequenceDark 	 (FILE *simfile, FILE *inject, psMetadata *sequence, int nSeq, psRandom *rng, const char *path, const char *basename, const char *injectCommand);
+bool ppSimSequenceFlat 	 (FILE *simfile, FILE *inject, psMetadata *sequence, int nSeq, psRandom *rng, const char *path, const char *basename, const char *injectCommand);
+bool ppSimSequenceObject (FILE *simfile, FILE *inject, psMetadata *sequence, int nSeq, psRandom *rng, const char *path, const char *basename, const char *injectCommand);
+
+#endif
Index: /trunk/ppSim/src/ppSimSequenceBias.c
===================================================================
--- /trunk/ppSim/src/ppSimSequenceBias.c	(revision 16500)
+++ /trunk/ppSim/src/ppSimSequenceBias.c	(revision 16500)
@@ -0,0 +1,50 @@
+# include "ppSimSequence.h"
+
+bool ppSimSequenceBias (FILE *simfile, FILE *inject, psMetadata *sequence, int nSeq, psRandom *rng, const char *path, const char *basename, const char *injectCommand) {
+
+    bool status, setLevel, setRange;
+
+    char *camera = psMetadataLookupStr (&status, sequence, "CAMERA");
+
+    // optional details
+    float level = psMetadataLookupF32 (&setLevel, sequence, "BIAS.LEVEL");
+    float range = psMetadataLookupF32 (&setRange, sequence, "BIAS.RANGE");
+
+    int nImages = psMetadataLookupS32 (&status, sequence, "NIMAGES");
+
+    // loop over the filters & exposure times
+    int nImage = 0;
+    for (int i = 0; i < nImages; i++) {
+	    
+      psString command = NULL;
+
+      psStringAppend (&command, "ppSim -type BIAS");
+      psStringAppend (&command, " -camera %s", camera);
+
+      if (setLevel) psStringAppend (&command, " -biaslevel %f", level);
+      if (setRange) psStringAppend (&command, " -biasrange %f", range);
+
+      // XXX need to add output filename
+      psString filename = NULL;
+      if (path) {
+	psStringAppend (&filename, "%s/%s.%03d.%03d", path, basename, nSeq, nImage);
+      } else {
+	psStringAppend (&filename, "%s.%03d.%03d", basename, nSeq, nImage);
+      }
+      psStringAppend (&command, " %s", filename);
+
+      fprintf (simfile, "%s\n", command);
+      psFree (command);
+			    
+      // path should be dirname/filename
+      command = psStringCopy (injectCommand);
+      psStringAppend (&command, " --camera %s", camera);
+      psStringAppend (&command, " %s*.fits",    filename);
+      fprintf (inject, "%s\n", command);
+      psFree (command);
+      psFree (filename);
+
+      nImage ++;
+    }
+    return true;
+}
Index: /trunk/ppSim/src/ppSimSequenceDark.c
===================================================================
--- /trunk/ppSim/src/ppSimSequenceDark.c	(revision 16500)
+++ /trunk/ppSim/src/ppSimSequenceDark.c	(revision 16500)
@@ -0,0 +1,67 @@
+# include "ppSimSequence.h"
+
+bool ppSimSequenceDark (FILE *simfile, FILE *inject, psMetadata *sequence, int nSeq, psRandom *rng, const char *path, const char *basename, const char *injectCommand) {
+
+    bool status, setRate;
+    float min, max;
+
+    char *camera = psMetadataLookupStr (&status, sequence, "CAMERA");
+
+    setRate = false;
+    min = psMetadataLookupF32 (&status, sequence, "DARK.MIN");
+    if (status) {
+	max = psMetadataLookupF32 (&status, sequence, "DARK.MAX");
+	setRate = true;
+    }
+
+    psVector *exptimes = psMetadataLookupPtr (&status, sequence, "EXPTIMES");
+    psVector *nImages = psMetadataLookupPtr (&status, sequence, "NIMAGES");
+
+    assert (exptimes->n == nImages->n);
+
+    // loop over the filters & exposure times
+    int nImage = 0;
+    for (int i = 0; i < nImages->n; i++) {
+	    
+	float exptime = exptimes->data.F32[i];
+	float n = nImages->data.S32[i];
+
+	for (int j = 0; j < n; j++) {
+	    psString command = NULL;
+
+	    psStringAppend (&command, "ppSim -type DARK");
+	    psStringAppend (&command, " -camera %s", camera);
+
+	    if (setRate) {
+		double frnd = psRandomUniform(rng);
+		float rate = min + (max - min)*frnd;
+		psStringAppend (&command, " -darkrate %f", rate);
+	    }
+
+	    psStringAppend (&command, " -exptime %f", exptime);
+
+	    // XXX need to add output filename
+	    psString filename = NULL;
+	    if (path) {
+		psStringAppend (&filename, "%s/%s.%03d.%03d", path, basename, nSeq, nImage);
+	    } else {
+		psStringAppend (&filename, "%s.%03d.%03d", basename, nSeq, nImage);
+	    }
+	    psStringAppend (&command, " %s", filename);
+
+	    fprintf (simfile, "%s\n", command);
+	    psFree (command);
+			    
+	    // path should be dirname/filename
+	    command = psStringCopy (injectCommand);
+	    psStringAppend (&command, " --camera %s", camera);
+	    psStringAppend (&command, " %s*.fits",    filename);
+	    fprintf (inject, "%s\n", command);
+	    psFree (command);
+	    psFree (filename);
+
+	    nImage ++;
+	}
+    }
+    return true;
+}
Index: /trunk/ppSim/src/ppSimSequenceFlat.c
===================================================================
--- /trunk/ppSim/src/ppSimSequenceFlat.c	(revision 16500)
+++ /trunk/ppSim/src/ppSimSequenceFlat.c	(revision 16500)
@@ -0,0 +1,64 @@
+# include "ppSimSequence.h"
+
+bool ppSimSequenceFlat (FILE *simfile, FILE *inject, psMetadata *sequence, int nSeq, psRandom *rng, const char *path, const char *basename, const char *injectCommand) {
+
+    bool status;
+
+    char *camera = psMetadataLookupStr (&status, sequence, "CAMERA");
+
+    // determine the filters & exposure times
+    char *filterList = psMetadataLookupStr (&status, sequence, "FILTERS");
+    psArray *filters = psStringSplitArray (filterList, ",: ", false);
+
+    psVector *exptimes = psMetadataLookupPtr (&status, sequence, "EXPTIMES");
+
+    if (filters->n != exptimes->n) {
+	psLogMsg ("ppSimSequence", PS_LOG_WARN, "mis-match in filter and exptime lists");
+	exit (1);
+    }
+
+    // number of images for each filter, exptime set
+    int nSetup = psMetadataLookupS32 (&status, sequence, "NSETUP");
+
+    int nImage = 0;
+
+    // loop over the filters & exposure times
+    for (int i = 0; i < filters->n; i++) {
+	    
+      // loop over the filters & exposure times
+      for (int j = 0; j < nSetup; j++) {
+	    
+	psString command = NULL;
+
+	psStringAppend (&command, "ppSim -type FLAT");
+	psStringAppend (&command, " -camera %s", camera);
+
+	psStringAppend (&command, " -filter %s", (char *) filters->data[i]);
+	psStringAppend (&command, " -exptime %f", exptimes->data.F32[i]);
+
+	// XXX need to add output filename
+	psString filename = NULL;
+	if (path) {
+	  psStringAppend (&filename, "%s/%s.%03d.%03d", path, basename, nSeq, nImage);
+	} else {
+	  psStringAppend (&filename, "%s.%03d.%03d", basename, nSeq, nImage);
+	}
+	psStringAppend (&command, " %s", filename);
+
+
+	fprintf (simfile, "%s\n", command);
+	psFree (command);
+
+	// path should be dirname/filename
+	command = psStringCopy (injectCommand);
+	psStringAppend (&command, " --camera %s", camera);
+	psStringAppend (&command, " %s*.fits",    filename);
+	fprintf (inject, "%s\n", command);
+	psFree (command);
+	psFree (filename);
+
+	nImage ++;
+      }
+    }
+    return true;
+}
Index: /trunk/ppSim/src/ppSimSequenceObject.c
===================================================================
--- /trunk/ppSim/src/ppSimSequenceObject.c	(revision 16500)
+++ /trunk/ppSim/src/ppSimSequenceObject.c	(revision 16500)
@@ -0,0 +1,125 @@
+# include "ppSimSequence.h"
+
+bool ppSimSequenceObject (FILE *simfile, FILE *inject, psMetadata *sequence, int nSeq, psRandom *rng, const char *path, const char *basename, const char *injectCommand) {
+
+    bool status;
+
+    // generate ppSim lines that look like:
+    // ppSim -camera $camera -type OBJECT -filter $filter -exptime $exptime
+    //       -skyrate $sky -ra $ra -dec $dec -pa $pa -scale $scale -zp $zp -seeing $seeing $filename",
+
+    char *camera = psMetadataLookupStr (&status, sequence, "CAMERA");
+
+    // sequence reference coordinate
+    float Ro = psMetadataLookupF32 (&status, sequence, "CENTER.RA");
+    float Do = psMetadataLookupF32 (&status, sequence, "CENTER.DEC");
+
+    // determine the filters & exposure times
+    char *filterList = psMetadataLookupStr (&status, sequence, "FILTERS");
+    psArray *filters = psStringSplitArray (filterList, ",: ", false);
+
+    psVector *exptimes = psMetadataLookupPtr (&status, sequence, "EXPTIMES");
+
+    psVector *skymags = psMetadataLookupPtr (&status, sequence, "SKYMAGS");
+
+    float IQmin = psMetadataLookupF32 (&status, sequence, "IQ_MIN");
+    float IQmax = psMetadataLookupF32 (&status, sequence, "IQ_MAX");
+
+    if (filters->n != exptimes->n) {
+	psLogMsg ("ppSimSequence", PS_LOG_WARN, "mis-match in filter and exptime lists");
+	exit (1);
+    }
+
+    // track the number of files produced
+    int nImage = 0;
+
+    // loop over the filters & exposure times
+    for (int i = 0; i < filters->n; i++) {
+	    
+	// offset parameters
+	float dR = psMetadataLookupF32 (&status, sequence, "OFFSET.RA");
+	float dD = psMetadataLookupF32 (&status, sequence, "OFFSET.DEC");
+  
+	int nR = psMetadataLookupS32 (&status, sequence, "OFFSET.NR");
+	int nD = psMetadataLookupS32 (&status, sequence, "OFFSET.ND");
+  
+	// loop over the offset sequence
+	for (int iR = 0; iR < nR; iR++) {
+	    for (int iD = 0; iD < nD; iD++) {
+
+		// RA & DEC in degrees XXX (should be radians...)
+		// offsets are in arcseconds
+		float R = Ro + dR*(iR - 0.5*nR + 0.5) / cos (RAD_DEG*Do) / 3600.0;
+		float D = Do + dD*(iD - 0.5*nD + 0.5) / 3600.0;
+      
+		// dither parameters
+		float dr = psMetadataLookupF32 (&status, sequence, "DITHER.RA");
+		float dd = psMetadataLookupF32 (&status, sequence, "DITHER.DEC");
+  
+		int nr = psMetadataLookupS32 (&status, sequence, "DITHER.NR");
+		int nd = psMetadataLookupS32 (&status, sequence, "DITHER.ND");
+  
+		// loop over the dither sequence
+		for (int ir = 0; ir < nr; ir++) {
+		    for (int id = 0; id < nd; id++) {
+
+			// ra, dec in degrees; offsets in arcsec
+			float ra = R + dr*(ir - 0.5*nr + 0.5) / cos (RAD_DEG*D) / 3600.0;
+			float dec = D + dd*(id - 0.5*nd + 0.5) / 3600.0;
+	  
+			// rotation sequence parameters
+			float pos_min   = psMetadataLookupF32 (&status, sequence, "POS_MIN");
+			float pos_max   = psMetadataLookupF32 (&status, sequence, "POS_MAX");
+			float pos_delta = psMetadataLookupF32 (&status, sequence, "POS_DELTA");
+			assert (pos_delta > 0.0);
+			assert (pos_max >= pos_min);
+	    
+			// loop over rotation sequence
+			for (float pos = pos_min; pos <= pos_max; pos += pos_delta) {
+	      
+			    psString command = NULL;
+
+			    psStringAppend (&command, "ppSim -type OBJECT");
+			    psStringAppend (&command, " -camera %s", camera);
+			    psStringAppend (&command, " -filter %s", (char *) filters->data[i]);
+			    psStringAppend (&command, " -exptime %f", exptimes->data.F32[i]);
+			    psStringAppend (&command, " -skymags %f", skymags->data.F32[i]);
+
+			    psStringAppend (&command, " -ra %f", ra);
+			    psStringAppend (&command, " -dec %f", dec);
+			    psStringAppend (&command, " -pa %f", pos);
+
+			    double frnd = psRandomUniform(rng);
+			    float seeing = IQmin + (IQmax - IQmin)*frnd;
+	      
+			    psStringAppend (&command, " -seeing %f", seeing);
+
+			    // XXX need to add output filename
+			    psString filename = NULL;
+			    if (path) {
+				psStringAppend (&filename, "%s/%s.%03d.%03d", path, basename, nSeq, nImage);
+			    } else {
+				psStringAppend (&filename, "%s.%03d.%03d", basename, nSeq, nImage);
+			    }
+			    psStringAppend (&command, " %s", filename);
+
+			    fprintf (simfile, "%s\n", command);
+			    psFree (command);
+			    
+			    // path should be dirname/filename
+			    command = psStringCopy (injectCommand);
+			    psStringAppend (&command, " --camera %s", camera);
+			    psStringAppend (&command, " %s*.fits",    filename);
+			    fprintf (inject, "%s\n", command);
+			    psFree (command);
+			    psFree (filename);
+
+			    nImage ++;
+			}
+		    }
+		}
+	    }
+	}
+    }
+    return true;
+}
