Index: /branches/eam_branches/psModules.20230123/src/detrend/pmNewNonLinear.c
===================================================================
--- /branches/eam_branches/psModules.20230123/src/detrend/pmNewNonLinear.c	(revision 42327)
+++ /branches/eam_branches/psModules.20230123/src/detrend/pmNewNonLinear.c	(revision 42327)
@@ -0,0 +1,55 @@
+#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 pmNonLinearityApply(pmReadout *inputReadout, psArray *table)
+{
+    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);
+    PS_ASSERT_PTR_NON_NULL(Ltab, 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];
+	
+	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/psModules.20230123/src/detrend/pmNewNonLinear.h
===================================================================
--- /branches/eam_branches/psModules.20230123/src/detrend/pmNewNonLinear.h	(revision 42327)
+++ /branches/eam_branches/psModules.20230123/src/detrend/pmNewNonLinear.h	(revision 42327)
@@ -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 pmNonLinearityApply(pmReadout *inputReadout, psArray *table);
+
+/// @}
+#endif
Index: /branches/eam_branches/psModules.20230123/src/detrend/pmOverscan.c
===================================================================
--- /branches/eam_branches/psModules.20230123/src/detrend/pmOverscan.c	(revision 42326)
+++ /branches/eam_branches/psModules.20230123/src/detrend/pmOverscan.c	(revision 42327)
@@ -136,6 +136,9 @@
         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
+
+        // 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);
