コード例 #1
0
ファイル: acssum.c プロジェクト: jhunkeler/hstcal
static int RptSumLine (SingleGroup *a, int line, SingleGroupLine *b) {

/* arguments:
SingleGroup *a      io: input data; output sum
int line             i: line from input/output to be summed
SingleGroupLine *b   i: second input data line
*/

    extern int status;

    int i;
    short dqa, dqb, dqab;    /* data quality for a, b, combined */

    if (a->sci.data.nx != b->sci.tot_nx)
        return (status = SIZE_MISMATCH);

    /* science data */
    for (i = 0;  i < a->sci.data.nx;  i++) {
        Pix (a->sci.data, i, line) = Pix(a->sci.data, i, line) + b->sci.line[i];
    }

    /* error array (actually contains variance) */
        for (i = 0;  i < a->err.data.nx;  i++) {
        Pix (a->err.data, i, line) = Pix (a->err.data, i, line) + b->err.line[i];
        }

    /* data quality */
        for (i = 0;  i < a->dq.data.nx;  i++) {
        dqa = DQPix (a->dq.data, i, line);
        dqb = b->dq.line[i];
        dqab = dqa | dqb;
        DQSetPix (a->dq.data, i, line, dqab);
        }

    return (status);
}
コード例 #2
0
ファイル: sink.c プロジェクト: sosey/hstcal
int SinkDetect(WF3Info *wf3, SingleGroup *x){

    extern int status;
    int i,j, jj;
    short dqval=0;
    float scipix; /*to save the value of the science pixel*/
    float refdate=50000.;
    int keep_going=1;
    
    sprintf(MsgText,"\nPerforming SINK pixel detection for imset %i",x->group_num);
    trlmessage(MsgText);
    

    /*THE SCIENCE IMAGE*/
    SingleGroup raz; /*quad rotated image to work with*/    

    /* INIT THE SCIENCE INPUT  */
    initSingleGroup (&raz);
    allocSingleGroup (&raz,RAZ_COLS/2, RAZ_ROWS);
        
    /*CONVERT DQ DATA TO RAZ FORMAT FOR SCIENCE FILE*/
    makedqRAZ(x, &raz);
    makeSciSingleRAZ(x, &raz);

	/* GET THE SINK FILE REFERENCE IMAGE FROM SINKFILE AND INITIALIZE */
    FloatHdrData sinkref;
    initFloatHdrData(&sinkref);
    getFloatHD(wf3->sink.name,"SCI",x->group_num,&sinkref);
                 
    /*NOW TURN THE SINK REFERENCE IMAGES INTO RAZ FORMAT*/
    FloatTwoDArray sinkraz;    
    initFloatData(&sinkraz); /*float 2d arrays*/
    allocFloatData(&sinkraz,RAZ_COLS/2, RAZ_ROWS);     

    makeFloatRaz(&sinkref.data,&sinkraz,x->group_num);

       
    /*THE MJD OF THE SCIENCE EXPOSURE IS THE COMPARISON DATE
     THE FOLLOWING TRANSLATION TAKEN FROM ISR WFC3-2014-22.PDF */
    
    scipix=0.;
    for (i=0;i<(RAZ_COLS/2);i++){
        for (j=0; j<RAZ_ROWS; j++){
        
            if (  (PPix(&sinkraz,i,j) > refdate)  &&  ( wf3->expstart > PPix(&sinkraz,i,j))  ){
                keep_going=1;
                
                /*FLAG THE PRIMARY SINK PIXEL*/
                dqval = TRAP | DQPix (raz.dq.data, i, j);
                DQSetPix (raz.dq.data, i, j, dqval);
                scipix = Pix(raz.sci.data,i,j);
                
                /*FLAG THE DOWNSTREAM PIXEL*/
                if (PPix(&sinkraz,i,j-1) < 0 ){
                    dqval = TRAP | DQPix (raz.dq.data, i, j-1);
                    DQSetPix (raz.dq.data, i, j-1, dqval);
                }

                /*FLAG THE UPSTREAM PIXELS*/
                for (jj=j+1; jj<RAZ_ROWS; jj++){
                    if ((int) PPix(&sinkraz,i,jj) == 0)
                        keep_going=0;
                    if ( PPix(&sinkraz,i,jj) > refdate)
                        keep_going=0;
                    if ( 0. < PPix(&sinkraz,i,jj) &&  PPix(&sinkraz,i,jj) < 1000. && keep_going){
                        if (scipix <= PPix(&sinkraz,i,jj) ){
                           dqval = TRAP | DQPix (raz.dq.data, i, jj);
                           DQSetPix (raz.dq.data, i, jj, dqval);
                        }                
                    } else {
                        keep_going=0;
                    }
                }                
            } /*end if*/ 
        } /*end j*/
    }/*end i*/   

    
    /*format the dq data back to expected orientation*/
    undodqRAZ(x,&raz);

    freeSingleGroup(&raz);
    freeFloatData(&sinkraz);
    freeFloatHdrData(&sinkref);
    trlmessage("Sink pixel flagging complete");
    return(status);
}
コード例 #3
0
ファイル: doatod.c プロジェクト: jhunkeler/hstcal
int doAtoD (WF3Info *wf3, SingleGroup *x) {

/* arguments:
WF3Info *wf3	 i: calibration switches, etc
SingleGroup *x	io: image to be calibrated; written to in-place
*/

	extern int status;

	TblInfo tabinfo;	/* pointer to table descriptor, etc */
	TblRow tabrow;		/* values read from a table row */
	TblArray tabarray;	/* correction array read from table row */

	int foundit;		/* row found in table? */
	int row;		/* loop index for row number */
	int row_min;		/* row with matching keyword */
	double ref_key_value;	/* value gotten from image header */
	double dt, dt_min;	/* for finding desired row in table */
	int ival;		/* input science data value from x */
	int i, j;
	short dqval;

	int GetKeyDbl (Hdr *, char *, int, double, double *);
	int RowPedigree (RefTab *, int, IRAFPointer, IRAFPointer, IRAFPointer);
	int SameFlt (float, float);
	int SameString (char *, char *);

    row_min=0;
    dt_min=0.0f;
    
	if (wf3->atodcorr != PERFORM)
	    return (status);

	if (wf3->ncombine > 1) {
	    trlerror 
		("NCOMBINE is already > 1 before ATODCORR has been performed.");
	    return (status = 1010);
	}

	/* Open the A-to-D table. */
	if (OpenAtoDTab (wf3->atod.name, &tabinfo))
	    return (status);

	/* Find the row with value closest to the temperature. */

	foundit = 0;
	for (row = 1;  row <= tabinfo.nrows;  row++) {
	    if (ReadAtoDTab (&tabinfo, row, &tabrow))
		return (status);
	    if (SameString (tabrow.ccdamp, wf3->ccdamp) &&
		SameFlt (tabrow.ccdgain, wf3->ccdgain)) {
		if (GetKeyDbl (x->globalhdr, tabrow.ref_key, NO_DEFAULT,
			       0., &ref_key_value))
		    return (status);
		if (!foundit) {
		    /* assign initial values */
		    foundit = 1;
		    row_min = row;
		    dt_min = fabs (ref_key_value - tabrow.ref_key_value);
		} else {
		    /* Get value from image, and update dt_min. */
		    dt = fabs (ref_key_value - tabrow.ref_key_value);
		    if (dt < dt_min) {
			dt_min = dt;
			row_min = row;
		    }
		}
	    }
	}

	if (!foundit) {
	    sprintf (MsgText, "CCD amp %s, gain %g, not found in ATODTAB `%s'.",
		wf3->ccdamp, wf3->ccdgain, wf3->atod.name);
	    trlerror (MsgText);
	    CloseAtoDTab (&tabinfo);
	    return (status = TABLE_ERROR);
	}

	/* Get pedigree & descrip from the row. */
	if (RowPedigree (&wf3->atod, row_min,
		tabinfo.tp, tabinfo.cp_pedigree, tabinfo.cp_descrip))
	    return (status);
	if (wf3->atod.goodPedigree == DUMMY_PEDIGREE) {
	    wf3->atodcorr = DUMMY;
	    CloseAtoDTab (&tabinfo);
	    return (status);
	}

	/* Reread the appropriate row to get the correction array. */
	if (ReadAtoDArray (&tabinfo, row_min, &tabarray))
	    return (status);

	/* Apply this correction to each pixel in the image.  At this
	   stage the values should still be integers, so assigning
	   a value to an integer (ival) should not result in truncation.
	*/
	dqval = 0;
	for (j = 0;  j < x->sci.data.ny;  j++) {
	    for (i = 0;  i < x->sci.data.nx;  i++) {
		ival = (int) Pix (x->sci.data, i, j);
		if (ival >= tabarray.nelem) {
		    Pix (x->sci.data, i, j) = tabarray.atod[tabarray.nelem-1];
			dqval = SATPIXEL | DQPix (x->dq.data, i, j);
		    DQSetPix (x->dq.data, i, j, dqval);	/* saturated */
		} else if (ival >= 0) {
		    Pix (x->sci.data, i, j) = tabarray.atod[ival];
		}		/* else if ival < 0, no change */
	    }
	}

	free (tabarray.atod);
	if (CloseAtoDTab (&tabinfo))
	    return (status);

	return (status);
}
コード例 #4
0
ファイル: dodqi.c プロジェクト: jhunkeler/hstcal
int doDQI (StisInfo1 *sts, SingleGroup *x) {

/* arguments:
StisInfo1 *sts    i: calibration switches, etc
SingleGroup *x    io: image to be calibrated; DQ array written to in-place
*/

	int status;

	TblInfo tabinfo;	/* pointer to table descriptor, etc */
	TblRow tabrow;		/* values read from a table row */

	ShortTwoDArray ydq;		/* scratch space */

	/* mappings from one coordinate system to another */
	double ri_m[2], ri_v[2];	/* reference to image */
	double rs_m[2], rs_v[2];	/* reference to scratch */
	double si_m[2], si_v[2];	/* scratch to image */

	/* for copying from scratch array (only copy overlap region): */
	int first[2], last[2];	/* corners of overlap region in image coords */
	int sfirst[2];		/* lower left corner of overlap in scratch */
	int rbin[2];		/* bin size of image relative to ref bin size */

	int snpix[2];		/* size of scratch array */
	int npix[2];		/* size of current image */

	float *ds;		/* Doppler smearing array */
	int nds, d0;		/* size of ds and index in ds of zero point */
	int k, kmin, kmax;	/* loop index; range of indexes in ds */
	int doppmin, doppmax;	/* Doppler offsets relative to d0 */

	int in_place;		/* true if same bin size and no Doppler */
	int high_res;		/* true if Doppler or either axis is high-res */
	int i, j, i0, j0;	/* indexes for scratch array ydq */
	int m, n;		/* indexes for data quality array in x */
	short sum_dq;		/* for binning data quality array */

	int row;		/* loop index for row number */

	void FlagFilter (StisInfo1 *, ShortTwoDArray *,
		int, int, double *, double *);
	int MakeDopp (double, double, double, double, double, int,
		float *, int *, int *);

	/* We could still flag saturation even if the bpixtab was dummy. */
	if (sts->dqicorr != PERFORM && sts->dqicorr != DUMMY)
	    return (0);

	/* For the CCD, check for and flag saturation. */
	if (sts->detector == CCD_DETECTOR) {
	    for (j = 0;  j < x->sci.data.ny;  j++) {
		for (i = 0;  i < x->sci.data.nx;  i++) {
		    if ((int) Pix (x->sci.data, i, j) > sts->saturate) {
			sum_dq = DQPix (x->dq.data, i, j) | SATPIXEL;
			DQSetPix (x->dq.data, i, j, sum_dq);	/* saturated */
		    }
		}
	    }
	}

	/* Get the linear transformation between reference and input image. */
	if ((status = GetLT0 (&x->sci.hdr, ri_m, ri_v))) /* zero indexed LTV */
	    return (status);

	/* Flag regions beyond the bounderies of the aperture, for CCD data. */
	if (sts->detector == CCD_DETECTOR) {
	    FlagFilter (sts, &x->dq.data, x->dq.data.nx, x->dq.data.ny,
			ri_m, ri_v);
	}

	/* There might not be any bad pixel table.  If not, quit now. */
	if (sts->bpix.exists == EXISTS_NO || sts->dqicorr != PERFORM)
	    return (0);

	initShortData (&ydq);

	/* In some cases we can set the data quality flags directly in
	   the DQ array, but in other cases we must create a scratch
	   array and copy back to the original.  Either the original or
	   the scratch may be in high-res mode.
	*/
	if (sts->detector == CCD_DETECTOR) {

	    if (sts->bin[0] == 1 && sts->bin[1] == 1)
		in_place = 1;			/* no binning */
	    else
		in_place = 0;
	    high_res = 0;

	} else {				/* MAMA */

	    if (sts->doppcorr == PERFORM) {

		high_res = 1;

		if (sts->bin[0] == 1 && sts->bin[1] == 1)
		    in_place = 1;		/* high-res in both axes */
		else
		    in_place = 0;

	    } else {				/* no Doppler convolution */

		if (sts->bin[0] == 2 && sts->bin[1] == 2) {
		    high_res = 0;		/* both axes low-res */
		    in_place = 1;
		} else if (sts->bin[0] == 1 && sts->bin[1] == 1) {
		    high_res = 1;		/* both axes high-res */
		    in_place = 1;
		} else {
		    high_res = 1;		/* low-res in one axis */
		    in_place = 0;
		}
	    }
	}

	/* Get the other linear transformations (ri_m & ri_v were gotten
	   earlier, just after checking for saturation.)
	*/
	if (!in_place) {
	    if (high_res) {
		/* DQ array is binned finer than reference coords */
		rs_m[0] = 2.;
		rs_m[1] = 2.;
		rs_v[0] = 0.5;
		rs_v[1] = 0.5;
		/* assumes rs_m = 2, rs_v = 0.5 */
		si_m[0] = ri_m[0] * 0.5;
		si_m[1] = ri_m[1] * 0.5;
		si_v[0] = ri_v[0] - ri_m[0] * 0.25;
		si_v[1] = ri_v[1] - ri_m[1] * 0.25;
	    } else {
		/* scratch is in reference coords */
		rs_m[0] = 1.;
		rs_m[1] = 1.;
		rs_v[0] = 0.;
		rs_v[1] = 0.;
		/* assumes rs_m = 1, rs_v = 0 */
		si_m[0] = ri_m[0];
		si_m[1] = ri_m[1];
		si_v[0] = ri_v[0];
		si_v[1] = ri_v[1];
	    }
	}

	if (sts->doppcorr == PERFORM) {
	    /* Compute the Doppler smearing array, if we need it.  We need
		the size (nds) and zero point (d0), not the array itself.
	    */
	    nds = 2 * (sts->doppmag + 1) + 21;	/* reassigned by makeDopp */
	    ds = (float *) calloc (nds, sizeof (float));
	    if ((status = MakeDopp (sts->doppzero, sts->doppmag, sts->orbitper,
                                    sts->expstart, sts->exptime, sts->dispsign,
                                    ds, &nds, &d0)))
		return (status);
	    /* Find the range of non-zero elements in ds. */
	    kmin = nds - 1;		/* initial values */
	    kmax = 0;
	    for (k = 0;  k < nds;  k++) {
		if (ds[k] > 0.) {	/* there will be no negative values */
		    if (k < kmin)
			kmin = k;
		    if (k > kmax)
			kmax = k;
		}
	    }
	    /* It's the indexes relative to d0 that are important. */
	    doppmin = kmin - d0;
	    doppmax = kmax - d0;
	    free (ds);
	} else {
	    doppmin = 0;
	    doppmax = 0;
	}

	/* Open the data quality initialization table, find columns, etc. */
	if ((status = OpenBpixTab (sts->bpix.name, &tabinfo)))
	    return (status);

	/* Size of scratch image */
	if (high_res) {
	    snpix[0] = 2 * tabinfo.axlen1;
	    snpix[1] = 2 * tabinfo.axlen2;
	} else {
	    snpix[0] = tabinfo.axlen1;
	    snpix[1] = tabinfo.axlen2;
	}

	/* size of current image */
	npix[0] = x->dq.data.nx;
	npix[1] = x->dq.data.ny;

	if (!in_place) {
	    /* Allocate space for a scratch array. */
	    allocShortData (&ydq, snpix[0], snpix[1], True);
	    if (hstio_err()) {
		printf (
		"ERROR    (doDQI) couldn't allocate data quality array.\n");
		return (OUT_OF_MEMORY);
	    }
	    for (j = 0;  j < snpix[1];  j++)
		for (i = 0;  i < snpix[0];  i++)
		    DQSetPix (ydq, i, j, 0);		/* initially OK */
	}

	/* Read each row of the table, and fill in data quality values. */

	for (row = 1;  row <= tabinfo.nrows;  row++) {

	    if ((status = ReadBpixTab (&tabinfo, row, &tabrow))) {
		printf ("ERROR    Error reading BPIXTAB.\n");
		return (status);
	    }

	    if (!SameString (tabrow.opt_elem, sts->opt_elem))
		continue;

	    if (tabrow.xstart < 0 || tabrow.xstart >= tabinfo.axlen1 ||
		tabrow.ystart < 0 || tabrow.ystart >= tabinfo.axlen2) {
		printf (
	"Warning  Starting pixel (%d,%d) in BPIXTAB is out of range.\n",
			tabrow.xstart+1, tabrow.ystart+1);
		continue;			/* ignore this row */
	    }

	    /* Assign the flag value to all relevant pixels. */
	    if (in_place) {
		if (high_res)
		    DQIHigh (&x->dq.data, ri_v, &tabrow, doppmin, doppmax);
		else
		    DQINormal (&x->dq.data, ri_v, &tabrow);
	    } else {				/* use scratch array */
		if (high_res)
		    DQIHigh (&ydq, rs_v, &tabrow, doppmin, doppmax);
		else
		    DQINormal (&ydq, rs_v, &tabrow);
	    }
	}

	if ((status = CloseBpixTab (&tabinfo)))	/* done with the table */
	    return (status);

	if (!in_place) {

	    /* Get corners of region of overlap between image and
		scratch array.
	    */
	    FirstLast (si_m, si_v, snpix, npix, rbin, first, last, sfirst);

	    /* We have been writing to a scratch array ydq.  Now copy or
		bin the values down to the actual size of x.
	    */
	    j0 = sfirst[1];
	    for (n = first[1];  n <= last[1];  n++) {
		i0 = sfirst[0];
		for (m = first[0];  m <= last[0];  m++) {
		    sum_dq = DQPix (x->dq.data, m, n);
		    for (j = j0;  j < j0+rbin[1];  j++)
			for (i = i0;  i < i0+rbin[0];  i++)
			    sum_dq |= DQPix (ydq, i, j);
		    DQSetPix (x->dq.data, m, n, sum_dq);
		    i0 += rbin[0];
		}
		j0 += rbin[1];
	    }

	    freeShortData (&ydq);			/* done with ydq */
	}

	return (0);
}
コード例 #5
0
ファイル: doatod.c プロジェクト: jhunkeler/hstcal
int doAtoD (StisInfo1 *sts, SingleGroup *x) {

/* arguments:
StisInfo1 *sts     i: calibration switches, etc
SingleGroup *x    io: image to be calibrated; written to in-place
*/

	int status;

	TblInfo tabinfo;	/* pointer to table descriptor, etc */
	TblRow tabrow;		/* values read from a table row */
	TblArray tabarray;	/* correction array read from table row */

	int foundit;		/* row found in table? */
	int row;		/* loop index for row number */
	int row_min;		/* row with closest temperature (min dt) */
	double ref_key_value;	/* value gotten from image header */
	double dt, dt_min;	/* for finding temperature in table */
	int ival;		/* input science data value from x */
	int i, j;
	short dq;		/* a data quality value */

	int no_default = 0;	/* missing keyword is fatal error */

	if (sts->atodcorr != PERFORM)
	    return (0);

	if (sts->ncombine > 1) {
	    printf (
"ERROR    NCOMBINE is already > 1 before ATODCORR has been performed.\n");
	    return (GENERIC_ERROR_CODE);
	}

	/* Open the A-to-D table. */
	if ((status = OpenAtoDTab (sts->atod.name, &tabinfo)))
	    return (status);

	/* Find the row with value closest to the temperature. */

	foundit = 0;
	for (row = 1;  row <= tabinfo.nrows;  row++) {
	    if ((status = ReadAtoDTab (&tabinfo, row, &tabrow)))
		return (status);
	    if (SameString (tabrow.ccdamp, sts->ccdamp) &&
		SameInt (tabrow.ccdgain, sts->ccdgain)) {
		/* Get value from header. */
		if ((status = Get_KeyD (&x->sci.hdr, tabrow.ref_key, no_default,
                                        0., &ref_key_value)))
		    return (status);
		dt = fabs (ref_key_value - tabrow.ref_key_value);
		if (!foundit) {
		    foundit = 1;	/* assign initial values */
		    dt_min = dt;
		    row_min = row;
		} else if (dt < dt_min) {	/* update dt_min */
		    dt_min = dt;
		    row_min = row;
		}
	    }
	}

	if (!foundit) {
	    printf (
	"ERROR    CCD amp %s, gain %d, not found in ATODTAB `%s'.\n",
		sts->ccdamp, sts->ccdgain, sts->atod.name);
	    CloseAtoDTab (&tabinfo);
	    return (TABLE_ERROR);
	}

	/* Get pedigree & descrip from the row. */
	if ((status = RowPedigree (&sts->atod, row_min,
                tabinfo.tp, tabinfo.cp_pedigree, tabinfo.cp_descrip)))
	    return (status);
	if (sts->atod.goodPedigree == DUMMY_PEDIGREE) {
	    sts->atodcorr = DUMMY;
	    CloseAtoDTab (&tabinfo);
	    return (0);
	}

	/* Reread the appropriate row to get the correction array. */
	if ((status = ReadAtoDArray (&tabinfo, row_min, &tabarray)))
	    return (status);

	/* Apply this correction to each pixel in the image.  At this
	   stage the values should still be integers, so assigning
	   a value to an integer (ival) should not result in truncation.
	*/
	for (j = 0;  j < x->sci.data.ny;  j++) {
	    for (i = 0;  i < x->sci.data.nx;  i++) {
		ival = (int) Pix (x->sci.data, i, j);
		if (ival >= tabarray.nelem) {
		    Pix (x->sci.data, i, j) = tabarray.atod[tabarray.nelem-1];
		    dq = DQPix (x->dq.data, i, j) | SATPIXEL;
		    DQSetPix (x->dq.data, i, j, dq);	/* saturated */
		} else if (ival >= 0) {
		    Pix (x->sci.data, i, j) = tabarray.atod[ival];
		}		/* else if ival < 0, no change */
	    }
	}

	free (tabarray.atod);
	if ((status = CloseAtoDTab (&tabinfo)))
	    return (status);

	return (0);
}
コード例 #6
0
ファイル: nlincorr.c プロジェクト: brechmos-stsci/hstcal
static int nlincorr (WF3Info *wf3, SingleNicmosGroup *input, NlinData *nlin,
		     SingleNicmosGroup *zsig) {

/* Arguments:
**	wf3	 i: WFC3 info structure
**	input	io: input image to be corrected
**	nlin	 i: nonlinearity reference data
**	zsig	 i: MULTIACCUM zero-read signal image
*/

	/* Local variables */
	int i, j, li, lj, k;	/* pixel indexes */
	int ibeg, iend;		/* loop limits */
	int jbeg, jend;		/* loop limits */
	int li_beg, lj_beg;	/* loop limits */
	int rsize = 1;		/* for use by GetCorner */
	int sci_bin[2];		/* bin size of science image */
	int sci_corner[2];	/* science image corner location */
	int ref_bin[2];		/* bin size of reference image */
	int ref_corner[2];	/* ref image corner location */
	int nsatpix;		/* number of saturated pixels */
	float sval, eval;	/* science and err image values */
	float corr;		/* correction value */
	float n1;		/* node value */

	/* Function definitions */
	int GetCorner (Hdr *, int, int *, int*);

	/* Compute subarray offsets, if any, between ref data
	** science data. */
	if ( (status = GetCorner(&input->sci.hdr, rsize, sci_bin, sci_corner)))
	    return (status);
	if ( (status = GetCorner(&nlin->coeff[0].hdr, rsize, ref_bin, ref_corner)))
	    return (status);

	/* Initialize saturated pixel counter */
	nsatpix = 0;

	/* Loop through science image */
	ibeg = wf3->trimx[0]; iend = input->sci.data.nx - wf3->trimx[1];
	jbeg = wf3->trimy[0]; jend = input->sci.data.ny - wf3->trimy[1];
	li_beg = (sci_corner[0] - ref_corner[0]) + ibeg;
	lj_beg = (sci_corner[1] - ref_corner[1]) + jbeg;

	for (j = jbeg, lj = lj_beg; j < jend; j++, lj++) {
	for (i = ibeg, li = li_beg; i < iend; i++, li++) {

	     /* Get the science and error image values */
	     sval = Pix(input->sci.data,i,j);
	     eval = Pix(input->err.data,i,j);

	     /* Temporarily add the MULTIACCUM zero-read signal back into the
	     ** the pixel value, but only if ZSIG step is turned on and only 
	     ** for groups other than the zeroth-read itself */
	     if (wf3->zsigcorr == PERFORM && wf3->group != wf3->ngroups) {
		 sval += Pix(zsig->sci.data,i,j);
		 if (DQPix(zsig->dq.data,i,j) & ZEROSIG) {
		     DQSetPix(input->dq.data,i,j,
			DQPix(input->dq.data,i,j) | ZEROSIG);
		 }
	     }

	     /* Get the node values for this pixel */
	     n1 = Pix(nlin->nodes[0].data,li,lj);

	     /* Propagate the DQ value from the NLIN ref data */
	     DQSetPix(input->dq.data,i,j,
		DQPix(input->dq.data,i,j) | DQPix(nlin->dqual[0].data,li,lj));

	     /* If it's already flagged as saturated,
	     ** skip the correction */
	     if (DQPix(input->dq.data,i,j) & SATPIXEL) {
		 nsatpix++;

	     /* Apply the correction for the non-linear region */
	     /*} else if (sval >= n1 && sval <= n2) {*/
	     } else if (sval <= n1) {

	       /* Compute the new science image pixel value */
	       corr = 1.0;
	       for (k=0; k < nlin->ncoeff; k++)
		    corr += Pix(nlin->coeff[k].data,li,lj) * (pow(sval,k));
	       Pix(input->sci.data,i,j) = sval * corr;

	       /* Remove the MULTIACCUM zero-read signal that was added in
	       ** above, but only if ZSIG step is turned on and only for 
	       ** groups other than the zeroth-read itself */
	       if (wf3->zsigcorr == PERFORM && wf3->group != wf3->ngroups)
		   Pix(input->sci.data,i,j) -= Pix(zsig->sci.data,i,j);

	     /* Above the saturation node, just mark the pixel as saturated */
	     } else if (sval > n1) {
	       nsatpix++;
	       DQSetPix(input->dq.data,i,j,
		  DQPix(input->dq.data,i,j) | SATPIXEL);
	     }
	}}

	/* Report the number of saturated pixels */
	sprintf (MsgText, "NLINCORR detected %d saturated pixels in imset %d",
		 nsatpix, wf3->group);
	trlmessage (MsgText);

	/* Successful return */
	return (status = 0);
}