Index: /trunk/ippTools/src/dettool.c
===================================================================
--- /trunk/ippTools/src/dettool.c	(revision 9136)
+++ /trunk/ippTools/src/dettool.c	(revision 9137)
@@ -2583,18 +2583,4 @@
     PS_ASSERT_PTR_NON_NULL(config, false);
   
-    // select detProcessedImfile.det_id
-    // select detRun.iteration
-    // select detRun.det_type
-    // select detProcessedImfile.exp_tag
-    // by:
-    // find the current iteration bassed on det_id
-    // find all exp_tags in the current det_id/iteration from detInputExp
-    // find all rawImfiles in the current exp_tags
-    // compare to detProcessedImfiles by det_id/exp_tag
-    // found how many imfile there are in each class_id
-    // and:
-    // det_id is not in detProcessedExp;
-    // iteration is not in detProcessedExp;
-
     psString query = psStringCopy(
         " SELECT DISTINCT"
@@ -2679,5 +2665,4 @@
     psFree(output);
 
-
     return true;
 }
@@ -2686,4 +2671,146 @@
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
+ 
+    // det_id, recip, -bg, -bg_stdev, & -bg_mean_stdev
+    // are required
+    bool status = false;
+    psString det_id = psMetadataLookupStr(&status, config->args, "-det_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -det_id");
+        return false;
+    }
+    if (!det_id) {
+        psError(PS_ERR_UNKNOWN, true, "-det_id is required");
+        return false;
+    }
+    psString recipe = psMetadataLookupStr(&status, config->args, "-recip");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -recip");
+        return false;
+    }
+    if (!recipe) {
+        psError(PS_ERR_UNKNOWN, true, "-recip is required");
+        return false;
+    }
+    psF64 bg = psMetadataLookupF64(&status, config->args, "-bg");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -bg");
+        return false;
+    }
+    if (isnan(bg)) {
+        psError(PS_ERR_UNKNOWN, true, "-bg is required");
+        return false;
+    }
+    psF64 bg_stdev = psMetadataLookupF64(&status, config->args, "-bg_stdev");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -bg_stdev");
+        return false;
+    }
+    if (isnan(bg_stdev)) {
+        psError(PS_ERR_UNKNOWN, true, "-bg_stdev is required");
+        return false;
+    }
+    psF64 bg_mean_stdev = psMetadataLookupF64(&status, config->args, "-bg_mean_stdev");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -bg_mean_stdev");
+        return false;
+    }
+    if (isnan(bg_mean_stdev)) {
+        psError(PS_ERR_UNKNOWN, true, "-bg_mean_stdev is required");
+        return false;
+    }
+    // iteration has a default value
+    psS32 iteration = psMetadataLookupS32(&status, config->args, "-iteration");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -iteration");        return false;
+    }
+    // optional
+    psString b1_uri = psMetadataLookupStr(&status, config->args, "-b1_uri");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -b1_uri");
+        return false;
+    }
+    psString b2_uri = psMetadataLookupStr(&status, config->args, "-b2_uri");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -b2_uri");
+        return false;
+    }
+
+    psString query = psStringCopy(
+        " SELECT DISTINCT"
+        "    detRun.position as det_id,"
+        "    detRun.iteration,"
+        "    detRun.det_type,"
+        "    rawDetrendExp.camera,"
+        "    rawDetrendExp.telescope,"
+        "    rawDetrendExp.exp_type,"
+        "    rawDetrendExp.imfiles"
+        " FROM detRun"
+        " JOIN detInputExp"
+        "    ON detRun.position = detInputExp.det_id"
+        "    AND detRun.iteration = detInputExp.iteration"
+        " JOIN rawDetrendExp"
+        "    ON detInputExp.exp_tag = rawDetrendExp.exp_tag"
+        " JOIN detNormalizedImfile"
+        "    ON detInputExp.det_id = detNormalizedImfile.det_id"
+        "    AND detInputExp.iteration = detNormalizedImfile.iteration"
+        " LEFT JOIN rawImfile"
+        "    ON detInputExp.exp_tag = rawImfile.exp_tag"
+        "    AND detNormalizedImfile.class_id = rawImfile.class_id"
+        " LEFT JOIN detNormalizedExp"
+        "    ON detInputExp.det_id = detNormalizedExp.det_id"
+        "    AND detInputExp.iteration = detNormalizedExp.iteration"
+        " WHERE"
+        "    detNormalizedExp.det_id IS NULL"
+        "    AND detNormalizedExp.iteration IS NULL"
+        "    AND detInputExp.include = 1"
+        "    AND detRun.position = %s"
+        "    AND detNormalizedImfile.iteration = %d"
+        " GROUP BY"
+        "    detNormalizedImfile.iteration,"
+        "    detRun.position"
+        " HAVING"
+        "    COUNT(detNormalizedImfile.class_id) = COUNT(rawImfile.class_id)"
+        );
+
+    if (!p_psDBRunQuery(config->dbh, query, det_id, iteration)) {
+        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");
+        psFree(query);
+    }
+    if (!psArrayLength(output)) {
+        // XXX check psError here
+        psError(PS_ERR_UNKNOWN, false, "no complete detNormalizedImfile exp found");
+        psFree(output);
+        return true;
+    }
+
+    // create a new detProcessedImfile object
+    detNormalizedExpRow *detRow = detNormalizedExpRowAlloc(
+        (psS32)atol(det_id),
+        iteration,
+        recipe,
+        bg,
+        bg_stdev,
+        bg_mean_stdev,
+        b1_uri,
+        b2_uri
+    );
+
+    // insert the new row into the detProcessedImfile table
+    if (!detNormalizedExpInsertObject(config->dbh, detRow)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(detRow);
+        return false;
+    }
+
+    psFree(detRow);
 
     return true;
Index: /trunk/ippTools/src/dettoolConfig.c
===================================================================
--- /trunk/ippTools/src/dettoolConfig.c	(revision 9136)
+++ /trunk/ippTools/src/dettoolConfig.c	(revision 9137)
@@ -288,6 +288,6 @@
     psMetadataAddS32(addnormalizedexpArgs, PS_LIST_TAIL, "-iteration",  0,
         "define iteration number", 0);
-    psMetadataAddStr(addnormalizedexpArgs, PS_LIST_TAIL, "-exp_tag",  0,
-        "define detrend ID (required)", NULL);
+    psMetadataAddStr(addnormalizedexpArgs, PS_LIST_TAIL, "-recip",  0,
+        "search for recipe", NULL);
     psMetadataAddF64(addnormalizedexpArgs, PS_LIST_TAIL, "-bg",  0,
         "define exposue background", NAN);
@@ -303,4 +303,20 @@
     // -normalizedexp
     psMetadata *normalizedexpArgs = psMetadataAlloc();
+    psMetadataAddStr(normalizedexpArgs, PS_LIST_TAIL, "-det_id",  0,
+        "define detrend ID (required)", NULL);
+    psMetadataAddS32(normalizedexpArgs, PS_LIST_TAIL, "-iteration",  0,
+        "define iteration number", 0);
+    psMetadataAddStr(normalizedexpArgs, PS_LIST_TAIL, "-recip",  0,
+        "search for recipe", NULL);
+    psMetadataAddF64(normalizedexpArgs, PS_LIST_TAIL, "-bg",  0,
+        "define exposue background", NAN);
+    psMetadataAddF64(normalizedexpArgs, PS_LIST_TAIL, "-bg_stdev",  0,
+        "define exposue background stdev", NAN);
+    psMetadataAddF64(normalizedexpArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
+        "define exposue background mean stdev", NAN);
+    psMetadataAddStr(normalizedexpArgs, PS_LIST_TAIL, "-b1_uri",  0,
+        "define banana 1", NULL);
+    psMetadataAddStr(normalizedexpArgs, PS_LIST_TAIL, "-b2_uri",  0,
+        "define banana 2", NULL);
     psMetadataAddBool(normalizedexpArgs, PS_LIST_TAIL, "-simple",  0,
         "use the simple output format", false);
