Index: trunk/ippTools/share/Makefile.am
===================================================================
--- trunk/ippTools/share/Makefile.am	(revision 27184)
+++ trunk/ippTools/share/Makefile.am	(revision 27192)
@@ -28,4 +28,5 @@
      chiptool_change_imfile_data_state.sql \
      chiptool_completely_processed_exp.sql \
+     chiptool_definecopy.sql \
      chiptool_donecleanup.sql \
      chiptool_find_rawexp.sql \
Index: trunk/ippTools/share/chiptool_definecopy.sql
===================================================================
--- trunk/ippTools/share/chiptool_definecopy.sql	(revision 27192)
+++ trunk/ippTools/share/chiptool_definecopy.sql	(revision 27192)
@@ -0,0 +1,6 @@
+SELECT
+    rawExp.*
+FROM chipRun AS chipOld
+JOIN rawExp USING(exp_id)
+LEFT JOIN chipRun AS chipNew USING(exp_id)
+WHERE chipNew.chip_id IS NULL
Index: trunk/ippTools/src/chiptool.c
===================================================================
--- trunk/ippTools/src/chiptool.c	(revision 27184)
+++ trunk/ippTools/src/chiptool.c	(revision 27192)
@@ -36,4 +36,5 @@
 
 static bool definebyqueryMode(pxConfig *config);
+static bool definecopyMode(pxConfig *config);
 static bool updaterunMode(pxConfig *config);
 static bool pendingimfileMode(pxConfig *config);
@@ -77,4 +78,5 @@
     switch (config->mode) {
         MODECASE(CHIPTOOL_MODE_DEFINEBYQUERY,           definebyqueryMode);
+        MODECASE(CHIPTOOL_MODE_DEFINECOPY,              definecopyMode);
         MODECASE(CHIPTOOL_MODE_UPDATERUN,               updaterunMode);
         MODECASE(CHIPTOOL_MODE_PENDINGIMFILE,           pendingimfileMode);
@@ -120,92 +122,29 @@
 }
 
-
-static bool definebyqueryMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, NULL);
-
-    PXOPT_LOOKUP_S64(exp_id, config->args, "-exp_id", false, false);
-
-    psMetadata *where = psMetadataAlloc();
-    pxchipGetSearchArgs (config, where); // rawExp only
-    pxAddLabelSearchArgs (config, where, "-label", "newExp.label", "LIKE"); // define using newExp label
-
-    // psListLength(where->list) is at least 1 because exp_type defaults to "object"
-    // so we require a list longer than 1 entry
-    if ((psListLength(where->list) <= 1) && !psMetadataLookupBool(NULL, config->args, "-all")) {
-        psFree(where);
-        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
-        return false;
-    }
-
-    PXOPT_LOOKUP_STR(workdir, config->args, "-set_workdir", true, false);
-    PXOPT_LOOKUP_STR(label, config->args, "-set_label", false, false);
-    PXOPT_LOOKUP_STR(reduction, config->args, "-set_reduction", false, false);
-    PXOPT_LOOKUP_STR(expgroup, config->args, "-set_expgroup", false, false);
-    PXOPT_LOOKUP_STR(dvodb, config->args, "-set_dvodb", false, false);
-    PXOPT_LOOKUP_STR(tess_id, config->args, "-set_tess_id", false, false);
-    PXOPT_LOOKUP_STR(end_stage, config->args, "-set_end_stage", false, false);
-    PXOPT_LOOKUP_STR(dist_group, config->args, "-set_dist_group", false, false);
-    PXOPT_LOOKUP_STR(data_group, config->args, "-set_data_group", false, false);
-    PXOPT_LOOKUP_STR(note, config->args, "-set_note", false, false);
-
-    // default
-    PXOPT_LOOKUP_BOOL(pretend, config->args, "-pretend", false);
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    // find the exp_id of all the exposures that we want to queue up.
-    psString query = pxDataGet("chiptool_find_rawexp.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
-        psFree(where);
-        return false;
-    }
-
-    psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
-    psStringAppend(&query, " AND %s", whereClause);
-
-    psFree(whereClause);
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("chiptool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-
-    if (pretend) {
-        // negative simple so the default is true
-        if (!ippdbPrintMetadatas(stdout, output, "rawExp", !simple)) {
-            psError(PS_ERR_UNKNOWN, false, "failed to print array");
-            psFree(output);
-            return false;
-        }
-        psFree(output);
-        return true;
-    }
-
+// Queue exposures for chip processing
+static bool queue_exposures(pxConfig *config,  // Configuration
+                            const psArray *exps, // Exposures information
+                            const char *workdir, // Working directory, or NULL to inherit
+                            const char *label,   // Label, or NULL to inherit
+                            const char *data_group, // Data group, or NULL to inherit
+                            const char *dist_group, // Distribution group, or NULL to inherit
+                            const char *reduction, // Reduction class, or NULL to inherit
+                            const char *expgroup,  // Exposure group
+                            const char *dvodb,     // DVO database, or NULL to inherit
+                            const char *tess_id,   // Tessellation identifier, or NULL to inherit
+                            const char *end_stage,  // End stage, or NULL to inherit
+                            const char *note        // Note
+    )
+{
     // start a transaction so we don't end up with an exp without any associted
     // imfiles
     if (!psDBTransaction(config->dbh)) {
         psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(output);
         return false;
     }
 
     // if end_stage is warp (or NULL), check for valid tess_id
-    for (long i = 0; i < psArrayLength(output); i++) {
-        psMetadata *md = output->data[i];
+    for (long i = 0; i < psArrayLength(exps); i++) {
+        psMetadata *md = exps->data[i];
 
         bool status;
@@ -220,6 +159,7 @@
 
         if (!status) {
-            psError(PS_ERR_UNKNOWN, false, "cannot queue analysis to WARP without a defined tess id: label: %s, exp_id %" PRId64, label, exp_id);
-            psFree(output);
+            psError(PS_ERR_UNKNOWN, false,
+                    "cannot queue analysis to WARP without a defined tess id: label: %s, exp_id %" PRId64,
+                    label, exp_id);
             return false;
         }
@@ -229,20 +169,20 @@
 # define GET_VALUE(PTYPE,CTYPE,VALUE,NAME)                              \
     PTYPE VALUE;                                                        \
-    { bool status;                                                      \
+    {                                                                   \
+        bool status;                                                    \
         VALUE = psMetadataLookup##CTYPE(&status, md, NAME);             \
         if (!status) {                                                  \
             psError(PS_ERR_UNKNOWN, false, "failed to lookup value for %s", NAME); \
-            psFree(output);                                             \
             return false;                                               \
-        } }
+        }                                                               \
+    }
 
     // loop over our list of exp_ids
-    for (long i = 0; i < psArrayLength(output); i++) {
-        psMetadata *md = output->data[i];
+    for (long i = 0; i < psArrayLength(exps); i++) {
+        psMetadata *md = exps->data[i];
 
         rawExpRow *row = rawExpObjectFromMetadata(md);
         if (!row) {
             psError(PS_ERR_UNKNOWN, false, "failed to convert metadata into chipRun");
-            psFree(output);
             return false;
         }
@@ -259,5 +199,4 @@
         if (!row->exp_id) {
             psError(PS_ERR_UNKNOWN, false, "failed to find value for exp_id");
-            psFree(output);
             return false;
         }
@@ -284,14 +223,187 @@
             psError(PS_ERR_UNKNOWN, false,
                     "failed to trying to queue exp_id: %" PRId64, exp_id);
+            return false;
+        }
+    }
+
+    if (!psDBCommit(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    return true;
+}
+
+static bool definebyqueryMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_S64(exp_id, config->args, "-exp_id", false, false);
+
+    psMetadata *where = psMetadataAlloc();
+    pxchipGetSearchArgs (config, where); // rawExp only
+    pxAddLabelSearchArgs (config, where, "-label", "newExp.label", "LIKE"); // define using newExp label
+
+    // psListLength(where->list) is at least 1 because exp_type defaults to "object"
+    // so we require a list longer than 1 entry
+    if ((psListLength(where->list) <= 1) && !psMetadataLookupBool(NULL, config->args, "-all")) {
+        psFree(where);
+        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
+        return false;
+    }
+
+    PXOPT_LOOKUP_STR(workdir, config->args, "-set_workdir", true, false);
+    PXOPT_LOOKUP_STR(label, config->args, "-set_label", false, false);
+    PXOPT_LOOKUP_STR(reduction, config->args, "-set_reduction", false, false);
+    PXOPT_LOOKUP_STR(expgroup, config->args, "-set_expgroup", false, false);
+    PXOPT_LOOKUP_STR(dvodb, config->args, "-set_dvodb", false, false);
+    PXOPT_LOOKUP_STR(tess_id, config->args, "-set_tess_id", false, false);
+    PXOPT_LOOKUP_STR(end_stage, config->args, "-set_end_stage", false, false);
+    PXOPT_LOOKUP_STR(dist_group, config->args, "-set_dist_group", false, false);
+    PXOPT_LOOKUP_STR(data_group, config->args, "-set_data_group", false, false);
+    PXOPT_LOOKUP_STR(note, config->args, "-set_note", false, false);
+
+    // default
+    PXOPT_LOOKUP_BOOL(pretend, config->args, "-pretend", false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    // find the exp_id of all the exposures that we want to queue up.
+    psString query = pxDataGet("chiptool_find_rawexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+        psFree(where);
+        return false;
+    }
+
+    psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+    psStringAppend(&query, " AND %s", whereClause);
+
+    psFree(whereClause);
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("chiptool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    if (pretend) {
+        // negative simple so the default is true
+        if (!ippdbPrintMetadatas(stdout, output, "rawExp", !simple)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to print array");
             psFree(output);
             return false;
         }
+        psFree(output);
+        return true;
+    }
+
+    if (!queue_exposures(config, output, workdir, label, data_group, dist_group, reduction, expgroup,
+                         dvodb, tess_id, end_stage, note)) {
+        psError(psErrorCodeLast(), false, "Unable to queue exposures for chip.");
+        psFree(output);
+        return false;
     }
     psFree(output);
 
-    if (!psDBCommit(config->dbh)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
+    return true;
+}
+
+static bool definecopyMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_S64(exp_id, config->args, "-exp_id", false, false);
+
+    psMetadata *where = psMetadataAlloc();
+    pxchipGetSearchArgs (config, where); // rawExp only
+    pxAddLabelSearchArgs (config, where, "-label", "chipOld.label", "LIKE");
+    pxAddLabelSearchArgs (config, where, "-set_label", "chipNew.label", "LIKE");
+
+    // psListLength(where->list) is at least 1 because exp_type defaults to "object"
+    // so we require a list longer than 1 entry
+    if ((psListLength(where->list) <= 1) && !psMetadataLookupBool(NULL, config->args, "-all")) {
+        psFree(where);
+        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
+        return false;
+    }
+
+    PXOPT_LOOKUP_STR(workdir, config->args, "-set_workdir", true, false);
+    PXOPT_LOOKUP_STR(label, config->args, "-set_label", false, false);
+    PXOPT_LOOKUP_STR(reduction, config->args, "-set_reduction", false, false);
+    PXOPT_LOOKUP_STR(expgroup, config->args, "-set_expgroup", false, false);
+    PXOPT_LOOKUP_STR(dvodb, config->args, "-set_dvodb", false, false);
+    PXOPT_LOOKUP_STR(tess_id, config->args, "-set_tess_id", false, false);
+    PXOPT_LOOKUP_STR(end_stage, config->args, "-set_end_stage", false, false);
+    PXOPT_LOOKUP_STR(dist_group, config->args, "-set_dist_group", false, false);
+    PXOPT_LOOKUP_STR(data_group, config->args, "-set_data_group", false, false);
+    PXOPT_LOOKUP_STR(note, config->args, "-set_note", false, false);
+
+    // default
+    PXOPT_LOOKUP_BOOL(pretend, config->args, "-pretend", false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    // find the exp_id of all the exposures that we want to queue up.
+    psString query = pxDataGet("chiptool_definecopy.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+        psFree(where);
+        return false;
+    }
+
+    psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+    psStringAppend(&query, " AND %s", whereClause);
+
+    psFree(whereClause);
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("chiptool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    if (pretend) {
+        // negative simple so the default is true
+        if (!ippdbPrintMetadatas(stdout, output, "rawExp", !simple)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to print array");
+            psFree(output);
+            return false;
+        }
+        psFree(output);
+        return true;
+    }
+
+    if (!queue_exposures(config, output, workdir, label, data_group, dist_group, reduction, expgroup,
+                         dvodb, tess_id, end_stage, note)) {
+        psError(psErrorCodeLast(), false, "Unable to queue exposures for chip.");
+        psFree(output);
+        return false;
+    }
+    psFree(output);
 
     return true;
Index: trunk/ippTools/src/chiptool.h
===================================================================
--- trunk/ippTools/src/chiptool.h	(revision 27184)
+++ trunk/ippTools/src/chiptool.h	(revision 27192)
@@ -26,4 +26,5 @@
     CHIPTOOL_MODE_NONE      = 0x0,
     CHIPTOOL_MODE_DEFINEBYQUERY,
+    CHIPTOOL_MODE_DEFINECOPY,
     CHIPTOOL_MODE_UPDATERUN,
     CHIPTOOL_MODE_PENDINGIMFILE,
Index: trunk/ippTools/src/chiptoolConfig.c
===================================================================
--- trunk/ippTools/src/chiptoolConfig.c	(revision 27184)
+++ trunk/ippTools/src/chiptoolConfig.c	(revision 27192)
@@ -63,4 +63,24 @@
     psMetadataAddBool(definebyqueryArgs, PS_LIST_TAIL, "-pretend",  0,            "do not actually modify the database", false);
     psMetadataAddBool(definebyqueryArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+
+    // -definecopy
+    psMetadata *definecopyArgs = psMetadataAlloc();
+    pxchipSetSearchArgs (definecopyArgs);
+    psMetadataAddStr(definecopyArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "search by rawExp label (LIKE comparison)", NULL);
+
+    psMetadataAddStr(definecopyArgs, PS_LIST_TAIL, "-exp_type", PS_META_REPLACE, "search by exp_type", "object");
+
+    psMetadataAddStr(definecopyArgs, PS_LIST_TAIL, "-set_workdir", 0, "define workdir (required)", NULL);
+    psMetadataAddStr(definecopyArgs, PS_LIST_TAIL, "-set_label", 0, "define label", NULL);
+    psMetadataAddStr(definecopyArgs, PS_LIST_TAIL, "-set_reduction", 0, "define reduction class", NULL);
+    psMetadataAddStr(definecopyArgs, PS_LIST_TAIL, "-set_expgroup", 0, "define exposure group", NULL);
+    psMetadataAddStr(definecopyArgs, PS_LIST_TAIL, "-set_dvodb", 0, "define DVO db", NULL);
+    psMetadataAddStr(definecopyArgs, PS_LIST_TAIL, "-set_tess_id", 0, "define tessellation identifier", NULL);
+    psMetadataAddStr(definecopyArgs, PS_LIST_TAIL, "-set_end_stage", 0, "define end stage", NULL);
+    psMetadataAddStr(definecopyArgs, PS_LIST_TAIL, "-set_data_group", 0, "define data group", NULL);
+    psMetadataAddStr(definecopyArgs, PS_LIST_TAIL, "-set_dist_group", 0, "define distribution group", NULL);
+    psMetadataAddStr(definecopyArgs, PS_LIST_TAIL, "-set_note", 0, "define note", NULL);
+    psMetadataAddBool(definecopyArgs, PS_LIST_TAIL, "-pretend", 0, "do not actually modify the database", false);
+    psMetadataAddBool(definecopyArgs, PS_LIST_TAIL, "-simple", 0, "use the simple output format", false);
 
     // -updaterun
@@ -293,4 +313,5 @@
 
     PXOPT_ADD_MODE("-definebyquery",        "create runs from raw exposures",       CHIPTOOL_MODE_DEFINEBYQUERY,        definebyqueryArgs);
+    PXOPT_ADD_MODE("-definecopy",           "create copy runs",                     CHIPTOOL_MODE_DEFINECOPY,        definecopyArgs);
     PXOPT_ADD_MODE("-updaterun",            "change chip run properties",           CHIPTOOL_MODE_UPDATERUN,            updaterunArgs);
     PXOPT_ADD_MODE("-pendingimfile",        "show pending imfiles",                 CHIPTOOL_MODE_PENDINGIMFILE,        pendingimfileArgs);
