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
87 bpars->
overscan = cpl_strdup(cpl_parameter_get_string(param));
89 bpars->
rejection = cpl_strdup(cpl_parameter_get_string(param));
91 cpl_errorstate state = cpl_errorstate_get();
92 bpars->
ovscsigma = cpl_parameter_get_double(param);
93 if (!cpl_errorstate_is_equal(state)) {
94 cpl_errorstate_set(state);
95 bpars->
ovscsigma = cpl_parameter_get_int(param);
98 bpars->
ovscignore = cpl_parameter_get_int(param);
100 if (strstr(aPrefix,
"muse_scibasic")) {
102 bpars->
crmethod = cpl_strdup(cpl_parameter_get_string(param));
104 bpars->
dcrxbox = cpl_parameter_get_int(param);
106 bpars->
dcrybox = cpl_parameter_get_int(param);
108 bpars->
dcrpasses = cpl_parameter_get_int(param);
110 state = cpl_errorstate_get();
111 bpars->
dcrthres = cpl_parameter_get_double(param);
112 if (!cpl_errorstate_is_equal(state)) {
113 cpl_errorstate_set(state);
114 bpars->
dcrthres = cpl_parameter_get_int(param);
140 cpl_ensure(aHeader, CPL_ERROR_NULL_INPUT, NULL);
145 cpl_ensure(parlist, CPL_ERROR_ILLEGAL_INPUT, NULL);
146 const char *recipe = cpl_propertylist_get_string(aHeader,
"ESO PRO REC1 ID");
147 char *prefix = cpl_sprintf(
"muse.%s", recipe);
149 cpl_parameterlist_delete(parlist);
194 static cpl_error_code
197 cpl_ensure_code(aImage && aRef, CPL_ERROR_NULL_INPUT);
198 cpl_ensure_code(aImage->
header && aRef->
header, CPL_ERROR_NULL_INPUT);
200 cpl_propertylist *him = aImage->
header,
203 const char *fn1 = cpl_propertylist_get_string(him, MUSE_HDR_TMP_FN),
204 *fn2 = cpl_propertylist_get_string(href, MUSE_HDR_TMP_FN),
207 cpl_msg_error(__func__,
"\"%s\" does not contain a category (ESO.PRO.CATG)!",
209 return CPL_ERROR_ILLEGAL_INPUT;
216 *rawtag = cpl_propertylist_get_string(him, MUSE_HDR_TMP_INTAG);
229 cpl_boolean chipinfo = chipname1 && chipid1
230 && chipname2 && chipid2;
232 cpl_msg_warning(__func__,
"CHIP information is missing (ESO.DET.CHIP."
233 "{NAME,ID}) from \"%s\" (%s, %s) or \"%s\" (%s, %s)",
234 fn1, chipname1, chipid1, fn2, chipname2, chipid2);
237 if (binx1 != binx2 || biny1 != biny2) {
238 cpl_msg_error(__func__,
"Binning of \"%s\" (%dx%d) and \"%s\" (%dx%d) does "
239 "not match", fn1, binx1, biny1, fn2, binx2, biny2);
240 return CPL_ERROR_TYPE_MISMATCH;
246 if (!strncmp(catg,
"MASTER_BIAS", 12)) {
247 if (readid1 != readid2) {
248 cpl_msg_error(__func__,
"Read-out mode of \"%s\" (%d: %s) and \"%s\" (%d:"
249 " %s) does not match", fn1, readid1, readname1, fn2,
251 return CPL_ERROR_TYPE_MISMATCH;
253 if (chipinfo && (strcmp(chipname1, chipname2) || strcmp(chipid1, chipid2))) {
254 cpl_msg_error(__func__,
"CHIP information (ESO.DET.CHIP.{NAME,ID}) "
255 "does not match for \"%s\" (%s, %s) and \"%s\" (%s, %s)",
256 fn1, chipname1, chipid1, fn2, chipname2, chipid2);
257 return CPL_ERROR_TYPE_MISMATCH;
263 if (!strncmp(catg,
"MASTER_FLAT", 12)) {
264 if (mode1 != mode2) {
265 if (rawtag && !strncmp(rawtag, MUSE_TAG_ILLUM, strlen(MUSE_TAG_ILLUM) + 1)) {
267 cpl_msg_debug(__func__,
"Instrument modes for \"%s\" (%s, is %s) and \"%s\""
268 " (%s) do not match", fn1, modestr1, rawtag, fn2, modestr2);
270 cpl_msg_error(__func__,
"Instrument modes for \"%s\" (%s) and \"%s\" (%s)"
271 " do not match", fn1, modestr1, fn2, modestr2);
272 return CPL_ERROR_TYPE_MISMATCH;
282 if (readid1 != readid2) {
283 cpl_msg_warning(__func__,
"Read-out mode of \"%s\" (%d: %s) and \"%s\" (%d:"
284 " %s) does not match", fn1, readid1, readname1, fn2,
287 if (chipinfo && (strcmp(chipname1, chipname2) || strcmp(chipid1, chipid2))) {
288 cpl_msg_warning(__func__,
"CHIP information (ESO.DET.CHIP.{NAME,ID,DATE}) "
289 "does not match for \"%s\" (%s, %s) and \"%s\" (%s, %s)",
290 fn1, chipname1, chipid1, fn2, chipname2, chipid2);
293 return CPL_ERROR_NONE;
312 static cpl_error_code
316 cpl_ensure_code(aList, CPL_ERROR_NULL_INPUT);
318 for (k = 0; k < aList->
size; k++) {
323 cpl_msg_warning(__func__,
"Could not compute overscan statistics in IFU "
325 k+1, cpl_error_get_message());
328 return CPL_ERROR_NONE;
345 static cpl_error_code
349 cpl_ensure_code(aList, CPL_ERROR_NULL_INPUT);
350 cpl_boolean ovscvpoly = aBPars && aBPars->
overscan
351 && !strncmp(aBPars->
overscan,
"vpoly", 5);
353 cpl_msg_debug(__func__,
"not vpoly: %s!", aBPars ? aBPars->
overscan :
"");
354 return CPL_ERROR_NONE;
357 unsigned char ovscvorder = 5;
360 char *rest = strchr(aBPars->
overscan,
':');
361 if (strlen(aBPars->
overscan) > 6 && rest) {
362 ovscvorder = strtol(++rest, &rest, 10);
363 if (strlen(rest) > 0) {
364 frms = strtod(++rest, &rest);
365 if (strlen(rest) > 0) {
366 fchisq = strtod(++rest, &rest);
370 cpl_msg_debug(__func__,
"vpoly: %s (vorder=%hhu, frms=%f, fchisq=%f, ignore=%u,"
371 " sigma=%.3f)", aBPars->
overscan, ovscvorder, frms, fchisq,
374 cpl_error_code rc = CPL_ERROR_NONE;
376 for (k = 0; k < aList->
size; k++) {
381 if (rc != CPL_ERROR_NONE) {
383 cpl_msg_error(__func__,
"Could not correct quadrants levels using vertical"
384 " overscan fit in IFU %hhu: %s", ifu, cpl_error_get_message());
405 static cpl_error_code
408 cpl_ensure_code(aList, CPL_ERROR_NULL_INPUT);
411 for (k = 0; k < aList->
size; k++) {
414 cpl_ensure_code(trimmed, cpl_error_get_code());
420 : CPL_ERROR_ILLEGAL_OUTPUT;
442 static cpl_error_code
447 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
450 return CPL_ERROR_NONE;
452 cpl_boolean ovscoffset = aBPars && aBPars->
overscan
453 && !strncmp(aBPars->
overscan,
"offset", 7);
455 return CPL_ERROR_NONE;
458 cpl_msg_info(__func__,
"Running overscan correction using %u %s images in IFU"
459 " %hhu", aList->
size, MUSE_TAG_BIAS, ifu);
462 for (k = 1; k < aList->
size; k++) {
465 return CPL_ERROR_NONE;
494 static cpl_error_code
499 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
503 return CPL_ERROR_NONE;
505 if (aList->
size < 2) {
506 return CPL_ERROR_NONE;
508 cpl_boolean ovscnone = aBPars && aBPars->
overscan
509 && !strncmp(aBPars->
overscan,
"none", 5);
511 return CPL_ERROR_NONE;
513 double sigma = aBPars ? aBPars->
ovscsigma : 1.;
517 cpl_propertylist *refheader = refimage->
header;
518 cpl_error_code rc = CPL_ERROR_NONE;
520 for (n = 1; n <= 4; n++) {
522 char *keywordmean = cpl_sprintf(MUSE_HDR_OVSC_MEAN, n),
523 *keywordstdev = cpl_sprintf(MUSE_HDR_OVSC_STDEV, n);
526 const char *reffn = cpl_propertylist_get_string(refheader, MUSE_HDR_TMP_FN);
527 float refmean = cpl_propertylist_get_float(refheader, keywordmean),
528 refstdev = cpl_propertylist_get_float(refheader, keywordstdev),
529 hilimit = refmean + sigma * refstdev,
530 lolimit = refmean - sigma * refstdev;
532 double summean = refmean,
533 sumstdev = pow(refstdev, 2.);
537 for (k = 1; k < aList->
size; k++) {
539 float mean = cpl_propertylist_get_float(h, keywordmean),
540 stdev = cpl_propertylist_get_float(h, keywordstdev);
542 sumstdev += pow(stdev, 2.) + pow(mean - refmean, 2.);
543 const char *fn = cpl_propertylist_get_string(h, MUSE_HDR_TMP_FN);
544 if (mean > hilimit || mean < lolimit) {
545 cpl_msg_error(__func__,
"Overscan of IFU %hhu, quadrant %1hhu of image %u [%s] "
546 "(%.3f+/-%.3f) differs from first image [%s] (%.3f+/-%.3f)!",
547 ifu, n, k+1, fn, mean, stdev, reffn, refmean, refstdev);
548 rc = cpl_error_set(__func__, CPL_ERROR_INCOMPATIBLE_INPUT);
551 cpl_msg_debug(__func__,
"Overscan of IFU %hhu, quadrant %1hhu of image %u [%s] "
552 "%.3f+/-%.3f (first image [%s] %.3f+/-%.3f)",
553 ifu, n, k+1, fn, mean, stdev, reffn, refmean, refstdev);
558 summean /= aList->
size;
559 sumstdev = sqrt(sumstdev) / aList->
size;
560 cpl_msg_debug(__func__,
"Averaged overscan values in IFU %hhu, quadrant %1hhu: "
561 "%.3f +/- %.3f (%d images)", ifu, n, summean, sumstdev, aList->
size);
562 cpl_propertylist_update_float(refheader, keywordmean, summean);
563 cpl_propertylist_update_float(refheader, keywordstdev, sumstdev);
565 cpl_free(keywordmean);
566 cpl_free(keywordstdev);
591 static cpl_error_code
595 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
596 cpl_table *table =
muse_table_load(aProcessing, MUSE_TAG_BADPIX_TABLE, aIFU);
598 return CPL_ERROR_NONE;
601 if (rc != CPL_ERROR_NONE) {
602 cpl_table_delete(table);
603 return CPL_ERROR_INCOMPATIBLE_INPUT;
606 int nrow = cpl_table_get_nrow(table);
607 unsigned int k, nbadpix = 0,
609 for (k = 0; k < aList->
size && rc == CPL_ERROR_NONE; k++) {
613 for (i = 0; i < nrow; i++) {
614 int x = cpl_table_get(table, MUSE_BADPIX_X, i, NULL),
615 y = cpl_table_get(table, MUSE_BADPIX_Y, i, NULL);
619 uint32_t dq = cpl_table_get(table, MUSE_BADPIX_DQ, i, NULL);
620 cpl_errorstate state = cpl_errorstate_get();
622 uint32_t value = cpl_image_get(image->
dq, x, y, &err);
623 if (err != 0 || !cpl_errorstate_is_equal(state)) {
624 cpl_errorstate_set(state);
632 rc = cpl_image_set(image->
dq, x, y, dq | value);
638 cpl_table_delete(table);
639 cpl_msg_debug(__func__,
"Applied %u bad pixels from %s in IFU %hhu.", nbadpix,
640 MUSE_TAG_BADPIX_TABLE, aIFU);
643 cpl_msg_warning(__func__,
"%s contained %u entries outside the CCD in IFU "
644 "%hhu!", MUSE_TAG_BADPIX_TABLE, nbadpos, aIFU);
659 static cpl_error_code
662 cpl_ensure_code(aList, CPL_ERROR_NULL_INPUT);
664 for (k = 0; k < aList->
size; k++) {
669 int npix = cpl_image_get_size_x(image->
data)
670 * cpl_image_get_size_y(image->
data);
671 if (nsaturated > (0.01 * npix)) {
672 const char *fn = cpl_propertylist_get_string(image->
header,
674 cpl_msg_error(__func__,
"Raw exposure %u [%s] is strongly saturated in "
675 "IFU %hhu (%d of %d pixels)!", k+1, fn, ifu, nsaturated,
677 }
else if (nsaturated > (0.001 * npix)) {
678 const char *fn = cpl_propertylist_get_string(image->
header,
680 cpl_msg_warning(__func__,
"Raw exposure %u [%s] is probably saturated in "
681 "IFU %hhu (%d of %d pixels)!", k+1, fn, ifu, nsaturated,
684 cpl_msg_debug(__func__,
"Raw exposure %u in IFU %hhu (%d of %d pixels "
685 "saturated)!", k+1, ifu, nsaturated, npix);
687 cpl_propertylist_update_int(image->
header, MUSE_HDR_TMP_NSAT, nsaturated);
689 return CPL_ERROR_NONE;
706 static cpl_error_code
710 cpl_ensure_code(aList, CPL_ERROR_NULL_INPUT);
713 return CPL_ERROR_NONE;
716 cpl_msg_info(__func__,
"Computing per-quadrant medians for %u exposures in "
717 "IFU %hhu", aList->
size, ifu);
719 for (k = 0; k < aList->
size; k++) {
722 for (n = 1; n <= 4; n++) {
724 float median = cpl_image_get_median_window(image->
data, w[0], w[2],
727 char *kw = cpl_sprintf(MUSE_HDR_TMP_QUADnMED, n);
728 cpl_propertylist_append_float(image->
header, kw, median);
732 return CPL_ERROR_NONE;
758 static cpl_error_code
762 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
764 MUSE_TAG_MASTER_BIAS, aIFU);
765 cpl_errorstate prestate = cpl_errorstate_get();
766 if (!biasframe)
return CPL_ERROR_NONE;
767 cpl_errorstate_set(prestate);
768 const char *biasname = cpl_frame_get_filename(biasframe);
773 char *errmsg = cpl_strdup(cpl_error_get_message());
774 cpl_errorstate_set(prestate);
779 cpl_msg_error(__func__,
"%s", errmsg);
780 cpl_msg_error(__func__,
"%s", cpl_error_get_message());
782 cpl_frame_delete(biasframe);
783 return cpl_error_get_code();
786 cpl_msg_info(__func__,
"Bias correction in IFU %hhu using \"%s[CHAN%02hhu."
787 "DATA]\"", aIFU, biasname, aIFU);
789 cpl_msg_info(__func__,
"Bias correction in IFU %hhu using \"%s[DATA]\"",
793 cpl_propertylist_append_string(biasimage->
header, MUSE_HDR_TMP_FN, biasname);
795 cpl_boolean ovscoffset = aBPars && aBPars->
overscan
796 && !strncmp(aBPars->
overscan,
"offset", 7),
797 ovscvpoly = aBPars && aBPars->
overscan
798 && !strncmp(aBPars->
overscan,
"vpoly", 5);
800 cpl_error_code rc = CPL_ERROR_NONE;
802 for (k = 0; k < aList->
size && rc == CPL_ERROR_NONE; k++) {
804 rc = muse_basicproc_verify_setup(image, biasimage);
805 if (rc != CPL_ERROR_NONE) {
811 }
else if (ovscvpoly) {
817 cpl_msg_error(__func__,
"Very different overscan levels found between "
818 "%s and raw exposure %u in IFU %hhu: incompatible overscan"
819 " parameters?", MUSE_TAG_MASTER_BIAS, k + 1, aIFU);
820 rc = cpl_error_set(__func__, CPL_ERROR_INCOMPATIBLE_INPUT);
829 #if GENERATE_TEST_IMAGES
861 static cpl_error_code
865 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
868 return CPL_ERROR_NONE;
871 CPL_ERROR_INCOMPATIBLE_INPUT);
874 MUSE_TAG_MASTER_BIAS, aIFU);
877 return CPL_ERROR_NONE;
879 const char *biasname = cpl_frame_get_filename(fbias);
880 cpl_propertylist *hbias = cpl_propertylist_load(biasname, 0);
881 if (!cpl_propertylist_has(hbias, QC_BIAS_MASTER_RON)) {
882 cpl_propertylist_delete(hbias);
884 char *extname = cpl_sprintf(
"CHAN%02hhu.%s", aIFU, EXTNAME_DATA);
885 int extension = cpl_fits_find_extension(biasname, extname);
886 hbias = cpl_propertylist_load(biasname, extension);
889 cpl_frame_delete(fbias);
893 cpl_image *diff = cpl_image_subtract_create(f1, f2);
896 for (n = 1; n <= 4; n++) {
898 double m1 = cpl_image_get_mean_window(f1, w[0], w[2], w[1], w[3]),
899 m2 = cpl_image_get_mean_window(f2, w[0], w[2], w[1], w[3]),
900 sf = cpl_image_get_stdev_window(diff, w[0], w[2], w[1], w[3]);
901 char *keyword = cpl_sprintf(QC_BIAS_MASTERn_PREFIX
" MEAN", n);
902 float mb = cpl_propertylist_get_float(hbias, keyword);
904 keyword = cpl_sprintf(QC_BIAS_MASTER_RON, n);
907 sb = cpl_propertylist_get_float(hbias, keyword) * sqrt(2.)
910 gain = (m1 + m2 - 2*mb) / (sf*sf - sb*sb),
911 dgain = 1. - gain / gainheader;
914 cpl_msg_warning(__func__,
"IFU %hhu, quadrant %1hhu: estimated gain %.3f "
915 "count/adu but header gives %.3f!", aIFU, n, gain,
918 cpl_msg_info(__func__,
"IFU %hhu, quadrant %1hhu: estimated gain %.3f "
919 "count/adu (header %.3f, delta %.3f)", aIFU, n, gain,
926 cpl_image_delete(diff);
927 cpl_propertylist_delete(hbias);
929 return CPL_ERROR_NONE;
952 static cpl_error_code
956 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
958 MUSE_TAG_NONLINGAIN, aIFU);
961 return CPL_ERROR_NONE;
963 if (getenv(
"MUSE_BASICPROC_SKIP_GAIN_OVERRIDE") &&
964 atoi(getenv(
"MUSE_BASICPROC_SKIP_GAIN_OVERRIDE")) > 0) {
965 cpl_msg_info(__func__,
"Skipping gain override, although %s is given",
966 MUSE_TAG_NONLINGAIN);
967 return CPL_ERROR_NONE;
969 cpl_errorstate state = cpl_errorstate_get();
970 const char *fn = cpl_frame_get_filename(fnonlingain);
972 char *extname = cpl_sprintf(
"CHAN%02hhu", aIFU);
973 int extension = cpl_fits_find_extension(fn, extname);
974 cpl_propertylist *header = cpl_propertylist_load(fn, extension);
975 cpl_msg_info(__func__,
"Overriding gain in IFU %hhu using \"%s[%s]\"",
981 for (k = 0; k < aList->
size; k++) {
985 for (n = 1; n <= 4; n++) {
988 char *kw = cpl_sprintf(
"ESO DET OUT%d GAIN", n);
989 cpl_propertylist_update_double(image->
header, kw, gain);
993 cpl_propertylist_delete(header);
994 return cpl_errorstate_is_equal(state) ? CPL_ERROR_NONE : cpl_error_get_code();
1012 static cpl_error_code
1015 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
1018 return CPL_ERROR_NONE;
1022 cpl_msg_info(__func__,
"Converting %u exposures from adu to count (= electron)"
1023 " units in IFU %hhu", aList->
size, ifu);
1024 cpl_error_code rc = CPL_ERROR_NONE;
1026 for (k = 0; k < aList->
size; k++) {
1055 static cpl_error_code
1060 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
1064 return CPL_ERROR_NONE;
1068 MUSE_TAG_NONLINGAIN, aIFU);
1071 return CPL_ERROR_NONE;
1073 if (getenv(
"MUSE_BASICPROC_SKIP_NONLIN_CORR") &&
1074 atoi(getenv(
"MUSE_BASICPROC_SKIP_NONLIN_CORR")) > 0) {
1075 cpl_msg_debug(__func__,
"Skipping nonlinearity correction, although %s is "
1076 "given", MUSE_TAG_NONLINGAIN);
1077 return CPL_ERROR_NONE;
1079 const char *fn = cpl_frame_get_filename(fnonlingain);
1081 char *extname = cpl_sprintf(
"CHAN%02hhu", aIFU);
1082 int extension = cpl_fits_find_extension(fn, extname);
1083 cpl_propertylist *header = cpl_propertylist_load(fn, extension);
1084 cpl_msg_info(__func__,
"Correcting nonlinearity in IFU %hhu using \"%s[%s]\"",
1089 cpl_error_code rc = CPL_ERROR_NONE;
1091 for (k = 0; k < aList->
size; k++) {
1093 int nx = cpl_image_get_size_x(image->
data);
1094 float *data = cpl_image_get_data_float(image->
data),
1095 *stat = cpl_image_get_data_float(image->
stat);
1100 for (n = 1; n <= 4; n++) {
1103 cpl_polynomial *poly = cpl_polynomial_new(1);
1104 char *kw = cpl_sprintf(MUSE_HDR_NONLINn_ORDER, n);
1105 unsigned char o, order = cpl_propertylist_get_int(header, kw);
1107 for (o = 0; o <= order; o++) {
1108 kw = cpl_sprintf(MUSE_HDR_NONLINn_COEFFo, n, o);
1110 cpl_polynomial_set_coeff(poly, &pows,
1111 cpl_propertylist_get_double(header, kw));
1115 kw = cpl_sprintf(MUSE_HDR_NONLINn_LLO, n);
1116 double lolim = cpl_propertylist_get_double(header, kw);
1118 kw = cpl_sprintf(MUSE_HDR_NONLINn_LHI, n);
1119 double hilim = cpl_propertylist_get_double(header, kw);
1122 double p1lo, p0lo = cpl_polynomial_eval_1d(poly, lolim, &p1lo),
1123 p1hi, p0hi = cpl_polynomial_eval_1d(poly, hilim, &p1hi);
1125 lolim = pow(10, lolim);
1126 hilim = pow(10, hilim);
1128 double values[] = { 1., 20., 200., 2000., 20000., 65000.,
1129 lolim, hilim, -1. };
1131 while (values[idx] > 0) {
1132 double v = values[idx],
1134 cpl_msg_debug(__func__,
"%f adu -> %f log10(adu) ==> poly = %f ==> x %f",
1135 v, logv, cpl_polynomial_eval_1d(poly, logv, NULL),
1136 1. / (1. + cpl_polynomial_eval_1d(poly, logv, NULL)));
1139 cpl_polynomial_dump(poly, stdout);
1141 cpl_msg_debug(__func__,
"beyond low limit (%f adu): %f + (%f) * (log10(adu) - %f)",
1142 lolim, p0lo, p1lo, log10(lolim));
1143 cpl_msg_debug(__func__,
"beyond high limit (%f adu): %f + (%f) * (log10(adu) - %f)",
1144 hilim, p0hi, p1hi, log10(hilim));
1150 for (i = w[0] - 1; i < w[1]; i++) {
1152 for (j = w[2] - 1; j < w[3]; j++) {
1153 if (data[i + j*nx] <= 0) {
1158 if (data[i + j*nx] < lolim) {
1159 pcor = p0lo + p1lo * (log10(data[i + j*nx]) - log10(lolim));
1160 }
else if (data[i + j*nx] > hilim) {
1161 pcor = p0hi + p1hi * (log10(data[i + j*nx]) - log10(hilim));
1163 pcor = cpl_polynomial_eval_1d(poly, log10(data[i + j*nx]), NULL);
1166 double fcor = 1. / (1. + pcor);
1167 data[i + j*nx] *= fcor;
1168 stat[i + j*nx] *= fcor*fcor;
1172 cpl_polynomial_delete(poly);
1175 cpl_propertylist_delete(header);
1197 static cpl_error_code
1201 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
1204 MUSE_TAG_MASTER_DARK, aIFU);
1205 cpl_errorstate prestate = cpl_errorstate_get();
1206 if (!darkframe)
return CPL_ERROR_NONE;
1207 cpl_errorstate_set(prestate);
1208 const char *darkname = cpl_frame_get_filename(darkframe);
1211 char *errmsg = cpl_strdup(cpl_error_get_message());
1212 cpl_errorstate_set(prestate);
1215 cpl_msg_error(__func__,
"%s", errmsg);
1216 cpl_msg_error(__func__,
"%s", cpl_error_get_message());
1218 cpl_frame_delete(darkframe);
1219 return cpl_error_get_code();
1222 cpl_msg_info(__func__,
"Dark correction in IFU %hhu using \"%s[CHAN%02hhu."
1223 "DATA]\"", aIFU, darkname, aIFU);
1225 cpl_msg_info(__func__,
"Dark correction in IFU %hhu using \"%s[DATA]\"",
1228 cpl_propertylist_append_string(darkimage->
header, MUSE_HDR_TMP_FN, darkname);
1231 cpl_error_code rc = CPL_ERROR_NONE;
1233 for (k = 0; k < aList->
size; k++) {
1235 rc = muse_basicproc_verify_setup(image, darkimage);
1236 if (rc != CPL_ERROR_NONE) {
1274 static cpl_error_code
1278 cpl_ensure_code(aList, CPL_ERROR_NULL_INPUT);
1282 cpl_boolean isdcr = aBPars && aBPars->
crmethod
1283 && !strncmp(aBPars->
crmethod,
"dcr", 4);
1285 return CPL_ERROR_NONE;
1288 cpl_error_code rc = CPL_ERROR_NONE;
1290 for (k = 0; k < aList->
size; k++) {
1297 cpl_msg_error(__func__,
"Cosmic ray rejection using DCR in IFU %hhu failed"
1298 " for image %u (ncr = %d): %s", ifu, k+1, ncr,
1299 cpl_error_get_message());
1300 rc = cpl_error_get_code();
1302 cpl_msg_info(__func__,
"Cosmic ray rejection using DCR in IFU %hhu found "
1303 "%d affected pixels in image %u", ifu, ncr, k+1);
1326 static cpl_error_code
1330 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
1333 MUSE_TAG_MASTER_FLAT, aIFU);
1334 cpl_errorstate prestate = cpl_errorstate_get();
1335 if (!flatframe)
return CPL_ERROR_NONE;
1336 cpl_errorstate_set(prestate);
1337 const char *flatname = cpl_frame_get_filename(flatframe);
1338 prestate = cpl_errorstate_get();
1341 char *errmsg = cpl_strdup(cpl_error_get_message());
1342 cpl_errorstate_set(prestate);
1345 cpl_msg_error(__func__,
"%s", errmsg);
1346 cpl_msg_error(__func__,
"%s", cpl_error_get_message());
1348 cpl_frame_delete(flatframe);
1349 return cpl_error_get_code();
1352 cpl_msg_info(__func__,
"Flat-field correction in IFU %hhu using \"%s[CHAN%02hhu."
1353 "DATA]\"", aIFU, flatname, aIFU);
1355 cpl_msg_info(__func__,
"Flat-field correction in IFU %hhu using \"%s[DATA]\"",
1359 double fflux = cpl_propertylist_get_double(flatimage->
header,
1360 QC_FLAT_MASTER_INTFLUX);
1361 cpl_propertylist_append_string(flatimage->
header, MUSE_HDR_TMP_FN, flatname);
1364 cpl_error_code rc = CPL_ERROR_NONE;
1366 for (k = 0; k < aList->
size; k++) {
1367 cpl_msg_debug(__func__,
"Flat-field division in IFU %hhu of image %u of %u",
1368 aIFU, k+1, aList->
size);
1370 rc = muse_basicproc_verify_setup(image, flatimage);
1371 if (rc != CPL_ERROR_NONE) {
1375 cpl_propertylist_update_double(image->
header, MUSE_HDR_FLAT_FLUX_LAMP, fflux);
1405 muse_basicproc_load_raw(
muse_processing *aProcessing,
unsigned char aIFU)
1407 cpl_ensure(aProcessing, CPL_ERROR_NULL_INPUT, NULL);
1411 aProcessing->
intags, aIFU);
1412 cpl_ensure(rawframes, CPL_ERROR_NULL_INPUT, NULL);
1416 cpl_size iframe, nframes = cpl_frameset_get_size(rawframes);
1417 for (iframe = 0; iframe < nframes; iframe++) {
1418 cpl_frame *frame = cpl_frameset_get_position(rawframes, iframe);
1419 const char *fileName = cpl_frame_get_filename(frame);
1421 if (extension == -1) {
1422 cpl_msg_error(__func__,
"\"%s\" does not contain data from IFU %hhu",
1431 cpl_propertylist_append_string(raw->
header, MUSE_HDR_TMP_FN, fileName);
1433 cpl_propertylist_append_string(raw->
header, MUSE_HDR_TMP_INTAG,
1434 cpl_frame_get_tag(frame));
1440 cpl_frameset_delete(rawframes);
1443 if (!images->
size) {
1444 if (cpl_error_get_code() != MUSE_ERROR_CHIP_NOT_LIVE) {
1445 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_OUTPUT);
1446 cpl_msg_error(__func__,
"No raw images loaded for IFU %hhu", aIFU);
1452 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_OUTPUT);
1453 cpl_msg_error(__func__,
"Non-uniform imagelist for IFU %hhu", aIFU);
1512 muse_imagelist *images = muse_basicproc_load_raw(aProcessing, aIFU);
1516 cpl_errorstate prestate = cpl_errorstate_get();
1517 if (muse_basicproc_apply_badpix(images, aProcessing, aIFU) != CPL_ERROR_NONE) {
1518 cpl_msg_warning(__func__,
"Applying bad pixel table to IFU %hhu failed: %s",
1519 aIFU, cpl_error_get_message());
1520 cpl_errorstate_set(prestate);
1522 if (muse_basicproc_check_saturation(images) != CPL_ERROR_NONE) {
1526 muse_basicproc_quadrant_statistics(images, aProcessing);
1527 if (muse_basicproc_overscans_compute_stats(images, aBPars)
1528 != CPL_ERROR_NONE) {
1532 if (muse_basicproc_correct_overscans_vpoly(images, aBPars)
1533 != CPL_ERROR_NONE) {
1537 if (muse_basicproc_trim_images(images) != CPL_ERROR_NONE) {
1541 if (muse_basicproc_correct_overscans_offset(images, aProcessing, aBPars)
1542 != CPL_ERROR_NONE) {
1543 cpl_msg_warning(__func__,
"Bias-level correction using overscans failed in "
1544 "IFU %hhu: %s", aIFU, cpl_error_get_message());
1546 if (muse_basicproc_check_overscans(images, aProcessing, aBPars)
1547 != CPL_ERROR_NONE) {
1551 muse_basicproc_gain_override(images, aProcessing, aIFU);
1552 muse_basicproc_check_gain(images, aProcessing, aIFU);
1553 if (muse_basicproc_apply_bias(images, aProcessing, aIFU, aBPars)
1554 != CPL_ERROR_NONE) {
1558 if (muse_basicproc_corr_nonlinearity(images, aProcessing, aIFU) != CPL_ERROR_NONE) {
1562 if (muse_basicproc_adu_to_count(images, aProcessing) != CPL_ERROR_NONE) {
1566 if (muse_basicproc_apply_dark(images, aProcessing, aIFU) != CPL_ERROR_NONE) {
1570 if (muse_basicproc_apply_cr(images, aBPars) != CPL_ERROR_NONE) {
1574 if (muse_basicproc_apply_flat(images, aProcessing, aIFU) != CPL_ERROR_NONE) {
1602 cpl_size iframe, nframes = cpl_frameset_get_size(redframes);
1603 for (iframe = 0; iframe < nframes; iframe++) {
1604 cpl_frame *frame = cpl_frameset_get_position(redframes, iframe);
1605 cpl_errorstate prestate = cpl_errorstate_get();
1606 const char *imagename = cpl_frame_get_filename(frame);
1609 cpl_errorstate_set(prestate);
1615 cpl_frameset_delete(redframes);
1638 CPL_ERROR_NULL_INPUT, NULL);
1647 cpl_msg_info(__func__,
"Preparing %s flat: %d slices in the data of IFU %hhu "
1648 "found.", MUSE_TAG_ILLUM, npt, ifu);
1649 cpl_table *tattached = cpl_table_new(npt);
1650 cpl_table_new_column(tattached,
"slice", CPL_TYPE_INT);
1651 cpl_table_new_column(tattached,
"fflat", CPL_TYPE_DOUBLE);
1652 for (ipt = 0; ipt < npt; ipt++) {
1653 uint32_t origin = cpl_table_get_int(pts[ipt]->table, MUSE_PIXTABLE_ORIGIN, 0, NULL);
1655 double median = cpl_table_get_column_median(pts[ipt]->table,
1656 MUSE_PIXTABLE_DATA);
1657 cpl_msg_debug(__func__,
"Found median of %f in slice %d of IFU %hhu "
1658 "of illum flat.", median, slice, ifu);
1659 cpl_table_set_int(tattached,
"slice", ipt, slice);
1660 cpl_table_set_double(tattached,
"fflat", ipt, 1. / median);
1664 double mean = cpl_table_get_column_mean(tattached,
"fflat");
1665 cpl_msg_debug(__func__,
"Normalizing whole illum-flat table if IFU %hhu to "
1667 cpl_table_multiply_scalar(tattached,
"fflat", 1. / mean);
1668 cpl_table_set_column_format(tattached,
"fflat",
"%.6f");
1689 cpl_ensure_code(aPT && aPT->
header && aPT->
table && aAttached,
1690 CPL_ERROR_NULL_INPUT);
1696 cpl_msg_info(__func__,
"Applying %s flat-field in IFU %hhu (%d slices)",
1697 MUSE_TAG_ILLUM, ifu, npt);
1698 cpl_array *afactors = cpl_array_new(npt, CPL_TYPE_DOUBLE);
1699 for (ipt = 0; ipt < npt; ipt++) {
1700 uint32_t origin = cpl_table_get_int(pts[ipt]->table, MUSE_PIXTABLE_ORIGIN, 0, NULL);
1702 fslice = cpl_table_get_int(aAttached,
"slice", ipt, NULL);
1704 double fflat = cpl_table_get_double(aAttached,
"fflat", ipt, &err);
1705 if (!err && slice == fslice) {
1706 cpl_table_multiply_scalar(pts[ipt]->table, MUSE_PIXTABLE_DATA, fflat);
1707 cpl_table_multiply_scalar(pts[ipt]->table, MUSE_PIXTABLE_STAT, fflat*fflat);
1708 cpl_array_set_double(afactors, ipt, fflat);
1710 cpl_propertylist_update_double(aPT->
header, kw, fflat);
1713 cpl_msg_warning(__func__,
"some error (%d) occurred when applying illum-"
1714 "flat correction to slice %hu/%hu of IFU %hhu: %s", err,
1715 slice, fslice, ifu, cpl_error_get_message());
1720 cpl_array_get_mean(afactors));
1722 cpl_array_get_stdev(afactors));
1723 cpl_array_delete(afactors);
1724 return CPL_ERROR_NONE;
1748 cpl_ensure_code(aPT && aPT->
header && aPT->
table && aTwilight,
1749 CPL_ERROR_NULL_INPUT);
1756 char *kw = cpl_sprintf(MUSE_HDR_FLAT_FLUX_SKY
"%hhu", ifu);
1757 double flux = cpl_propertylist_get_double(aTwilight->
header, kw);
1759 cpl_propertylist_update_double(aPT->
header, MUSE_HDR_FLAT_FLUX_SKY, flux);
1762 int nx = cpl_image_get_size_x(cpl_imagelist_get(aTwilight->
data, 0)),
1763 ny = cpl_image_get_size_y(cpl_imagelist_get(aTwilight->
data, 0)),
1764 nz = cpl_imagelist_get_size(aTwilight->
data);
1765 cpl_msg_debug(__func__,
"Working with %d planes in twilight cube", nz);
1766 double cd12 = cpl_propertylist_get_double(aTwilight->
header,
"CD1_2"),
1767 cd21 = cpl_propertylist_get_double(aTwilight->
header,
"CD2_1");
1768 if (cd12 > DBL_EPSILON || cd21 > DBL_EPSILON) {
1769 cpl_msg_warning(__func__,
"Twilight cube contains WCS cross-terms (CD1_2"
1770 "=%e, CD2_1=%e), results will be inaccurate!", cd12, cd21);
1773 double crval1 = cpl_propertylist_get_double(aTwilight->
header,
"CRVAL1"),
1774 crpix1 = cpl_propertylist_get_double(aTwilight->
header,
"CRPIX1"),
1775 cd11 = cpl_propertylist_get_double(aTwilight->
header,
"CD1_1"),
1776 crval2 = cpl_propertylist_get_double(aTwilight->
header,
"CRVAL2"),
1777 crpix2 = cpl_propertylist_get_double(aTwilight->
header,
"CRPIX2"),
1778 cd22 = cpl_propertylist_get_double(aTwilight->
header,
"CD2_2"),
1779 crval3 = cpl_propertylist_get_double(aTwilight->
header,
"CRVAL3"),
1780 crpix3 = cpl_propertylist_get_double(aTwilight->
header,
"CRPIX3"),
1781 cd33 = cpl_propertylist_get_double(aTwilight->
header,
"CD3_3");
1784 float *data = cpl_table_get_data_float(aPT->
table, MUSE_PIXTABLE_DATA),
1785 *stat = cpl_table_get_data_float(aPT->
table, MUSE_PIXTABLE_STAT),
1786 *xpos = cpl_table_get_data_float(aPT->
table, MUSE_PIXTABLE_XPOS),
1787 *ypos = cpl_table_get_data_float(aPT->
table, MUSE_PIXTABLE_YPOS),
1788 *lbda = cpl_table_get_data_float(aPT->
table, MUSE_PIXTABLE_LAMBDA);
1791 for (irow = 0; irow < nrow; irow++) {
1794 int x = lround((xpos[irow] - crval1) / cd11 + crpix1),
1795 y = lround((ypos[irow] - crval2) / cd22 + crpix2);
1809 double z = (lbda[irow] - crval3) / cd33 + crpix3;
1811 cpl_msg_debug(__func__,
"%"CPL_SIZE_FORMAT
": %.3f %.3f %.3f => %d %d %.3f",
1812 irow, xpos[irow], ypos[irow], lbda[irow], x, y, z);
1815 int zp1 = floor(z) - 1,
1831 double v1 = cpl_image_get(cpl_imagelist_get(aTwilight->
data, zp1),
1833 v2 = cpl_image_get(cpl_imagelist_get(aTwilight->
data, zp2),
1849 f = fabs(z - 1 - zp1);
1850 villum = v1 * (1. - f) + v2 * f;
1852 double fillum = 1. / villum;
1854 cpl_msg_debug(__func__,
"%d/%d, %f/%f -> %f -> %f => %f", zp1, zp2, v1, v2,
1859 data[irow] *= fillum;
1861 stat[irow] *= fillum*fillum;
1864 cpl_msg_warning(__func__,
"Failed to correct twilight in %"CPL_SIZE_FORMAT
1865 " of %"CPL_SIZE_FORMAT
", pixels in IFU %hhu!", nfailed,
1868 cpl_msg_debug(__func__,
"No failures during twilight correction of %"
1869 CPL_SIZE_FORMAT
" pixels in IFU %hhu", nrow, ifu);
1872 return CPL_ERROR_NONE;
1903 muse_basicproc_combine_compare_lamp(
const cpl_frame *aFrame1,
const cpl_frame *aFrame2)
1905 cpl_ensure(aFrame1 && aFrame2, CPL_ERROR_NULL_INPUT, -1);
1906 const char *fn1 = cpl_frame_get_filename(aFrame1),
1907 *fn2 = cpl_frame_get_filename(aFrame2);
1908 cpl_propertylist *head1 = cpl_propertylist_load(fn1, 0),
1909 *head2 = cpl_propertylist_load(fn2, 0);
1910 if (!head1 || !head2) {
1911 cpl_propertylist_delete(head1);
1912 cpl_propertylist_delete(head2);
1919 int nlamp = 1, status1, status2;
1920 cpl_errorstate prestate = cpl_errorstate_get();
1925 cpl_errorstate_set(prestate);
1926 if (name1 && name2 && strncmp(name1, name2, strlen(name1) + 1)) {
1927 cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
1928 "Files \"%s\" and \"%s\" have incompatible lamp "
1929 "setups", fn1, fn2);
1930 cpl_propertylist_delete(head1);
1931 cpl_propertylist_delete(head2);
1936 if (name1 && name2 && strncmp(name1, name2, strlen(name1) + 1)) {
1937 cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
1938 "Files \"%s\" and \"%s\" have incompatible shutter "
1939 "setups", fn1, fn2);
1940 cpl_propertylist_delete(head1);
1941 cpl_propertylist_delete(head2);
1947 cpl_errorstate_set(prestate);
1948 if (status1 != status2) {
1953 if (status1 != status2) {
1957 }
while (cpl_errorstate_is_equal(prestate));
1958 cpl_errorstate_set(prestate);
1960 cpl_propertylist_delete(head1);
1961 cpl_propertylist_delete(head2);
1962 return status1 == status2;
1996 cpl_frameset ***aLabeledFrames)
1998 if (aLabeledFrames) {
1999 *aLabeledFrames = NULL;
2001 cpl_ensure(aProcessing, CPL_ERROR_NULL_INPUT, NULL);
2005 aProcessing->
intags, aIFU,
2007 char *prefix = cpl_sprintf(
"muse.%s", aProcessing->
name);
2012 printf(
"rawframes\n");
2013 cpl_frameset_dump(rawframes, stdout);
2017 *labels = cpl_frameset_labelise(rawframes,
2018 muse_basicproc_combine_compare_lamp,
2020 if (!labels || nlabels <= 1) {
2023 cpl_frameset_delete(rawframes);
2030 if (aLabeledFrames) {
2031 *aLabeledFrames = cpl_calloc(1,
sizeof(cpl_frameset *));
2032 (*aLabeledFrames)[0] = cpl_frameset_duplicate(aProcessing->
usedframes);
2041 cpl_array *alabels = cpl_array_wrap_int(labels, cpl_frameset_get_size(rawframes));
2042 cpl_array_dump(alabels, 0, 1000, stdout);
2044 cpl_array_unwrap(alabels);
2048 if (aLabeledFrames) {
2049 *aLabeledFrames = cpl_calloc(nlabels,
sizeof(cpl_frameset *));
2056 cpl_frameset *inframes = proc->
inframes;
2061 int ilabel, ipos = 0;
2062 for (ilabel = 0; ilabel < nlabels; ilabel++) {
2064 cpl_frameset *frames = cpl_frameset_extract(rawframes, labels, ilabel);
2066 cpl_frameset_join(frames, auxframes);
2075 cpl_frameset_delete(frames);
2080 if (aLabeledFrames) {
2081 cpl_free(*aLabeledFrames);
2082 *aLabeledFrames = NULL;
2089 cpl_msg_error(__func__,
"Image combination failed for IFU %hhu for lamp "
2090 "with label %d of %"CPL_SIZE_FORMAT, aIFU, ilabel + 1, nlabels);
2092 cpl_frameset_delete(frames);
2096 if (aLabeledFrames) {
2098 cpl_size iframe, nframes = cpl_frameset_get_size(frames);
2099 for (iframe = 0; iframe < nframes; iframe++) {
2100 cpl_frame *frame = cpl_frameset_get_position(frames, iframe);
2101 const char *fn = cpl_frame_get_filename(frame),
2102 *tag = cpl_frame_get_tag(frame);
2103 cpl_size iuframe, nuframes = cpl_frameset_get_size(aProcessing->
usedframes);
2105 (iuframe < nuframes) && fn && tag;
2107 cpl_frame *uframe = cpl_frameset_get_position(aProcessing->
usedframes,
2109 const char *fnu = cpl_frame_get_filename(uframe),
2110 *tagu = cpl_frame_get_tag(uframe);
2111 if (fnu && !strncmp(fn, fnu, strlen(fn) + 1) &&
2112 tagu && !strncmp(tag, tagu, strlen(tag) + 1)) {
2113 cpl_frame_set_group(frame, cpl_frame_get_group(uframe));
2118 (*aLabeledFrames)[ipos] = frames;
2120 cpl_frameset_delete(frames);
2126 char *keyword = cpl_sprintf(QC_WAVECAL_PREFIXi
" "QC_BASIC_NSATURATED, k+1);
2129 cpl_propertylist_update_int(lampimage->
header, keyword, nsaturated);
2139 cpl_frameset_delete(rawframes);
2140 cpl_frameset_delete(auxframes);
2145 if (aLabeledFrames) {
2146 cpl_free(*aLabeledFrames);
2147 *aLabeledFrames = NULL;
2176 double aHalfWidth,
double aBinWidth)
2178 cpl_ensure_code(aPt && aLines, CPL_ERROR_NULL_INPUT);
2179 cpl_ensure_code(cpl_array_get_type(aLines) == CPL_TYPE_DOUBLE ||
2180 cpl_array_get_type(aLines) == CPL_TYPE_FLOAT,
2181 CPL_ERROR_ILLEGAL_INPUT);
2185 double shift = 0., wshift = 0.;
2186 cpl_array *errors = cpl_array_new(4, CPL_TYPE_DOUBLE);
2187 int i, n = cpl_array_get_size(aLines), nvalid = 0;
2188 for (i = 0; i < n; i++) {
2190 double lambda = cpl_array_get(aLines, i, &err);
2191 if (err || lambda >= lmax || lambda <= lmin) {
2192 cpl_msg_debug(__func__,
"Invalid wavelength at position %d of %d in "
2193 "skylines", i + 1, n);
2198 aBinWidth, NULL, errors),
2199 cerr = cpl_array_get_double(errors, 0, NULL);
2200 shift += (lambda - center) / cerr;
2201 wshift += 1. / cerr;
2202 cpl_msg_debug(__func__,
"dlambda = %.4f +/- %.4f (for skyline at %.4f "
2203 "Angstrom)", lambda - center, cerr, lambda);
2205 cpl_array_delete(errors);
2207 if (nvalid > 0 && isfinite(shift)) {
2208 cpl_msg_info(__func__,
"Skyline correction (%d lines): shifting data of IFU "
2211 cpl_table_add_scalar(aPt->
table, MUSE_PIXTABLE_LAMBDA, shift);
2212 cpl_propertylist_update_float(aPt->
header, QC_SCIBASIC_SHIFT, shift);
2214 cpl_propertylist_update_float(aPt->
header, QC_SCIBASIC_SHIFT, 0.);
2216 return CPL_ERROR_NONE;
2234 const char *aPrefix,
unsigned aStats)
2236 cpl_ensure_code(aImage, CPL_ERROR_NULL_INPUT);
2238 int nx = cpl_image_get_size_x(aImage),
2239 ny = cpl_image_get_size_y(aImage);
2241 aStats, 1, 1, nx, ny);
2264 cpl_propertylist *aHeader,
2265 const char *aPrefix,
unsigned aStats,
2266 int aX1,
int aY1,
int aX2,
int aY2)
2268 cpl_ensure_code(aImage && aHeader, CPL_ERROR_NULL_INPUT);
2269 cpl_ensure_code(aPrefix, CPL_ERROR_ILLEGAL_INPUT);
2270 cpl_ensure_code(aPrefix, CPL_ERROR_ILLEGAL_INPUT);
2272 cpl_stats *stats = cpl_stats_new_from_image_window(aImage, aStats,
2273 aX1, aY1, aX2, aY2);
2275 return cpl_error_get_code();
2278 char keyword[KEYWORD_LENGTH];
2279 if (aStats & CPL_STATS_MEDIAN) {
2280 snprintf(keyword, KEYWORD_LENGTH,
"%s MEDIAN", aPrefix);
2281 cpl_propertylist_append_float(aHeader, keyword,
2282 cpl_stats_get_median(stats));
2284 if (aStats & CPL_STATS_MEAN) {
2285 snprintf(keyword, KEYWORD_LENGTH,
"%s MEAN", aPrefix);
2286 cpl_propertylist_append_float(aHeader, keyword, cpl_stats_get_mean(stats));
2288 if (aStats & CPL_STATS_STDEV) {
2289 snprintf(keyword, KEYWORD_LENGTH,
"%s STDEV", aPrefix);
2290 cpl_propertylist_append_float(aHeader, keyword, cpl_stats_get_stdev(stats));
2292 if (aStats & CPL_STATS_MIN) {
2293 snprintf(keyword, KEYWORD_LENGTH,
"%s MIN", aPrefix);
2294 cpl_propertylist_append_float(aHeader, keyword, cpl_stats_get_min(stats));
2296 if (aStats & CPL_STATS_MAX) {
2297 snprintf(keyword, KEYWORD_LENGTH,
"%s MAX", aPrefix);
2298 cpl_propertylist_append_float(aHeader, keyword, cpl_stats_get_max(stats));
2300 if (aStats & CPL_STATS_FLUX) {
2301 snprintf(keyword, KEYWORD_LENGTH,
"%s INTFLUX", aPrefix);
2302 cpl_propertylist_append_float(aHeader, keyword, cpl_stats_get_flux(stats));
2305 cpl_stats_delete(stats);
2307 return CPL_ERROR_NONE;
2329 cpl_ensure_code(aImage && aImage->
dq && aImage->
header && aPrefix,
2330 CPL_ERROR_NULL_INPUT);
2332 cpl_mask *mask = cpl_mask_threshold_image_create(aImage->
dq,
2333 EURO3D_SATURATED - 0.1,
2334 EURO3D_SATURATED + 0.1);
2335 int nsaturated = cpl_mask_count(mask);
2336 cpl_mask_delete(mask);
2338 char *keyword = NULL;
2339 if (aPrefix[strlen(aPrefix)-1] ==
' ') {
2340 keyword = cpl_sprintf(
"%s%s", aPrefix, QC_BASIC_NSATURATED);
2342 keyword = cpl_sprintf(
"%s %s", aPrefix, QC_BASIC_NSATURATED);
2344 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.
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.
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
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.
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.
double muse_utils_pixtable_fit_line_gaussian(muse_pixtable *aPixtable, double aLambda, double aHalfWidth, double aBinSize, cpl_array *aResults, cpl_array *aErrors)
Fit a 1D Gaussian to a given wavelength range in a pixel table.
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_error_code muse_cpltable_check(const cpl_table *aTable, const muse_cpltable_def *aDef)
Check whether the table contains the fields of the definition.
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.
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.
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.
#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_basicproc_shift_pixtable(muse_pixtable *aPt, cpl_array *aLines, double aHalfWidth, double aBinWidth)
Compute wavelength corrections for science data based on reference sky lines.
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.
int muse_pfits_get_binx(const cpl_propertylist *aHeaders)
find out the binning factor in x direction
cpl_propertylist * header
the FITS header
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.
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_table * muse_table_load(muse_processing *aProcessing, const char *aTag, unsigned char aIFU)
load a table according to its tag and IFU/channel number
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_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...
cpl_table * muse_basicproc_prepare_illum(muse_pixtable *aPT)
Apply an illum/attached flat-field to a pixel table.
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
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.