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_qi_mask_z.h"
00033
00034
00035
00036
00037
00038
00048
00049 static void
00050 muse_qi_mask_wavecal_polys(cpl_propertylist *aHeader, cpl_table *aWC,
00051 cpl_table *aTT)
00052 {
00053 if (!aHeader || !aWC || !aTT) {
00054 cpl_error_set_message(__func__, CPL_ERROR_NULL_INPUT, "Could not create per"
00055 "-slice wavelength polynomials in the FITS header!");
00056 return;
00057 }
00058
00059
00060 const unsigned int kSteps = 50;
00061
00062
00063 cpl_matrix *pos = cpl_matrix_new(1, kMuseSlicesPerCCD * kSteps);
00064 cpl_vector *val = cpl_vector_new(kMuseSlicesPerCCD * kSteps),
00065 *ycenters = cpl_vector_new(kMuseSlicesPerCCD);
00066 cpl_size ipos = 0;
00067 unsigned short nslice;
00068 for (nslice = 1; nslice <= kMuseSlicesPerCCD; nslice++) {
00069 cpl_polynomial *pw = muse_wave_table_get_poly_for_slice(aWC, nslice),
00070 **pt = muse_trace_table_get_polys_for_slice(aTT, nslice);
00071
00072 double x = cpl_polynomial_eval_1d(pt[MUSE_TRACE_CENTER], kMuseOutputYTop/2,
00073 NULL);
00074 muse_trace_polys_delete(pt);
00075
00076 cpl_polynomial *pconst = cpl_polynomial_new(1);
00077 cpl_size pows = 0;
00078 cpl_polynomial_set_coeff(pconst, &pows, x);
00079
00080 cpl_polynomial *pwcen = cpl_polynomial_extract(pw, 0, pconst);
00081 double ycen = cpl_polynomial_eval_1d(pwcen, kMuseOutputYTop/2, NULL);
00082 cpl_vector_set(ycenters, nslice - 1, ycen);
00083 cpl_polynomial_delete(pconst);
00084 cpl_polynomial_delete(pw);
00085
00086
00087 pows = 0;
00088 double c0 = cpl_polynomial_get_coeff(pwcen, &pows);
00089 cpl_polynomial_set_coeff(pwcen, &pows, c0 - ycen);
00090
00091 unsigned int iy;
00092 for (iy = 1;
00093 iy <= (unsigned)kMuseOutputYTop;
00094 iy += ((unsigned)kMuseOutputYTop) / (kSteps - 1)) {
00095 cpl_matrix_set(pos, 0, ipos, iy);
00096 cpl_vector_set(val, ipos++, cpl_polynomial_eval_1d(pwcen, iy, NULL));
00097 }
00098 }
00099
00100
00101 cpl_polynomial *fit = cpl_polynomial_new(1);
00102 cpl_size maxdeg = 2;
00103 cpl_polynomial_fit(fit, pos, NULL, val, NULL, CPL_TRUE, NULL, &maxdeg);
00104 #if 0
00105 cpl_vector *res = cpl_vector_duplicate(val);
00106 double chisq;
00107 cpl_vector_fill_polynomial_fit_residual(res, val, NULL, fit, pos, &chisq);
00108 const double mse = cpl_vector_product(res, res)
00109 / cpl_vector_get_size(res);
00110 cpl_vector_delete(res);
00111 cpl_msg_debug(__func__, "MSE=%g ChiSq=%g", mse, chisq);
00112 #endif
00113 cpl_vector_delete(val);
00114 cpl_matrix_delete(pos);
00115
00116
00117 char keyword[KEYWORD_LENGTH];
00118 cpl_size j = 0;
00119 for (nslice = 1; nslice <= kMuseSlicesPerCCD; nslice++) {
00120 snprintf(keyword, KEYWORD_LENGTH, "ESO DET WLEN SLICE%hu POLY0", nslice);
00121
00122 double zeropoint = cpl_polynomial_get_coeff(fit, &j)
00123 + cpl_vector_get(ycenters, nslice - 1);
00124 cpl_propertylist_append_float(aHeader, keyword, zeropoint);
00125 cpl_propertylist_set_comment(aHeader, keyword,
00126 "[Angstrom] Slice-specific zero-point");
00127 }
00128 cpl_vector_delete(ycenters);
00129
00130
00131 for (j = 1; j <= 2; j++) {
00132 snprintf(keyword, KEYWORD_LENGTH, "ESO DET WLEN POLY%d", (int)j);
00133 cpl_propertylist_append_float(aHeader, keyword,
00134 cpl_polynomial_get_coeff(fit, &j));
00135 char comment[100];
00136 snprintf(comment, 99, "[Angstrom] Common %s-order polynomial coefficient",
00137 j == 1 ? "1st" : "2nd");
00138 cpl_propertylist_set_comment(aHeader, keyword, comment);
00139 }
00140 cpl_polynomial_delete(fit);
00141 }
00142
00143
00154
00155 int
00156 muse_qi_mask_compute(muse_processing *aProcessing,
00157 muse_qi_mask_params_t *aParams)
00158 {
00159
00160 double wmin = 4650.,
00161 wmax = 9300.;
00162
00163 cpl_msg_info(__func__, "Creating mask for full MUSE wavelength range "
00164 "(%.1f...%.1f)", wmin, wmax);
00165
00166
00167
00168 cpl_frame *frame = cpl_frameset_find(aProcessing->inframes, MUSE_TAG_BIAS);
00169 if (frame) {
00170 muse_processing_append_used(aProcessing, frame, CPL_FRAME_GROUP_RAW, 1);
00171 }
00172
00173
00174 cpl_propertylist *header = cpl_propertylist_new();
00175 cpl_propertylist_append_string(header, "OBJECT", "Mask full MUSE range");
00176 cpl_propertylist_append_float(header, "ESO DET FRS WMIN", wmin);
00177 cpl_propertylist_set_comment(header, "ESO DET FRS WMIN", "[Angstrom] Minimum wavelength");
00178 cpl_propertylist_append_float(header, "ESO DET FRS WMAX", wmax);
00179 cpl_propertylist_set_comment(header, "ESO DET FRS WMAX", "[Angstrom] Maximum wavelength");
00180 muse_processing_save_header(aProcessing, aParams->nifu ? aParams->nifu : -1,
00181 header, MUSE_TAG_MASK_IMAGE);
00182 cpl_propertylist_delete(header);
00183
00184
00185 frame = cpl_frameset_find(aProcessing->outframes, MUSE_TAG_MASK_IMAGE);
00186 const char *fn = cpl_frame_get_filename(frame);
00187
00188
00189 int n1 = aParams->nifu ? aParams->nifu : 1,
00190 n2 = aParams->nifu ? aParams->nifu : kMuseNumIFUs,
00191 nifu;
00192 for (nifu = n1; nifu <= n2; nifu++) {
00193
00194 cpl_errorstate prestate = cpl_errorstate_get();
00195 muse_imagelist *images = muse_basicproc_load(aProcessing, nifu, NULL);
00196 muse_image *image = NULL;
00197 if (images) {
00198 cpl_msg_debug(__func__, "succeeded to load %u raw images, using first one",
00199 muse_imagelist_get_size(images));
00200 image = muse_imagelist_get(images, 0);
00201 } else {
00202 cpl_msg_warning(__func__, "failed to load raw image, assuming 1x1 binning");
00203 cpl_errorstate_dump(prestate, CPL_FALSE, muse_cplerrorstate_dump_some);
00204 image = muse_image_new();
00205
00206 image->data = cpl_image_new(kMuseOutputXRight, kMuseOutputYTop,
00207 CPL_TYPE_FLOAT);
00208 image->header = cpl_propertylist_new();
00209 cpl_propertylist_append_int(image->header, "ESO DET BINX", 1);
00210 cpl_propertylist_append_int(image->header, "ESO DET BINY", 1);
00211 images = muse_imagelist_new();
00212 muse_imagelist_set(images, image, 0);
00213 }
00214
00215
00216 cpl_table *wavecaltable = muse_table_load(aProcessing,
00217 MUSE_TAG_WAVECAL_TABLE, nifu);
00218 cpl_table *tracetable = muse_table_load(aProcessing,
00219 MUSE_TAG_TRACE_TABLE, nifu);
00220
00221
00222 int binx = muse_pfits_get_binx(image->header),
00223 biny = muse_pfits_get_biny(image->header);
00224 muse_image *imunbinned = image;
00225 if (binx != 1 || biny != 1) {
00226 imunbinned = muse_image_new();
00227 imunbinned->data = cpl_image_new(kMuseOutputXRight, kMuseOutputYTop,
00228 CPL_TYPE_FLOAT);
00229 }
00230 cpl_image *wavemap = muse_wave_map(imunbinned, wavecaltable, tracetable);
00231
00232
00233 if (binx != 1 || biny != 1) {
00234 muse_image_delete(imunbinned);
00235 cpl_msg_info(__func__, "Rebinning wavelength map %dx%d", binx, biny);
00236 cpl_image *binned = cpl_image_rebin(wavemap, 1, 1, binx, biny);
00237 cpl_image_delete(wavemap);
00238
00239 wavemap = cpl_image_divide_scalar_create(binned, binx * biny);
00240 cpl_image_delete(binned);
00241 }
00242
00243
00244 cpl_mask *mask = cpl_mask_threshold_image_create(wavemap, wmin, wmax);
00245
00246
00247 header = cpl_propertylist_new();
00248 if (binx == 1 && biny == 1) {
00249 muse_qi_mask_wavecal_polys(header, wavecaltable, tracetable);
00250 }
00251
00252
00253
00254
00255
00256 int nx = cpl_mask_get_size_x(mask),
00257 ny = cpl_mask_get_size_y(mask);
00258 cpl_size ndet;
00259 cpl_image *labeled = cpl_image_labelise_mask_create(mask, &ndet);
00260
00261 cpl_apertures *apertures = cpl_apertures_new_from_image(labeled, labeled);
00262 int napertures = cpl_apertures_get_size(apertures);
00263
00264
00265
00266 cpl_matrix *mlabels = cpl_matrix_new(2, napertures);
00267 int n;
00268 for (n = 1; n <= napertures; n++) {
00269 cpl_matrix_set(mlabels, 0, n - 1,
00270 cpl_apertures_get_left(apertures, n));
00271 cpl_matrix_set(mlabels, 1, n - 1, n);
00272 }
00273 cpl_matrix_sort_columns(mlabels, 1);
00274 #if 0
00275 cpl_matrix_dump(mlabels, stdout);
00276 #endif
00277 int m,
00278 nslice = 1;
00279 for (m = 1; m <= ndet; m++) {
00280 n = cpl_matrix_get(mlabels, 1, m - 1);
00281
00282 int x1 = cpl_apertures_get_left(apertures, n),
00283 x2 = cpl_apertures_get_right(apertures, n),
00284 y1 = cpl_apertures_get_bottom(apertures, n),
00285 y2 = cpl_apertures_get_top(apertures, n);
00286 if (x1 == x2 || y1 == y2) {
00287
00288
00289 int i;
00290 for (i = x1; i <= x2; i++) {
00291 int j;
00292 for (j = y1; j <= y2; j++) {
00293 cpl_mask_set(mask, i, j, CPL_BINARY_0);
00294 }
00295 }
00296 cpl_msg_debug(__func__, "Excluding aperture [%d:%d,%d:%d]", x1, x2, y1, y2);
00297 continue;
00298 }
00299
00300 x1 += 32 / binx;
00301 x2 += 32 / binx;
00302 y1 += 32 / biny;
00303 y2 += 32 / biny;
00304
00305 if (x1 > nx/2+32/binx) x1 += 64 / binx;
00306 if (x2 > nx/2+32/binx) x2 += 64 / binx;
00307 if (y1 > ny/2+32/biny) y1 += 64 / biny;
00308 if (y2 > ny/2+32/biny) y2 += 64 / biny;
00309 #if 0
00310 int xc = (x1 + x2) / 2,
00311 yc = (y1 + y2) / 2,
00312 w = x2 - x1 + 1,
00313 h = y2 - y1 + 1;
00314 cpl_msg_debug(__func__, "Aperture %2d Slice %2d: [%d:%d,%d:%d] center %d,%d size %dx%d",
00315 n, m, x1, x2, y1, y2, xc, yc, w, h);
00316 #endif
00317 char keyword[KEYWORD_LENGTH];
00318 snprintf(keyword, KEYWORD_LENGTH, "ESO DET SLICE%d XSTART", nslice);
00319 cpl_propertylist_append_int(header, keyword, x1);
00320 cpl_propertylist_set_comment(header, keyword, "[pix] Start position of the slice along X");
00321 snprintf(keyword, KEYWORD_LENGTH, "ESO DET SLICE%d YSTART", nslice);
00322 cpl_propertylist_append_int(header, keyword, y1);
00323 cpl_propertylist_set_comment(header, keyword, "[pix] Start position of the slice along Y");
00324 snprintf(keyword, KEYWORD_LENGTH, "ESO DET SLICE%d XEND", nslice);
00325 cpl_propertylist_append_int(header, keyword, x2);
00326 cpl_propertylist_set_comment(header, keyword, "[pix] End position of the slice along X");
00327 snprintf(keyword, KEYWORD_LENGTH, "ESO DET SLICE%d YEND", nslice);
00328 cpl_propertylist_append_int(header, keyword, y2);
00329 cpl_propertylist_set_comment(header, keyword, "[pix] End position of the slice along Y");
00330 nslice++;
00331 }
00332 cpl_image_delete(labeled);
00333 cpl_apertures_delete(apertures);
00334 cpl_matrix_delete(mlabels);
00335 if (nslice - 1 != kMuseSlicesPerCCD) {
00336 cpl_msg_warning(__func__, "Found %d slices (%d apertures) instead of %d",
00337 nslice - 1, napertures, kMuseSlicesPerCCD);
00338 }
00339
00340
00341 cpl_mask *untrimmed = cpl_mask_new(nx + 4*32/binx, ny + 4*32/biny);
00342 cpl_mask *m1 = cpl_mask_extract(mask, 1, 1, nx/2-1, ny/2-1),
00343 *m2 = cpl_mask_extract(mask, 1, ny/2, nx/2-1, ny),
00344 *m3 = cpl_mask_extract(mask, nx/2, 1, nx, ny/2-1),
00345 *m4 = cpl_mask_extract(mask, nx/2, ny/2, nx, ny);
00346 cpl_mask_copy(untrimmed, m1, 32/binx+1, 32/biny+1);
00347 cpl_mask_copy(untrimmed, m2, 32/binx+1, ny/2+3*32/biny);
00348 cpl_mask_copy(untrimmed, m3, nx/2+3*32/binx, 32/biny+1);
00349 cpl_mask_copy(untrimmed, m4, nx/2+3*32/binx, ny/2+3*32/biny);
00350 cpl_mask_delete(m1);
00351 cpl_mask_delete(m2);
00352 cpl_mask_delete(m3);
00353 cpl_mask_delete(m4);
00354 cpl_mask_delete(mask);
00355 mask = untrimmed;
00356
00357
00358 if (image->header) {
00359
00360 cpl_propertylist_copy_property_regexp(header, image->header,
00361 "ESO DET (CHIP |OUT)|EXTNAME", 0);
00362 } else {
00363
00364 char *extname = cpl_sprintf("CHAN%02d", nifu);
00365 cpl_propertylist_append_string(header, "EXTNAME", extname);
00366 cpl_free(extname);
00367 }
00368 cpl_mask_save(mask, fn, header, CPL_IO_EXTEND);
00369 cpl_propertylist_delete(header);
00370 cpl_image_delete(wavemap);
00371 cpl_mask_delete(mask);
00372 cpl_table_delete(tracetable);
00373 cpl_table_delete(wavecaltable);
00374 muse_imagelist_delete(images);
00375 }
00376
00377 return 0;
00378 }