diff --git a/pkg/wfc3/Dates b/pkg/wfc3/Dates index de3acdf9e..460a8bceb 100644 --- a/pkg/wfc3/Dates +++ b/pkg/wfc3/Dates @@ -1,3 +1,6 @@ +07-Feb-2026 - PLL - Version 3.8.0 + - New crosstalk correction for WFC3/UVIS fullframe unbinned exposures. + 07-Jan-2026 - PLL - Version 3.7.3 - Bug fix to remove per-second in BUNIT for CRREJ output for IR data. diff --git a/pkg/wfc3/History b/pkg/wfc3/History index 751e0b30b..9c097a298 100644 --- a/pkg/wfc3/History +++ b/pkg/wfc3/History @@ -1,3 +1,6 @@ +### 07-Feb-2026 - PLL - Version 3.8.0 + - New crosstalk correction for WFC3/UVIS fullframe unbinned exposures. + ### 07-Jan-2026 - PLL - Version 3.7.3 - Bug fix to remove per-second in BUNIT for CRREJ output for IR data. diff --git a/pkg/wfc3/Updates b/pkg/wfc3/Updates index 2ef336487..e6475a71d 100644 --- a/pkg/wfc3/Updates +++ b/pkg/wfc3/Updates @@ -1,3 +1,6 @@ +Updates for Version 3.8.0 07-Feb-2026 - PLL + - New crosstalk correction for WFC3/UVIS fullframe unbinned exposures. + Updates for Version 3.7.3 07-Jan-2026 - PLL - Bug fix to remove per-second in BUNIT for CRREJ output for IR data. diff --git a/pkg/wfc3/include/doccd.h b/pkg/wfc3/include/doccd.h index 5b3c0dd3f..4e04a0d2d 100644 --- a/pkg/wfc3/include/doccd.h +++ b/pkg/wfc3/include/doccd.h @@ -23,6 +23,7 @@ int doFlash (WF3Info *, SingleGroup *, float *); int flashHistory (WF3Info *, Hdr *); int doBlev (WF3Info *, SingleGroup *, int, float *, int *, int *); int blevHistory (WF3Info *, Hdr *, int, int); +int cross_talk_corr(WF3Info *, SingleGroup *); int CCDHistory (WF3Info *, Hdr *); int doDQI (WF3Info *, SingleGroup *, int overscan); int dqiHistory (WF3Info *, Hdr *); diff --git a/pkg/wfc3/include/wf3version.h b/pkg/wfc3/include/wf3version.h index 3a7c5e050..e0248af95 100644 --- a/pkg/wfc3/include/wf3version.h +++ b/pkg/wfc3/include/wf3version.h @@ -4,7 +4,7 @@ /* This string is written to the output primary header as CAL_VER. */ -# define WF3_CAL_VER "3.7.3 (Jan-07-2026)" -# define WF3_CAL_VER_NUM "3.7.3" +# define WF3_CAL_VER "3.8.0 (Feb-07-2026)" +# define WF3_CAL_VER_NUM "3.8.0" #endif /* INCL_WF3VERSION_H */ diff --git a/pkg/wfc3/lib/CMakeLists.txt b/pkg/wfc3/lib/CMakeLists.txt index a59725724..c7c288190 100644 --- a/pkg/wfc3/lib/CMakeLists.txt +++ b/pkg/wfc3/lib/CMakeLists.txt @@ -85,6 +85,7 @@ add_library(${PROJECT_NAME} SHARED wf32d/wf32d.c wf3ccd/blevdrift.c wf3ccd/blevfit.c + wf3ccd/crosstalk.c wf3ccd/doatod.c wf3ccd/dobias.c wf3ccd/doblev.c diff --git a/pkg/wfc3/lib/wf3ccd/crosstalk.c b/pkg/wfc3/lib/wf3ccd/crosstalk.c new file mode 100644 index 000000000..099fd0d9c --- /dev/null +++ b/pkg/wfc3/lib/wf3ccd/crosstalk.c @@ -0,0 +1,58 @@ +# include /* for sqrt */ + +#include "hstio.h" +#include "wf3.h" +#include "wf3info.h" + + +/* remove amplifier cross-talk */ +int cross_talk_corr(WF3Info *wf3, SingleGroup *x) { + extern int status; + const int arr_rows = x->sci.data.ny; + const int arr_cols = x->sci.data.nx; + int i, j, cur_amp; /* iteration variables */ + float *y; + double corr_fac, cur_err; + + /* Correction coefficients (ABCD) from WFC3 ISR 2012-02 */ + const double intercept[NAMPS] = {0.0180206, 0.15501201,-0.038376406, 0.19124641}; + const double slope[NAMPS] = {-6.0494304e-5, -2.0746221e-4, -7.9701178e-5, -2.3177171e-4}; + + /* Crosstalk correction in electrons but then converted back to DN */ + for (i = 0; i < arr_rows; i++) { + /* Copy out original row for corr_fac calculation. */ + if ((y = calloc(arr_cols, sizeof(float))) == NULL) { + return (status = OUT_OF_MEMORY); + } + for (j = 0; j < arr_cols; j++) { + y[j] = Pix(x->sci.data, j, i); + } + + for (j = 0; j < arr_cols; j++) { + if (x->group_num == 1) { + if (j < wf3->ampx) { + cur_amp = AMP_C; + } else { + cur_amp = AMP_D; + } + } else { + if (j < wf3->ampx) { + cur_amp = AMP_A; + } else { + cur_amp = AMP_B; + } + } + corr_fac = intercept[cur_amp] + y[arr_cols - j - 1] * wf3->atodgain[cur_amp] * slope[cur_amp]; + /* Only fix when we can recover the signal, not removing more signal */ + if (corr_fac < 0) { + Pix(x->sci.data, j, i) = (y[j] * wf3->atodgain[cur_amp] - corr_fac) / wf3->atodgain[cur_amp]; + + /* Propagate error; assume ERR of correction is sqrt(corr_fac) */ + cur_err = Pix(x->err.data, j, i) * wf3->atodgain[cur_amp]; + Pix(x->err.data, j, i) = sqrt(cur_err * cur_err + fabs(corr_fac)) / wf3->atodgain[cur_amp]; + } + } + } + + return status; +} diff --git a/pkg/wfc3/lib/wf3ccd/doccd.c b/pkg/wfc3/lib/wf3ccd/doccd.c index de336435a..44eeade6e 100644 --- a/pkg/wfc3/lib/wf3ccd/doccd.c +++ b/pkg/wfc3/lib/wf3ccd/doccd.c @@ -101,6 +101,7 @@ int DoCCD (WF3Info *wf3, int extver) { int sizex, sizey; /* size of output image */ int i, j, x1, dx; /* loop index */ + int is_binned; int overscan; int blevcorr; char buff[SZ_FITS_REC+1]; @@ -319,6 +320,16 @@ int DoCCD (WF3Info *wf3, int extver) { if (biasHistory (wf3, x.globalhdr)) return (status); + is_binned = checkBinned(&x); + + /* Apply crosstalk correction after BIASCORR but before everything else. */ + if (wf3->biascorr == PERFORM && wf3->blevcorr == PERFORM && !is_binned & !wf3->subarray) { + trlmessage("\nCrosstalk correction is being performed."); + if (cross_talk_corr(wf3, &x)) { + return (status); + } + } + /* Apply the saturation image. Strictly speaking, the application of the full-well saturation image is not a calibration step (i.e., there is no SATCORR), but the application @@ -346,7 +357,7 @@ int DoCCD (WF3Info *wf3, int extver) { BINNED IMAGES ARE NOT SUPPORTED AT ALL */ if (wf3->dqicorr == PERFORM) { - if (checkBinned(&x)){ + if (is_binned){ trlmessage("Binned data not supported for Sink Pixel detection"); } else { if (wf3->subarray){