void Interp2D (SingleGroup *in, short sdqflags, double ix, double iy, double jacobian, int err_algorithm, float *oSci, float *oErr, short *oDQ) { /* arguments: SingleGroup *in i: input data short sdqflags i: which data quality flags are serious double ix, iy i: pixel location in input double jacobian i: factor for conserving flux float *oSci o: interpolated value in science array float *oErr o: interpolated error value short *oDQ o: interpolated data quality value */ float p, q, r, s; /* 1-D weights */ float w0, w1, w2, w3; /* weight for each pixel */ float e0, e1, e2, e3; /* error * weight for each pixel */ float sumw; /* sum of weights */ float value; /* interpolated value (sci or err) */ int inx, iny; /* size of input image */ int ii, ij; /* a pixel location in input */ int iix, iiy; /* nearest integers to ix & iy */ int ngood; /* number of neighbors (1-4) flagged as good */ inx = in->sci.data.nx; iny = in->sci.data.ny; /* Round off to nearest integer, and check for out of bounds. */ iix = NINT(ix); iiy = NINT(iy); if (iix < 0 || iix > inx-1 || iiy < 0 || iiy > iny-1) { /* The current point is outside the input image. */ *oSci = 0.; /* harmless values */ *oErr = 0.; *oDQ = DETECTORPROB; return; } /* Use bilinear interpolation on the four pixels centered near (ix,iy). These pixels are: [ii, ij+1] [ii+1, ij+1] [ii, ij ] [ii+1, ij ] */ ii = (int)ix; if (ii < 0) ii = 0; if (ii > inx-2) ii = inx-2; q = ix - ii; /* weights for X direction */ p = 1.0F - q; ij = (int)iy; if (ij < 0) ij = 0; if (ij > iny-2) ij = iny-2; s = iy - ij; /* weights for Y direction */ r = 1.0F - s; /* Assign a weight for each of the four pixels. */ ngood = 0; if (DQPix (in->dq.data, ii, ij) & sdqflags) { w0 = 0.0F; } else { w0 = p * r; /* lower left pixel */ ngood++; } if (DQPix (in->dq.data, ii+1, ij) & sdqflags) { w1 = 0.0F; } else { w1 = q * r; /* lower right pixel */ ngood++; } if (DQPix (in->dq.data, ii, ij+1) & sdqflags) { w2 = 0.0F; } else { w2 = p * s; /* upper left pixel */ ngood++; } if (DQPix (in->dq.data, ii+1, ij+1) & sdqflags) { w3 = 0.0F; } else { w3 = q * s; /* upper right pixel */ ngood++; } sumw = w0 + w1 + w2 + w3; if (ngood == 0 || sumw <= 0.) { /* All four are bad, or the sum of weights is zero, so just copy values from the nearest pixel. */ *oSci = Pix (in->sci.data, iix, iiy) * jacobian; *oErr = Pix (in->err.data, iix, iiy) * sqrt (jacobian); } else { if (ngood < 4) { /* Normalize the weights so their sum is one. */ w0 /= sumw; w1 /= sumw; w2 /= sumw; w3 /= sumw; } /* Interpolate. */ value = w0 * Pix (in->sci.data, ii, ij) + w1 * Pix (in->sci.data, ii+1, ij) + w2 * Pix (in->sci.data, ii, ij+1) + w3 * Pix (in->sci.data, ii+1, ij+1); *oSci = jacobian * value; e0 = Pix (in->err.data, ii, ij); e1 = Pix (in->err.data, ii+1, ij); e2 = Pix (in->err.data, ii, ij+1); e3 = Pix (in->err.data, ii+1, ij+1); if (err_algorithm == WGT_VARIANCE) { value = (w0 * e0 * e0) + (w1 * e1 * e1) + (w2 * e2 * e2) + (w3 * e3 * e3); } else if (err_algorithm == WGT_ERROR) { value = (w0 * w0 * e0 * e0) + (w1 * w1 * e1 * e1) + (w2 * w2 * e2 * e2) + (w3 * w3 * e3 * e3); } else { value = -1.; /* cannot happen */ } if (jacobian * value > 0.) *oErr = sqrt (jacobian * value); else *oErr = 0.; } *oDQ = DQPix (in->dq.data, ii, ij) | DQPix (in->dq.data, ii+1, ij) | DQPix (in->dq.data, ii, ij+1) | DQPix (in->dq.data, ii+1, ij+1); }
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); }
int RebinData (SingleGroup *iim, SingleGroup *oim, RowContents **ix1d, RowContents **ox1d , int rebinfactor, int nrows) { /* arguments SingleGroup *iim; i: input image SingleGroup *oim; o: output image RowContents **ix1d; i: input array with table data. RowContents **ox1d; o: output array with table data. int rebinfactor; i: rebinning factor int nrows; i: number of rows */ int i, j, i2, j2, rf; double hold; /* Alloc memory in output x1d array. */ rf = (rebinfactor > 0) ? rebinfactor : -rebinfactor; for (j = 0; j < nrows; j++) { ox1d[j]->sporder = ix1d[j]->sporder; ox1d[j]->npts = ix1d[j]->npts / rf; ox1d[j]->wave = (double *) calloc (ox1d[j]->npts, sizeof(double)); ox1d[j]->gross = (float *) calloc (ox1d[j]->npts, sizeof(float)); ox1d[j]->net = (float *) calloc (ox1d[j]->npts, sizeof(float)); ox1d[j]->extrlocy = (float *) calloc (ox1d[j]->npts, sizeof(float)); if (ox1d[j]->wave == NULL || ox1d[j]->gross == NULL || ox1d[j]->net == NULL || ox1d[j]->extrlocy == NULL) { printf ("Not enough memory to allocate data arrays.\n"); return (OUT_OF_MEMORY); } } switch (rebinfactor) { case 1: /* Just copy. */ for (j = 0; j < iim->sci.data.ny; j++) { for (i = 0; i < iim->sci.data.nx; i++) { Pix (oim->sci.data, j, i) = Pix (iim->sci.data, j, i); Pix (oim->err.data, j, i) = Pix (iim->err.data, j, i); DQPix (oim->dq.data, j, i) = DQPix (iim->dq.data, j, i); } } for (j = 0; j < nrows; j++) { for (i = 0; i < iim->sci.data.nx; i++) { ox1d[j]->wave[i] = ix1d[j]->wave[i]; ox1d[j]->gross[i] = ix1d[j]->gross[i]; ox1d[j]->net[i] = ix1d[j]->net[i]; ox1d[j]->extrlocy[i] = ix1d[j]->extrlocy[i]; } } return (STIS_OK); case 2: /* Squeeze by a factor 2. Only the SCI data is processed since the algorithm doesn't propagate ERR and DQ info anyway. */ for (j = 0; j < oim->sci.data.ny-1; j++) { j2 = 2 * j; for (i = 0; i < oim->sci.data.nx-1; i++) { i2 = 2 * i; Pix (oim->sci.data, j, i) = (Pix (iim->sci.data, j2, i2) + Pix (iim->sci.data, j2, i2+1) + Pix (iim->sci.data, j2+1, i2) + Pix (iim->sci.data, j2+1, i2+1)) / 4.0; } } for (j = 0; j < nrows; j++) { for (i = 0; i < oim->sci.data.nx-1; i++) { i2 = 2 * i; ox1d[j]->wave[i] = (ix1d[j]->wave[i2] + ix1d[j]->wave[i2+1]) / 2.0 ; ox1d[j]->gross[i] = (ix1d[j]->gross[i2] + ix1d[j]->gross[i2+1]) / 2.0 ; ox1d[j]->net[i] = (ix1d[j]->net[i2] + ix1d[j]->net[i2+1]) / 2.0 ; ox1d[j]->extrlocy[i] = (ix1d[j]->extrlocy[i2] + ix1d[j]->extrlocy[i2+1]) / 2.0 ; ox1d[j]->extrlocy[i] /= (double)rebinfactor; } ox1d[j]->wave[oim->sci.data.nx-1] = ox1d[j]->wave[oim->sci.data.nx-2]; ox1d[j]->gross[oim->sci.data.nx-1] = ox1d[j]->gross[oim->sci.data.nx-2]; ox1d[j]->net[oim->sci.data.nx-1] = ox1d[j]->net[oim->sci.data.nx-2]; ox1d[j]->extrlocy[oim->sci.data.nx-1] = ox1d[j]->extrlocy[oim->sci.data.nx-2]; } return (STIS_OK); case -2: /* Expand by a factor 2. Only the SCI data is processed since the algorithm doesn't propagate ERR and DQ info anyway. It is assumed that the output image already stores this info. */ for (j = 0; j < iim->sci.data.ny; j++) { j2 = 2 * j; for (i = 0; i < iim->sci.data.nx; i++) { i2 = 2 * i; hold = Pix (iim->sci.data,j,i) / 2.0; Pix (oim->sci.data, j2,i2) = hold; Pix (oim->sci.data, j2+1,i2) = hold; Pix (oim->sci.data, j2,i2+1) = hold; Pix (oim->sci.data, j2+1,i2+1) = hold; } } /* No need to expand x1d array. */ return (STIS_OK); default: return (ERROR_RETURN); } }
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); }
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); }
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); }
int doStat (SingleGroup *out, short sdqflags) { /* arguments: SingleGroup *out io: image to be calibrated; the headers are modified short sdqflags i: "serious" data quality flags */ extern int status; double value; /* current data value */ double valsum, valmin, valmax; double stddev; /* current error estimate */ double errsum, errmin, errmax; double snr; /* current signal-to-noise ratio */ double snrsum, snrmin, snrmax; int numgood; /* number of good pixels */ int num_bad_stddev; /* number of pixels with err = 0 */ int area; /* total number of pixels */ int i, j; int dimx, dimy; short flagval; /* data quality flag value */ int PutKeyFlt (Hdr *, char *, float, char *); int PutKeyInt (Hdr *, char *, int, char *); /* Statistics for the science data. */ numgood = 0; valmin=0.0f; valmax=0.0f; errmin=0.0f; errmax=0.0f; snrmin=0.0f; snrmax=0.0f; num_bad_stddev = 0; valsum = 0.; errsum = 0.; snrsum = 0.; dimx = out->sci.data.nx; dimy = out->sci.data.ny; for (j = 0; j < dimy; j++) { for (i = 0; i < dimx; i++) { flagval = DQPix (out->dq.data, i, j); if (!(sdqflags & flagval)) { /* no serious flag bit set */ value = Pix (out->sci.data, i, j); stddev = Pix (out->err.data, i, j); if (stddev <= 0.) { num_bad_stddev++; continue; /* bad error value */ } else { snr = value / stddev; } if (numgood < 1) { valsum = value; valmin = value; valmax = value; errsum = stddev; errmin = stddev; errmax = stddev; snrsum = snr; snrmin = snr; snrmax = snr; numgood = 1; } else { valsum += value; errsum += stddev; snrsum += snr; if (value < valmin) valmin = value; if (value > valmax) valmax = value; if (stddev < errmin) errmin = stddev; if (stddev > errmax) errmax = stddev; if (snr < snrmin) snrmin = snr; if (snr > snrmax) snrmax = snr; numgood++; } } } } if (numgood > 0) { valsum /= (double) numgood; errsum /= (double) numgood; snrsum /= (double) numgood; } else { area = dimy * dimx; if (area == 0) { trlwarn ("Output image size is zero."); } else if (num_bad_stddev > 0) { if (num_bad_stddev == area) { trlwarn ("No ERR values > 0."); } else { trlwarn ("All output pixels either flagged as bad or ERR <= 0."); } } else { trlwarn ("All output pixels flagged as bad."); } PutKeyInt (&out->sci.hdr, "NGOODPIX", numgood, ""); PutKeyInt (&out->err.hdr, "NGOODPIX", numgood, ""); return (status); } /* Update header values for the science array. */ if (PutKeyInt (&out->sci.hdr, "NGOODPIX", numgood, "number of good pixels")) return (status); if (PutKeyFlt (&out->sci.hdr, "GOODMIN", (float) valmin, "minimum good data value")) return (status); if (PutKeyFlt (&out->sci.hdr, "GOODMAX", (float) valmax, "maximum good data value")) return (status); if (PutKeyFlt (&out->sci.hdr, "GOODMEAN", (float) valsum, "average of good data values")) return (status); if (PutKeyFlt (&out->sci.hdr, "SNRMIN", (float) snrmin, "minimum S/N of good data values")) return (status); if (PutKeyFlt (&out->sci.hdr, "SNRMAX", (float) snrmax, "maximum S/N of good data values")) return (status); if (PutKeyFlt (&out->sci.hdr, "SNRMEAN", (float) snrsum, "mean S/N of good data values")) return (status); /* Update header values for the error array. */ if (PutKeyInt (&out->err.hdr, "NGOODPIX", numgood, "number of good pixels")) return (status); if (PutKeyFlt (&out->err.hdr, "GOODMIN", (float) errmin, "minimum sigma for good data")) return (status); if (PutKeyFlt (&out->err.hdr, "GOODMAX", (float) errmax, "maximum sigma for good data")) return (status); if (PutKeyFlt (&out->err.hdr, "GOODMEAN", (float) errsum, "average of sigma for good data")) return (status); return (status); }
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); }