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 <string.h>
00030
00031 #include <muse.h>
00032 #include "muse_twilight_z.h"
00033
00034
00035
00036
00037
00038
00045
00046 static cpl_error_code
00047 muse_twilight_qc_header(muse_image *aImage, muse_imagelist *aList)
00048 {
00049 cpl_ensure_code(aImage && aList, CPL_ERROR_NULL_INPUT);
00050 unsigned char ifu = muse_utils_get_ifu(aImage->header);
00051 cpl_msg_debug(__func__, "Adding QC keywords for IFU %hhu", ifu);
00052
00053 unsigned stats = CPL_STATS_MEDIAN | CPL_STATS_MEAN | CPL_STATS_STDEV
00054 | CPL_STATS_MIN | CPL_STATS_MAX;
00055
00056
00057 unsigned int k;
00058 for (k = 0; k < muse_imagelist_get_size(aList); k++) {
00059 char *keyword = cpl_sprintf(QC_TWILIGHTm_PREFIXi, ifu, k+1);
00060 muse_basicproc_stats_append_header(muse_imagelist_get(aList, k)->data,
00061 aImage->header, keyword, stats);
00062 cpl_free(keyword);
00063 keyword = cpl_sprintf(QC_TWILIGHTm_PREFIXi" "QC_BASIC_NSATURATED, ifu, k+1);
00064 int nsaturated = cpl_propertylist_get_int(muse_imagelist_get(aList, k)->header,
00065 MUSE_HDR_TMP_NSAT);
00066 cpl_propertylist_update_int(aImage->header, keyword, nsaturated);
00067 cpl_free(keyword);
00068 }
00069
00070
00071 char *kw = cpl_sprintf(QC_TWILIGHTm_MASTER_PREFIX, ifu);
00072 stats |= CPL_STATS_FLUX;
00073 muse_basicproc_stats_append_header(aImage->data, aImage->header, kw, stats);
00074 cpl_free(kw);
00075 return CPL_ERROR_NONE;
00076 }
00077
00078
00120
00121 static muse_datacube *
00122 muse_twilight_reconstruct(muse_processing *aProcessing,
00123 muse_twilight_params_t *aParams,
00124 muse_basicproc_params *aBPars,
00125 muse_combinepar *aCPars,
00126 muse_resampling_params *aRPars)
00127 {
00128 cpl_ensure(aProcessing && aParams, CPL_ERROR_NULL_INPUT, NULL);
00129 double lmin = aParams->lambdamin,
00130 lmax = aParams->lambdamax;
00131 cpl_ensure(lmax > lmin, CPL_ERROR_ILLEGAL_INPUT, NULL);
00132
00133 cpl_table *geo = muse_table_load(aProcessing, MUSE_TAG_GEOMETRY_TABLE, 0);
00134 cpl_ensure(geo, CPL_ERROR_FILE_NOT_FOUND, NULL);
00135
00136 muse_pixtable **pts = cpl_calloc(kMuseNumIFUs, sizeof(muse_pixtable));
00137 unsigned char nifu;
00138 #pragma omp parallel for default(none) \
00139 shared(aBPars, aCPars, aProcessing, geo, pts)
00140 for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
00141 cpl_table *trace = muse_table_load(aProcessing, MUSE_TAG_TRACE_TABLE, nifu),
00142 *wavecal = muse_table_load(aProcessing, MUSE_TAG_WAVECAL_TABLE, nifu);
00143 if (!trace || !wavecal) {
00144 cpl_msg_warning(__func__, "Calibrations could not be loaded for IFU "
00145 "%2hhu:%s%s", nifu, !trace ? " "MUSE_TAG_TRACE_TABLE : "",
00146 !wavecal ? " "MUSE_TAG_WAVECAL_TABLE : "");
00147 cpl_table_delete(trace);
00148 cpl_table_delete(wavecal);
00149 continue;
00150 }
00151
00152 cpl_msg_debug(__func__, "load raw files of IFU %2hhu", nifu);
00153 muse_imagelist *images = muse_basicproc_load(aProcessing, nifu, aBPars);
00154 if (!images) {
00155 cpl_msg_warning(__func__, "Basic processing failed for IFU %2hhu: %s",
00156 nifu, cpl_error_get_message());
00157 cpl_table_delete(trace);
00158 cpl_table_delete(wavecal);
00159 continue;
00160 }
00161
00162
00163 cpl_table *tattached = muse_basicproc_get_illum(images, trace, wavecal, geo);
00164
00165 cpl_msg_debug(__func__, "combine raw files of IFU %2hhu", nifu);
00166 muse_image *masterimage = muse_combine_images(aCPars, images);
00167 muse_twilight_qc_header(masterimage, images);
00168 muse_imagelist_delete(images);
00169 if (!masterimage) {
00170 cpl_msg_warning(__func__, "Combining individual images failed for IFU %2hhu: %s",
00171 nifu, cpl_error_get_message());
00172 cpl_table_delete(tattached);
00173 cpl_table_delete(trace);
00174 cpl_table_delete(wavecal);
00175 continue;
00176 }
00177
00178
00179
00180 int nbad = muse_quality_image_reject_using_dq(masterimage->data,
00181 masterimage->dq,
00182 masterimage->stat);
00183 cpl_detector_interpolate_rejected(masterimage->data);
00184
00185 cpl_detector_interpolate_rejected(masterimage->stat);
00186
00187 cpl_msg_debug(__func__, "interpolated over %d bad pixels in IFU %2hhu",
00188 nbad, nifu);
00189
00190
00191 cpl_msg_debug(__func__, "create pixel table for IFU %2hhu", nifu);
00192 pts[nifu - 1] = muse_pixtable_create(masterimage, trace, wavecal, geo);
00193 cpl_table_delete(trace);
00194 cpl_table_delete(wavecal);
00195
00196 if (pts[nifu - 1]) {
00197 cpl_propertylist_copy_property_regexp(pts[nifu - 1]->header,
00198 masterimage->header,
00199 QC_TWILIGHT_REGEXP, 0);
00200 if (tattached) {
00201 muse_basicproc_apply_illum(pts[nifu - 1], tattached);
00202 }
00203 }
00204 muse_image_delete(masterimage);
00205 cpl_table_delete(tattached);
00206 }
00207 cpl_table_delete(geo);
00208
00209 muse_pixtable *pt = pts[0];
00210 muse_pixtable_restrict_wavelength(pt, lmin, lmax);
00211 if (muse_pixtable_get_nrow(pt) < 1) {
00212 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_OUTPUT,
00213 "After cutting to %.2f..%.2f Angstrom in wavelength "
00214 "no pixels for cube reconstruction are left!", lmin,
00215 lmax);
00216 for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
00217 muse_pixtable_delete(pts[nifu - 1]);
00218 }
00219 cpl_free(pts);
00220 return NULL;
00221 }
00222
00223 cpl_array *scales = NULL;
00224 if (getenv("MUSE_TWILIGHT_SCALES")) {
00225 scales = muse_cplarray_new_from_delimited_string(getenv("MUSE_TWILIGHT_SCALES"), ",");
00226 double scale = atof(cpl_array_get_string(scales, 0));
00227 cpl_table_divide_scalar(pt->table, MUSE_PIXTABLE_DATA, scale);
00228 cpl_table_divide_scalar(pt->table, MUSE_PIXTABLE_STAT, scale*scale);
00229 int nscales = cpl_array_get_size(scales);
00230 if (nscales != kMuseNumIFUs) {
00231 cpl_msg_warning(__func__, "%d external scales found instead of %d! Not "
00232 "using them.", nscales, kMuseNumIFUs);
00233 cpl_array_delete(scales);
00234 scales = NULL;
00235 } else {
00236 cpl_msg_info(__func__, "Using %d external scales.", nscales);
00237 }
00238 #if 1
00239 cpl_array_dump(scales, 0, 30, stdout);
00240 fflush(stdout);
00241 #endif
00242 }
00243
00244 double fluxref = cpl_table_get_column_mean(pt->table, MUSE_PIXTABLE_DATA)
00245 * muse_pixtable_get_nrow(pt);
00246 cpl_msg_debug(__func__, "pixel table of IFU 1, fluxref = %e, %"CPL_SIZE_FORMAT
00247 " rows", fluxref, muse_pixtable_get_nrow(pt));
00248
00249
00250
00251 cpl_propertylist_append_double(pt->header, MUSE_HDR_FLAT_FLUX_SKY"1", fluxref);
00252 char *kw = cpl_sprintf(QC_TWILIGHTm_INTFLUX, (unsigned char)1);
00253 cpl_propertylist_append_float(pt->header, kw, fluxref);
00254 cpl_free(kw);
00255 for (nifu = 2; nifu <= kMuseNumIFUs; nifu++) {
00256 if (!pts[nifu - 1]) {
00257 continue;
00258 }
00259 muse_pixtable_restrict_wavelength(pts[nifu - 1], lmin, lmax);
00260 if (muse_pixtable_get_nrow(pts[nifu - 1]) < 1) {
00261 continue;
00262 }
00263 double flux = cpl_table_get_column_mean(pts[nifu - 1]->table, MUSE_PIXTABLE_DATA)
00264 * muse_pixtable_get_nrow(pts[nifu - 1]),
00265 scale = 1.;
00266 if (scales) {
00267 scale = atof(cpl_array_get_string(scales, nifu - 1));
00268
00269 flux = scale * fluxref;
00270 } else {
00271 scale = flux / fluxref;
00272 }
00273 kw = cpl_sprintf(MUSE_HDR_FLAT_FLUX_SKY"%hhu", nifu);
00274 cpl_propertylist_append_double(pt->header, kw, flux);
00275 cpl_free(kw);
00276 cpl_msg_debug(__func__, "merging pixel table of IFU %2hhu, flux = %e, scale = %f",
00277 nifu, flux, scale);
00278 cpl_table_divide_scalar(pts[nifu - 1]->table, MUSE_PIXTABLE_DATA, scale);
00279 cpl_table_divide_scalar(pts[nifu - 1]->table, MUSE_PIXTABLE_STAT, scale*scale);
00280 cpl_table_insert(pt->table, pts[nifu - 1]->table, muse_pixtable_get_nrow(pt));
00281
00282 cpl_propertylist_copy_property_regexp(pt->header, pts[nifu - 1]->header,
00283 QC_TWILIGHT_REGEXP, 0);
00284
00285 kw = cpl_sprintf(QC_TWILIGHTm_INTFLUX, nifu);
00286 cpl_propertylist_append_float(pt->header, kw, flux);
00287 cpl_free(kw);
00288 muse_pixtable_delete(pts[nifu - 1]);
00289 }
00290 cpl_free(pts);
00291
00292 muse_pixtable_compute_limits(pt);
00293 cpl_array_delete(scales);
00294
00295
00296 muse_datacube *cube = muse_resampling_cube(pt, aRPars, NULL);
00297 muse_pixtable_delete(pt);
00298 if (!cube) {
00299 return NULL;
00300 }
00301
00302 muse_image *white = muse_datacube_collapse(cube, NULL);
00303 cube->recimages = muse_imagelist_new();
00304 cube->recnames = cpl_array_new(1, CPL_TYPE_STRING);
00305 muse_imagelist_set(cube->recimages, white, 0);
00306 cpl_array_set_string(cube->recnames, 0, "white");
00307
00308
00309 muse_datacube_convert_dq(cube);
00310
00311 return cube;
00312 }
00313
00314
00338
00339 static cpl_image *
00340 muse_twilight_image_normalize_and_fit(muse_image *aImage,
00341 unsigned int aXOrder,
00342 unsigned int aYOrder,
00343 const cpl_mask *aBPM,
00344 const cpl_mask *aVign)
00345 {
00346 cpl_ensure(aImage && aImage->data, CPL_ERROR_NULL_INPUT, NULL);
00347
00348
00349 if (aBPM) {
00350 cpl_image_reject_from_mask(aImage->data, aBPM);
00351 }
00352 cpl_image_reject_value(aImage->data, CPL_VALUE_NOTFINITE | CPL_VALUE_ZERO);
00353
00354
00355
00356 cpl_image *filtered = cpl_image_duplicate(aImage->data);
00357 cpl_mask *mask = cpl_mask_new(5, 7);
00358 cpl_mask_not(mask);
00359 cpl_errorstate prestate = cpl_errorstate_get();
00360 cpl_image_filter_mask(filtered, aImage->data, mask, CPL_FILTER_MEDIAN,
00361 CPL_BORDER_FILTER);
00362 cpl_mask_delete(mask);
00363 if (!cpl_errorstate_is_equal(prestate)) {
00364 cpl_msg_warning(__func__, "filtering cube plane failed: %s",
00365 cpl_error_get_message());
00366 }
00367 #if 0
00368
00369 cpl_image *filtered2 = cpl_image_duplicate(filtered);
00370 cpl_matrix *gauss = muse_matrix_new_gaussian_2d(7, 7, 10. * CPL_MATH_SIG_FWHM);
00371 cpl_image_filter(filtered2, filtered, gauss, CPL_FILTER_LINEAR,
00372 CPL_BORDER_FILTER);
00373 cpl_matrix_delete(gauss);
00374 if (!cpl_errorstate_is_equal(prestate)) {
00375 cpl_msg_warning(__func__, "filtering 2 failed: %s", cpl_error_get_message());
00376 } else {
00377 cpl_image_reject_from_mask(filtered2, bpm2);
00378 cpl_image_fill_rejected(filtered2, 1.);
00379 muse_processing_save_cimage(aProcessing, -1, filtered2, wmuse->header,
00380 "TWILIGHT_IMAGE2_SMOOTHED" );
00381 cpl_detector_interpolate_rejected(filtered2);
00382 muse_processing_save_cimage(aProcessing, -1, filtered2, wmuse->header,
00383 "TWILIGHT_IMAGE2_INTERPOLATED" );
00384 }
00385 cpl_image_delete(filtered2);
00386 #endif
00387
00388
00389 double mean = cpl_image_get_mean(filtered);
00390 cpl_msg_debug(__func__, "mean = %f", mean);
00391 cpl_image_multiply_scalar(filtered, 1. / mean);
00392
00393
00394 cpl_mask *bpm = cpl_image_get_bpm(filtered);
00395 if (aVign) {
00396 cpl_mask_or(bpm, aVign);
00397 }
00398 cpl_image *fit = muse_utils_image_fit_polynomial(filtered,
00399 aXOrder, aYOrder);
00400
00401 mean = cpl_image_get_mean(fit);
00402 cpl_msg_debug(__func__, "mean(fit) = %f", mean);
00403 cpl_image_multiply_scalar(fit, 1. / mean);
00404 cpl_image_delete(filtered);
00405 return fit;
00406 }
00407
00408
00415
00416 int
00417 muse_twilight_compute(muse_processing *aProcessing,
00418 muse_twilight_params_t *aParams)
00419 {
00420 muse_datacube *cube = NULL,
00421 *cubefit = cpl_calloc(1, sizeof(muse_datacube));
00422 cubefit->data = cpl_imagelist_new();
00423 if (getenv("MUSE_TWILIGHT_SKIP")) {
00424 char *fn = getenv("MUSE_TWILIGHT_SKIP");
00425 cube = muse_datacube_load(fn);
00426 cpl_msg_warning(__func__, "Skipping active: loaded previously generated "
00427 "cube from \"%s\"", fn);
00428
00429 if (!cube->recimages) {
00430
00431 cube->recimages = muse_imagelist_new();
00432 cube->recnames = cpl_array_new(1, CPL_TYPE_STRING);
00433 muse_image *white = muse_datacube_collapse(cube, NULL);
00434 muse_imagelist_set(cube->recimages, white, 0);
00435 cpl_array_set_string(cube->recnames, 0, "white");
00436 } else if (!cube->recnames ||
00437 (cube->recnames &&
00438 strncmp("white", cpl_array_get_string(cube->recnames, 0), 6))) {
00439
00440 muse_image *white = muse_datacube_collapse(cube, NULL);
00441 muse_imagelist_set(cube->recimages, white, 0);
00442 cpl_array_set_string(cube->recnames, 0, "white");
00443 }
00444
00445
00446 cpl_frameset *frames = muse_frameset_find_tags(aProcessing->inframes,
00447 aProcessing->intags, -1, 0);
00448 cpl_size iframe, nframes = cpl_frameset_get_size(frames);
00449 for (iframe = 0; iframe < nframes; iframe++) {
00450 cpl_frame *frame = cpl_frameset_get_position(frames, iframe);
00451 muse_processing_append_used(aProcessing, frame, CPL_FRAME_GROUP_RAW, 1);
00452 }
00453 cpl_frameset_delete(frames);
00454 cpl_msg_warning(__func__, "Skipping active: faked used frames using only "
00455 "raw inputs:");
00456 cpl_frameset_dump(aProcessing->usedframes, stdout);
00457 fflush(stdout);
00458 cubefit->header = cpl_propertylist_duplicate(cube->header);
00459 }
00460
00461 cpl_error_code rc = CPL_ERROR_NONE;
00462 if (!cube) {
00463 muse_basicproc_params *bpars = muse_basicproc_params_new(aProcessing->parameters,
00464 "muse.muse_twilight");
00465 muse_combinepar *cpars = muse_combinepar_new(aProcessing->parameters,
00466 "muse.muse_twilight");
00467 muse_resampling_type resample
00468 = muse_postproc_get_resampling_type(aParams->resample_s);
00469 muse_resampling_params *rp = muse_resampling_params_new(resample);
00470 rp->crtype = muse_postproc_get_cr_type(aParams->crtype_s);
00471 rp->crsigma = aParams->crsigma;
00472 rp->dlambda = aParams->dlambda;
00473 rp->pfx = 1.;
00474 rp->pfy = 1.;
00475 rp->pfl = 1.;
00476 cube = muse_twilight_reconstruct(aProcessing, aParams, bpars, cpars, rp);
00477 muse_basicproc_params_delete(bpars);
00478 muse_combinepar_delete(cpars);
00479 muse_resampling_params_delete(rp);
00480 if (!cube) {
00481 muse_datacube_delete(cubefit);
00482 return -1;
00483 }
00484
00485 cubefit->header = cpl_propertylist_duplicate(cube->header);
00486 rc = muse_processing_save_cube(aProcessing, -1, cube,
00487 MUSE_TAG_CUBE_SKYFLAT,
00488 MUSE_CUBE_TYPE_FITS);
00489
00490 cpl_propertylist_erase_regexp(cubefit->header, QC_TWILIGHT_REGEXP, 0);
00491 }
00492
00493
00494
00495
00496 muse_image *wmuse = muse_imagelist_get(cube->recimages, 0);
00497 if (!wmuse) {
00498 muse_datacube_delete(cube);
00499 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_OUTPUT,
00500 "White-light image is missing!");
00501 muse_datacube_delete(cubefit);
00502 return -1;
00503 }
00504 cpl_image *white = cpl_image_duplicate(wmuse->data);
00505 cpl_image_reject_value(white, CPL_VALUE_NOTFINITE | CPL_VALUE_ZERO);
00506 cpl_mask *bpm = cpl_image_get_bpm(white),
00507 *bpm2 = cpl_mask_duplicate(bpm);
00508
00509 cpl_mask *border = cpl_mask_new(1, cpl_mask_get_size_y(bpm2));
00510 cpl_mask_not(border);
00511 cpl_mask_copy(bpm2, border, 1, 1);
00512 cpl_mask_copy(bpm2, border, cpl_mask_get_size_x(bpm2), 1);
00513 cpl_mask_delete(border);
00514
00515
00516 cpl_mask *kernel = cpl_mask_new(5, 1);
00517 cpl_mask_not(kernel);
00518 cpl_mask_filter(bpm2, bpm, kernel, CPL_FILTER_DILATION, CPL_BORDER_NOP);
00519 cpl_mask_delete(kernel);
00520 bpm = cpl_image_set_bpm(white, bpm2);
00521 cpl_mask_delete(bpm);
00522 bpm = bpm2;
00523
00524
00525 muse_mask *maskimage = muse_processing_mask_load(aProcessing,
00526 MUSE_TAG_VIGN_MASK);
00527
00528 if (maskimage) {
00529 cpl_mask *mask = muse_cplmask_adapt_to_image(maskimage->mask,
00530 cpl_imagelist_get(cube->data, 0));
00531 cpl_mask_delete(maskimage->mask);
00532 maskimage->mask = mask;
00533 }
00534 #if 0 // only for smoothing in wavelength direction (see below)
00535
00536 double crpix3 = muse_pfits_get_crpix(cube->header, 3),
00537 crval3 = muse_pfits_get_crval(cube->header, 3),
00538 cd33 = muse_pfits_get_cd(cube->header, 3, 3);
00539 cpl_propertylist *pbla = cpl_propertylist_new();
00540 cpl_propertylist_copy_property_regexp(pbla, cube->header, "^C", 0);
00541 cpl_propertylist_dump(pbla, stdout);
00542 fflush(stdout);
00543 cpl_msg_debug(__func__, "%f %f %f", crpix3, crval3, cd33);
00544 cpl_vector *pos = cpl_vector_new(npl);
00545 #endif
00546
00547 muse_image *image = muse_image_new();
00548 int ipl, npl = cpl_imagelist_get_size(cube->data);
00549 for (ipl = 0; ipl < npl; ipl++) {
00550 image->data = cpl_imagelist_get(cube->data, ipl);
00551 image->stat = cpl_imagelist_get(cube->stat, ipl);
00552 cpl_mask *vignmask = maskimage ? maskimage->mask : NULL;
00553 cpl_image *fit = muse_twilight_image_normalize_and_fit(image,
00554 aParams->xorder,
00555 aParams->yorder,
00556 bpm, vignmask);
00557 cpl_imagelist_set(cubefit->data, fit, ipl);
00558 #if 0 // only for smoothing in wavelength direction (see below)
00559
00560 cpl_vector_set(pos, ipl, ipl+1);
00561 #endif
00562 }
00563 image->data = NULL;
00564 image->stat = NULL;
00565 muse_image_delete(image);
00566 muse_datacube_delete(cube);
00567
00568 #if 0 // XXX try to smooth with a fit in wavelenth direction?
00569 cpl_image *error = cpl_image_new(cpl_image_get_size_x(white),
00570 cpl_image_get_size_y(white),
00571 CPL_TYPE_DOUBLE);
00572 cpl_imagelist *cubefit2 = cpl_fit_imagelist_polynomial(pos, cubefit->data,
00573 0, 2, CPL_FALSE,
00574 CPL_TYPE_DOUBLE, error);
00575 cpl_vector_dump(pos, stdout);
00576 fflush(stdout);
00577 cpl_vector_delete(pos);
00578 muse_processing_save_cimage(aProcessing, -1, error, wmuse->header, "ERROR_IMAGE");
00579 cpl_image_delete(error);
00580
00581 cpl_imagelist_save(cubefit2, "cubefit2.fits", CPL_TYPE_UNSPECIFIED, NULL, CPL_IO_CREATE);
00582 cpl_imagelist_delete(cubefit2);
00583 #endif
00584
00585 #if 0
00586 rc = muse_processing_save_cube(aProcessing, -1, cubefit,
00587 "TWILIGHT_CUBE_FIT", MUSE_CUBE_TYPE_FITS);
00588 #endif
00589
00590 muse_image *whitefit = muse_datacube_collapse(cubefit, NULL);
00591 cpl_image_delete(whitefit->dq);
00592 whitefit->dq = NULL;
00593 cpl_propertylist_update_string(whitefit->header, "OBJECT",
00594 "white from global fit");
00595 cubefit->recimages = muse_imagelist_new();
00596 muse_imagelist_set(cubefit->recimages, whitefit, 0);
00597 cubefit->recnames = cpl_array_new(1, CPL_TYPE_STRING);
00598 cpl_array_set_string(cubefit->recnames, 0, "white_global_fit");
00599
00600
00601
00602 double mean = cpl_image_get_mean(white);
00603 cpl_image_divide_scalar(white, mean);
00604 cpl_image *wdiv = cpl_image_divide_create(white, whitefit->data);
00605
00606 image = muse_image_new();
00607 image->header = cpl_propertylist_new();
00608 cpl_propertylist_append_string(image->header, "OBJECT", "normalized "
00609 "white-light divided by white global fit");
00610 cpl_propertylist_append_string(image->header, "BUNIT", "1");
00611 image->data = wdiv;
00612 image->dq = cpl_image_new_from_mask(cpl_image_get_bpm(wdiv));
00613 muse_imagelist_set(cubefit->recimages, image,
00614 muse_imagelist_get_size(cubefit->recimages));
00615 cpl_array_set_size(cubefit->recnames,
00616 cpl_array_get_size(cubefit->recnames) + 1);
00617 cpl_array_set_string(cubefit->recnames, cpl_array_get_size(cubefit->recnames) - 1,
00618 "white_div_global");
00619
00620 cpl_mask *fovmask = cpl_mask_duplicate(cpl_image_get_bpm(white));
00621 if (maskimage) {
00622 bpm = cpl_image_get_bpm(white);
00623 cpl_mask_or(bpm, maskimage->mask);
00624 }
00625 cpl_image_delete(white);
00626
00627
00628 if (maskimage) {
00629
00630 cpl_mask *vignmask = cpl_mask_duplicate(fovmask);
00631 cpl_mask_not(maskimage->mask);
00632 cpl_mask_or(vignmask, maskimage->mask);
00633 cpl_image *wdiv2 = cpl_image_duplicate(wdiv);
00634 cpl_image_reject_from_mask(wdiv2, vignmask);
00635
00636
00637 if (aParams->vignmaskedges > 0.) {
00638 cpl_msg_info(__func__, "Excluding strong edges (stronger than %.1f%%) "
00639 "from the vignetted area", aParams->vignmaskedges * 100.);
00640 cpl_image *wdivX = cpl_image_duplicate(wdiv2);
00641 cpl_mask *wdivXmask = cpl_mask_duplicate(cpl_image_get_bpm(wdivX));
00642 cpl_image_fill_rejected(wdivX, 1.);
00643 cpl_image_accept_all(wdivX);
00644 int i, nx = cpl_image_get_size_x(wdivX),
00645 j, ny = cpl_image_get_size_y(wdivX);
00646
00647 for (i = 1; i <= nx; i++) {
00648 for (j = 2; j <= ny; j++) {
00649 int err;
00650 double v1 = cpl_image_get(wdivX, i, j - 1, &err),
00651 v2 = cpl_image_get(wdivX, i, j, &err);
00652 if (fabs(v2 - v1) < aParams->vignmaskedges) {
00653 continue;
00654 }
00655
00656 cpl_msg_debug(__func__, "%03d %03d v1 %f V2 %f --> delta %f",
00657 i, j, v1, v2, fabs(v2 - v1));
00658 double dv1 = fabs(v1 - 1.),
00659 dv2 = fabs(v2 - 1.);
00660 if (dv1 > dv2) {
00661 cpl_mask_set(wdivXmask, i, j - 1, CPL_BINARY_1);
00662 } else {
00663 cpl_mask_set(wdivXmask, i, j, CPL_BINARY_1);
00664 }
00665 }
00666 }
00667
00668 for (j = 1; j <= ny; j++) {
00669 for (i = 2; i <= nx; i++) {
00670 int err;
00671 double v1 = cpl_image_get(wdivX, i - 1, j, &err),
00672 v2 = cpl_image_get(wdivX, i, j, &err);
00673 if (fabs(v2 - v1) < aParams->vignmaskedges) {
00674 continue;
00675 }
00676
00677 cpl_msg_debug(__func__, "%03d %03d v1 %f V2 %f --> delta %f",
00678 i, j, v1, v2, fabs(v2 - v1));
00679 double dv1 = fabs(v1 - 1.),
00680 dv2 = fabs(v2 - 1.);
00681 if (dv1 > dv2) {
00682 cpl_mask_set(wdivXmask, i - 1, j, CPL_BINARY_1);
00683 } else {
00684 cpl_mask_set(wdivXmask, i, j, CPL_BINARY_1);
00685 }
00686 }
00687 }
00688
00689 cpl_image_reject_from_mask(wdiv2, wdivXmask);
00690
00691
00692 image = muse_image_new();
00693 image->header = cpl_propertylist_new();
00694 cpl_propertylist_append_string(image->header, "OBJECT",
00695 "white-light divided by white global, mask excl edges");
00696 cpl_propertylist_append_string(image->header, "BUNIT", "1");
00697 image->data = wdivX;
00698 image->dq = cpl_image_new_from_mask(wdivXmask);
00699 cpl_mask_delete(wdivXmask);
00700 muse_imagelist_set(cubefit->recimages, image,
00701 muse_imagelist_get_size(cubefit->recimages));
00702 cpl_array_set_size(cubefit->recnames,
00703 cpl_array_get_size(cubefit->recnames) + 1);
00704 cpl_array_set_string(cubefit->recnames, cpl_array_get_size(cubefit->recnames) - 1,
00705 "white_div_global_excl_edges");
00706 }
00707
00708
00709 cpl_image *fit = NULL;
00710 if (aParams->vignsmooth == MUSE_TWILIGHT_PARAM_VIGNSMOOTH_GAUSSIAN) {
00711
00712 double fwhm = (aParams->vignxpar + aParams->vignypar) / 2.;
00713 cpl_msg_info(__func__, "Running %.1f pix FWHM Gaussian filter...", fwhm);
00714 fit = cpl_image_duplicate(wdiv2);
00715
00716 int hw = lround(fwhm);
00717 hw = hw % 2 ? hw : hw + 1;
00718 cpl_msg_debug(__func__, "using width 2 x %d + 1 for Gaussian matrix", hw);
00719 cpl_matrix *gauss = muse_matrix_new_gaussian_2d(hw, hw,
00720 fwhm * CPL_MATH_SIG_FWHM);
00721 cpl_errorstate prestate = cpl_errorstate_get();
00722 cpl_image_filter(fit, wdiv2, gauss, CPL_FILTER_LINEAR, CPL_BORDER_FILTER);
00723 cpl_matrix_delete(gauss);
00724 cpl_image_reject_from_mask(fit, cpl_image_get_bpm(wdiv2));
00725
00726 cpl_image_threshold(fit, 1., FLT_MAX, 1., FLT_MAX);
00727 if (!cpl_errorstate_is_equal(prestate)) {
00728 cpl_msg_warning(__func__, "filtering vignetted area failed: %s",
00729 cpl_error_get_message());
00730 }
00731 #if 0
00732
00733
00734 cpl_msg_info(__func__, "Running Gaussian filter on extended region...");
00735
00736 fit = cpl_image_duplicate(wdiv2);
00737
00738
00739 cpl_image *wdiv3 = cpl_image_duplicate(wdiv2);
00740 cpl_image_fill_rejected(wdiv3, 1.);
00741 cpl_mask *masktest = cpl_mask_load("masktest3.fits", 0, 0);
00742 cpl_image_reject_from_mask(wdiv3, masktest);
00743 cpl_mask_delete(masktest);
00744
00745
00746
00747 cpl_matrix *gauss = muse_matrix_new_gaussian_2d(7, 7,
00748 10. * CPL_MATH_SIG_FWHM);
00749 cpl_errorstate prestate = cpl_errorstate_get();
00750 cpl_image_filter(fit, wdiv3, gauss, CPL_FILTER_LINEAR, CPL_BORDER_FILTER);
00751 cpl_image_delete(wdiv3);
00752 cpl_matrix_delete(gauss);
00753 cpl_image_reject_from_mask(fit, cpl_image_get_bpm(wdiv2));
00754
00755 cpl_image_threshold(fit, 1., FLT_MAX, 1., FLT_MAX);
00756 if (!cpl_errorstate_is_equal(prestate)) {
00757 cpl_msg_warning(__func__, "filtering vignetted area failed: %s",
00758 cpl_error_get_message());
00759 }
00760 #endif
00761 } else if (aParams->vignsmooth == MUSE_TWILIGHT_PARAM_VIGNSMOOTH_MEDIAN) {
00762 cpl_msg_info(__func__, "Running %dx%d median filter...",
00763 aParams->vignxpar, aParams->vignypar);
00764 fit = cpl_image_duplicate(wdiv2);
00765 cpl_mask *mask = cpl_mask_new(aParams->vignxpar, aParams->vignypar);
00766 cpl_mask_not(mask);
00767 cpl_errorstate prestate = cpl_errorstate_get();
00768 cpl_image_filter_mask(fit, wdiv2, mask, CPL_FILTER_MEDIAN,
00769 CPL_BORDER_FILTER);
00770 cpl_mask_delete(mask);
00771
00772 cpl_image_threshold(fit, 1., FLT_MAX, 1., FLT_MAX);
00773 if (!cpl_errorstate_is_equal(prestate)) {
00774 cpl_msg_warning(__func__, "filtering vignetted ared failed: %s",
00775 cpl_error_get_message());
00776 }
00777 } else {
00778 cpl_msg_info(__func__, "Running polyfit...");
00779
00780
00781 cpl_image *wdiv3 = cpl_image_duplicate(wdiv2);
00782 cpl_image_threshold(wdiv3, 1., FLT_MAX, 1., FLT_MAX);
00783
00784
00785 fit = muse_utils_image_fit_polynomial(wdiv3, aParams->vignxpar,
00786 aParams->vignypar);
00787 cpl_image_delete(wdiv3);
00788
00789 cpl_image_threshold(fit, 1., FLT_MAX, 1., FLT_MAX);
00790 }
00791
00792
00793 cpl_image_reject_from_mask(fit, vignmask);
00794
00795
00796 cpl_image_fill_rejected(fit, 1.);
00797
00798
00799 image = muse_image_new();
00800 image->header = cpl_propertylist_new();
00801 cpl_propertylist_append_string(image->header, "OBJECT", "vignetting fit");
00802
00803 cpl_propertylist_append_string(image->header, "BUNIT", "");
00804 image->data = fit;
00805 image->dq = cpl_image_new_from_mask(cpl_image_get_bpm(fit));
00806 muse_imagelist_set(cubefit->recimages, image,
00807 muse_imagelist_get_size(cubefit->recimages));
00808 cpl_array_set_size(cubefit->recnames,
00809 cpl_array_get_size(cubefit->recnames) + 1);
00810 cpl_array_set_string(cubefit->recnames, cpl_array_get_size(cubefit->recnames) - 1,
00811 "vign_fit");
00812
00813
00814 image = muse_image_new();
00815 image->header = cpl_propertylist_new();
00816 cpl_propertylist_append_string(image->header, "OBJECT",
00817 "white image corrected by vignetting fit");
00818
00819 cpl_propertylist_append_string(image->header, "BUNIT", "count");
00820 image->data = cpl_image_divide_create(wdiv2, fit);
00821 image->dq = cpl_image_new_from_mask(cpl_image_get_bpm(image->data));
00822 muse_imagelist_set(cubefit->recimages, image,
00823 muse_imagelist_get_size(cubefit->recimages));
00824 cpl_array_set_size(cubefit->recnames,
00825 cpl_array_get_size(cubefit->recnames) + 1);
00826 cpl_array_set_string(cubefit->recnames, cpl_array_get_size(cubefit->recnames) - 1,
00827 "white_cor");
00828 cpl_image_delete(wdiv2);
00829
00830
00831 cpl_msg_info(__func__, "Combining smooth field of view and vignetted corner"
00832 " in %d planes", npl);
00833 for (ipl = 0; ipl < npl; ipl++) {
00834 cpl_image *cimage = cpl_imagelist_get(cubefit->data, ipl);
00835
00836
00837 cpl_image_accept_all(cimage);
00838 double mean1 = cpl_image_get_mean(cimage);
00839 cpl_image_multiply(cimage, fit);
00840
00841
00842 cpl_image_accept_all(cimage);
00843 double mean2 = cpl_image_get_mean(cimage);
00844 cpl_image_multiply_scalar(cimage, 1. / mean2);
00845 double mean3 = cpl_image_get_mean(cimage);
00846 if (fabs(mean3 - 1.) > FLT_EPSILON) {
00847 cpl_msg_warning(__func__, "normalization failed in plane %d: mean("
00848 "plane) = %f -> %f -> %f", ipl + 1, mean1, mean2, mean3);
00849 }
00850 }
00851 cpl_mask_delete(vignmask);
00852 }
00853 cpl_mask_delete(fovmask);
00854 muse_mask_delete(maskimage);
00855
00856 rc = muse_processing_save_cube(aProcessing, -1, cubefit,
00857 MUSE_TAG_TWILIGHT_CUBE,
00858 MUSE_CUBE_TYPE_FITS);
00859 muse_datacube_delete(cubefit);
00860
00861 return rc == CPL_ERROR_NONE ? 0 : -1;
00862 }