00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifdef HAVE_CONFIG_H
00023 #include <config.h>
00024 #endif
00025
00026
00027
00028
00029 #include <stdio.h>
00030 #include <float.h>
00031 #include <math.h>
00032 #include <string.h>
00033 #include <cpl.h>
00034
00035 #include "muse_basicproc.h"
00036
00037 #include "muse_combine.h"
00038 #include "muse_pfits.h"
00039 #include "muse_quadrants.h"
00040 #include "muse_quality.h"
00041 #include "muse_utils.h"
00042 #include "muse_data_format_z.h"
00043
00044
00045
00046
00047
00048 #define GENERATE_TEST_IMAGES 0
00049
00050
00057
00058
00061
00080
00081 muse_basicproc_params *
00082 muse_basicproc_params_new(cpl_parameterlist *aParameters, const char *aPrefix)
00083 {
00084 muse_basicproc_params *bpars = cpl_calloc(1, sizeof(muse_basicproc_params));
00085 cpl_parameter *param;
00086 param = muse_cplparamerterlist_find_prefix(aParameters, aPrefix, "overscan");
00087 bpars->overscan = cpl_strdup(cpl_parameter_get_string(param));
00088 param = muse_cplparamerterlist_find_prefix(aParameters, aPrefix, "ovscreject");
00089 bpars->rejection = cpl_strdup(cpl_parameter_get_string(param));
00090 param = muse_cplparamerterlist_find_prefix(aParameters, aPrefix, "ovscsigma");
00091 cpl_errorstate state = cpl_errorstate_get();
00092 bpars->ovscsigma = cpl_parameter_get_double(param);
00093 if (!cpl_errorstate_is_equal(state)) {
00094 cpl_errorstate_set(state);
00095 bpars->ovscsigma = cpl_parameter_get_int(param);
00096 }
00097 param = muse_cplparamerterlist_find_prefix(aParameters, aPrefix, "ovscignore");
00098 bpars->ovscignore = cpl_parameter_get_int(param);
00099
00100 if (strstr(aPrefix, "muse_scibasic")) {
00101 param = muse_cplparamerterlist_find_prefix(aParameters, aPrefix, "cr");
00102 bpars->crmethod = cpl_strdup(cpl_parameter_get_string(param));
00103 param = muse_cplparamerterlist_find_prefix(aParameters, aPrefix, "xbox");
00104 bpars->dcrxbox = cpl_parameter_get_int(param);
00105 param = muse_cplparamerterlist_find_prefix(aParameters, aPrefix, "ybox");
00106 bpars->dcrybox = cpl_parameter_get_int(param);
00107 param = muse_cplparamerterlist_find_prefix(aParameters, aPrefix, "passes");
00108 bpars->dcrpasses = cpl_parameter_get_int(param);
00109 param = muse_cplparamerterlist_find_prefix(aParameters, aPrefix, "thres");
00110 state = cpl_errorstate_get();
00111 bpars->dcrthres = cpl_parameter_get_double(param);
00112 if (!cpl_errorstate_is_equal(state)) {
00113 cpl_errorstate_set(state);
00114 bpars->dcrthres = cpl_parameter_get_int(param);
00115 }
00116 }
00117 return bpars;
00118 }
00119
00120
00136
00137 muse_basicproc_params *
00138 muse_basicproc_params_new_from_propertylist(const cpl_propertylist *aHeader)
00139 {
00140 cpl_ensure(aHeader, CPL_ERROR_NULL_INPUT, NULL);
00141
00142
00143
00144 cpl_parameterlist *parlist = muse_cplparameterlist_from_propertylist(aHeader, 1);
00145 cpl_ensure(parlist, CPL_ERROR_ILLEGAL_INPUT, NULL);
00146 const char *recipe = cpl_propertylist_get_string(aHeader, "ESO PRO REC1 ID");
00147 char *prefix = cpl_sprintf("muse.%s", recipe);
00148 muse_basicproc_params *bpars = muse_basicproc_params_new(parlist, prefix);
00149 cpl_parameterlist_delete(parlist);
00150 cpl_free(prefix);
00151 return bpars;
00152 }
00153
00154
00161
00162 void
00163 muse_basicproc_params_delete(muse_basicproc_params *aBPars)
00164 {
00165 if (!aBPars) {
00166 return;
00167 }
00168 cpl_free(aBPars->overscan);
00169 cpl_free(aBPars->rejection);
00170 cpl_free(aBPars->crmethod);
00171 cpl_free(aBPars);
00172 }
00173
00174
00193
00194 static cpl_error_code
00195 muse_basicproc_verify_setup(const muse_image *aImage, const muse_image *aRef)
00196 {
00197 cpl_ensure_code(aImage && aRef, CPL_ERROR_NULL_INPUT);
00198 cpl_ensure_code(aImage->header && aRef->header, CPL_ERROR_NULL_INPUT);
00199
00200 cpl_propertylist *him = aImage->header,
00201 *href = aRef->header;
00202
00203 const char *fn1 = cpl_propertylist_get_string(him, MUSE_HDR_TMP_FN),
00204 *fn2 = cpl_propertylist_get_string(href, MUSE_HDR_TMP_FN),
00205 *catg = muse_pfits_get_pro_catg(href);
00206 if (!catg) {
00207 cpl_msg_error(__func__, "\"%s\" does not contain a category (ESO.PRO.CATG)!",
00208 fn2);
00209 return CPL_ERROR_ILLEGAL_INPUT;
00210 }
00211
00212 muse_ins_mode mode1 = muse_pfits_get_mode(him),
00213 mode2 = muse_pfits_get_mode(href);
00214 const char *modestr1 = muse_pfits_get_insmode(him),
00215 *modestr2 = muse_pfits_get_insmode(href),
00216 *rawtag = cpl_propertylist_get_string(him, MUSE_HDR_TMP_INTAG);
00217 int binx1 = muse_pfits_get_binx(him),
00218 biny1 = muse_pfits_get_biny(him),
00219 readid1 = muse_pfits_get_read_id(him),
00220 binx2 = muse_pfits_get_binx(href),
00221 biny2 = muse_pfits_get_biny(href),
00222 readid2 = muse_pfits_get_read_id(href);
00223 const char *readname1 = muse_pfits_get_read_name(him),
00224 *readname2 = muse_pfits_get_read_name(href),
00225 *chipname1 = muse_pfits_get_chip_name(him),
00226 *chipid1 = muse_pfits_get_chip_id(him),
00227 *chipname2 = muse_pfits_get_chip_name(href),
00228 *chipid2 = muse_pfits_get_chip_id(href);
00229 cpl_boolean chipinfo = chipname1 && chipid1
00230 && chipname2 && chipid2;
00231 if (!chipinfo) {
00232 cpl_msg_warning(__func__, "CHIP information is missing (ESO.DET.CHIP."
00233 "{NAME,ID}) from \"%s\" (%s, %s) or \"%s\" (%s, %s)",
00234 fn1, chipname1, chipid1, fn2, chipname2, chipid2);
00235 }
00236
00237 if (binx1 != binx2 || biny1 != biny2) {
00238 cpl_msg_error(__func__, "Binning of \"%s\" (%dx%d) and \"%s\" (%dx%d) does "
00239 "not match", fn1, binx1, biny1, fn2, binx2, biny2);
00240 return CPL_ERROR_TYPE_MISMATCH;
00241 }
00242
00243
00244
00245
00246 if (!strncmp(catg, "MASTER_BIAS", 12)) {
00247 if (readid1 != readid2) {
00248 cpl_msg_error(__func__, "Read-out mode of \"%s\" (%d: %s) and \"%s\" (%d:"
00249 " %s) does not match", fn1, readid1, readname1, fn2,
00250 readid2, readname2);
00251 return CPL_ERROR_TYPE_MISMATCH;
00252 }
00253 if (chipinfo && (strcmp(chipname1, chipname2) || strcmp(chipid1, chipid2))) {
00254 cpl_msg_error(__func__, "CHIP information (ESO.DET.CHIP.{NAME,ID}) "
00255 "does not match for \"%s\" (%s, %s) and \"%s\" (%s, %s)",
00256 fn1, chipname1, chipid1, fn2, chipname2, chipid2);
00257 return CPL_ERROR_TYPE_MISMATCH;
00258 }
00259 }
00260
00261
00262
00263 if (!strncmp(catg, "MASTER_FLAT", 12)) {
00264 if (mode1 != mode2) {
00265 if (rawtag && !strncmp(rawtag, MUSE_TAG_ILLUM, strlen(MUSE_TAG_ILLUM) + 1)) {
00266
00267 cpl_msg_debug(__func__, "Instrument modes for \"%s\" (%s, is %s) and \"%s\""
00268 " (%s) do not match", fn1, modestr1, rawtag, fn2, modestr2);
00269 } else {
00270 cpl_msg_error(__func__, "Instrument modes for \"%s\" (%s) and \"%s\" (%s)"
00271 " do not match", fn1, modestr1, fn2, modestr2);
00272 return CPL_ERROR_TYPE_MISMATCH;
00273 }
00274 }
00275 }
00276
00277
00278
00279
00280
00281
00282 if (readid1 != readid2) {
00283 cpl_msg_warning(__func__, "Read-out mode of \"%s\" (%d: %s) and \"%s\" (%d:"
00284 " %s) does not match", fn1, readid1, readname1, fn2,
00285 readid2, readname2);
00286 }
00287 if (chipinfo && (strcmp(chipname1, chipname2) || strcmp(chipid1, chipid2))) {
00288 cpl_msg_warning(__func__, "CHIP information (ESO.DET.CHIP.{NAME,ID,DATE}) "
00289 "does not match for \"%s\" (%s, %s) and \"%s\" (%s, %s)",
00290 fn1, chipname1, chipid1, fn2, chipname2, chipid2);
00291 }
00292
00293 return CPL_ERROR_NONE;
00294 }
00295
00296
00311
00312 static cpl_error_code
00313 muse_basicproc_overscans_compute_stats(muse_imagelist *aList,
00314 muse_basicproc_params *aBPars)
00315 {
00316 cpl_ensure_code(aList, CPL_ERROR_NULL_INPUT);
00317 unsigned int k;
00318 for (k = 0; k < aList->size; k++) {
00319 muse_image *image = muse_imagelist_get(aList, k);
00320 if (muse_quadrants_overscan_stats(image, aBPars ? aBPars->rejection : NULL,
00321 aBPars ? aBPars->ovscignore : 0)
00322 != CPL_ERROR_NONE) {
00323 cpl_msg_warning(__func__, "Could not compute overscan statistics in IFU "
00324 "%hhu of exposure %u: %s", muse_utils_get_ifu(image->header),
00325 k+1, cpl_error_get_message());
00326 }
00327 }
00328 return CPL_ERROR_NONE;
00329 }
00330
00331
00344
00345 static cpl_error_code
00346 muse_basicproc_correct_overscans_vpoly(muse_imagelist *aList,
00347 muse_basicproc_params *aBPars)
00348 {
00349 cpl_ensure_code(aList, CPL_ERROR_NULL_INPUT);
00350 cpl_boolean ovscvpoly = aBPars && aBPars->overscan
00351 && !strncmp(aBPars->overscan, "vpoly", 5);
00352 if (!ovscvpoly) {
00353 cpl_msg_debug(__func__, "not vpoly: %s!", aBPars ? aBPars->overscan : "");
00354 return CPL_ERROR_NONE;
00355 }
00356
00357 unsigned char ovscvorder = 5;
00358 double frms = 1.01,
00359 fchisq = 1.04;
00360 char *rest = strchr(aBPars->overscan, ':');
00361 if (strlen(aBPars->overscan) > 6 && rest++) {
00362 ovscvorder = strtol(rest, &rest, 10);
00363 if (strlen(rest++) > 0) {
00364 frms = strtod(rest, &rest);
00365 if (strlen(rest++) > 0) {
00366 fchisq = strtod(rest, &rest);
00367 }
00368 }
00369 }
00370 cpl_msg_debug(__func__, "vpoly: %s (vorder=%hhu, frms=%f, fchisq=%f, ignore=%u,"
00371 " sigma=%.3f)", aBPars->overscan, ovscvorder, frms, fchisq,
00372 aBPars->ovscignore, aBPars->ovscsigma);
00373
00374 cpl_error_code rc = CPL_ERROR_NONE;
00375 unsigned int k;
00376 for (k = 0; k < aList->size; k++) {
00377 muse_image *image = muse_imagelist_get(aList, k);
00378 rc = muse_quadrants_overscan_polyfit_vertical(image, aBPars->ovscignore,
00379 ovscvorder, aBPars->ovscsigma,
00380 frms, fchisq);
00381 if (rc != CPL_ERROR_NONE) {
00382 unsigned char ifu = muse_utils_get_ifu(image->header);
00383 cpl_msg_error(__func__, "Could not correct quadrants levels using vertical"
00384 " overscan fit in IFU %hhu: %s", ifu, cpl_error_get_message());
00385 }
00386 }
00387 return rc;
00388 }
00389
00390
00404
00405 static cpl_error_code
00406 muse_basicproc_trim_images(muse_imagelist *aList)
00407 {
00408 cpl_ensure_code(aList, CPL_ERROR_NULL_INPUT);
00409
00410 unsigned int k;
00411 for (k = 0; k < aList->size; k++) {
00412 muse_image *image = muse_imagelist_get(aList, k);
00413 muse_image *trimmed = muse_quadrants_trim_image(image);
00414 cpl_ensure_code(trimmed, cpl_error_get_code());
00415
00416
00417 muse_imagelist_set(aList, trimmed, k);
00418 }
00419 return muse_imagelist_is_uniform(aList) == 0 ? CPL_ERROR_NONE
00420 : CPL_ERROR_ILLEGAL_OUTPUT;
00421 }
00422
00423
00441
00442 static cpl_error_code
00443 muse_basicproc_correct_overscans_offset(muse_imagelist *aList,
00444 muse_processing *aProcessing,
00445 muse_basicproc_params *aBPars)
00446 {
00447 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
00448
00449 if (!muse_processing_check_intags(aProcessing, MUSE_TAG_BIAS, 5)) {
00450 return CPL_ERROR_NONE;
00451 }
00452 cpl_boolean ovscoffset = aBPars && aBPars->overscan
00453 && !strncmp(aBPars->overscan, "offset", 7);
00454 if (!ovscoffset) {
00455 return CPL_ERROR_NONE;
00456 }
00457 unsigned char ifu = muse_utils_get_ifu(muse_imagelist_get(aList, 0)->header);
00458 cpl_msg_info(__func__, "Running overscan correction using %u %s images in IFU"
00459 " %hhu", aList->size, MUSE_TAG_BIAS, ifu);
00460 muse_image *ref = muse_imagelist_get(aList, 0);
00461 unsigned int k;
00462 for (k = 1; k < aList->size; k++) {
00463 muse_quadrants_overscan_correct(ref, muse_imagelist_get(aList, k));
00464 }
00465 return CPL_ERROR_NONE;
00466 }
00467
00468
00493
00494 static cpl_error_code
00495 muse_basicproc_check_overscans(muse_imagelist *aList,
00496 muse_processing *aProcessing,
00497 muse_basicproc_params *aBPars)
00498 {
00499 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
00500
00501
00502 if (!muse_processing_check_intags(aProcessing, MUSE_TAG_BIAS, 5)) {
00503 return CPL_ERROR_NONE;
00504 }
00505 if (aList->size < 2) {
00506 return CPL_ERROR_NONE;
00507 }
00508 cpl_boolean ovscnone = aBPars && aBPars->overscan
00509 && !strncmp(aBPars->overscan, "none", 5);
00510 if (!ovscnone) {
00511 return CPL_ERROR_NONE;
00512 }
00513 double sigma = aBPars ? aBPars->ovscsigma : 1.;
00514
00515
00516 muse_image *refimage = muse_imagelist_get(aList, 0);
00517 cpl_propertylist *refheader = refimage->header;
00518 cpl_error_code rc = CPL_ERROR_NONE;
00519 unsigned char n, ifu = muse_utils_get_ifu(refheader);
00520 for (n = 1; n <= 4; n++) {
00521
00522 char *keywordmean = cpl_sprintf(MUSE_HDR_OVSC_MEAN, n),
00523 *keywordstdev = cpl_sprintf(MUSE_HDR_OVSC_STDEV, n);
00524
00525
00526 const char *reffn = cpl_propertylist_get_string(refheader, MUSE_HDR_TMP_FN);
00527 float refmean = cpl_propertylist_get_float(refheader, keywordmean),
00528 refstdev = cpl_propertylist_get_float(refheader, keywordstdev),
00529 hilimit = refmean + sigma * refstdev,
00530 lolimit = refmean - sigma * refstdev;
00531
00532 double summean = refmean,
00533 sumstdev = pow(refstdev, 2.);
00534
00535
00536 unsigned int k;
00537 for (k = 1; k < aList->size; k++) {
00538 cpl_propertylist *h = muse_imagelist_get(aList, k)->header;
00539 float mean = cpl_propertylist_get_float(h, keywordmean),
00540 stdev = cpl_propertylist_get_float(h, keywordstdev);
00541 summean += mean;
00542 sumstdev += pow(stdev, 2.) + pow(mean - refmean, 2.);
00543 const char *fn = cpl_propertylist_get_string(h, MUSE_HDR_TMP_FN);
00544 if (mean > hilimit || mean < lolimit) {
00545 cpl_msg_error(__func__, "Overscan of IFU %hhu, quadrant %1hhu of image %u [%s] "
00546 "(%.3f+/-%.3f) differs from first image [%s] (%.3f+/-%.3f)!",
00547 ifu, n, k+1, fn, mean, stdev, reffn, refmean, refstdev);
00548 rc = cpl_error_set(__func__, CPL_ERROR_INCOMPATIBLE_INPUT);
00549 continue;
00550 }
00551 cpl_msg_debug(__func__, "Overscan of IFU %hhu, quadrant %1hhu of image %u [%s] "
00552 "%.3f+/-%.3f (first image [%s] %.3f+/-%.3f)",
00553 ifu, n, k+1, fn, mean, stdev, reffn, refmean, refstdev);
00554 }
00555
00556
00557
00558 summean /= aList->size;
00559 sumstdev = sqrt(sumstdev) / aList->size;
00560 cpl_msg_debug(__func__, "Averaged overscan values in IFU %hhu, quadrant %1hhu: "
00561 "%.3f +/- %.3f (%d images)", ifu, n, summean, sumstdev, aList->size);
00562 cpl_propertylist_update_float(refheader, keywordmean, summean);
00563 cpl_propertylist_update_float(refheader, keywordstdev, sumstdev);
00564
00565 cpl_free(keywordmean);
00566 cpl_free(keywordstdev);
00567 }
00568
00569 return rc;
00570 }
00571
00572
00590
00591 static cpl_error_code
00592 muse_basicproc_apply_badpix(muse_imagelist *aList, muse_processing *aProcessing,
00593 unsigned char aIFU)
00594 {
00595 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
00596 cpl_table *table = muse_table_load(aProcessing, MUSE_TAG_BADPIX_TABLE, aIFU);
00597 if (table == NULL) {
00598 return CPL_ERROR_NONE;
00599 }
00600 cpl_error_code rc = muse_cpltable_check(table, muse_badpix_table_def);
00601 if (rc != CPL_ERROR_NONE) {
00602 cpl_table_delete(table);
00603 return CPL_ERROR_INCOMPATIBLE_INPUT;
00604 }
00605
00606 int nrow = cpl_table_get_nrow(table);
00607 unsigned int k, nbadpix = 0,
00608 nbadpos = 0;
00609 for (k = 0; k < aList->size && rc == CPL_ERROR_NONE; k++) {
00610 muse_image *image = muse_imagelist_get(aList, k);
00611
00612 int i;
00613 for (i = 0; i < nrow; i++) {
00614 int x = cpl_table_get(table, MUSE_BADPIX_X, i, NULL),
00615 y = cpl_table_get(table, MUSE_BADPIX_Y, i, NULL);
00616
00617
00618
00619 uint32_t dq = cpl_table_get(table, MUSE_BADPIX_DQ, i, NULL);
00620 cpl_errorstate state = cpl_errorstate_get();
00621 int err;
00622 uint32_t value = cpl_image_get(image->dq, x, y, &err);
00623 if (err != 0 || !cpl_errorstate_is_equal(state)) {
00624 cpl_errorstate_set(state);
00625 if (k == 0) {
00626 nbadpos++;
00627 }
00628 continue;
00629 }
00630
00631
00632 rc = cpl_image_set(image->dq, x, y, dq | value);
00633 if (k == 0) {
00634 nbadpix++;
00635 }
00636 }
00637 }
00638 cpl_table_delete(table);
00639 cpl_msg_debug(__func__, "Applied %u bad pixels from %s in IFU %hhu.", nbadpix,
00640 MUSE_TAG_BADPIX_TABLE, aIFU);
00641
00642 if (nbadpos > 0) {
00643 cpl_msg_warning(__func__, "%s contained %u entries outside the CCD in IFU "
00644 "%hhu!", MUSE_TAG_BADPIX_TABLE, nbadpos, aIFU);
00645 }
00646 return rc;
00647 }
00648
00649
00658
00659 static cpl_error_code
00660 muse_basicproc_check_saturation(muse_imagelist *aList)
00661 {
00662 cpl_ensure_code(aList, CPL_ERROR_NULL_INPUT);
00663 unsigned int k;
00664 for (k = 0; k < aList->size; k++) {
00665 muse_image *image = muse_imagelist_get(aList, k);
00666 unsigned char ifu = muse_utils_get_ifu(image->header);
00667 int nsaturated = muse_quality_set_saturated(image);
00668
00669 int npix = cpl_image_get_size_x(image->data)
00670 * cpl_image_get_size_y(image->data);
00671 if (nsaturated > (0.01 * npix)) {
00672 const char *fn = cpl_propertylist_get_string(image->header,
00673 MUSE_HDR_TMP_FN);
00674 cpl_msg_error(__func__, "Raw exposure %u [%s] is strongly saturated in "
00675 "IFU %hhu (%d of %d pixels)!", k+1, fn, ifu, nsaturated,
00676 npix);
00677 } else if (nsaturated > (0.001 * npix)) {
00678 const char *fn = cpl_propertylist_get_string(image->header,
00679 MUSE_HDR_TMP_FN);
00680 cpl_msg_warning(__func__, "Raw exposure %u [%s] is probably saturated in "
00681 "IFU %hhu (%d of %d pixels)!", k+1, fn, ifu, nsaturated,
00682 npix);
00683 } else {
00684 cpl_msg_debug(__func__, "Raw exposure %u in IFU %hhu (%d of %d pixels "
00685 "saturated)!", k+1, ifu, nsaturated, npix);
00686 }
00687 cpl_propertylist_update_int(image->header, MUSE_HDR_TMP_NSAT, nsaturated);
00688 }
00689 return CPL_ERROR_NONE;
00690 }
00691
00692
00705
00706 static cpl_error_code
00707 muse_basicproc_quadrant_statistics(muse_imagelist *aList,
00708 muse_processing *aProcessing)
00709 {
00710 cpl_ensure_code(aList, CPL_ERROR_NULL_INPUT);
00711
00712 if (!muse_processing_check_intags(aProcessing, MUSE_TAG_BIAS, 5)) {
00713 return CPL_ERROR_NONE;
00714 }
00715 unsigned char ifu = muse_utils_get_ifu(muse_imagelist_get(aList, 0)->header);
00716 cpl_msg_info(__func__, "Computing per-quadrant medians for %u exposures in "
00717 "IFU %hhu", aList->size, ifu);
00718 unsigned int k;
00719 for (k = 0; k < aList->size; k++) {
00720 muse_image *image = muse_imagelist_get(aList, k);
00721 unsigned char n;
00722 for (n = 1; n <= 4; n++) {
00723 cpl_size *w = muse_quadrants_get_window(muse_imagelist_get(aList, k), n);
00724 float median = cpl_image_get_median_window(image->data, w[0], w[2],
00725 w[1], w[3]);
00726 cpl_free(w);
00727 char *kw = cpl_sprintf(MUSE_HDR_TMP_QUADnMED, n);
00728 cpl_propertylist_append_float(image->header, kw, median);
00729 cpl_free(kw);
00730 }
00731 }
00732 return CPL_ERROR_NONE;
00733 }
00734
00735
00757
00758 static cpl_error_code
00759 muse_basicproc_apply_bias(muse_imagelist *aList, muse_processing *aProcessing,
00760 unsigned char aIFU, muse_basicproc_params *aBPars)
00761 {
00762 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
00763 cpl_frame *biasframe = muse_frameset_find_master(aProcessing->inframes,
00764 MUSE_TAG_MASTER_BIAS, aIFU);
00765 cpl_errorstate prestate = cpl_errorstate_get();
00766 if (!biasframe) return CPL_ERROR_NONE;
00767 cpl_errorstate_set(prestate);
00768 const char *biasname = cpl_frame_get_filename(biasframe);
00769 muse_image *biasimage = muse_image_load(biasname);
00770 if (!biasimage) {
00771
00772
00773 char *errmsg = cpl_strdup(cpl_error_get_message());
00774 cpl_errorstate_set(prestate);
00775 biasimage = muse_image_load_from_extensions(biasname, aIFU);
00776 if (!biasimage) {
00777
00778
00779 cpl_msg_error(__func__, "%s", errmsg);
00780 cpl_msg_error(__func__, "%s", cpl_error_get_message());
00781 cpl_free(errmsg);
00782 cpl_frame_delete(biasframe);
00783 return cpl_error_get_code();
00784 }
00785 cpl_free(errmsg);
00786 cpl_msg_info(__func__, "Bias correction in IFU %hhu using \"%s[CHAN%02hhu."
00787 "DATA]\"", aIFU, biasname, aIFU);
00788 } else {
00789 cpl_msg_info(__func__, "Bias correction in IFU %hhu using \"%s[DATA]\"",
00790 aIFU, biasname);
00791 }
00792
00793 cpl_propertylist_append_string(biasimage->header, MUSE_HDR_TMP_FN, biasname);
00794
00795
00796 muse_basicproc_params *mbpars
00797 = muse_basicproc_params_new_from_propertylist(biasimage->header);
00798 cpl_boolean parmatch = mbpars && aBPars;
00799 if (parmatch) {
00800 parmatch = parmatch && mbpars->overscan && aBPars->overscan
00801 && !strncmp(aBPars->overscan, mbpars->overscan,
00802 CPL_MIN(strlen(aBPars->overscan), strlen(mbpars->overscan) + 1));
00803 parmatch = parmatch && mbpars->rejection && aBPars->rejection
00804 && !strncmp(aBPars->rejection, mbpars->rejection,
00805 CPL_MIN(strlen(aBPars->rejection), strlen(mbpars->rejection) + 1));
00806 parmatch = parmatch && fabs(aBPars->ovscsigma - mbpars->ovscsigma)
00807 < 10 * DBL_EPSILON;
00808 parmatch = parmatch && aBPars->ovscignore == mbpars->ovscignore;
00809 }
00810 if (!parmatch) {
00811 cpl_msg_warning(__func__, "overscan parameters differ between %s and recipe"
00812 " parameters!", MUSE_TAG_MASTER_BIAS);
00813 } else {
00814 cpl_msg_debug(__func__, "overscan parameters between %s and given "
00815 "parameters nicely match", MUSE_TAG_MASTER_BIAS);
00816 }
00817 muse_basicproc_params_delete(mbpars);
00818
00819 cpl_boolean ovscoffset = aBPars && aBPars->overscan
00820 && !strncmp(aBPars->overscan, "offset", 7),
00821 ovscvpoly = aBPars && aBPars->overscan
00822 && !strncmp(aBPars->overscan, "vpoly", 5);
00823 muse_processing_append_used(aProcessing, biasframe, CPL_FRAME_GROUP_CALIB, 0);
00824 cpl_error_code rc = CPL_ERROR_NONE;
00825 unsigned int k;
00826 for (k = 0; k < aList->size && rc == CPL_ERROR_NONE; k++) {
00827 muse_image *image = muse_imagelist_get(aList, k);
00828 rc = muse_basicproc_verify_setup(image, biasimage);
00829 if (rc != CPL_ERROR_NONE) {
00830 break;
00831 }
00832 rc = muse_image_variance_create(image, biasimage);
00833 if (ovscoffset) {
00834 muse_quadrants_overscan_correct(image, biasimage);
00835 } else if (ovscvpoly) {
00836
00837
00838
00839 cpl_boolean good = muse_quadrants_overscan_check(image, biasimage, 100.);
00840 if (!good) {
00841 cpl_msg_error(__func__, "Very different overscan levels found between "
00842 "%s and raw exposure %u in IFU %hhu: incompatible overscan"
00843 " parameters?", MUSE_TAG_MASTER_BIAS, k + 1, aIFU);
00844 rc = cpl_error_set(__func__, CPL_ERROR_INCOMPATIBLE_INPUT);
00845 break;
00846 }
00847 } else {
00848
00849 muse_quadrants_overscan_check(image, biasimage,
00850 aBPars ? aBPars->ovscsigma : 1.);
00851 }
00852 rc = muse_image_subtract(image, biasimage);
00853 #if GENERATE_TEST_IMAGES
00854
00855
00856 if (k == 0) {
00857 muse_image_save(image, "trimmed_bias_sub.fits");
00858 }
00859 #endif
00860 }
00861 muse_image_delete(biasimage);
00862 return rc;
00863 }
00864
00865
00884
00885 static cpl_error_code
00886 muse_basicproc_check_gain(muse_imagelist *aList, muse_processing *aProcessing,
00887 unsigned char aIFU)
00888 {
00889 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
00890
00891 if (!muse_processing_check_intags(aProcessing, MUSE_TAG_FLAT, 5)) {
00892 return CPL_ERROR_NONE;
00893 }
00894 cpl_ensure_code(muse_imagelist_get_size(aList) >= 2,
00895 CPL_ERROR_INCOMPATIBLE_INPUT);
00896
00897 cpl_frame *fbias = muse_frameset_find_master(aProcessing->inframes,
00898 MUSE_TAG_MASTER_BIAS, aIFU);
00899 if (!fbias) {
00900
00901 return CPL_ERROR_NONE;
00902 }
00903 const char *biasname = cpl_frame_get_filename(fbias);
00904 cpl_propertylist *hbias = cpl_propertylist_load(biasname, 0);
00905 if (!cpl_propertylist_has(hbias, QC_BIAS_MASTER_RON)) {
00906 cpl_propertylist_delete(hbias);
00907
00908 char *extname = cpl_sprintf("CHAN%02hhu.%s", aIFU, EXTNAME_DATA);
00909 int extension = cpl_fits_find_extension(biasname, extname);
00910 hbias = cpl_propertylist_load(biasname, extension);
00911 cpl_free(extname);
00912 }
00913 cpl_frame_delete(fbias);
00914 cpl_image *f1 = muse_imagelist_get(aList, 0)->data,
00915 *f2 = muse_imagelist_get(aList, 1)->data;
00916 cpl_propertylist *header = muse_imagelist_get(aList, 0)->header;
00917 cpl_image *diff = cpl_image_subtract_create(f1, f2);
00918
00919 unsigned char n;
00920 for (n = 1; n <= 4; n++) {
00921 cpl_size *w = muse_quadrants_get_window(muse_imagelist_get(aList, 0), n);
00922 double m1 = cpl_image_get_mean_window(f1, w[0], w[2], w[1], w[3]),
00923 m2 = cpl_image_get_mean_window(f2, w[0], w[2], w[1], w[3]),
00924 sf = cpl_image_get_stdev_window(diff, w[0], w[2], w[1], w[3]);
00925 char *keyword = cpl_sprintf(QC_BIAS_MASTERn_PREFIX" MEAN", n);
00926 float mb = cpl_propertylist_get_float(hbias, keyword);
00927 cpl_free(keyword);
00928 keyword = cpl_sprintf(QC_BIAS_MASTER_RON, n);
00929
00930 double gainheader = muse_pfits_get_gain(header, n),
00931 sb = cpl_propertylist_get_float(hbias, keyword) * sqrt(2.)
00932 / gainheader,
00933
00934 gain = (m1 + m2 - 2*mb) / (sf*sf - sb*sb),
00935 dgain = 1. - gain / gainheader;
00936
00937 if (dgain > 0.2) {
00938 cpl_msg_warning(__func__, "IFU %hhu, quadrant %1hhu: estimated gain %.3f "
00939 "count/adu but header gives %.3f!", aIFU, n, gain,
00940 gainheader);
00941 } else {
00942 cpl_msg_info(__func__, "IFU %hhu, quadrant %1hhu: estimated gain %.3f "
00943 "count/adu (header %.3f, delta %.3f)", aIFU, n, gain,
00944 gainheader, dgain);
00945 }
00946 cpl_free(keyword);
00947 cpl_free(w);
00948 }
00949
00950 cpl_image_delete(diff);
00951 cpl_propertylist_delete(hbias);
00952
00953 return CPL_ERROR_NONE;
00954 }
00955
00956
00975
00976 static cpl_error_code
00977 muse_basicproc_gain_override(muse_imagelist *aList,
00978 muse_processing *aProcessing, unsigned char aIFU)
00979 {
00980 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
00981
00982 if (muse_processing_check_intags(aProcessing, MUSE_TAG_LINEARITY_BIAS, 16) ||
00983 muse_processing_check_intags(aProcessing, MUSE_TAG_LINEARITY_FLAT, 15))
00984 {
00985 return CPL_ERROR_NONE;
00986 }
00987
00988 cpl_frame *fnonlingain = muse_frameset_find_master(aProcessing->inframes,
00989 MUSE_TAG_NONLINGAIN, aIFU);
00990 if (!fnonlingain) {
00991
00992 return CPL_ERROR_NONE;
00993 }
00994 if (getenv("MUSE_BASICPROC_SKIP_GAIN_OVERRIDE") &&
00995 atoi(getenv("MUSE_BASICPROC_SKIP_GAIN_OVERRIDE")) > 0) {
00996 cpl_msg_info(__func__, "Skipping gain override, although %s is given",
00997 MUSE_TAG_NONLINGAIN);
00998 return CPL_ERROR_NONE;
00999 }
01000 cpl_errorstate state = cpl_errorstate_get();
01001 const char *fn = cpl_frame_get_filename(fnonlingain);
01002
01003 char *extname = cpl_sprintf("CHAN%02hhu", aIFU);
01004 int extension = cpl_fits_find_extension(fn, extname);
01005 cpl_propertylist *header = cpl_propertylist_load(fn, extension);
01006 cpl_msg_info(__func__, "Overriding gain in IFU %hhu using \"%s[%s]\"",
01007 aIFU, fn, extname);
01008 cpl_free(extname);
01009 muse_processing_append_used(aProcessing, fnonlingain, CPL_FRAME_GROUP_CALIB, 0);
01010
01011 unsigned int k;
01012 for (k = 0; k < aList->size; k++) {
01013 muse_image *image = muse_imagelist_get(aList, k);
01014
01015 unsigned char n;
01016 for (n = 1; n <= 4; n++) {
01017
01018 double gain = muse_pfits_get_gain(header, n);
01019 char *kw = cpl_sprintf("ESO DET OUT%d GAIN", n);
01020 cpl_propertylist_update_double(image->header, kw, gain);
01021 cpl_free(kw);
01022 }
01023 }
01024 cpl_propertylist_delete(header);
01025 return cpl_errorstate_is_equal(state) ? CPL_ERROR_NONE : cpl_error_get_code();
01026 }
01027
01028
01042
01043 static cpl_error_code
01044 muse_basicproc_adu_to_count(muse_imagelist *aList, muse_processing *aProcessing)
01045 {
01046 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
01047
01048
01049 if (muse_processing_check_intags(aProcessing, MUSE_TAG_BIAS, 5) ||
01050 muse_processing_check_intags(aProcessing, MUSE_TAG_LINEARITY_BIAS, 16) ||
01051 muse_processing_check_intags(aProcessing, MUSE_TAG_LINEARITY_FLAT, 15)) {
01052 return CPL_ERROR_NONE;
01053 }
01054
01055 unsigned char ifu = muse_utils_get_ifu(muse_imagelist_get(aList, 0)->header);
01056 cpl_msg_info(__func__, "Converting %u exposures from adu to count (= electron)"
01057 " units in IFU %hhu", aList->size, ifu);
01058 cpl_error_code rc = CPL_ERROR_NONE;
01059 unsigned int k;
01060 for (k = 0; k < aList->size; k++) {
01061 rc = muse_image_adu_to_count(muse_imagelist_get(aList, k));
01062 }
01063 return rc;
01064 }
01065
01066
01088
01089 static cpl_error_code
01090 muse_basicproc_corr_nonlinearity(muse_imagelist *aList,
01091 muse_processing *aProcessing,
01092 unsigned char aIFU)
01093 {
01094 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
01095
01096
01097 if (muse_processing_check_intags(aProcessing, MUSE_TAG_BIAS, 5) ||
01098 muse_processing_check_intags(aProcessing, MUSE_TAG_DARK, 5) ||
01099 muse_processing_check_intags(aProcessing, MUSE_TAG_LINEARITY_BIAS, 16) ||
01100 muse_processing_check_intags(aProcessing, MUSE_TAG_LINEARITY_FLAT, 15)) {
01101 return CPL_ERROR_NONE;
01102 }
01103
01104 cpl_frame *fnonlingain = muse_frameset_find_master(aProcessing->inframes,
01105 MUSE_TAG_NONLINGAIN, aIFU);
01106 if (!fnonlingain) {
01107
01108 return CPL_ERROR_NONE;
01109 }
01110 if (getenv("MUSE_BASICPROC_SKIP_NONLIN_CORR") &&
01111 atoi(getenv("MUSE_BASICPROC_SKIP_NONLIN_CORR")) > 0) {
01112 cpl_msg_debug(__func__, "Skipping nonlinearity correction, although %s is "
01113 "given", MUSE_TAG_NONLINGAIN);
01114 return CPL_ERROR_NONE;
01115 }
01116 const char *fn = cpl_frame_get_filename(fnonlingain);
01117
01118 char *extname = cpl_sprintf("CHAN%02hhu", aIFU);
01119 int extension = cpl_fits_find_extension(fn, extname);
01120 cpl_propertylist *header = cpl_propertylist_load(fn, extension);
01121 cpl_msg_info(__func__, "Correcting nonlinearity in IFU %hhu using \"%s[%s]\"",
01122 aIFU, fn, extname);
01123 cpl_free(extname);
01124 muse_processing_append_used(aProcessing, fnonlingain, CPL_FRAME_GROUP_CALIB, 0);
01125
01126 cpl_error_code rc = CPL_ERROR_NONE;
01127 unsigned int k;
01128 for (k = 0; k < aList->size; k++) {
01129 muse_image *image = muse_imagelist_get(aList, k);
01130 int nx = cpl_image_get_size_x(image->data);
01131 float *data = cpl_image_get_data_float(image->data),
01132 *stat = cpl_image_get_data_float(image->stat);
01133
01134
01135
01136 unsigned char n;
01137 for (n = 1; n <= 4; n++) {
01138
01139
01140 cpl_polynomial *poly = cpl_polynomial_new(1);
01141 char *kw = cpl_sprintf(MUSE_HDR_NONLINn_ORDER, n);
01142 unsigned char o, order = cpl_propertylist_get_int(header, kw);
01143 cpl_free(kw);
01144 for (o = 0; o <= order; o++) {
01145 kw = cpl_sprintf(MUSE_HDR_NONLINn_COEFFo, n, o);
01146 cpl_size pows = o;
01147 cpl_polynomial_set_coeff(poly, &pows,
01148 cpl_propertylist_get_double(header, kw));
01149 cpl_free(kw);
01150 }
01151
01152 kw = cpl_sprintf(MUSE_HDR_NONLINn_LLO, n);
01153 double lolim = cpl_propertylist_get_double(header, kw);
01154 cpl_free(kw);
01155 kw = cpl_sprintf(MUSE_HDR_NONLINn_LHI, n);
01156 double hilim = cpl_propertylist_get_double(header, kw);
01157 cpl_free(kw);
01158
01159 double p1lo, p0lo = cpl_polynomial_eval_1d(poly, lolim, &p1lo),
01160 p1hi, p0hi = cpl_polynomial_eval_1d(poly, hilim, &p1hi);
01161
01162 lolim = pow(10, lolim);
01163 hilim = pow(10, hilim);
01164 #if 0
01165 double values[] = { 1., 20., 200., 2000., 20000., 65000.,
01166 lolim, hilim, -1. };
01167 int idx = 0;
01168 while (values[idx] > 0) {
01169 double v = values[idx],
01170 logv = log10(v);
01171 cpl_msg_debug(__func__, "%f adu -> %f log10(adu) ==> poly = %f ==> x %f",
01172 v, logv, cpl_polynomial_eval_1d(poly, logv, NULL),
01173 1. / (1. + cpl_polynomial_eval_1d(poly, logv, NULL)));
01174 idx++;
01175 }
01176 cpl_polynomial_dump(poly, stdout);
01177 fflush(stdout);
01178 cpl_msg_debug(__func__, "beyond low limit (%f adu): %f + (%f) * (log10(adu) - %f)",
01179 lolim, p0lo, p1lo, log10(lolim));
01180 cpl_msg_debug(__func__, "beyond high limit (%f adu): %f + (%f) * (log10(adu) - %f)",
01181 hilim, p0hi, p1hi, log10(hilim));
01182 #endif
01183
01184
01185 cpl_size *w = muse_quadrants_get_window(image, n);
01186 int i;
01187 for (i = w[0] - 1; i < w[1]; i++) {
01188 int j;
01189 for (j = w[2] - 1; j < w[3]; j++) {
01190 if (data[i + j*nx] <= 0) {
01191 continue;
01192 }
01193
01194 double pcor;
01195 if (data[i + j*nx] < lolim) {
01196 pcor = p0lo + p1lo * (log10(data[i + j*nx]) - log10(lolim));
01197 } else if (data[i + j*nx] > hilim) {
01198 pcor = p0hi + p1hi * (log10(data[i + j*nx]) - log10(hilim));
01199 } else {
01200 pcor = cpl_polynomial_eval_1d(poly, log10(data[i + j*nx]), NULL);
01201 }
01202
01203 double fcor = 1. / (1. + pcor);
01204 data[i + j*nx] *= fcor;
01205 stat[i + j*nx] *= fcor*fcor;
01206 }
01207 }
01208 cpl_free(w);
01209 cpl_polynomial_delete(poly);
01210 }
01211 }
01212 cpl_propertylist_delete(header);
01213
01214 return rc;
01215 }
01216
01217
01233
01234 static cpl_error_code
01235 muse_basicproc_apply_dark(muse_imagelist *aList, muse_processing *aProcessing,
01236 unsigned char aIFU)
01237 {
01238 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
01239
01240 cpl_frame *darkframe = muse_frameset_find_master(aProcessing->inframes,
01241 MUSE_TAG_MASTER_DARK, aIFU);
01242 cpl_errorstate prestate = cpl_errorstate_get();
01243 if (!darkframe) return CPL_ERROR_NONE;
01244 cpl_errorstate_set(prestate);
01245 const char *darkname = cpl_frame_get_filename(darkframe);
01246 muse_image *darkimage = muse_image_load(darkname);
01247 if (!darkimage) {
01248 char *errmsg = cpl_strdup(cpl_error_get_message());
01249 cpl_errorstate_set(prestate);
01250 darkimage = muse_image_load_from_extensions(darkname, aIFU);
01251 if (!darkimage) {
01252 cpl_msg_error(__func__, "%s", errmsg);
01253 cpl_msg_error(__func__, "%s", cpl_error_get_message());
01254 cpl_free(errmsg);
01255 cpl_frame_delete(darkframe);
01256 return cpl_error_get_code();
01257 }
01258 cpl_free(errmsg);
01259 cpl_msg_info(__func__, "Dark correction in IFU %hhu using \"%s[CHAN%02hhu."
01260 "DATA]\"", aIFU, darkname, aIFU);
01261 } else {
01262 cpl_msg_info(__func__, "Dark correction in IFU %hhu using \"%s[DATA]\"",
01263 aIFU, darkname);
01264 }
01265 cpl_propertylist_append_string(darkimage->header, MUSE_HDR_TMP_FN, darkname);
01266
01267 muse_processing_append_used(aProcessing, darkframe, CPL_FRAME_GROUP_CALIB, 0);
01268 cpl_error_code rc = CPL_ERROR_NONE;
01269 unsigned int k;
01270 for (k = 0; k < aList->size; k++) {
01271 muse_image *image = muse_imagelist_get(aList, k);
01272 rc = muse_basicproc_verify_setup(image, darkimage);
01273 if (rc != CPL_ERROR_NONE) {
01274 break;
01275 }
01276
01277
01278 muse_image *dark = muse_image_duplicate(darkimage);
01279
01280
01281 double scale = muse_pfits_get_exptime(image->header);
01282 if (muse_pfits_get_exptime(dark->header) > 0) {
01283 scale /= muse_pfits_get_exptime(dark->header);
01284 }
01285 rc = muse_image_scale(dark, scale);
01286 rc = muse_image_subtract(image, dark);
01287
01288 muse_image_delete(dark);
01289 }
01290 muse_image_delete(darkimage);
01291
01292 return rc;
01293 }
01294
01295
01310
01311 static cpl_error_code
01312 muse_basicproc_apply_cr(muse_imagelist *aList,
01313 muse_basicproc_params *aBPars)
01314 {
01315 cpl_ensure_code(aList, CPL_ERROR_NULL_INPUT);
01316
01317
01318
01319 cpl_boolean isdcr = aBPars && aBPars->crmethod
01320 && !strncmp(aBPars->crmethod, "dcr", 4);
01321 if (!isdcr) {
01322 return CPL_ERROR_NONE;
01323 }
01324
01325 cpl_error_code rc = CPL_ERROR_NONE;
01326 unsigned int k;
01327 for (k = 0; k < aList->size; k++) {
01328 muse_image *image = muse_imagelist_get(aList, k);
01329 unsigned char ifu = muse_utils_get_ifu(image->header);
01330 int ncr = 0;
01331 ncr = muse_cosmics_dcr(image, aBPars->dcrxbox, aBPars->dcrybox,
01332 aBPars->dcrpasses, aBPars->dcrthres);
01333 if (ncr <= 0) {
01334 cpl_msg_error(__func__, "Cosmic ray rejection using DCR in IFU %hhu failed"
01335 " for image %u (ncr = %d): %s", ifu, k+1, ncr,
01336 cpl_error_get_message());
01337 rc = cpl_error_get_code();
01338 } else {
01339 cpl_msg_info(__func__, "Cosmic ray rejection using DCR in IFU %hhu found "
01340 "%d affected pixels in image %u", ifu, ncr, k+1);
01341 }
01342 }
01343
01344 return rc;
01345 }
01346
01347
01362
01363 static cpl_error_code
01364 muse_basicproc_apply_flat(muse_imagelist *aList, muse_processing *aProcessing,
01365 unsigned char aIFU)
01366 {
01367 cpl_ensure_code(aList && aProcessing, CPL_ERROR_NULL_INPUT);
01368
01369 cpl_frame *flatframe = muse_frameset_find_master(aProcessing->inframes,
01370 MUSE_TAG_MASTER_FLAT, aIFU);
01371 cpl_errorstate prestate = cpl_errorstate_get();
01372 if (!flatframe) return CPL_ERROR_NONE;
01373 cpl_errorstate_set(prestate);
01374 const char *flatname = cpl_frame_get_filename(flatframe);
01375 prestate = cpl_errorstate_get();
01376 muse_image *flatimage = muse_image_load(flatname);
01377 if (!flatimage) {
01378 char *errmsg = cpl_strdup(cpl_error_get_message());
01379 cpl_errorstate_set(prestate);
01380 flatimage = muse_image_load_from_extensions(flatname, aIFU);
01381 if (!flatimage) {
01382 cpl_msg_error(__func__, "%s", errmsg);
01383 cpl_msg_error(__func__, "%s", cpl_error_get_message());
01384 cpl_free(errmsg);
01385 cpl_frame_delete(flatframe);
01386 return cpl_error_get_code();
01387 }
01388 cpl_free(errmsg);
01389 cpl_msg_info(__func__, "Flat-field correction in IFU %hhu using \"%s[CHAN%02hhu."
01390 "DATA]\"", aIFU, flatname, aIFU);
01391 } else {
01392 cpl_msg_info(__func__, "Flat-field correction in IFU %hhu using \"%s[DATA]\"",
01393 aIFU, flatname);
01394 }
01395
01396 double fflux = cpl_propertylist_get_double(flatimage->header,
01397 QC_FLAT_MASTER_INTFLUX);
01398 cpl_propertylist_append_string(flatimage->header, MUSE_HDR_TMP_FN, flatname);
01399 muse_processing_append_used(aProcessing, flatframe, CPL_FRAME_GROUP_CALIB, 0);
01400
01401 cpl_error_code rc = CPL_ERROR_NONE;
01402 unsigned int k;
01403 for (k = 0; k < aList->size; k++) {
01404 cpl_msg_debug(__func__, "Flat-field division in IFU %hhu of image %u of %u",
01405 aIFU, k+1, aList->size);
01406 muse_image *image = muse_imagelist_get(aList, k);
01407 rc = muse_basicproc_verify_setup(image, flatimage);
01408 if (rc != CPL_ERROR_NONE) {
01409 break;
01410 }
01411 rc = muse_image_divide(image, flatimage);
01412 cpl_propertylist_update_double(image->header, MUSE_HDR_FLAT_FLUX_LAMP, fflux);
01413 }
01414
01415 muse_image_delete(flatimage);
01416 return rc;
01417 }
01418
01419
01440
01441 static muse_imagelist *
01442 muse_basicproc_load_raw(muse_processing *aProcessing, unsigned char aIFU)
01443 {
01444 cpl_ensure(aProcessing, CPL_ERROR_NULL_INPUT, NULL);
01445
01446
01447 cpl_frameset *rawframes = muse_frameset_check_raw(aProcessing->inframes,
01448 aProcessing->intags, aIFU);
01449 cpl_ensure(rawframes, CPL_ERROR_NULL_INPUT, NULL);
01450
01451 muse_imagelist *images = muse_imagelist_new();
01452 unsigned int k = 0;
01453 cpl_size iframe, nframes = cpl_frameset_get_size(rawframes);
01454 for (iframe = 0; iframe < nframes; iframe++) {
01455 cpl_frame *frame = cpl_frameset_get_position(rawframes, iframe);
01456 const char *fileName = cpl_frame_get_filename(frame);
01457 int extension = muse_utils_get_extension_for_ifu(fileName, aIFU);
01458 if (extension == -1) {
01459 cpl_msg_error(__func__, "\"%s\" does not contain data from IFU %hhu",
01460 fileName, aIFU);
01461 break;
01462 }
01463 muse_image *raw = muse_image_load_from_raw(fileName, extension);
01464 if (!raw) {
01465 continue;
01466 }
01467
01468 cpl_propertylist_append_string(raw->header, MUSE_HDR_TMP_FN, fileName);
01469
01470 cpl_propertylist_append_string(raw->header, MUSE_HDR_TMP_INTAG,
01471 cpl_frame_get_tag(frame));
01472
01473 muse_imagelist_set(images, raw, k);
01474 muse_processing_append_used(aProcessing, frame, CPL_FRAME_GROUP_RAW, 1);
01475 k++;
01476 }
01477 cpl_frameset_delete(rawframes);
01478
01479
01480 if (!images->size) {
01481 if ((int)cpl_error_get_code() != MUSE_ERROR_CHIP_NOT_LIVE) {
01482 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_OUTPUT);
01483 cpl_msg_error(__func__, "No raw images loaded for IFU %hhu", aIFU);
01484 }
01485 muse_imagelist_delete(images);
01486 return NULL;
01487 }
01488 if (muse_imagelist_is_uniform(images) != 0) {
01489 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_OUTPUT);
01490 cpl_msg_error(__func__, "Non-uniform imagelist for IFU %hhu", aIFU);
01491 muse_imagelist_delete(images);
01492 return NULL;
01493 }
01494
01495 return images;
01496 }
01497
01498
01541
01542 muse_imagelist *
01543 muse_basicproc_load(muse_processing *aProcessing, unsigned char aIFU,
01544 muse_basicproc_params *aBPars)
01545 {
01546 if (muse_processing_check_input(aProcessing, aIFU) != CPL_ERROR_NONE) {
01547 return NULL;
01548 }
01549 muse_imagelist *images = muse_basicproc_load_raw(aProcessing, aIFU);
01550 if (!images) {
01551 return NULL;
01552 }
01553 cpl_errorstate prestate = cpl_errorstate_get();
01554 if (muse_basicproc_apply_badpix(images, aProcessing, aIFU) != CPL_ERROR_NONE) {
01555 cpl_msg_warning(__func__, "Applying bad pixel table to IFU %hhu failed: %s",
01556 aIFU, cpl_error_get_message());
01557 cpl_errorstate_set(prestate);
01558 }
01559 if (muse_basicproc_check_saturation(images) != CPL_ERROR_NONE) {
01560 muse_imagelist_delete(images);
01561 return NULL;
01562 }
01563 muse_basicproc_quadrant_statistics(images, aProcessing);
01564 if (muse_basicproc_overscans_compute_stats(images, aBPars)
01565 != CPL_ERROR_NONE) {
01566 muse_imagelist_delete(images);
01567 return NULL;
01568 }
01569 if (muse_basicproc_correct_overscans_vpoly(images, aBPars)
01570 != CPL_ERROR_NONE) {
01571 muse_imagelist_delete(images);
01572 return NULL;
01573 }
01574 if (muse_basicproc_trim_images(images) != CPL_ERROR_NONE) {
01575 muse_imagelist_delete(images);
01576 return NULL;
01577 }
01578 if (muse_basicproc_correct_overscans_offset(images, aProcessing, aBPars)
01579 != CPL_ERROR_NONE) {
01580 cpl_msg_warning(__func__, "Bias-level correction using overscans failed in "
01581 "IFU %hhu: %s", aIFU, cpl_error_get_message());
01582 }
01583 if (muse_basicproc_check_overscans(images, aProcessing, aBPars)
01584 != CPL_ERROR_NONE) {
01585 muse_imagelist_delete(images);
01586 return NULL;
01587 }
01588 muse_basicproc_gain_override(images, aProcessing, aIFU);
01589 muse_basicproc_check_gain(images, aProcessing, aIFU);
01590 if (muse_basicproc_apply_bias(images, aProcessing, aIFU, aBPars)
01591 != CPL_ERROR_NONE) {
01592 muse_imagelist_delete(images);
01593 return NULL;
01594 }
01595 if (muse_basicproc_corr_nonlinearity(images, aProcessing, aIFU) != CPL_ERROR_NONE) {
01596 muse_imagelist_delete(images);
01597 return NULL;
01598 }
01599 if (muse_basicproc_adu_to_count(images, aProcessing) != CPL_ERROR_NONE) {
01600 muse_imagelist_delete(images);
01601 return NULL;
01602 }
01603 if (muse_basicproc_apply_dark(images, aProcessing, aIFU) != CPL_ERROR_NONE) {
01604 muse_imagelist_delete(images);
01605 return NULL;
01606 }
01607 if (muse_basicproc_apply_cr(images, aBPars) != CPL_ERROR_NONE) {
01608 muse_imagelist_delete(images);
01609 return NULL;
01610 }
01611 if (muse_basicproc_apply_flat(images, aProcessing, aIFU) != CPL_ERROR_NONE) {
01612 muse_imagelist_delete(images);
01613 return NULL;
01614 }
01615 return images;
01616 }
01617
01618
01631
01632 muse_imagelist *
01633 muse_basicproc_load_reduced(muse_processing *aProcessing, unsigned char aIFU)
01634 {
01635 muse_imagelist *images = muse_imagelist_new();
01636 cpl_frameset *redframes = muse_frameset_find_tags(aProcessing->inframes,
01637 aProcessing->intags,
01638 aIFU, CPL_FALSE);
01639 cpl_size iframe, nframes = cpl_frameset_get_size(redframes);
01640 for (iframe = 0; iframe < nframes; iframe++) {
01641 cpl_frame *frame = cpl_frameset_get_position(redframes, iframe);
01642 cpl_errorstate prestate = cpl_errorstate_get();
01643 const char *imagename = cpl_frame_get_filename(frame);
01644 muse_image *image = muse_image_load(imagename);
01645 if (!image) {
01646 cpl_errorstate_set(prestate);
01647 image = muse_image_load_from_extensions(imagename, aIFU);
01648 }
01649 muse_imagelist_set(images, image, iframe);
01650 muse_processing_append_used(aProcessing, frame, CPL_FRAME_GROUP_RAW, 1);
01651 }
01652 cpl_frameset_delete(redframes);
01653 return images;
01654 }
01655
01656
01671
01672 static cpl_table *
01673 muse_basicproc_prepare_illum(muse_pixtable *aPT)
01674 {
01675 cpl_ensure(aPT && aPT->header && aPT->table,
01676 CPL_ERROR_NULL_INPUT, NULL);
01677
01678
01679
01680 muse_pixtable_restrict_wavelength(aPT, 6500., 7500.);
01681 muse_pixtable **pts = muse_pixtable_extracted_get_slices(aPT);
01682 int ipt, npt = muse_pixtable_extracted_get_size(pts);
01683
01684 unsigned char ifu = muse_utils_get_ifu(aPT->header);
01685 cpl_msg_info(__func__, "Preparing %s flat: %d slices in the data of IFU %hhu "
01686 "found.", MUSE_TAG_ILLUM, npt, ifu);
01687 cpl_table *tattached = cpl_table_new(npt);
01688 cpl_table_new_column(tattached, "slice", CPL_TYPE_INT);
01689 cpl_table_new_column(tattached, "fflat", CPL_TYPE_DOUBLE);
01690 for (ipt = 0; ipt < npt; ipt++) {
01691 uint32_t origin = cpl_table_get_int(pts[ipt]->table, MUSE_PIXTABLE_ORIGIN, 0, NULL);
01692 unsigned short slice = muse_pixtable_origin_get_slice(origin);
01693 double median = cpl_table_get_column_median(pts[ipt]->table,
01694 MUSE_PIXTABLE_DATA);
01695 cpl_msg_debug(__func__, "Found median of %f in slice %d of IFU %hhu "
01696 "of illum flat.", median, slice, ifu);
01697 cpl_table_set_int(tattached, "slice", ipt, slice);
01698 cpl_table_set_double(tattached, "fflat", ipt, 1. / median);
01699 }
01700 muse_pixtable_extracted_delete(pts);
01701
01702 double mean = cpl_table_get_column_mean(tattached, "fflat");
01703 cpl_msg_debug(__func__, "Normalizing whole illum-flat table if IFU %hhu to "
01704 "%e.", ifu, mean);
01705 cpl_table_multiply_scalar(tattached, "fflat", 1. / mean);
01706 cpl_table_set_column_format(tattached, "fflat", "%.6f");
01707 return tattached;
01708 }
01709
01710
01728
01729 cpl_table *
01730 muse_basicproc_get_illum(muse_imagelist *aImages, cpl_table *aTrace,
01731 cpl_table *aWave, cpl_table *aGeo)
01732 {
01733 cpl_ensure(aImages && aTrace && aWave && aGeo, CPL_ERROR_NULL_INPUT, NULL);
01734
01735 cpl_table *tattached = NULL;
01736 unsigned int k, nimages = muse_imagelist_get_size(aImages);
01737
01738 cpl_boolean *isillum = cpl_calloc(nimages, sizeof(cpl_boolean));
01739 for (k = 0; k < nimages; k++) {
01740 isillum[k] = CPL_FALSE;
01741 muse_image *image = muse_imagelist_get(aImages, k);
01742 const char *tag = cpl_propertylist_get_string(image->header,
01743 MUSE_HDR_TMP_INTAG);
01744 if (tag && !strncmp(tag, MUSE_TAG_ILLUM, strlen(MUSE_TAG_ILLUM) + 1)) {
01745 isillum[k] = CPL_TRUE;
01746
01747 if (cpl_propertylist_has(image->header, "ESO TPL ID")) {
01748 const char *tplid = cpl_propertylist_get_string(image->header,
01749 "ESO TPL ID"),
01750 *fn = cpl_propertylist_get_string(image->header,
01751 MUSE_HDR_TMP_FN),
01752 *tplatt = "MUSE_wfm_cal_specflatatt",
01753 *tplill = "MUSE_wfm_cal_illum";
01754 if (strncmp(tplid, tplatt, strlen(tplatt) + 1) &&
01755 strncmp(tplid, tplill, strlen(tplill) + 1)) {
01756 cpl_msg_warning(__func__, "%s input (\"%s\") was taken with neither"
01757 " %s nor %s template, but %s!", MUSE_TAG_ILLUM, fn,
01758 tplatt, tplill, tplid);
01759 } else {
01760 cpl_msg_debug(__func__, "%s input (\"%s\") was taken with template "
01761 "%s", MUSE_TAG_ILLUM, fn, tplid);
01762 }
01763 }
01764 }
01765 unsigned char ifu = muse_utils_get_ifu(image->header);
01766 if (isillum[k]) {
01767 if (tattached) {
01768 cpl_msg_warning(__func__, "Image %u of %u of IFU %hhu is illum flat, "
01769 "but not the first; not using it!", k + 1, nimages, ifu);
01770 continue;
01771 }
01772 cpl_msg_debug(__func__, "Image %u of %u of IFU %hhu is illum flat.",
01773 k + 1, nimages, ifu);
01774 muse_pixtable *pt = muse_pixtable_create(image, aTrace, aWave, aGeo);
01775 tattached = muse_basicproc_prepare_illum(pt);
01776 muse_pixtable_delete(pt);
01777 } else {
01778 cpl_msg_debug(__func__, "Image %u of %u of IFU %hhu is not an illum flat.",
01779 k + 1, nimages, ifu);
01780 }
01781 }
01782
01783
01784 unsigned int k2;
01785 for (k = 0, k2 = 0; k < nimages; k++) {
01786 if (isillum[k]) {
01787 muse_image *image = muse_imagelist_unset(aImages, k2);
01788 muse_image_delete(image);
01789 } else {
01790 k2++;
01791 }
01792 }
01793 cpl_free(isillum);
01794
01795 return tattached;
01796 }
01797
01798
01811
01812 cpl_error_code
01813 muse_basicproc_apply_illum(muse_pixtable *aPT, cpl_table *aAttached)
01814 {
01815 cpl_ensure_code(aPT && aPT->header && aPT->table && aAttached,
01816 CPL_ERROR_NULL_INPUT);
01817
01818 unsigned char ifu = muse_utils_get_ifu(aPT->header);
01819
01820 muse_pixtable **pts = muse_pixtable_extracted_get_slices(aPT);
01821 int ipt, npt = muse_pixtable_extracted_get_size(pts);
01822 cpl_msg_info(__func__, "Applying %s flat-field in IFU %hhu (%d slices)",
01823 MUSE_TAG_ILLUM, ifu, npt);
01824 cpl_array *afactors = cpl_array_new(npt, CPL_TYPE_DOUBLE);
01825 for (ipt = 0; ipt < npt; ipt++) {
01826 uint32_t origin = cpl_table_get_int(pts[ipt]->table, MUSE_PIXTABLE_ORIGIN, 0, NULL);
01827 unsigned short slice = muse_pixtable_origin_get_slice(origin),
01828 fslice = cpl_table_get_int(aAttached, "slice", ipt, NULL);
01829 int err;
01830 double fflat = cpl_table_get_double(aAttached, "fflat", ipt, &err);
01831 if (!err && slice == fslice) {
01832 cpl_table_multiply_scalar(pts[ipt]->table, MUSE_PIXTABLE_DATA, fflat);
01833 cpl_table_multiply_scalar(pts[ipt]->table, MUSE_PIXTABLE_STAT, fflat*fflat);
01834 cpl_array_set_double(afactors, ipt, fflat);
01835 char *kw = cpl_sprintf(MUSE_HDR_PT_ILLUMi, slice);
01836 cpl_propertylist_update_double(aPT->header, kw, fflat);
01837 cpl_free(kw);
01838 } else {
01839 cpl_msg_warning(__func__, "some error (%d) occurred when applying illum-"
01840 "flat correction to slice %hu/%hu of IFU %hhu: %s", err,
01841 slice, fslice, ifu, cpl_error_get_message());
01842 }
01843 }
01844 muse_pixtable_extracted_delete(pts);
01845 cpl_propertylist_update_double(aPT->header, MUSE_HDR_PT_ILLUM_MEAN,
01846 cpl_array_get_mean(afactors));
01847 cpl_propertylist_update_double(aPT->header, MUSE_HDR_PT_ILLUM_STDEV,
01848 cpl_array_get_stdev(afactors));
01849 cpl_array_delete(afactors);
01850 return CPL_ERROR_NONE;
01851 }
01852
01853
01870
01871 cpl_error_code
01872 muse_basicproc_apply_twilight(muse_pixtable *aPT, muse_datacube *aTwilight)
01873 {
01874 cpl_ensure_code(aPT && aPT->header && aPT->table && aTwilight,
01875 CPL_ERROR_NULL_INPUT);
01876
01877
01878
01879 unsigned char ifu = muse_utils_get_ifu(aPT->header);
01880
01881
01882 char *kw = cpl_sprintf(MUSE_HDR_FLAT_FLUX_SKY"%hhu", ifu);
01883 double flux = cpl_propertylist_get_double(aTwilight->header, kw);
01884 cpl_free(kw);
01885 cpl_propertylist_update_double(aPT->header, MUSE_HDR_FLAT_FLUX_SKY, flux);
01886
01887
01888 int nx = cpl_image_get_size_x(cpl_imagelist_get(aTwilight->data, 0)),
01889 ny = cpl_image_get_size_y(cpl_imagelist_get(aTwilight->data, 0)),
01890 nz = cpl_imagelist_get_size(aTwilight->data);
01891 cpl_msg_debug(__func__, "Working with %d planes in twilight cube", nz);
01892 double cd12 = muse_pfits_get_cd(aTwilight->header, 1, 2),
01893 cd21 = muse_pfits_get_cd(aTwilight->header, 2, 1);
01894 if (cd12 > DBL_EPSILON || cd21 > DBL_EPSILON) {
01895 cpl_msg_warning(__func__, "Twilight cube contains WCS cross-terms (CD1_2"
01896 "=%e, CD2_1=%e), results will be inaccurate!", cd12, cd21);
01897 }
01898
01899 double crval1 = muse_pfits_get_crval(aTwilight->header, 1),
01900 crpix1 = muse_pfits_get_crpix(aTwilight->header, 1),
01901 cd11 = muse_pfits_get_cd(aTwilight->header, 1, 1),
01902 crval2 = muse_pfits_get_crval(aTwilight->header, 2),
01903 crpix2 = muse_pfits_get_crpix(aTwilight->header, 2),
01904 cd22 = muse_pfits_get_cd(aTwilight->header, 2, 2),
01905 crval3 = muse_pfits_get_crval(aTwilight->header, 3),
01906 crpix3 = muse_pfits_get_crpix(aTwilight->header, 3),
01907 cd33 = muse_pfits_get_cd(aTwilight->header, 3, 3);
01908
01909
01910 float *data = cpl_table_get_data_float(aPT->table, MUSE_PIXTABLE_DATA),
01911 *stat = cpl_table_get_data_float(aPT->table, MUSE_PIXTABLE_STAT),
01912 *xpos = cpl_table_get_data_float(aPT->table, MUSE_PIXTABLE_XPOS),
01913 *ypos = cpl_table_get_data_float(aPT->table, MUSE_PIXTABLE_YPOS),
01914 *lbda = cpl_table_get_data_float(aPT->table, MUSE_PIXTABLE_LAMBDA);
01915 cpl_size irow, nrow = muse_pixtable_get_nrow(aPT),
01916 nfailed = 0;
01917 for (irow = 0; irow < nrow; irow++) {
01918
01919
01920 int x = lround((xpos[irow] - crval1) / cd11 + crpix1),
01921 y = lround((ypos[irow] - crval2) / cd22 + crpix2);
01922
01923 if (x < 1) {
01924 x = 1;
01925 }
01926 if (x > nx) {
01927 x = nx;
01928 }
01929 if (y < 1) {
01930 y = 1;
01931 }
01932 if (y > ny) {
01933 y = ny;
01934 }
01935 double z = (lbda[irow] - crval3) / cd33 + crpix3;
01936 #if 0
01937 cpl_msg_debug(__func__, "%"CPL_SIZE_FORMAT": %.3f %.3f %.3f => %d %d %.3f",
01938 irow, xpos[irow], ypos[irow], lbda[irow], x, y, z);
01939 #endif
01940
01941 int zp1 = floor(z) - 1,
01942 zp2 = ceil(z) - 1;
01943
01944 if (zp1 < 1) {
01945 zp1 = 0;
01946 }
01947 if (zp1 >= nz) {
01948 zp1 = nz - 1;
01949 }
01950 if (zp2< 1) {
01951 zp2 = 0;
01952 }
01953 if (zp2 >= nz) {
01954 zp2 = nz - 1;
01955 }
01956 int err1, err2;
01957 double v1 = cpl_image_get(cpl_imagelist_get(aTwilight->data, zp1),
01958 x, y, &err1),
01959 v2 = cpl_image_get(cpl_imagelist_get(aTwilight->data, zp2),
01960 x, y, &err2);
01961 double villum = 1.;
01962 double f = 1.;
01963
01964 if (err1 && err2) {
01965 nfailed++;
01966 continue;
01967 }
01968 if (zp1 == zp2) {
01969 villum = v1;
01970 } else if (err1) {
01971 villum = v2;
01972 } else if (err2) {
01973 villum = v1;
01974 } else {
01975 f = fabs(z - 1 - zp1);
01976 villum = v1 * (1. - f) + v2 * f;
01977 }
01978 double fillum = 1. / villum;
01979 #if 0
01980 cpl_msg_debug(__func__, "%d/%d, %f/%f -> %f -> %f => %f", zp1, zp2, v1, v2,
01981 f, villum, fillum);
01982 #endif
01983
01984
01985 data[irow] *= fillum;
01986
01987 stat[irow] *= fillum*fillum;
01988 }
01989 if (nfailed) {
01990 cpl_msg_warning(__func__, "Failed to correct twilight in %"CPL_SIZE_FORMAT
01991 " of %"CPL_SIZE_FORMAT", pixels in IFU %hhu!", nfailed,
01992 nrow, ifu);
01993 } else {
01994 cpl_msg_debug(__func__, "No failures during twilight correction of %"
01995 CPL_SIZE_FORMAT" pixels in IFU %hhu", nrow, ifu);
01996 }
01997
01998 return CPL_ERROR_NONE;
01999 }
02000
02001
02027
02028 static int
02029 muse_basicproc_combine_compare_lamp(const cpl_frame *aFrame1, const cpl_frame *aFrame2)
02030 {
02031 cpl_ensure(aFrame1 && aFrame2, CPL_ERROR_NULL_INPUT, -1);
02032 const char *fn1 = cpl_frame_get_filename(aFrame1),
02033 *fn2 = cpl_frame_get_filename(aFrame2);
02034 cpl_propertylist *head1 = cpl_propertylist_load(fn1, 0),
02035 *head2 = cpl_propertylist_load(fn2, 0);
02036 if (!head1 || !head2) {
02037 cpl_propertylist_delete(head1);
02038 cpl_propertylist_delete(head2);
02039 return -1;
02040 }
02041
02042
02043
02044
02045 int nlamp = 1, status1, status2;
02046 cpl_errorstate prestate = cpl_errorstate_get();
02047 do {
02048
02049 const char *name1 = muse_pfits_get_lamp_name(head1, nlamp),
02050 *name2 = muse_pfits_get_lamp_name(head2, nlamp);
02051 cpl_errorstate_set(prestate);
02052 if (name1 && name2 && strncmp(name1, name2, strlen(name1) + 1)) {
02053 cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
02054 "Files \"%s\" and \"%s\" have incompatible lamp "
02055 "setups", fn1, fn2);
02056 cpl_propertylist_delete(head1);
02057 cpl_propertylist_delete(head2);
02058 return -1;
02059 }
02060 name1 = muse_pfits_get_shut_name(head1, nlamp);
02061 name2 = muse_pfits_get_shut_name(head2, nlamp);
02062 if (name1 && name2 && strncmp(name1, name2, strlen(name1) + 1)) {
02063 cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
02064 "Files \"%s\" and \"%s\" have incompatible shutter "
02065 "setups", fn1, fn2);
02066 cpl_propertylist_delete(head1);
02067 cpl_propertylist_delete(head2);
02068 return -1;
02069 }
02070
02071 status1 = muse_pfits_get_lamp_status(head1, nlamp);
02072 status2 = muse_pfits_get_lamp_status(head2, nlamp);
02073 cpl_errorstate_set(prestate);
02074 if (status1 != status2) {
02075 break;
02076 }
02077 status1 = muse_pfits_get_shut_status(head1, nlamp);
02078 status2 = muse_pfits_get_shut_status(head2, nlamp);
02079 if (status1 != status2) {
02080 break;
02081 }
02082 nlamp++;
02083 } while (cpl_errorstate_is_equal(prestate));
02084 cpl_errorstate_set(prestate);
02085
02086 cpl_propertylist_delete(head1);
02087 cpl_propertylist_delete(head2);
02088 return status1 == status2;
02089 }
02090
02091
02117
02118 muse_imagelist *
02119 muse_basicproc_combine_images_lampwise(muse_processing *aProcessing,
02120 unsigned char aIFU,
02121 muse_basicproc_params *aBPars,
02122 cpl_frameset ***aLabeledFrames)
02123 {
02124 if (aLabeledFrames) {
02125 *aLabeledFrames = NULL;
02126 }
02127 cpl_ensure(aProcessing, CPL_ERROR_NULL_INPUT, NULL);
02128
02129
02130 cpl_frameset *rawframes = muse_frameset_find_tags(aProcessing->inframes,
02131 aProcessing->intags, aIFU,
02132 CPL_FALSE);
02133 char *prefix = cpl_sprintf("muse.%s", aProcessing->name);
02134 muse_combinepar *cpars = muse_combinepar_new(aProcessing->parameters,
02135 prefix);
02136 cpl_free(prefix);
02137 #if 0
02138 printf("rawframes\n");
02139 cpl_frameset_dump(rawframes, stdout);
02140 fflush(stdout);
02141 #endif
02142 cpl_size nlabels,
02143 *labels = cpl_frameset_labelise(rawframes,
02144 muse_basicproc_combine_compare_lamp,
02145 &nlabels);
02146 if (!labels || nlabels <= 1) {
02147
02148 cpl_free(labels);
02149 cpl_frameset_delete(rawframes);
02150 muse_imagelist *list = muse_basicproc_load(aProcessing, aIFU, aBPars),
02151 *images = NULL;
02152 if (nlabels == 1) {
02153 muse_image *image = muse_combine_images(cpars, list);
02154 images = muse_imagelist_new();
02155 muse_imagelist_set(images, image, 0);
02156 if (aLabeledFrames) {
02157 *aLabeledFrames = cpl_calloc(1, sizeof(cpl_frameset *));
02158 (*aLabeledFrames)[0] = cpl_frameset_duplicate(aProcessing->usedframes);
02159 }
02160 }
02161 muse_imagelist_delete(list);
02162 muse_combinepar_delete(cpars);
02163 return images;
02164 }
02165
02166 #if 0
02167 cpl_array *alabels = cpl_array_wrap_int(labels, cpl_frameset_get_size(rawframes));
02168 cpl_array_dump(alabels, 0, 1000, stdout);
02169 fflush(stdout);
02170 cpl_array_unwrap(alabels);
02171 #endif
02172
02173 muse_imagelist *images = muse_imagelist_new();
02174 if (aLabeledFrames) {
02175 *aLabeledFrames = cpl_calloc(nlabels, sizeof(cpl_frameset *));
02176 }
02177
02178
02179
02180 muse_processing *proc = cpl_malloc(sizeof(muse_processing));
02181 memcpy(proc, aProcessing, sizeof(muse_processing));
02182 cpl_frameset *inframes = proc->inframes;
02183
02184 cpl_frameset *auxframes = muse_frameset_find_tags(inframes, aProcessing->intags,
02185 aIFU, CPL_TRUE);
02186
02187 int ilabel, ipos = 0;
02188 for (ilabel = 0; ilabel < nlabels; ilabel++) {
02189
02190 cpl_frameset *frames = cpl_frameset_extract(rawframes, labels, ilabel);
02191
02192 cpl_frameset_join(frames, auxframes);
02193
02194 proc->inframes = frames;
02195
02196 muse_imagelist *list = muse_basicproc_load(proc, aIFU, aBPars);
02197
02198 proc->inframes = inframes;
02199 if (!list) {
02200 muse_imagelist_delete(images);
02201 cpl_frameset_delete(frames);
02202 images = NULL;
02203
02204
02205
02206 if (aLabeledFrames) {
02207 cpl_free(*aLabeledFrames);
02208 *aLabeledFrames = NULL;
02209 }
02210 break;
02211 }
02212
02213 muse_image *lampimage = muse_combine_images(cpars, list);
02214 if (!lampimage) {
02215 cpl_msg_error(__func__, "Image combination failed for IFU %hhu for lamp "
02216 "with label %d of %"CPL_SIZE_FORMAT, aIFU, ilabel + 1, nlabels);
02217 muse_imagelist_delete(list);
02218 cpl_frameset_delete(frames);
02219 continue;
02220 }
02221
02222 if (aLabeledFrames) {
02223
02224 cpl_size iframe, nframes = cpl_frameset_get_size(frames);
02225 for (iframe = 0; iframe < nframes; iframe++) {
02226 cpl_frame *frame = cpl_frameset_get_position(frames, iframe);
02227 const char *fn = cpl_frame_get_filename(frame),
02228 *tag = cpl_frame_get_tag(frame);
02229 cpl_size iuframe, nuframes = cpl_frameset_get_size(aProcessing->usedframes);
02230 for (iuframe = 0;
02231 (iuframe < nuframes) && fn && tag;
02232 iuframe++) {
02233 cpl_frame *uframe = cpl_frameset_get_position(aProcessing->usedframes,
02234 iuframe);
02235 const char *fnu = cpl_frame_get_filename(uframe),
02236 *tagu = cpl_frame_get_tag(uframe);
02237 if (fnu && !strncmp(fn, fnu, strlen(fn) + 1) &&
02238 tagu && !strncmp(tag, tagu, strlen(tag) + 1)) {
02239 cpl_frame_set_group(frame, cpl_frame_get_group(uframe));
02240 break;
02241 }
02242 }
02243 }
02244 (*aLabeledFrames)[ipos] = frames;
02245 } else {
02246 cpl_frameset_delete(frames);
02247 }
02248
02249
02250 unsigned int k;
02251 for (k = 0; k < muse_imagelist_get_size(list); k++) {
02252 char *keyword = cpl_sprintf(QC_WAVECAL_PREFIXi" "QC_BASIC_NSATURATED, k+1);
02253 int nsaturated = cpl_propertylist_get_int(muse_imagelist_get(list, k)->header,
02254 MUSE_HDR_TMP_NSAT);
02255 cpl_propertylist_update_int(lampimage->header, keyword, nsaturated);
02256 cpl_free(keyword);
02257 }
02258 muse_imagelist_delete(list);
02259
02260 muse_imagelist_set(images, lampimage, ipos++);
02261 }
02262 cpl_free(labels);
02263 cpl_free(proc);
02264 muse_combinepar_delete(cpars);
02265 cpl_frameset_delete(rawframes);
02266 cpl_frameset_delete(auxframes);
02267
02268 if (images && muse_imagelist_get_size(images) == 0) {
02269 muse_imagelist_delete(images);
02270 images = NULL;
02271 if (aLabeledFrames) {
02272 cpl_free(*aLabeledFrames);
02273 *aLabeledFrames = NULL;
02274 }
02275 }
02276
02277 return images;
02278 }
02279
02280
02302
02303 cpl_error_code
02304 muse_basicproc_shift_pixtable(muse_pixtable *aPt, cpl_array *aLines,
02305 double aHalfWidth, double aBinWidth,
02306 float aLo, float aHi, unsigned char aIter)
02307 {
02308 cpl_ensure_code(aPt && aLines, CPL_ERROR_NULL_INPUT);
02309 cpl_ensure_code(cpl_array_get_type(aLines) == CPL_TYPE_DOUBLE ||
02310 cpl_array_get_type(aLines) == CPL_TYPE_FLOAT,
02311 CPL_ERROR_ILLEGAL_INPUT);
02312
02313 double lmin = cpl_propertylist_get_float(aPt->header, MUSE_HDR_PT_LLO),
02314 lmax = cpl_propertylist_get_float(aPt->header, MUSE_HDR_PT_LHI);
02315 double shift = 0., wshift = 0.;
02316 cpl_array *errors = cpl_array_new(4, CPL_TYPE_DOUBLE);
02317 int i, n = cpl_array_get_size(aLines), nvalid = 0;
02318 for (i = 0; i < n; i++) {
02319 int err;
02320 double lambdasign = cpl_array_get(aLines, i, &err),
02321 lambda = fabs(lambdasign);
02322 if (err || lambda >= lmax || lambda <= lmin) {
02323 cpl_msg_debug(__func__, "Invalid wavelength at position %d of %d in "
02324 "skylines", i + 1, n);
02325 continue;
02326 }
02327 nvalid++;
02328 double center = muse_utils_pixtable_fit_line_gaussian(aPt, lambdasign, aHalfWidth,
02329 aBinWidth, aLo, aHi, aIter,
02330 NULL, errors),
02331 cerr = cpl_array_get_double(errors, 0, NULL);
02332 shift += (lambda - center) / cerr;
02333 wshift += 1. / cerr;
02334 cpl_msg_debug(__func__, "dlambda = %.4f +/- %.4f (for skyline at %.4f "
02335 "Angstrom)", lambda - center, cerr, lambda);
02336 }
02337 cpl_array_delete(errors);
02338 shift /= wshift;
02339 if (nvalid > 0 && isfinite(shift)) {
02340 cpl_msg_info(__func__, "Skyline correction (%d lines): shifting data of IFU "
02341 "%hhu by %.4f Angstrom", nvalid, muse_utils_get_ifu(aPt->header),
02342 shift);
02343 cpl_table_add_scalar(aPt->table, MUSE_PIXTABLE_LAMBDA, shift);
02344 cpl_propertylist_update_float(aPt->header, QC_SCIBASIC_SHIFT, shift);
02345 } else {
02346 cpl_propertylist_update_float(aPt->header, QC_SCIBASIC_SHIFT, 0.);
02347 }
02348 return CPL_ERROR_NONE;
02349 }
02350
02351
02363
02364 cpl_error_code
02365 muse_basicproc_stats_append_header(cpl_image *aImage, cpl_propertylist *aHeader,
02366 const char *aPrefix, unsigned aStats)
02367 {
02368 cpl_ensure_code(aImage, CPL_ERROR_NULL_INPUT);
02369
02370 int nx = cpl_image_get_size_x(aImage),
02371 ny = cpl_image_get_size_y(aImage);
02372 return muse_basicproc_stats_append_header_window(aImage, aHeader, aPrefix,
02373 aStats, 1, 1, nx, ny);
02374 }
02375
02376
02393
02394 cpl_error_code
02395 muse_basicproc_stats_append_header_window(cpl_image *aImage,
02396 cpl_propertylist *aHeader,
02397 const char *aPrefix, unsigned aStats,
02398 int aX1, int aY1, int aX2, int aY2)
02399 {
02400 cpl_ensure_code(aImage && aHeader, CPL_ERROR_NULL_INPUT);
02401 cpl_ensure_code(aPrefix, CPL_ERROR_ILLEGAL_INPUT);
02402 cpl_ensure_code(aPrefix, CPL_ERROR_ILLEGAL_INPUT);
02403
02404 cpl_stats *stats = cpl_stats_new_from_image_window(aImage, aStats,
02405 aX1, aY1, aX2, aY2);
02406 if (!stats) {
02407 return cpl_error_get_code();
02408 }
02409
02410 char keyword[KEYWORD_LENGTH];
02411 if (aStats & CPL_STATS_MEDIAN) {
02412 snprintf(keyword, KEYWORD_LENGTH, "%s MEDIAN", aPrefix);
02413 cpl_propertylist_append_float(aHeader, keyword,
02414 cpl_stats_get_median(stats));
02415 }
02416 if (aStats & CPL_STATS_MEAN) {
02417 snprintf(keyword, KEYWORD_LENGTH, "%s MEAN", aPrefix);
02418 cpl_propertylist_append_float(aHeader, keyword, cpl_stats_get_mean(stats));
02419 }
02420 if (aStats & CPL_STATS_STDEV) {
02421 snprintf(keyword, KEYWORD_LENGTH, "%s STDEV", aPrefix);
02422 cpl_propertylist_append_float(aHeader, keyword, cpl_stats_get_stdev(stats));
02423 }
02424 if (aStats & CPL_STATS_MIN) {
02425 snprintf(keyword, KEYWORD_LENGTH, "%s MIN", aPrefix);
02426 cpl_propertylist_append_float(aHeader, keyword, cpl_stats_get_min(stats));
02427 }
02428 if (aStats & CPL_STATS_MAX) {
02429 snprintf(keyword, KEYWORD_LENGTH, "%s MAX", aPrefix);
02430 cpl_propertylist_append_float(aHeader, keyword, cpl_stats_get_max(stats));
02431 }
02432 if (aStats & CPL_STATS_FLUX) {
02433 snprintf(keyword, KEYWORD_LENGTH, "%s INTFLUX", aPrefix);
02434 cpl_propertylist_append_float(aHeader, keyword, cpl_stats_get_flux(stats));
02435 }
02436
02437 cpl_stats_delete(stats);
02438
02439 return CPL_ERROR_NONE;
02440 }
02441
02442
02457
02458 cpl_error_code
02459 muse_basicproc_qc_saturated(muse_image *aImage, const char *aPrefix)
02460 {
02461 cpl_ensure_code(aImage && aImage->dq && aImage->header && aPrefix,
02462 CPL_ERROR_NULL_INPUT);
02463
02464 cpl_mask *mask = cpl_mask_threshold_image_create(aImage->dq,
02465 EURO3D_SATURATED - 0.1,
02466 EURO3D_SATURATED + 0.1);
02467 int nsaturated = cpl_mask_count(mask);
02468 cpl_mask_delete(mask);
02469
02470 char *keyword = NULL;
02471 if (aPrefix[strlen(aPrefix)-1] == ' ') {
02472 keyword = cpl_sprintf("%s%s", aPrefix, QC_BASIC_NSATURATED);
02473 } else {
02474 keyword = cpl_sprintf("%s %s", aPrefix, QC_BASIC_NSATURATED);
02475 }
02476 cpl_error_code rc = cpl_propertylist_update_int(aImage->header, keyword,
02477 nsaturated);
02478 cpl_free(keyword);
02479 return rc;
02480 }
02481