35 #include "muse_basicproc.h" 37 #include "muse_combine.h" 38 #include "muse_pfits.h" 39 #include "muse_quadrants.h" 40 #include "muse_quality.h" 41 #include "muse_utils.h" 42 #include "muse_data_format_z.h" 48 #define GENERATE_TEST_IMAGES 0 90 bpars->
overscan = cpl_strdup(cpl_parameter_get_string(param));
92 bpars->
rejection = cpl_strdup(cpl_parameter_get_string(param));
94 cpl_errorstate state = cpl_errorstate_get();
95 bpars->
ovscsigma = cpl_parameter_get_double(param);
96 if (!cpl_errorstate_is_equal(state)) {
97 cpl_errorstate_set(state);
98 bpars->
ovscsigma = cpl_parameter_get_int(param);
101 bpars->
ovscignore = cpl_parameter_get_int(param);
103 if (strstr(aPrefix,
"muse_scibasic")) {
105 bpars->
crmethod = cpl_strdup(cpl_parameter_get_string(param));
107 bpars->
dcrxbox = cpl_parameter_get_int(param);
109 bpars->
dcrybox = cpl_parameter_get_int(param);
111 bpars->
dcrpasses = cpl_parameter_get_int(param);
113 state = cpl_errorstate_get();
114 bpars->
dcrthres = cpl_parameter_get_double(param);
115 if (!cpl_errorstate_is_equal(state)) {
116 cpl_errorstate_set(state);
117 bpars->
dcrthres = cpl_parameter_get_int(param);
145 cpl_ensure(aHeader, CPL_ERROR_NULL_INPUT, NULL);
150 cpl_ensure(parlist, CPL_ERROR_ILLEGAL_INPUT, NULL);
151 const char *recipe = cpl_propertylist_get_string(aHeader,
"ESO PRO REC1 ID");
152 char *prefix = cpl_sprintf(
"muse.%s", recipe);
154 cpl_parameterlist_delete(parlist);
202 static cpl_error_code
205 cpl_ensure_code(aImage && aRef, CPL_ERROR_NULL_INPUT);
206 cpl_ensure_code(aImage->
header && aRef->
header, CPL_ERROR_NULL_INPUT);
208 cpl_propertylist *him = aImage->
header,
211 const char *fn1 = cpl_propertylist_get_string(him, MUSE_HDR_TMP_FN),
212 *fn2 = cpl_propertylist_get_string(href, MUSE_HDR_TMP_FN),
215 cpl_msg_error(__func__,
"\"%s\" does not contain a category (ESO.PRO.CATG)!",
217 return CPL_ERROR_ILLEGAL_INPUT;
224 *rawtag = cpl_propertylist_get_string(him, MUSE_HDR_TMP_INTAG);
237 cpl_boolean chipinfo = chipname1 && chipid1
238 && chipname2 && chipid2;
240 cpl_msg_warning(__func__,
"CHIP information is missing (ESO.DET.CHIP." 241 "{NAME,ID}) from \"%s\" (%s, %s) or \"%s\" (%s, %s)",
242 fn1, chipname1, chipid1, fn2, chipname2, chipid2);
245 if (binx1 != binx2 || biny1 != biny2) {
246 cpl_msg_error(__func__,
"Binning of \"%s\" (%dx%d) and \"%s\" (%dx%d) does " 247 "not match", fn1, binx1, biny1, fn2, binx2, biny2);
248 return CPL_ERROR_TYPE_MISMATCH;
254 if (!strncmp(catg,
"MASTER_BIAS", 12)) {
255 if (readid1 != readid2) {
256 cpl_msg_error(__func__,
"Read-out mode of \"%s\" (%d: %s) and \"%s\" (%d:" 257 " %s) does not match", fn1, readid1, readname1, fn2,
259 return CPL_ERROR_TYPE_MISMATCH;
261 if (chipinfo && (strcmp(chipname1, chipname2) || strcmp(chipid1, chipid2))) {
262 cpl_msg_error(__func__,
"CHIP information (ESO.DET.CHIP.{NAME,ID}) " 263 "does not match for \"%s\" (%s, %s) and \"%s\" (%s, %s)",
264 fn1, chipname1, chipid1, fn2, chipname2, chipid2);
265 return CPL_ERROR_TYPE_MISMATCH;
271 if (!strncmp(catg,
"MASTER_FLAT", 12)) {
272 if (mode1 != mode2) {
273 if (rawtag && !strncmp(rawtag, MUSE_TAG_ILLUM, strlen(MUSE_TAG_ILLUM) + 1)) {
275 cpl_msg_debug(__func__,
"Instrument modes for \"%s\" (%s, is %s) and \"%s\"" 276 " (%s) do not match", fn1, modestr1, rawtag, fn2, modestr2);
278 cpl_msg_error(__func__,
"Instrument modes for \"%s\" (%s) and \"%s\" (%s)" 279 " do not match", fn1, modestr1, fn2, modestr2);
280 return CPL_ERROR_TYPE_MISMATCH;
290 if (readid1 != readid2) {
291 cpl_msg_warning(__func__,
"Read-out mode of \"%s\" (%d: %s) and \"%s\" (%d:" 292 " %s) does not match", fn1, readid1, readname1, fn2,
295 if (chipinfo && (strcmp(chipname1, chipname2) || strcmp(chipid1, chipid2))) {
296 cpl_msg_warning(__func__,
"CHIP information (ESO.DET.CHIP.{NAME,ID,DATE}) " 297 "does not match for \"%s\" (%s, %s) and \"%s\" (%s, %s)",
298 fn1, chipname1, chipid1, fn2, chipname2, chipid2);
301 return CPL_ERROR_NONE;
320 static cpl_error_code
324 cpl_ensure_code(aList, CPL_ERROR_NULL_INPUT);
326 for (k = 0; k < aList->
size; k++) {
331 cpl_msg_warning(__func__,
"Could not compute overscan statistics in IFU " 333 k+1, cpl_error_get_message());
336 return CPL_ERROR_NONE;
353 static cpl_error_code
357 cpl_ensure_code(aList, CPL_ERROR_NULL_INPUT);
358 cpl_boolean ovscvpoly = aBPars && aBPars->
overscan 359 && !strncmp(aBPars->
overscan,
"vpoly", 5);
361 cpl_msg_debug(__func__,
"not vpoly: %s!", aBPars ? aBPars->
overscan :
"");
362 return CPL_ERROR_NONE;
365 unsigned char ovscvorder = 5;
368 char *rest = strchr(aBPars->
overscan,
':');
369 if (strlen(aBPars->
overscan) > 6 && rest++) {
370 ovscvorder = strtol(rest, &rest, 10);
371 if (strlen(rest++) > 0) {
372 frms = strtod(rest, &rest);
373 if (strlen(rest++) > 0) {
374 fchisq = strtod(rest, &rest);
378 cpl_msg_debug(__func__,
"vpoly: %s (vorder=%hhu, frms=%f, fchisq=%f, ignore=%u," 379 " sigma=%.3f)", aBPars->
overscan, ovscvorder, frms, fchisq,
382 cpl_error_code rc = CPL_ERROR_NONE;
384 for (k = 0; k < aList->
size; k++) {
389 if (rc != CPL_ERROR_NONE) {
391 cpl_msg_error(__func__,
"Could not correct quadrants levels using vertical" 392 " overscan fit in IFU %hhu: %s", ifu, cpl_error_get_message());
413 static cpl_error_code
416 cpl_ensure_code(aList, CPL_ERROR_NULL_INPUT);
419 for (k = 0; k < aList->
size; k++) {
422 cpl_ensure_code(trimmed, cpl_error_get_code());
428 : CPL_ERROR_ILLEGAL_OUTPUT;
450 static cpl_error_code
455 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
458 return CPL_ERROR_NONE;
460 cpl_boolean ovscoffset = aBPars && aBPars->
overscan 461 && !strncmp(aBPars->
overscan,
"offset", 7);
463 return CPL_ERROR_NONE;
466 cpl_msg_info(__func__,
"Running overscan correction using %u %s images in IFU" 467 " %hhu", aList->
size, MUSE_TAG_BIAS, ifu);
470 for (k = 1; k < aList->
size; k++) {
473 return CPL_ERROR_NONE;
502 static cpl_error_code
507 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
511 return CPL_ERROR_NONE;
513 if (aList->
size < 2) {
514 return CPL_ERROR_NONE;
516 cpl_boolean ovscnone = aBPars && aBPars->
overscan 517 && !strncmp(aBPars->
overscan,
"none", 5);
519 return CPL_ERROR_NONE;
521 double sigma = aBPars ? aBPars->
ovscsigma : 1.;
525 cpl_propertylist *refheader = refimage->
header;
526 cpl_error_code rc = CPL_ERROR_NONE;
528 for (n = 1; n <= 4; n++) {
530 char *keywordmean = cpl_sprintf(MUSE_HDR_OVSC_MEAN, n),
531 *keywordstdev = cpl_sprintf(MUSE_HDR_OVSC_STDEV, n);
534 const char *reffn = cpl_propertylist_get_string(refheader, MUSE_HDR_TMP_FN);
535 float refmean = cpl_propertylist_get_float(refheader, keywordmean),
536 refstdev = cpl_propertylist_get_float(refheader, keywordstdev),
537 hilimit = refmean + sigma * refstdev,
538 lolimit = refmean - sigma * refstdev;
540 double summean = refmean,
541 sumstdev = pow(refstdev, 2.);
545 for (k = 1; k < aList->
size; k++) {
547 float mean = cpl_propertylist_get_float(h, keywordmean),
548 stdev = cpl_propertylist_get_float(h, keywordstdev);
550 sumstdev += pow(stdev, 2.) + pow(mean - refmean, 2.);
551 const char *fn = cpl_propertylist_get_string(h, MUSE_HDR_TMP_FN);
552 if (mean > hilimit || mean < lolimit) {
553 cpl_msg_error(__func__,
"Overscan of IFU %hhu, quadrant %1hhu of image %u [%s] " 554 "(%.3f+/-%.3f) differs from first image [%s] (%.3f+/-%.3f)!",
555 ifu, n, k+1, fn, mean, stdev, reffn, refmean, refstdev);
556 rc = cpl_error_set(__func__, CPL_ERROR_INCOMPATIBLE_INPUT);
559 cpl_msg_debug(__func__,
"Overscan of IFU %hhu, quadrant %1hhu of image %u [%s] " 560 "%.3f+/-%.3f (first image [%s] %.3f+/-%.3f)",
561 ifu, n, k+1, fn, mean, stdev, reffn, refmean, refstdev);
566 summean /= aList->
size;
567 sumstdev = sqrt(sumstdev) / aList->
size;
568 cpl_msg_debug(__func__,
"Averaged overscan values in IFU %hhu, quadrant %1hhu: " 569 "%.3f +/- %.3f (%d images)", ifu, n, summean, sumstdev, aList->
size);
570 cpl_propertylist_update_float(refheader, keywordmean, summean);
571 cpl_propertylist_update_float(refheader, keywordstdev, sumstdev);
573 cpl_free(keywordmean);
574 cpl_free(keywordstdev);
600 static cpl_error_code
604 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
606 MUSE_TAG_BADPIX_TABLE, aIFU,
609 return CPL_ERROR_NONE;
613 cpl_errorstate prestate = cpl_errorstate_get();
614 cpl_size iframe, nframes = cpl_frameset_get_size(frames);
615 for (iframe = 0; iframe < nframes; iframe++) {
616 cpl_frame *frame = cpl_frameset_get_position(frames, iframe);
617 const char *fn = cpl_frame_get_filename(frame);
618 char *extname = cpl_sprintf(
"CHAN%02hhu", aIFU);
627 int nrow = cpl_table_get_nrow(table);
628 unsigned int k, nbadpix = 0,
630 for (k = 0; k < aList->
size; k++) {
634 for (i = 0; i < nrow; i++) {
635 int x = cpl_table_get(table, MUSE_BADPIX_X, i, NULL),
636 y = cpl_table_get(table, MUSE_BADPIX_Y, i, NULL);
640 uint32_t dq = cpl_table_get(table, MUSE_BADPIX_DQ, i, NULL);
641 cpl_errorstate state = cpl_errorstate_get();
643 uint32_t value = cpl_image_get(image->
dq, x, y, &err);
644 if (err != 0 || !cpl_errorstate_is_equal(state)) {
645 cpl_errorstate_set(state);
653 cpl_image_set(image->
dq, x, y, dq | value);
659 cpl_table_delete(table);
661 cpl_msg_debug(__func__,
"Applied %u bad pixels from %s \"%s\" in IFU %hhu.",
662 nbadpix, MUSE_TAG_BADPIX_TABLE, fn, aIFU);
665 cpl_msg_warning(__func__,
"\"%s\" contained %u entries outside the CCD in" 666 " IFU %hhu!", fn, nbadpos, aIFU);
669 cpl_frameset_delete(frames);
670 return cpl_errorstate_is_equal(prestate) ? CPL_ERROR_NONE
671 : cpl_error_get_code();
684 static cpl_error_code
687 cpl_ensure_code(aList, CPL_ERROR_NULL_INPUT);
689 for (k = 0; k < aList->
size; k++) {
694 int npix = cpl_image_get_size_x(image->
data)
695 * cpl_image_get_size_y(image->
data);
696 if (nsaturated > (0.01 * npix)) {
697 const char *fn = cpl_propertylist_get_string(image->
header,
699 cpl_msg_error(__func__,
"Raw exposure %u [%s] is strongly saturated in " 700 "IFU %hhu (%d of %d pixels)!", k+1, fn, ifu, nsaturated,
702 }
else if (nsaturated > (0.001 * npix)) {
703 const char *fn = cpl_propertylist_get_string(image->
header,
705 cpl_msg_warning(__func__,
"Raw exposure %u [%s] is probably saturated in " 706 "IFU %hhu (%d of %d pixels)!", k+1, fn, ifu, nsaturated,
709 cpl_msg_debug(__func__,
"Raw exposure %u in IFU %hhu (%d of %d pixels " 710 "saturated)!", k+1, ifu, nsaturated, npix);
712 cpl_propertylist_update_int(image->
header, MUSE_HDR_TMP_NSAT, nsaturated);
714 return CPL_ERROR_NONE;
731 static cpl_error_code
735 cpl_ensure_code(aList, CPL_ERROR_NULL_INPUT);
738 return CPL_ERROR_NONE;
741 cpl_msg_info(__func__,
"Computing per-quadrant medians for %u exposures in " 742 "IFU %hhu", aList->
size, ifu);
744 for (k = 0; k < aList->
size; k++) {
747 for (n = 1; n <= 4; n++) {
749 float median = cpl_image_get_median_window(image->
data, w[0], w[2],
752 char *kw = cpl_sprintf(MUSE_HDR_TMP_QUADnMED, n);
753 cpl_propertylist_append_float(image->
header, kw, median);
757 return CPL_ERROR_NONE;
783 static cpl_error_code
787 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
789 MUSE_TAG_MASTER_BIAS, aIFU);
790 cpl_errorstate prestate = cpl_errorstate_get();
791 if (!biasframe)
return CPL_ERROR_NONE;
792 cpl_errorstate_set(prestate);
793 const char *biasname = cpl_frame_get_filename(biasframe);
798 char *errmsg = cpl_strdup(cpl_error_get_message());
799 cpl_errorstate_set(prestate);
804 cpl_msg_error(__func__,
"%s", errmsg);
805 cpl_msg_error(__func__,
"%s", cpl_error_get_message());
807 cpl_frame_delete(biasframe);
808 return cpl_error_get_code();
811 cpl_msg_info(__func__,
"Bias correction in IFU %hhu using \"%s[CHAN%02hhu." 812 "DATA]\"", aIFU, biasname, aIFU);
814 cpl_msg_info(__func__,
"Bias correction in IFU %hhu using \"%s[DATA]\"",
818 cpl_propertylist_append_string(biasimage->
header, MUSE_HDR_TMP_FN, biasname);
823 cpl_boolean parmatch = mbpars && aBPars;
825 parmatch = parmatch && mbpars->
overscan && aBPars->overscan
826 && !strncmp(aBPars->overscan, mbpars->
overscan,
827 CPL_MIN(strlen(aBPars->overscan), strlen(mbpars->
overscan) + 1));
828 parmatch = parmatch && mbpars->
rejection && aBPars->rejection
829 && !strncmp(aBPars->rejection, mbpars->
rejection,
830 CPL_MIN(strlen(aBPars->rejection), strlen(mbpars->
rejection) + 1));
831 parmatch = parmatch && fabs(aBPars->ovscsigma - mbpars->
ovscsigma)
833 parmatch = parmatch && aBPars->ovscignore == mbpars->
ovscignore;
836 cpl_msg_warning(__func__,
"overscan parameters differ between %s and recipe" 837 " parameters!", MUSE_TAG_MASTER_BIAS);
839 cpl_msg_debug(__func__,
"overscan parameters between %s and given " 840 "parameters nicely match", MUSE_TAG_MASTER_BIAS);
844 cpl_boolean ovscoffset = aBPars && aBPars->overscan
845 && !strncmp(aBPars->overscan,
"offset", 7),
846 ovscvpoly = aBPars && aBPars->overscan
847 && !strncmp(aBPars->overscan,
"vpoly", 5);
849 cpl_error_code rc = CPL_ERROR_NONE;
851 for (k = 0; k < aList->
size && rc == CPL_ERROR_NONE; k++) {
853 rc = muse_basicproc_verify_setup(image, biasimage);
854 if (rc != CPL_ERROR_NONE) {
860 }
else if (ovscvpoly) {
866 cpl_msg_error(__func__,
"Very different overscan levels found between " 867 "%s and raw exposure %u in IFU %hhu: incompatible overscan" 868 " parameters?", MUSE_TAG_MASTER_BIAS, k + 1, aIFU);
869 rc = cpl_error_set(__func__, CPL_ERROR_INCOMPATIBLE_INPUT);
875 aBPars ? aBPars->ovscsigma : 1.);
878 #if GENERATE_TEST_IMAGES 910 static cpl_error_code
914 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
917 return CPL_ERROR_NONE;
920 CPL_ERROR_INCOMPATIBLE_INPUT);
923 MUSE_TAG_MASTER_BIAS, aIFU);
926 return CPL_ERROR_NONE;
928 const char *biasname = cpl_frame_get_filename(fbias);
929 cpl_propertylist *hbias = cpl_propertylist_load(biasname, 0);
930 if (!cpl_propertylist_has(hbias, QC_BIAS_MASTER_RON)) {
931 cpl_propertylist_delete(hbias);
933 char *extname = cpl_sprintf(
"CHAN%02hhu.%s", aIFU, EXTNAME_DATA);
934 int extension = cpl_fits_find_extension(biasname, extname);
935 hbias = cpl_propertylist_load(biasname, extension);
938 cpl_frame_delete(fbias);
942 cpl_image *diff = cpl_image_subtract_create(f1, f2);
945 for (n = 1; n <= 4; n++) {
947 double m1 = cpl_image_get_mean_window(f1, w[0], w[2], w[1], w[3]),
948 m2 = cpl_image_get_mean_window(f2, w[0], w[2], w[1], w[3]),
949 sf = cpl_image_get_stdev_window(diff, w[0], w[2], w[1], w[3]);
950 char *keyword = cpl_sprintf(QC_BIAS_MASTERn_PREFIX
" MEAN", n);
951 float mb = cpl_propertylist_get_float(hbias, keyword);
953 keyword = cpl_sprintf(QC_BIAS_MASTER_RON, n);
956 sb = cpl_propertylist_get_float(hbias, keyword) * sqrt(2.)
959 gain = (m1 + m2 - 2*mb) / (sf*sf - sb*sb),
960 dgain = 1. - gain / gainheader;
963 cpl_msg_warning(__func__,
"IFU %hhu, quadrant %1hhu: estimated gain %.3f " 964 "count/adu but header gives %.3f!", aIFU, n, gain,
967 cpl_msg_info(__func__,
"IFU %hhu, quadrant %1hhu: estimated gain %.3f " 968 "count/adu (header %.3f, delta %.3f)", aIFU, n, gain,
975 cpl_image_delete(diff);
976 cpl_propertylist_delete(hbias);
978 return CPL_ERROR_NONE;
1001 static cpl_error_code
1005 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
1010 return CPL_ERROR_NONE;
1014 MUSE_TAG_NONLINGAIN, aIFU);
1017 return CPL_ERROR_NONE;
1019 if (getenv(
"MUSE_BASICPROC_SKIP_GAIN_OVERRIDE") &&
1020 atoi(getenv(
"MUSE_BASICPROC_SKIP_GAIN_OVERRIDE")) > 0) {
1021 cpl_msg_info(__func__,
"Skipping gain override, although %s is given",
1022 MUSE_TAG_NONLINGAIN);
1023 return CPL_ERROR_NONE;
1025 cpl_errorstate state = cpl_errorstate_get();
1026 const char *fn = cpl_frame_get_filename(fnonlingain);
1028 char *extname = cpl_sprintf(
"CHAN%02hhu", aIFU);
1029 int extension = cpl_fits_find_extension(fn, extname);
1030 cpl_propertylist *header = cpl_propertylist_load(fn, extension);
1031 cpl_msg_info(__func__,
"Overriding gain in IFU %hhu using \"%s[%s]\"",
1037 for (k = 0; k < aList->
size; k++) {
1041 for (n = 1; n <= 4; n++) {
1044 char *kw = cpl_sprintf(
"ESO DET OUT%d GAIN", n);
1045 cpl_propertylist_update_double(image->
header, kw, gain);
1049 cpl_propertylist_delete(header);
1050 return cpl_errorstate_is_equal(state) ? CPL_ERROR_NONE : cpl_error_get_code();
1068 static cpl_error_code
1071 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
1077 return CPL_ERROR_NONE;
1081 cpl_msg_info(__func__,
"Converting %u exposures from adu to count (= electron)" 1082 " units in IFU %hhu", aList->
size, ifu);
1083 cpl_error_code rc = CPL_ERROR_NONE;
1085 for (k = 0; k < aList->
size; k++) {
1114 static cpl_error_code
1119 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
1126 return CPL_ERROR_NONE;
1130 MUSE_TAG_NONLINGAIN, aIFU);
1133 return CPL_ERROR_NONE;
1135 if (getenv(
"MUSE_BASICPROC_SKIP_NONLIN_CORR") &&
1136 atoi(getenv(
"MUSE_BASICPROC_SKIP_NONLIN_CORR")) > 0) {
1137 cpl_msg_debug(__func__,
"Skipping nonlinearity correction, although %s is " 1138 "given", MUSE_TAG_NONLINGAIN);
1139 return CPL_ERROR_NONE;
1141 const char *fn = cpl_frame_get_filename(fnonlingain);
1143 char *extname = cpl_sprintf(
"CHAN%02hhu", aIFU);
1144 int extension = cpl_fits_find_extension(fn, extname);
1145 cpl_propertylist *header = cpl_propertylist_load(fn, extension);
1146 cpl_msg_info(__func__,
"Correcting nonlinearity in IFU %hhu using \"%s[%s]\"",
1151 cpl_error_code rc = CPL_ERROR_NONE;
1153 for (k = 0; k < aList->
size; k++) {
1155 int nx = cpl_image_get_size_x(image->
data);
1156 float *data = cpl_image_get_data_float(image->
data),
1157 *stat = cpl_image_get_data_float(image->
stat);
1162 for (n = 1; n <= 4; n++) {
1165 cpl_polynomial *poly = cpl_polynomial_new(1);
1166 char *kw = cpl_sprintf(MUSE_HDR_NONLINn_ORDER, n);
1167 unsigned char o, order = cpl_propertylist_get_int(header, kw);
1169 for (o = 0; o <= order; o++) {
1170 kw = cpl_sprintf(MUSE_HDR_NONLINn_COEFFo, n, o);
1172 cpl_polynomial_set_coeff(poly, &pows,
1173 cpl_propertylist_get_double(header, kw));
1177 kw = cpl_sprintf(MUSE_HDR_NONLINn_LLO, n);
1178 double lolim = cpl_propertylist_get_double(header, kw);
1180 kw = cpl_sprintf(MUSE_HDR_NONLINn_LHI, n);
1181 double hilim = cpl_propertylist_get_double(header, kw);
1184 double p1lo, p0lo = cpl_polynomial_eval_1d(poly, lolim, &p1lo),
1185 p1hi, p0hi = cpl_polynomial_eval_1d(poly, hilim, &p1hi);
1187 lolim = pow(10, lolim);
1188 hilim = pow(10, hilim);
1190 double values[] = { 1., 20., 200., 2000., 20000., 65000.,
1191 lolim, hilim, -1. };
1193 while (values[idx] > 0) {
1194 double v = values[idx],
1196 cpl_msg_debug(__func__,
"%f adu -> %f log10(adu) ==> poly = %f ==> x %f",
1197 v, logv, cpl_polynomial_eval_1d(poly, logv, NULL),
1198 1. / (1. + cpl_polynomial_eval_1d(poly, logv, NULL)));
1201 cpl_polynomial_dump(poly, stdout);
1203 cpl_msg_debug(__func__,
"beyond low limit (%f adu): %f + (%f) * (log10(adu) - %f)",
1204 lolim, p0lo, p1lo, log10(lolim));
1205 cpl_msg_debug(__func__,
"beyond high limit (%f adu): %f + (%f) * (log10(adu) - %f)",
1206 hilim, p0hi, p1hi, log10(hilim));
1212 for (i = w[0] - 1; i < w[1]; i++) {
1214 for (j = w[2] - 1; j < w[3]; j++) {
1215 if (data[i + j*nx] <= 0) {
1220 if (data[i + j*nx] < lolim) {
1221 pcor = p0lo + p1lo * (log10(data[i + j*nx]) - log10(lolim));
1222 }
else if (data[i + j*nx] > hilim) {
1223 pcor = p0hi + p1hi * (log10(data[i + j*nx]) - log10(hilim));
1225 pcor = cpl_polynomial_eval_1d(poly, log10(data[i + j*nx]), NULL);
1228 double fcor = 1. / (1. + pcor);
1229 data[i + j*nx] *= fcor;
1230 stat[i + j*nx] *= fcor*fcor;
1234 cpl_polynomial_delete(poly);
1237 cpl_propertylist_delete(header);
1259 static cpl_error_code
1263 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
1266 MUSE_TAG_MASTER_DARK, aIFU);
1267 cpl_errorstate prestate = cpl_errorstate_get();
1268 if (!darkframe)
return CPL_ERROR_NONE;
1269 cpl_errorstate_set(prestate);
1270 const char *darkname = cpl_frame_get_filename(darkframe);
1273 char *errmsg = cpl_strdup(cpl_error_get_message());
1274 cpl_errorstate_set(prestate);
1277 cpl_msg_error(__func__,
"%s", errmsg);
1278 cpl_msg_error(__func__,
"%s", cpl_error_get_message());
1280 cpl_frame_delete(darkframe);
1281 return cpl_error_get_code();
1284 cpl_msg_info(__func__,
"Dark correction in IFU %hhu using \"%s[CHAN%02hhu." 1285 "DATA]\"", aIFU, darkname, aIFU);
1287 cpl_msg_info(__func__,
"Dark correction in IFU %hhu using \"%s[DATA]\"",
1290 cpl_propertylist_append_string(darkimage->
header, MUSE_HDR_TMP_FN, darkname);
1293 cpl_error_code rc = CPL_ERROR_NONE;
1295 for (k = 0; k < aList->
size; k++) {
1297 rc = muse_basicproc_verify_setup(image, darkimage);
1298 if (rc != CPL_ERROR_NONE) {
1336 static cpl_error_code
1340 cpl_ensure_code(aList, CPL_ERROR_NULL_INPUT);
1344 cpl_boolean isdcr = aBPars && aBPars->
crmethod 1345 && !strncmp(aBPars->
crmethod,
"dcr", 4);
1347 return CPL_ERROR_NONE;
1350 cpl_error_code rc = CPL_ERROR_NONE;
1352 for (k = 0; k < aList->
size; k++) {
1359 cpl_msg_error(__func__,
"Cosmic ray rejection using DCR in IFU %hhu failed" 1360 " for image %u (ncr = %d): %s", ifu, k+1, ncr,
1361 cpl_error_get_message());
1362 rc = cpl_error_get_code();
1364 cpl_msg_info(__func__,
"Cosmic ray rejection using DCR in IFU %hhu found " 1365 "%d affected pixels in image %u", ifu, ncr, k+1);
1388 static cpl_error_code
1392 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
1395 MUSE_TAG_MASTER_FLAT, aIFU);
1396 cpl_errorstate prestate = cpl_errorstate_get();
1397 if (!flatframe)
return CPL_ERROR_NONE;
1398 cpl_errorstate_set(prestate);
1399 const char *flatname = cpl_frame_get_filename(flatframe);
1400 prestate = cpl_errorstate_get();
1403 char *errmsg = cpl_strdup(cpl_error_get_message());
1404 cpl_errorstate_set(prestate);
1407 cpl_msg_error(__func__,
"%s", errmsg);
1408 cpl_msg_error(__func__,
"%s", cpl_error_get_message());
1410 cpl_frame_delete(flatframe);
1411 return cpl_error_get_code();
1414 cpl_msg_info(__func__,
"Flat-field correction in IFU %hhu using \"%s[CHAN%02hhu." 1415 "DATA]\"", aIFU, flatname, aIFU);
1417 cpl_msg_info(__func__,
"Flat-field correction in IFU %hhu using \"%s[DATA]\"",
1421 double fflux = cpl_propertylist_get_double(flatimage->
header,
1422 QC_FLAT_MASTER_INTFLUX);
1423 cpl_propertylist_append_string(flatimage->
header, MUSE_HDR_TMP_FN, flatname);
1426 cpl_error_code rc = CPL_ERROR_NONE;
1428 for (k = 0; k < aList->
size; k++) {
1429 cpl_msg_debug(__func__,
"Flat-field division in IFU %hhu of image %u of %u",
1430 aIFU, k+1, aList->
size);
1432 rc = muse_basicproc_verify_setup(image, flatimage);
1433 if (rc != CPL_ERROR_NONE) {
1437 cpl_propertylist_update_double(image->
header, MUSE_HDR_FLAT_FLUX_LAMP, fflux);
1471 muse_basicproc_load_raw(
muse_processing *aProcessing,
unsigned char aIFU)
1473 cpl_ensure(aProcessing, CPL_ERROR_NULL_INPUT, NULL);
1477 aProcessing->
intags, aIFU);
1478 cpl_ensure(rawframes, CPL_ERROR_NULL_INPUT, NULL);
1482 cpl_size iframe, nframes = cpl_frameset_get_size(rawframes);
1483 for (iframe = 0; iframe < nframes; iframe++) {
1484 cpl_frame *frame = cpl_frameset_get_position(rawframes, iframe);
1485 const char *fileName = cpl_frame_get_filename(frame);
1487 if (extension == -1) {
1488 cpl_msg_error(__func__,
"\"%s\" does not contain data from IFU %hhu",
1497 cpl_propertylist_append_string(raw->
header, MUSE_HDR_TMP_FN, fileName);
1499 cpl_propertylist_append_string(raw->
header, MUSE_HDR_TMP_INTAG,
1500 cpl_frame_get_tag(frame));
1506 cpl_frameset_delete(rawframes);
1509 if (!images->
size) {
1510 if ((
int)cpl_error_get_code() != MUSE_ERROR_CHIP_NOT_LIVE) {
1511 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_OUTPUT);
1512 cpl_msg_error(__func__,
"No raw images loaded for IFU %hhu", aIFU);
1518 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_OUTPUT);
1519 cpl_msg_error(__func__,
"Non-uniform imagelist for IFU %hhu", aIFU);
1578 muse_imagelist *images = muse_basicproc_load_raw(aProcessing, aIFU);
1582 cpl_errorstate prestate = cpl_errorstate_get();
1583 if (muse_basicproc_apply_badpix(images, aProcessing, aIFU) != CPL_ERROR_NONE) {
1584 cpl_msg_warning(__func__,
"Applying bad pixel table to IFU %hhu failed: %s",
1585 aIFU, cpl_error_get_message());
1586 cpl_errorstate_set(prestate);
1588 if (muse_basicproc_check_saturation(images) != CPL_ERROR_NONE) {
1592 muse_basicproc_quadrant_statistics(images, aProcessing);
1593 if (muse_basicproc_overscans_compute_stats(images, aBPars)
1594 != CPL_ERROR_NONE) {
1598 if (muse_basicproc_correct_overscans_vpoly(images, aBPars)
1599 != CPL_ERROR_NONE) {
1603 if (muse_basicproc_trim_images(images) != CPL_ERROR_NONE) {
1607 if (muse_basicproc_correct_overscans_offset(images, aProcessing, aBPars)
1608 != CPL_ERROR_NONE) {
1609 cpl_msg_warning(__func__,
"Bias-level correction using overscans failed in " 1610 "IFU %hhu: %s", aIFU, cpl_error_get_message());
1612 if (muse_basicproc_check_overscans(images, aProcessing, aBPars)
1613 != CPL_ERROR_NONE) {
1617 muse_basicproc_gain_override(images, aProcessing, aIFU);
1618 muse_basicproc_check_gain(images, aProcessing, aIFU);
1619 if (muse_basicproc_apply_bias(images, aProcessing, aIFU, aBPars)
1620 != CPL_ERROR_NONE) {
1624 if (muse_basicproc_corr_nonlinearity(images, aProcessing, aIFU) != CPL_ERROR_NONE) {
1628 if (muse_basicproc_adu_to_count(images, aProcessing) != CPL_ERROR_NONE) {
1632 if (muse_basicproc_apply_dark(images, aProcessing, aIFU) != CPL_ERROR_NONE) {
1636 if (muse_basicproc_apply_cr(images, aBPars) != CPL_ERROR_NONE) {
1640 if (muse_basicproc_apply_flat(images, aProcessing, aBPars, aIFU) != CPL_ERROR_NONE) {
1668 cpl_size iframe, nframes = cpl_frameset_get_size(redframes);
1669 for (iframe = 0; iframe < nframes; iframe++) {
1670 cpl_frame *frame = cpl_frameset_get_position(redframes, iframe);
1671 cpl_errorstate prestate = cpl_errorstate_get();
1672 const char *imagename = cpl_frame_get_filename(frame);
1675 cpl_errorstate_set(prestate);
1681 cpl_frameset_delete(redframes);
1705 CPL_ERROR_NULL_INPUT, NULL);
1714 cpl_msg_info(__func__,
"Preparing %s flat: %d slices in the data of IFU %hhu " 1715 "found.", MUSE_TAG_ILLUM, npt, ifu);
1716 cpl_table *tattached = cpl_table_new(npt);
1717 cpl_table_new_column(tattached,
"slice", CPL_TYPE_INT);
1718 cpl_table_new_column(tattached,
"fflat", CPL_TYPE_DOUBLE);
1719 for (ipt = 0; ipt < npt; ipt++) {
1722 double median = cpl_table_get_column_median(pts[ipt]->table,
1724 cpl_msg_debug(__func__,
"Found median of %f in slice %d of IFU %hhu " 1725 "of illum flat.", median, slice, ifu);
1726 cpl_table_set_int(tattached,
"slice", ipt, slice);
1727 cpl_table_set_double(tattached,
"fflat", ipt, 1. / median);
1731 double mean = cpl_table_get_column_mean(tattached,
"fflat");
1732 cpl_msg_debug(__func__,
"Normalizing whole illum-flat table if IFU %hhu to " 1734 cpl_table_multiply_scalar(tattached,
"fflat", 1. / mean);
1735 cpl_table_set_column_format(tattached,
"fflat",
"%.6f");
1760 cpl_table *aWave, cpl_table *aGeo)
1762 cpl_ensure(aImages && aTrace && aWave && aGeo, CPL_ERROR_NULL_INPUT, NULL);
1764 cpl_table *tattached = NULL;
1767 cpl_boolean *isillum = cpl_calloc(nimages,
sizeof(cpl_boolean));
1768 for (k = 0; k < nimages; k++) {
1769 isillum[k] = CPL_FALSE;
1771 const char *tag = cpl_propertylist_get_string(image->
header,
1772 MUSE_HDR_TMP_INTAG);
1773 if (tag && !strncmp(tag, MUSE_TAG_ILLUM, strlen(MUSE_TAG_ILLUM) + 1)) {
1774 isillum[k] = CPL_TRUE;
1776 if (cpl_propertylist_has(image->
header,
"ESO TPL ID")) {
1777 const char *tplid = cpl_propertylist_get_string(image->
header,
1779 *fn = cpl_propertylist_get_string(image->
header,
1781 *tplatt =
"MUSE_wfm_cal_specflatatt",
1782 *tplill =
"MUSE_wfm_cal_illum";
1783 if (strncmp(tplid, tplatt, strlen(tplatt) + 1) &&
1784 strncmp(tplid, tplill, strlen(tplill) + 1)) {
1785 cpl_msg_warning(__func__,
"%s input (\"%s\") was taken with neither" 1786 " %s nor %s template, but %s!", MUSE_TAG_ILLUM, fn,
1787 tplatt, tplill, tplid);
1789 cpl_msg_debug(__func__,
"%s input (\"%s\") was taken with template " 1790 "%s", MUSE_TAG_ILLUM, fn, tplid);
1797 cpl_msg_warning(__func__,
"Image %u of %u of IFU %hhu is illum flat, " 1798 "but not the first; not using it!", k + 1, nimages, ifu);
1801 cpl_msg_debug(__func__,
"Image %u of %u of IFU %hhu is illum flat.",
1802 k + 1, nimages, ifu);
1804 tattached = muse_basicproc_prepare_illum(pt);
1807 cpl_msg_debug(__func__,
"Image %u of %u of IFU %hhu is not an illum flat.",
1808 k + 1, nimages, ifu);
1814 for (k = 0, k2 = 0; k < nimages; k++) {
1844 cpl_ensure_code(aPT && aPT->
header && aPT->
table && aAttached,
1845 CPL_ERROR_NULL_INPUT);
1851 cpl_msg_info(__func__,
"Applying %s flat-field in IFU %hhu (%d slices)",
1852 MUSE_TAG_ILLUM, ifu, npt);
1853 cpl_array *afactors = cpl_array_new(npt, CPL_TYPE_DOUBLE);
1854 for (ipt = 0; ipt < npt; ipt++) {
1857 fslice = cpl_table_get_int(aAttached,
"slice", ipt, NULL);
1859 double fflat = cpl_table_get_double(aAttached,
"fflat", ipt, &err);
1860 if (!err && slice == fslice) {
1863 cpl_array_set_double(afactors, ipt, fflat);
1865 cpl_propertylist_update_double(aPT->
header, kw, fflat);
1868 cpl_msg_warning(__func__,
"some error (%d) occurred when applying illum-" 1869 "flat correction to slice %hu/%hu of IFU %hhu: %s", err,
1870 slice, fslice, ifu, cpl_error_get_message());
1875 cpl_array_get_mean(afactors));
1877 cpl_array_get_stdev(afactors));
1878 cpl_array_delete(afactors);
1879 return CPL_ERROR_NONE;
1903 cpl_ensure_code(aPT && aPT->
header && aPT->
table && aTwilight,
1904 CPL_ERROR_NULL_INPUT);
1911 char *kw = cpl_sprintf(MUSE_HDR_FLAT_FLUX_SKY
"%hhu", ifu);
1912 double flux = cpl_propertylist_get_double(aTwilight->
header, kw);
1914 cpl_propertylist_update_double(aPT->
header, MUSE_HDR_FLAT_FLUX_SKY, flux);
1917 int nx = cpl_image_get_size_x(cpl_imagelist_get(aTwilight->
data, 0)),
1918 ny = cpl_image_get_size_y(cpl_imagelist_get(aTwilight->
data, 0)),
1919 nz = cpl_imagelist_get_size(aTwilight->
data);
1920 cpl_msg_debug(__func__,
"Working with %d planes in twilight cube", nz);
1923 if (cd12 > DBL_EPSILON || cd21 > DBL_EPSILON) {
1924 cpl_msg_warning(__func__,
"Twilight cube contains WCS cross-terms (CD1_2" 1925 "=%e, CD2_1=%e), results will be inaccurate!", cd12, cd21);
1946 for (irow = 0; irow < nrow; irow++) {
1949 int x = lround((xpos[irow] - crval1) / cd11 + crpix1),
1950 y = lround((ypos[irow] - crval2) / cd22 + crpix2);
1964 double z = (lbda[irow] - crval3) / cd33 + crpix3;
1966 cpl_msg_debug(__func__,
"%"CPL_SIZE_FORMAT
": %.3f %.3f %.3f => %d %d %.3f",
1967 irow, xpos[irow], ypos[irow], lbda[irow], x, y, z);
1970 int zp1 = floor(z) - 1,
1986 double v1 = cpl_image_get(cpl_imagelist_get(aTwilight->
data, zp1),
1988 v2 = cpl_image_get(cpl_imagelist_get(aTwilight->
data, zp2),
2004 f = fabs(z - 1 - zp1);
2005 villum = v1 * (1. - f) + v2 * f;
2007 double fillum = 1. / villum;
2009 cpl_msg_debug(__func__,
"%d/%d, %f/%f -> %f -> %f => %f", zp1, zp2, v1, v2,
2014 data[irow] *= fillum;
2016 stat[irow] *= fillum*fillum;
2019 cpl_msg_warning(__func__,
"Failed to correct twilight in %"CPL_SIZE_FORMAT
2020 " of %"CPL_SIZE_FORMAT
", pixels in IFU %hhu!", nfailed,
2023 cpl_msg_debug(__func__,
"No failures during twilight correction of %" 2024 CPL_SIZE_FORMAT
" pixels in IFU %hhu", nrow, ifu);
2027 return CPL_ERROR_NONE;
2052 cpl_ensure_code(aPT && aPT->
header && aPT->
table, CPL_ERROR_NULL_INPUT);
2055 float lmin = kMuseNa2LambdaMin,
2056 lmax = kMuseNa2LambdaMax;
2059 if ((insmode == MUSE_MODE_WFM_AO_N) || (insmode == MUSE_MODE_NFM_AO_N)) {
2061 }
else if (insmode == MUSE_MODE_WFM_AO_E) {
2062 lmin = kMuseNaLambdaMin;
2063 lmax = kMuseNaLambdaMax;
2065 cpl_msg_warning(__func__,
"No notch filter for mode %s!", mode);
2066 return CPL_ERROR_ILLEGAL_INPUT;
2068 cpl_msg_info(__func__,
"%s mode: marking NaD region (%.1f..%.1f Angstrom) of " 2069 "IFU %d as 0x%08lx", mode, lmin, lmax, aIFU, EURO3D_NOTCH_NAD);
2070 cpl_table_unselect_all(aPT->
table);
2072 CPL_GREATER_THAN, lmin);
2074 CPL_LESS_THAN, lmax);
2075 cpl_array *asel = cpl_table_where_selected(aPT->
table);
2076 cpl_size isel, nsel = cpl_array_get_size(asel);
2077 const cpl_size *sel = cpl_array_get_data_cplsize_const(asel);
2079 for (isel = 0; isel < nsel; isel++) {
2080 dq[sel[isel]] = EURO3D_NOTCH_NAD;
2082 cpl_array_delete(asel);
2084 return CPL_ERROR_NONE;
2115 muse_basicproc_combine_compare_lamp(
const cpl_frame *aFrame1,
const cpl_frame *aFrame2)
2117 cpl_ensure(aFrame1 && aFrame2, CPL_ERROR_NULL_INPUT, -1);
2118 const char *fn1 = cpl_frame_get_filename(aFrame1),
2119 *fn2 = cpl_frame_get_filename(aFrame2);
2120 cpl_propertylist *head1 = cpl_propertylist_load(fn1, 0),
2121 *head2 = cpl_propertylist_load(fn2, 0);
2122 if (!head1 || !head2) {
2123 cpl_propertylist_delete(head1);
2124 cpl_propertylist_delete(head2);
2131 int nlamp = 1, status1, status2;
2132 cpl_errorstate prestate = cpl_errorstate_get();
2137 cpl_errorstate_set(prestate);
2138 if (name1 && name2 && strncmp(name1, name2, strlen(name1) + 1)) {
2139 cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
2140 "Files \"%s\" and \"%s\" have incompatible lamp " 2141 "setups", fn1, fn2);
2142 cpl_propertylist_delete(head1);
2143 cpl_propertylist_delete(head2);
2148 if (name1 && name2 && strncmp(name1, name2, strlen(name1) + 1)) {
2149 cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
2150 "Files \"%s\" and \"%s\" have incompatible shutter " 2151 "setups", fn1, fn2);
2152 cpl_propertylist_delete(head1);
2153 cpl_propertylist_delete(head2);
2159 cpl_errorstate_set(prestate);
2160 if (status1 != status2) {
2165 if (status1 != status2) {
2169 }
while (cpl_errorstate_is_equal(prestate));
2170 cpl_errorstate_set(prestate);
2172 cpl_propertylist_delete(head1);
2173 cpl_propertylist_delete(head2);
2174 return status1 == status2;
2208 cpl_frameset ***aLabeledFrames)
2210 if (aLabeledFrames) {
2211 *aLabeledFrames = NULL;
2213 cpl_ensure(aProcessing, CPL_ERROR_NULL_INPUT, NULL);
2217 aProcessing->
intags, aIFU,
2219 char *prefix = cpl_sprintf(
"muse.%s", aProcessing->
name);
2224 printf(
"rawframes\n");
2225 cpl_frameset_dump(rawframes, stdout);
2229 *labels = cpl_frameset_labelise(rawframes,
2230 muse_basicproc_combine_compare_lamp,
2232 if (!labels || nlabels <= 1) {
2235 cpl_frameset_delete(rawframes);
2242 if (aLabeledFrames) {
2243 *aLabeledFrames = cpl_calloc(1,
sizeof(cpl_frameset *));
2244 (*aLabeledFrames)[0] = cpl_frameset_duplicate(aProcessing->
usedframes);
2253 cpl_array *alabels = cpl_array_wrap_int(labels, cpl_frameset_get_size(rawframes));
2254 cpl_array_dump(alabels, 0, 1000, stdout);
2256 cpl_array_unwrap(alabels);
2260 if (aLabeledFrames) {
2261 *aLabeledFrames = cpl_calloc(nlabels,
sizeof(cpl_frameset *));
2268 cpl_frameset *inframes = proc->
inframes;
2273 int ilabel, ipos = 0;
2274 for (ilabel = 0; ilabel < nlabels; ilabel++) {
2276 cpl_frameset *frames = cpl_frameset_extract(rawframes, labels, ilabel);
2278 cpl_frameset_join(frames, auxframes);
2287 cpl_frameset_delete(frames);
2292 if (aLabeledFrames) {
2293 cpl_free(*aLabeledFrames);
2294 *aLabeledFrames = NULL;
2301 cpl_msg_error(__func__,
"Image combination failed for IFU %hhu for lamp " 2302 "with label %d of %"CPL_SIZE_FORMAT, aIFU, ilabel + 1, nlabels);
2304 cpl_frameset_delete(frames);
2308 if (aLabeledFrames) {
2310 cpl_size iframe, nframes = cpl_frameset_get_size(frames);
2311 for (iframe = 0; iframe < nframes; iframe++) {
2312 cpl_frame *frame = cpl_frameset_get_position(frames, iframe);
2313 const char *fn = cpl_frame_get_filename(frame),
2314 *tag = cpl_frame_get_tag(frame);
2315 cpl_size iuframe, nuframes = cpl_frameset_get_size(aProcessing->
usedframes);
2317 (iuframe < nuframes) && fn && tag;
2319 cpl_frame *uframe = cpl_frameset_get_position(aProcessing->
usedframes,
2321 const char *fnu = cpl_frame_get_filename(uframe),
2322 *tagu = cpl_frame_get_tag(uframe);
2323 if (fnu && !strncmp(fn, fnu, strlen(fn) + 1) &&
2324 tagu && !strncmp(tag, tagu, strlen(tag) + 1)) {
2325 cpl_frame_set_group(frame, cpl_frame_get_group(uframe));
2330 (*aLabeledFrames)[ipos] = frames;
2332 cpl_frameset_delete(frames);
2338 char *keyword = cpl_sprintf(QC_WAVECAL_PREFIXi
" "QC_BASIC_NSATURATED, k+1);
2341 cpl_propertylist_update_int(lampimage->
header, keyword, nsaturated);
2351 cpl_frameset_delete(rawframes);
2352 cpl_frameset_delete(auxframes);
2357 if (aLabeledFrames) {
2358 cpl_free(*aLabeledFrames);
2359 *aLabeledFrames = NULL;
2391 double aHalfWidth,
double aBinWidth,
2392 float aLo,
float aHi,
unsigned char aIter)
2394 cpl_ensure_code(aPt && aLines, CPL_ERROR_NULL_INPUT);
2395 cpl_ensure_code(cpl_array_get_type(aLines) == CPL_TYPE_DOUBLE ||
2396 cpl_array_get_type(aLines) == CPL_TYPE_FLOAT,
2397 CPL_ERROR_ILLEGAL_INPUT);
2401 double shift = 0., wshift = 0.;
2402 cpl_array *errors = cpl_array_new(4, CPL_TYPE_DOUBLE);
2403 int i, n = cpl_array_get_size(aLines), nvalid = 0;
2404 for (i = 0; i < n; i++) {
2406 double lambdasign = cpl_array_get(aLines, i, &err),
2407 lambda = fabs(lambdasign);
2408 if (err || lambda >= lmax || lambda <= lmin) {
2409 cpl_msg_debug(__func__,
"Invalid wavelength at position %d of %d in " 2410 "skylines", i + 1, n);
2415 aBinWidth, aLo, aHi, aIter,
2417 cerr = cpl_array_get_double(errors, 0, NULL);
2418 shift += (lambda - center) / cerr;
2419 wshift += 1. / cerr;
2420 cpl_msg_debug(__func__,
"dlambda = %.4f +/- %.4f (for skyline at %.4f " 2421 "Angstrom)", lambda - center, cerr, lambda);
2423 cpl_array_delete(errors);
2425 if (nvalid > 0 && isfinite(shift)) {
2426 cpl_msg_info(__func__,
"Skyline correction (%d lines): shifting data of IFU " 2430 cpl_propertylist_update_float(aPt->
header, QC_SCIBASIC_SHIFT, shift);
2432 cpl_propertylist_update_float(aPt->
header, QC_SCIBASIC_SHIFT, 0.);
2434 return CPL_ERROR_NONE;
2452 const char *aPrefix,
unsigned aStats)
2454 cpl_ensure_code(aImage, CPL_ERROR_NULL_INPUT);
2456 int nx = cpl_image_get_size_x(aImage),
2457 ny = cpl_image_get_size_y(aImage);
2459 aStats, 1, 1, nx, ny);
2482 cpl_propertylist *aHeader,
2483 const char *aPrefix,
unsigned aStats,
2484 int aX1,
int aY1,
int aX2,
int aY2)
2486 cpl_ensure_code(aImage && aHeader, CPL_ERROR_NULL_INPUT);
2487 cpl_ensure_code(aPrefix, CPL_ERROR_ILLEGAL_INPUT);
2488 cpl_ensure_code(aPrefix, CPL_ERROR_ILLEGAL_INPUT);
2490 cpl_stats *stats = cpl_stats_new_from_image_window(aImage, aStats,
2491 aX1, aY1, aX2, aY2);
2493 return cpl_error_get_code();
2496 char keyword[KEYWORD_LENGTH];
2497 if (aStats & CPL_STATS_MEDIAN) {
2498 snprintf(keyword, KEYWORD_LENGTH,
"%s MEDIAN", aPrefix);
2499 cpl_propertylist_append_float(aHeader, keyword,
2500 cpl_stats_get_median(stats));
2502 if (aStats & CPL_STATS_MEAN) {
2503 snprintf(keyword, KEYWORD_LENGTH,
"%s MEAN", aPrefix);
2504 cpl_propertylist_append_float(aHeader, keyword, cpl_stats_get_mean(stats));
2506 if (aStats & CPL_STATS_STDEV) {
2507 snprintf(keyword, KEYWORD_LENGTH,
"%s STDEV", aPrefix);
2508 cpl_propertylist_append_float(aHeader, keyword, cpl_stats_get_stdev(stats));
2510 if (aStats & CPL_STATS_MIN) {
2511 snprintf(keyword, KEYWORD_LENGTH,
"%s MIN", aPrefix);
2512 cpl_propertylist_append_float(aHeader, keyword, cpl_stats_get_min(stats));
2514 if (aStats & CPL_STATS_MAX) {
2515 snprintf(keyword, KEYWORD_LENGTH,
"%s MAX", aPrefix);
2516 cpl_propertylist_append_float(aHeader, keyword, cpl_stats_get_max(stats));
2518 if (aStats & CPL_STATS_FLUX) {
2519 snprintf(keyword, KEYWORD_LENGTH,
"%s INTFLUX", aPrefix);
2520 cpl_propertylist_append_float(aHeader, keyword, cpl_stats_get_flux(stats));
2523 cpl_stats_delete(stats);
2525 return CPL_ERROR_NONE;
2547 cpl_ensure_code(aImage && aImage->
dq && aImage->
header && aPrefix,
2548 CPL_ERROR_NULL_INPUT);
2550 cpl_mask *mask = cpl_mask_threshold_image_create(aImage->
dq,
2551 EURO3D_SATURATED - 0.1,
2552 EURO3D_SATURATED + 0.1);
2553 int nsaturated = cpl_mask_count(mask);
2554 cpl_mask_delete(mask);
2556 char *keyword = NULL;
2557 if (aPrefix[strlen(aPrefix)-1] ==
' ') {
2558 keyword = cpl_sprintf(
"%s%s", aPrefix, QC_BASIC_NSATURATED);
2560 keyword = cpl_sprintf(
"%s %s", aPrefix, QC_BASIC_NSATURATED);
2562 cpl_error_code rc = cpl_propertylist_update_int(aImage->
header, keyword,
cpl_error_code muse_quadrants_overscan_correct(muse_image *aImage, muse_image *aRefImage)
Adapt bias level to reference image using overscan statistics.
muse_imagelist * muse_basicproc_load(muse_processing *aProcessing, unsigned char aIFU, muse_basicproc_params *aBPars)
Load the raw input files from disk and do basic processing.
#define MUSE_PIXTABLE_XPOS
Structure definition of a MUSE datacube.
Structure definition for a collection of muse_images.
void muse_image_delete(muse_image *aImage)
Deallocate memory associated to a muse_image object.
void muse_pixtable_extracted_delete(muse_pixtable **aPixtables)
Delete a pixel table array.
double muse_pfits_get_cd(const cpl_propertylist *aHeaders, unsigned int aAxisI, unsigned int aAxisJ)
find out the WCS coordinate at the reference point
int muse_image_divide(muse_image *aImage, muse_image *aDivisor)
Divide a muse_image by another with correct treatment of bad pixels and variance. ...
const char * muse_pfits_get_insmode(const cpl_propertylist *aHeaders)
find out the observation mode
double muse_utils_pixtable_fit_line_gaussian(muse_pixtable *aPixtable, double aLambda, double aHalfWidth, double aBinSize, float aLo, float aHi, unsigned char aIter, cpl_array *aResults, cpl_array *aErrors)
Fit a 1D Gaussian to a given wavelength range in a pixel table.
unsigned short muse_pixtable_origin_get_slice(uint32_t aOrigin)
Get the slice number from the encoded 32bit origin number.
cpl_size * muse_quadrants_get_window(const muse_image *aImage, unsigned char aQuadrant)
Determine the data window of a given quadrant on the CCD.
int muse_image_scale(muse_image *aImage, double aScale)
Scale a muse_image with correct treatment of variance.
int muse_pfits_get_read_id(const cpl_propertylist *aHeaders)
find out the readout mode id
int muse_utils_get_extension_for_ifu(const char *aFilename, unsigned char aIFU)
Return extension number that corresponds to this IFU/channel number.
cpl_size muse_pixtable_extracted_get_size(muse_pixtable **aPixtables)
Get the size of an array of extracted pixel tables.
double muse_pfits_get_crval(const cpl_propertylist *aHeaders, unsigned int aAxis)
find out the WCS coordinate at the reference point
unsigned char muse_utils_get_ifu(const cpl_propertylist *aHeaders)
Find out the IFU/channel from which this header originated.
muse_imagelist * muse_basicproc_combine_images_lampwise(muse_processing *aProcessing, unsigned char aIFU, muse_basicproc_params *aBPars, cpl_frameset ***aLabeledFrames)
Combine several images into a lampwise image list.
muse_pixtable ** muse_pixtable_extracted_get_slices(muse_pixtable *aPixtable)
Extract one pixel table per IFU and slice.
double muse_pfits_get_gain(const cpl_propertylist *aHeaders, unsigned char aQuadrant)
find the detector gain (in units of count/adu)
cpl_image * data
the data extension
muse_image * muse_image_load_from_raw(const char *aFilename, int aExtension)
Load raw image into the data extension of a MUSE image.
cpl_size muse_pixtable_get_nrow(const muse_pixtable *aPixtable)
get the number of rows within the pixel table
int muse_pfits_get_shut_status(const cpl_propertylist *aHeaders, int aShutter)
query the status of one shutter
#define MUSE_HDR_PT_LHI
FITS header keyword contains the upper limit of the data in spectral direction.
int muse_cosmics_dcr(muse_image *aImage, unsigned int aXBox, unsigned int aYBox, unsigned int aPasses, float aThres)
Quickly mark cosmic rays in an image using the DCR algorithm.
muse_image * muse_image_duplicate(const muse_image *aImage)
Duplicate the three image extensions and the FITS headers of a MUSE image.
#define MUSE_HDR_PT_ILLUMi
cpl_image * stat
the statistics extension
int muse_image_subtract(muse_image *aImage, muse_image *aSubtract)
Subtract a muse_image from another with correct treatment of bad pixels and variance.
void muse_imagelist_delete(muse_imagelist *aList)
Free the memory of the MUSE image list.
#define MUSE_HDR_PT_ILLUM_MEAN
muse_imagelist * muse_basicproc_load_reduced(muse_processing *aProcessing, unsigned char aIFU)
Load reduced input files from disk.
muse_basicproc_params * muse_basicproc_params_new(cpl_parameterlist *aParameters, const char *aPrefix)
Create a new structure of basic processing parameters.
muse_image * muse_combine_images(muse_combinepar *aCPars, muse_imagelist *aImages)
Combine several images into one.
Structure definition of MUSE three extension FITS file.
cpl_error_code muse_quadrants_overscan_polyfit_vertical(muse_image *aImage, unsigned aIgnore, unsigned char aOrder, double aSigma, const double aFRMS, double aFChiSq)
Correct quadrants by polynomial representation of vertical overscan.
const char * muse_pfits_get_shut_name(const cpl_propertylist *aHeaders, int aShutter)
query the name of one shutter
cpl_table * table
The pixel table.
void muse_basicproc_params_delete(muse_basicproc_params *aBPars)
Free a structure of basic processing parameters.
cpl_propertylist * header
the FITS header
cpl_boolean muse_processing_check_intags(muse_processing *aProcessing, const char *aTag, int aNChars)
Check that a tag is part of the input tags of a processing structure.
int muse_image_variance_create(muse_image *aImage, muse_image *aBias)
Create the photon noise-based variance in the stat extension.
cpl_table * muse_cpltable_load(const char *aFile, const char *aExtension, const muse_cpltable_def aDefinition[])
Load a table from disk (and check against definition).
#define MUSE_PIXTABLE_DATA
unsigned int muse_imagelist_get_size(muse_imagelist *aList)
Return the number of stored images.
cpl_frameset * usedframes
void muse_combinepar_delete(muse_combinepar *aCPars)
Clear the combination parameters.
cpl_image * dq
the data quality extension
cpl_error_code muse_pixtable_restrict_wavelength(muse_pixtable *aPixtable, double aLow, double aHigh)
Restrict a pixel table to a certain wavelength range.
double muse_pfits_get_crpix(const cpl_propertylist *aHeaders, unsigned int aAxis)
find out the WCS reference point
int muse_pfits_get_biny(const cpl_propertylist *aHeaders)
find out the binning factor in y direction
Structure definition of MUSE pixel table.
cpl_boolean muse_quadrants_overscan_check(muse_image *aImage, muse_image *aRefImage, double aSigma)
Compare overscan statistics of all quadrants to those of reference image.
cpl_error_code muse_basicproc_shift_pixtable(muse_pixtable *aPt, cpl_array *aLines, double aHalfWidth, double aBinWidth, float aLo, float aHi, unsigned char aIter)
Compute wavelength corrections for science data based on reference sky lines.
const char * muse_pfits_get_lamp_name(const cpl_propertylist *aHeaders, int aLamp)
query the name of one lamp
muse_image * muse_imagelist_get(muse_imagelist *aList, unsigned int aIdx)
Get the muse_image of given list index.
cpl_error_code muse_basicproc_apply_twilight(muse_pixtable *aPT, muse_datacube *aTwilight)
Apply an attached flat-field to a pixel table.
cpl_error_code muse_basicproc_stats_append_header_window(cpl_image *aImage, cpl_propertylist *aHeader, const char *aPrefix, unsigned aStats, int aX1, int aY1, int aX2, int aY2)
Compute image statistics of an image window and add them to a header.
int muse_quality_set_saturated(muse_image *aImage)
Set all pixels above the saturation limit in the bad pixel image.
const char * muse_pfits_get_read_name(const cpl_propertylist *aHeaders)
find out the readout mode name
int muse_imagelist_is_uniform(muse_imagelist *aList)
Check that all images in the muse_imagelist have the same size.
muse_combinepar * muse_combinepar_new(cpl_parameterlist *aParameters, const char *aPrefix)
Create a new set of combination parameters.
cpl_imagelist * data
the cube containing the actual data values
void muse_processing_append_used(muse_processing *aProcessing, cpl_frame *aFrame, cpl_frame_group aGroup, int aDuplicate)
Add a frame to the set of used frames.
muse_pixtable * muse_pixtable_create(muse_image *aImage, cpl_table *aTrace, cpl_table *aWave, cpl_table *aGeoTable)
Create the pixel table for one CCD.
#define MUSE_PIXTABLE_ORIGIN
#define MUSE_HDR_PT_LLO
FITS header keyword contains the lower limit of the data in spectral direction.
const char * muse_pfits_get_chip_id(const cpl_propertylist *aHeaders)
find out the chip id
cpl_error_code muse_quadrants_overscan_stats(muse_image *aImage, const char *aRejection, unsigned int aIgnore)
Compute overscan statistics of all quadrants and save in FITS header.
cpl_error_code muse_basicproc_stats_append_header(cpl_image *aImage, cpl_propertylist *aHeader, const char *aPrefix, unsigned aStats)
Compute image statistics of an image and add them to a header.
cpl_table * muse_basicproc_get_illum(muse_imagelist *aImages, cpl_table *aTrace, cpl_table *aWave, cpl_table *aGeo)
Get an illum/attached flat-field from an imagelist and prepare it for use.
int muse_pfits_get_binx(const cpl_propertylist *aHeaders)
find out the binning factor in x direction
cpl_propertylist * header
the FITS header
#define MUSE_PIXTABLE_STAT
cpl_error_code muse_image_save(muse_image *aImage, const char *aFilename)
Save the three image extensions and the FITS headers of a MUSE image to a file.
muse_image * muse_image_load(const char *aFilename)
Load the three extensions and the FITS headers of a MUSE image from a file.
int muse_pfits_get_lamp_status(const cpl_propertylist *aHeaders, int aLamp)
query the status of one lamp
muse_imagelist * muse_imagelist_new(void)
Create a new (empty) MUSE image list.
#define MUSE_PIXTABLE_LAMBDA
cpl_error_code muse_basicproc_mask_notch_filter(muse_pixtable *aPT, unsigned char aIFU)
Mask the range of the NaD notch filter in the given pixel table.
muse_basicproc_params * muse_basicproc_params_new_from_propertylist(const cpl_propertylist *aHeader)
Create a structure of basic processing parameters from a FITS header.
double muse_pfits_get_exptime(const cpl_propertylist *aHeaders)
find out the exposure time
cpl_error_code muse_processing_check_input(muse_processing *aProcessing, unsigned char aIFU)
Check the input files for completeness.
Structure of basic processing parameters.
const char * muse_pfits_get_pro_catg(const cpl_propertylist *aHeaders)
find out the PRO category
#define MUSE_HDR_PT_ILLUM_STDEV
cpl_error_code muse_basicproc_apply_illum(muse_pixtable *aPT, cpl_table *aAttached)
Apply an illum/attached flat-field to a pixel table.
cpl_frameset * muse_frameset_check_raw(const cpl_frameset *aFrames, const cpl_array *aTags, unsigned char aIFU)
return frameset containing good raw input data
cpl_error_code muse_image_adu_to_count(muse_image *aImage)
Convert the data units from raw adu to count (= electron) units.
cpl_frameset * muse_frameset_find(const cpl_frameset *aFrames, const char *aTag, unsigned char aIFU, cpl_boolean aInvert)
return frameset containing data from an IFU/channel with a certain tag
cpl_parameter * muse_cplparamerterlist_find_prefix(cpl_parameterlist *aParameters, const char *aPrefix, const char *aName)
Return the full recipe parameter belonging to prefix and shortname.
muse_image * muse_image_load_from_extensions(const char *aFilename, unsigned char aIFU)
Load the three extensions and the FITS headers of a MUSE image from extensions of a merged file...
#define MUSE_PIXTABLE_YPOS
void muse_pixtable_delete(muse_pixtable *aPixtable)
Deallocate memory associated to a pixel table object.
cpl_error_code muse_imagelist_set(muse_imagelist *aList, muse_image *aImage, unsigned int aIdx)
Set the muse_image of given list index.
const char * muse_pfits_get_chip_name(const cpl_propertylist *aHeaders)
find out the chip name
cpl_frame * muse_frameset_find_master(const cpl_frameset *aFrames, const char *aTag, unsigned char aIFU)
find the master frame according to its CCD number and tag
muse_ins_mode muse_pfits_get_mode(const cpl_propertylist *aHeaders)
find out the observation mode
muse_image * muse_imagelist_unset(muse_imagelist *aList, unsigned int aIdx)
Unset the muse_image at given list index from the list.
cpl_parameterlist * parameters
muse_image * muse_quadrants_trim_image(muse_image *aImage)
Trim the input image of pre- and over-scan regions of all quadrants.
cpl_parameterlist * muse_cplparameterlist_from_propertylist(const cpl_propertylist *aHeader, int aRecNum)
Recreate a cpl_parameterlist from the RECi headers of an output MUSE product.
cpl_propertylist * header
The FITS header.
cpl_frameset * muse_frameset_find_tags(const cpl_frameset *aFrames, const cpl_array *aTags, unsigned char aIFU, cpl_boolean aInvert)
return frameset containing data from an IFU/channel with the given tag(s)
cpl_error_code muse_basicproc_qc_saturated(muse_image *aImage, const char *aPrefix)
Add QC parameter about saturated pixels to a muse_image.