Index: /branches/eam_branches/ipp-20220316/psModules/src/camera/pmFPAfile.c
===================================================================
--- /branches/eam_branches/ipp-20220316/psModules/src/camera/pmFPAfile.c	(revision 42370)
+++ /branches/eam_branches/ipp-20220316/psModules/src/camera/pmFPAfile.c	(revision 42371)
@@ -539,4 +539,7 @@
     if (!strcasecmp(type, "LINEARITY"))  {
       return PM_FPA_FILE_LINEARITY;
+    }
+    if (!strcasecmp(type, "NEWNONLIN"))  {
+      return PM_FPA_FILE_NEWNONLIN;
     }
     if (!strcasecmp(type, "ASTROM"))     {
Index: /branches/eam_branches/ipp-20220316/psModules/src/camera/pmFPAfile.h
===================================================================
--- /branches/eam_branches/ipp-20220316/psModules/src/camera/pmFPAfile.h	(revision 42370)
+++ /branches/eam_branches/ipp-20220316/psModules/src/camera/pmFPAfile.h	(revision 42371)
@@ -55,4 +55,5 @@
     PM_FPA_FILE_PATTERN_DEAD_CELLS,
     PM_FPA_FILE_LINEARITY,
+    PM_FPA_FILE_NEWNONLIN,
     PM_FPA_FILE_EXPNUM,
 } pmFPAfileType;
Index: /branches/eam_branches/ipp-20220316/psModules/src/camera/pmFPAfileDefine.c
===================================================================
--- /branches/eam_branches/ipp-20220316/psModules/src/camera/pmFPAfileDefine.c	(revision 42370)
+++ /branches/eam_branches/ipp-20220316/psModules/src/camera/pmFPAfileDefine.c	(revision 42371)
@@ -821,4 +821,8 @@
 
 // find the file in the config list & generate a pmFPAfile for it based on the filerule
+// return values (return, status):
+// (not NULL, true) : file defined on RUN and can be loaded
+// (NULL, true) : file not defined on RUN
+// (NULL, false) : file defined on RUN, cannot be loaded
 pmFPAfile *pmFPAfileDefineFromRun(bool *success, pmFPAfile *bind, pmConfig *config, const char *filename)
 {
Index: /branches/eam_branches/ipp-20220316/psModules/src/camera/pmFPAfileIO.c
===================================================================
--- /branches/eam_branches/ipp-20220316/psModules/src/camera/pmFPAfileIO.c	(revision 42370)
+++ /branches/eam_branches/ipp-20220316/psModules/src/camera/pmFPAfileIO.c	(revision 42371)
@@ -285,4 +285,5 @@
       case PM_FPA_FILE_KAPA:
       case PM_FPA_FILE_LINEARITY:
+      case PM_FPA_FILE_NEWNONLIN:
         break;
       default:
@@ -651,4 +652,5 @@
       case PM_FPA_FILE_PATTERN_DEAD_CELLS:
       case PM_FPA_FILE_LINEARITY:
+      case PM_FPA_FILE_NEWNONLIN:
       case PM_FPA_FILE_EXPNUM:
         psTrace ("psModules.camera", 5, "closing %s (%s) (%d:%d:%d)\n", file->filename, file->name, view->chip, view->cell, view->readout);
@@ -736,4 +738,5 @@
       case PM_FPA_FILE_KAPA:
       case PM_FPA_FILE_LINEARITY:
+      case PM_FPA_FILE_NEWNONLIN:
         psTrace ("psModules.camera", 5, "nothing to free for %s (%s)\n", file->filename, file->name);
         return true;
@@ -896,4 +899,5 @@
       case PM_FPA_FILE_PATTERN_DEAD_CELLS:
       case PM_FPA_FILE_LINEARITY:
+      case PM_FPA_FILE_NEWNONLIN:
       case PM_FPA_FILE_EXPNUM:
         psTrace ("psModules.camera", 5, "opening %s (%s) (%d:%d:%d)\n",
Index: /branches/eam_branches/ipp-20220316/psModules/src/concepts/pmConcepts.c
===================================================================
--- /branches/eam_branches/ipp-20220316/psModules/src/concepts/pmConcepts.c	(revision 42370)
+++ /branches/eam_branches/ipp-20220316/psModules/src/concepts/pmConcepts.c	(revision 42371)
@@ -315,4 +315,6 @@
         conceptRegisterStr("FPA.SHUTOUTC", "Time of exposure open", NULL,NULL,NULL,false, PM_FPA_LEVEL_FPA);
         conceptRegisterStr("FPA.SHUTCUTC", "Time of exposure close", NULL,NULL,NULL,false, PM_FPA_LEVEL_FPA);
+        conceptRegisterStr("FPA.SHMDOUTC", "Time of exposure open mid-focalplane", NULL,NULL,NULL,false, PM_FPA_LEVEL_FPA);
+        conceptRegisterStr("FPA.SHMDCUTC", "Time of exposure close mid-focalplane", NULL,NULL,NULL,false, PM_FPA_LEVEL_FPA);
 
         conceptRegisterF32("FPA.TEMP", "Temperature of focal plane", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
Index: /branches/eam_branches/ipp-20220316/psModules/src/config/pmConfig.c
===================================================================
--- /branches/eam_branches/ipp-20220316/psModules/src/config/pmConfig.c	(revision 42370)
+++ /branches/eam_branches/ipp-20220316/psModules/src/config/pmConfig.c	(revision 42371)
@@ -1304,6 +1304,5 @@
         while ((camerasItem = psMetadataGetAndIncrement(camerasIter))) {
             // Open the camera information
-            psTrace("psModules.config.format", 3, "Inspecting camera %s (%s)\n", camerasItem->name,
-                    camerasItem->comment);
+            psTrace("psModules.config.format", 3, "Inspecting camera %s (%s)\n", camerasItem->name, camerasItem->comment);
             assert(camerasItem->type == PS_DATA_METADATA); // It should be because we've read it in or deleted
             psMetadata *testCamera = camerasItem->data.md; // Camera to test against what we've got:
Index: /branches/eam_branches/ipp-20220316/psModules/src/detrend/Makefile.am
===================================================================
--- /branches/eam_branches/ipp-20220316/psModules/src/detrend/Makefile.am	(revision 42370)
+++ /branches/eam_branches/ipp-20220316/psModules/src/detrend/Makefile.am	(revision 42371)
@@ -10,4 +10,5 @@
 	pmMaskStats.c \
 	pmNonLinear.c \
+	pmNewNonLinear.c \
 	pmBias.c \
 	pmOverscan.c \
@@ -30,4 +31,5 @@
 	pmMaskStats.h \
 	pmNonLinear.h \
+	pmNewNonLinear.h \
 	pmBias.h \
 	pmOverscan.h \
Index: /branches/eam_branches/ipp-20220316/psModules/src/detrend/pmDetrendDB.h
===================================================================
--- /branches/eam_branches/ipp-20220316/psModules/src/detrend/pmDetrendDB.h	(revision 42370)
+++ /branches/eam_branches/ipp-20220316/psModules/src/detrend/pmDetrendDB.h	(revision 42371)
@@ -39,4 +39,5 @@
     PM_DETREND_TYPE_VIDEODARK,
     PM_DETREND_TYPE_LINEARITY,
+    PM_DETREND_TYPE_NEWNONLIN,
     PM_DETREND_TYPE_AUXMASK,
     PM_DETREND_TYPE_KH_CORRECT,
Index: /branches/eam_branches/ipp-20220316/psModules/src/detrend/pmNewNonLinear.c
===================================================================
--- /branches/eam_branches/ipp-20220316/psModules/src/detrend/pmNewNonLinear.c	(revision 42371)
+++ /branches/eam_branches/ipp-20220316/psModules/src/detrend/pmNewNonLinear.c	(revision 42371)
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <pslib.h>
+
+#include "pmHDU.h"
+#include "pmFPA.h"
+#include "pmNewNonLinear.h"
+
+// model is stored as a FITS table, read into an array
+// each row is one knot, with (X, Y, dY2)
+bool pmNewNonLinearityApply(pmReadout *inputReadout, psArray *table)
+{
+    PS_ASSERT_PTR_NON_NULL(table, false);
+    PS_ASSERT_PTR_NON_NULL(inputReadout, false);
+    PS_ASSERT_PTR_NON_NULL(inputReadout->image, false);
+    PS_ASSERT_IMAGE_TYPE(inputReadout->image, PS_TYPE_F32, false);
+
+    psTimerStart ("nonlinear");
+
+    psImage *image = inputReadout->image;
+
+    // create an empty 1D spline with table->n knots
+    psSpline1D *model = psSpline1DCreate(table->n);
+    
+    // parse the table entries
+    for (int i = 0; i < table->n; i++) {
+	psMetadata *row = table->data[i];
+	
+	bool status;
+	model->xKnots[i]   = psMetadataLookupF32(&status, row, "X_KNOT");
+	model->yKnots[i]   = psMetadataLookupF32(&status, row, "Y_KNOT");
+	model->d2yKnots[i] = psMetadataLookupF32(&status, row, "DY2_DX");
+    }
+
+    // set equal spacing info?
+    // psSpline1DisEqualSpacing (model);
+
+    for (int i = 0; i < image->numRows; i++) { // Loop over rows : note: problem with discontinuity here
+	for (int j = 0; j < image->numCols; j++) { // Loop over columns
+	    // Calculate correction factor contribution for this pixel.
+	    psF32 flux = image->data.F32[i][j];
+	    psF32 lFlux = log10(flux);
+	    
+	    psF32 factor = psSpline1DEval (model, lFlux);
+	    
+	    // Apply correction to image data
+	    image->data.F32[i][j] = flux * factor;
+
+	}
+    }
+    psLogMsg ("psModules", PS_LOG_MINUTIA, "apply correction: %f sec\n", psTimerMark ("nonlinear"));
+
+    psFree (model);
+  
+    return(true);
+}
+
Index: /branches/eam_branches/ipp-20220316/psModules/src/detrend/pmNewNonLinear.h
===================================================================
--- /branches/eam_branches/ipp-20220316/psModules/src/detrend/pmNewNonLinear.h	(revision 42371)
+++ /branches/eam_branches/ipp-20220316/psModules/src/detrend/pmNewNonLinear.h	(revision 42371)
@@ -0,0 +1,18 @@
+/* @file pmNewNonLinear.h
+ * @brief Perform new (2023) non-linear correction using spline fits
+ *
+ * @author Eugene Magnier, IfA
+ * Copyright 2023 Institute for Astronomy, University of Hawaii
+ */
+
+#ifndef PM_NEW_NON_LINEAR_H
+#define PM_NEW_NON_LINEAR_H
+
+/// @addtogroup detrend Detrend Creation and Application
+/// @{
+
+/// Correct non-linearity using spline
+bool pmNewNonLinearityApply(pmReadout *inputReadout, psArray *table);
+
+/// @}
+#endif
Index: /branches/eam_branches/ipp-20220316/psModules/src/detrend/pmOverscan.c
===================================================================
--- /branches/eam_branches/ipp-20220316/psModules/src/detrend/pmOverscan.c	(revision 42370)
+++ /branches/eam_branches/ipp-20220316/psModules/src/detrend/pmOverscan.c	(revision 42371)
@@ -140,8 +140,12 @@
         break;
       case PM_FIT_SPLINE:
-        // XXX I don't think psSpline1D is up to scratch yet --- it has no mask, and requires an
-        // input spline
-        overscanOpts->spline = psVectorFitSpline1D(reduced, ordinate);
-        fitted = psSpline1DEvalVector(overscanOpts->spline, ordinate);
+
+        // XXX I don't think psSpline1D is up to scratch yet --- it has no mask, and it assumes
+	// a knot for every input point.  it needs an argument like 'number of knots' for the
+	// output spline.  EAM: still true 2023.01.22
+
+        // overscanOpts->spline = psVectorFitSpline1D(reduced, ordinate);
+        // fitted = psSpline1DEvalVector(overscanOpts->spline, ordinate);
+        psError(PS_ERR_UNKNOWN, true, "Spline overscan fitting is broken\n");
         break;
       default:
@@ -189,4 +193,5 @@
       }
       case PM_FIT_SPLINE: {
+	/*
 	  psSpline1D *spline = overscanOpts->spline; // The spline
 	  for (int i = 0; i < spline->n; i++) {
@@ -201,4 +206,5 @@
 	      comment = NULL;
 	  }
+	*/
 	  // write metadata header value
 	  psMetadataAddF32(hdu->header, PS_LIST_TAIL, "OVER_VAL", PS_META_REPLACE,
Index: /branches/eam_branches/ipp-20220316/psModules/src/objects/pmSourceMasks.h
===================================================================
--- /branches/eam_branches/ipp-20220316/psModules/src/objects/pmSourceMasks.h	(revision 42370)
+++ /branches/eam_branches/ipp-20220316/psModules/src/objects/pmSourceMasks.h	(revision 42371)
@@ -72,4 +72,5 @@
     PM_SOURCE_MODE2_ON_GHOST      	  = 0x00800000, ///< > 25% of (PSF-weighted) pixels land on ghost
     PM_SOURCE_MODE2_ON_CROSSTALK      	  = 0x01000000, ///< peaks land on electronic crostalk
+    PM_SOURCE_MODE2_ON_CTE      	  = 0x02000000, ///< peaks land on CTE region
 
     
Index: /branches/eam_branches/ipp-20220316/psModules/src/objects/pmSourcePhotometry.c
===================================================================
--- /branches/eam_branches/ipp-20220316/psModules/src/objects/pmSourcePhotometry.c	(revision 42370)
+++ /branches/eam_branches/ipp-20220316/psModules/src/objects/pmSourcePhotometry.c	(revision 42371)
@@ -53,12 +53,13 @@
 
 // make this a bit more clever and dynamic
-static psImageMaskType maskSuspect  = 0;
-static psImageMaskType maskSpike    = 0;
-static psImageMaskType maskStarCore = 0;
-static psImageMaskType maskBurntool = 0;
-static psImageMaskType maskConvPoor = 0;
-static psImageMaskType maskGhost    = 0;
-static psImageMaskType maskGlint    = 0;
-static psImageMaskType maskCrosstalk    = 0;
+static psImageMaskType maskSuspect   = 0;
+static psImageMaskType maskSpike     = 0;
+static psImageMaskType maskStarCore  = 0;
+static psImageMaskType maskBurntool  = 0;
+static psImageMaskType maskConvPoor  = 0;
+static psImageMaskType maskGhost     = 0;
+static psImageMaskType maskGlint     = 0;
+static psImageMaskType maskCrosstalk = 0;
+static psImageMaskType maskCTE       = 0;
 
 bool pmSourceMagnitudesInit (pmConfig *config, psMetadata *recipe)
@@ -69,12 +70,13 @@
     // we are going to test specially against these poor values
     if (config) {
-	maskSpike    = pmConfigMaskGet("SPIKE", config);
-	maskStarCore = pmConfigMaskGet("STARCORE", config);
-	maskBurntool = pmConfigMaskGet("BURNTOOL", config);
-	maskConvPoor = pmConfigMaskGet("CONV.POOR", config);
-	maskGhost    = pmConfigMaskGet("GHOST", config);
-	maskGlint    = pmConfigMaskGet("GHOST", config);
-	maskCrosstalk    = pmConfigMaskGet("CROSSTALK", config);
-	maskSuspect  = maskSpike | maskStarCore | maskBurntool | maskConvPoor;
+	maskSpike     = pmConfigMaskGet("SPIKE", config);
+	maskStarCore  = pmConfigMaskGet("STARCORE", config);
+	maskBurntool  = pmConfigMaskGet("BURNTOOL", config);
+	maskConvPoor  = pmConfigMaskGet("CONV.POOR", config);
+	maskGhost     = pmConfigMaskGet("GHOST", config);
+	maskGlint     = pmConfigMaskGet("GHOST", config);
+	maskCrosstalk = pmConfigMaskGet("CROSSTALK", config);
+	maskCTE       = pmConfigMaskGet("CTE", config);
+	maskSuspect   = maskSpike | maskStarCore | maskBurntool | maskConvPoor;
     }
 
@@ -440,4 +442,5 @@
     float convpoorSum = 0;
     float ghostSum = 0;
+    float cteSum = 0;
 
     int Xo, Yo, dP;
@@ -534,4 +537,9 @@
 		convpoorSum += value;
 	    }
+	    // count pixels which are masked with an mask bit (bad or poor)
+            if (mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskCTE) {
+		cteSum += value;
+	    }
+
         }
     }
@@ -555,4 +563,7 @@
     if ((convpoorSum/modelSum) > 0.25) {
 	source->mode2 |= PM_SOURCE_MODE2_ON_CONVPOOR;
+    }
+    if ((cteSum/modelSum) > 0.25) {
+	source->mode2 |= PM_SOURCE_MODE2_ON_CTE;
     }
 
@@ -614,4 +625,5 @@
     float convpoorSum = 0;
     float ghostSum = 0;
+    float cteSum = 0;
 
     int Xo, Yo, dP;
@@ -683,4 +695,8 @@
 		convpoorSum += 1.;
 	    }
+	    // count pixels which are masked with an mask bit (bad or poor)
+            if (mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskCTE) {
+                cteSum += 1.;
+            }
         }
     }
@@ -701,4 +717,7 @@
     if ((convpoorSum/modelSum) > 0.25) {
 	source->mode2 |= PM_SOURCE_MODE2_ON_CONVPOOR;
+    }
+    if ((cteSum/modelSum) > 0.25) {
+	source->mode2 |= PM_SOURCE_MODE2_ON_CTE;
     }
 
Index: /branches/eam_branches/ipp-20220316/psModules/src/psmodules.h
===================================================================
--- /branches/eam_branches/ipp-20220316/psModules/src/psmodules.h	(revision 42370)
+++ /branches/eam_branches/ipp-20220316/psModules/src/psmodules.h	(revision 42371)
@@ -77,4 +77,5 @@
 #include <pmMaskStats.h>
 #include <pmNonLinear.h>
+#include <pmNewNonLinear.h>
 #include <pmOverscan.h>
 #include <pmBias.h>
