33 #include "muse_qi_mask_z.h"
51 muse_qi_mask_wavecal_polys(cpl_propertylist *aHeader, cpl_table *aWC,
54 if (!aHeader || !aWC || !aTT) {
55 cpl_error_set_message(__func__, CPL_ERROR_NULL_INPUT,
"Could not create per"
56 "-slice wavelength polynomials in the FITS header!");
61 const unsigned int kSteps = 50;
64 cpl_matrix *pos = cpl_matrix_new(1, kMuseSlicesPerCCD * kSteps);
65 cpl_vector *val = cpl_vector_new(kMuseSlicesPerCCD * kSteps),
66 *ycenters = cpl_vector_new(kMuseSlicesPerCCD);
68 unsigned short nslice;
69 for (nslice = 1; nslice <= kMuseSlicesPerCCD; nslice++) {
73 double x = cpl_polynomial_eval_1d(pt[MUSE_TRACE_CENTER], kMuseOutputYTop/2,
77 cpl_polynomial *pconst = cpl_polynomial_new(1);
79 cpl_polynomial_set_coeff(pconst, &pows, x);
81 cpl_polynomial *pwcen = cpl_polynomial_extract(pw, 0, pconst);
82 double ycen = cpl_polynomial_eval_1d(pwcen, kMuseOutputYTop/2, NULL);
83 cpl_vector_set(ycenters, nslice - 1, ycen);
84 cpl_polynomial_delete(pconst);
85 cpl_polynomial_delete(pw);
89 double c0 = cpl_polynomial_get_coeff(pwcen, &pows);
90 cpl_polynomial_set_coeff(pwcen, &pows, c0 - ycen);
94 iy <= (unsigned)kMuseOutputYTop;
95 iy += ((unsigned)kMuseOutputYTop) / (kSteps - 1)) {
96 cpl_matrix_set(pos, 0, ipos, iy);
97 cpl_vector_set(val, ipos++, cpl_polynomial_eval_1d(pwcen, iy, NULL));
102 cpl_polynomial *fit = cpl_polynomial_new(1);
104 cpl_polynomial_fit(fit, pos, CPL_FALSE, val, NULL, CPL_TRUE, NULL, &maxdeg);
106 cpl_vector *res = cpl_vector_duplicate(val);
108 cpl_vector_fill_polynomial_fit_residual(res, val, NULL, fit, pos, &chisq);
109 const double mse = cpl_vector_product(res, res)
110 / cpl_vector_get_size(res);
111 cpl_vector_delete(res);
112 cpl_msg_debug(__func__,
"MSE=%g ChiSq=%g", mse, chisq);
114 cpl_vector_delete(val);
115 cpl_matrix_delete(pos);
118 char keyword[KEYWORD_LENGTH];
120 for (nslice = 1; nslice <= kMuseSlicesPerCCD; nslice++) {
121 snprintf(keyword, KEYWORD_LENGTH,
"ESO DET WLEN SLICE%hu POLY0", nslice);
123 double zeropoint = cpl_polynomial_get_coeff(fit, &j)
124 + cpl_vector_get(ycenters, nslice - 1);
125 cpl_propertylist_append_float(aHeader, keyword, zeropoint);
126 cpl_propertylist_set_comment(aHeader, keyword,
127 "[Angstrom] Slice-specific zero-point");
129 cpl_vector_delete(ycenters);
132 for (j = 1; j <= 2; j++) {
133 snprintf(keyword, KEYWORD_LENGTH,
"ESO DET WLEN POLY%d", (
int)j);
134 cpl_propertylist_append_float(aHeader, keyword,
135 cpl_polynomial_get_coeff(fit, &j));
137 snprintf(comment, 99,
"[Angstrom] Common %s-order polynomial coefficient",
138 j == 1 ?
"1st" :
"2nd");
139 cpl_propertylist_set_comment(aHeader, keyword, comment);
141 cpl_polynomial_delete(fit);
161 double wmin = aParams->
wmin,
162 wmax = aParams->
wmax;
163 const char *wrange = aParams->
wrange_s;
164 if (!strncmp(wrange,
"MUSE", 5)) {
167 }
else if (!strncmp(wrange,
"B", 2)) {
170 }
else if (!strncmp(wrange,
"V", 2)) {
173 }
else if (!strncmp(wrange,
"R", 2)) {
176 }
else if (!strncmp(wrange,
"I", 2)) {
183 cpl_msg_info(__func__,
"Creating mask for wavelength range %s (%.2f ... %.2f)",
188 cpl_frame *frame = cpl_frameset_find(aProcessing->
inputFrames,
195 cpl_propertylist *header = cpl_propertylist_new();
196 char *
object = cpl_sprintf(
"Mask %s", wrange);
197 cpl_propertylist_append_string(header,
"OBJECT",
object);
198 cpl_propertylist_append_string(header,
"ESO DET FRS WRANGE", wrange);
199 cpl_propertylist_set_comment(header,
"ESO DET FRS WRANGE",
"Wavelength range");
200 cpl_propertylist_append_float(header,
"ESO DET FRS WMIN", wmin);
201 cpl_propertylist_set_comment(header,
"ESO DET FRS WMIN",
"[Angstrom] Minimum wavelength");
202 cpl_propertylist_append_float(header,
"ESO DET FRS WMAX", wmax);
203 cpl_propertylist_set_comment(header,
"ESO DET FRS WMAX",
"[Angstrom] Maximum wavelength");
205 header, MUSE_TAG_MASK_IMAGE);
207 cpl_propertylist_delete(header);
210 frame = cpl_frameset_find(aProcessing->
outputFrames, MUSE_TAG_MASK_IMAGE);
211 const char *fn = cpl_frame_get_filename(frame);
214 int n1 = aParams->
nifu ? aParams->
nifu : 1,
215 n2 = aParams->
nifu ? aParams->
nifu : kMuseNumIFUs,
217 for (nifu = n1; nifu <= n2; nifu++) {
219 cpl_errorstate prestate = cpl_errorstate_get();
223 cpl_msg_debug(__func__,
"succeeded to load %u raw images, using first one",
227 cpl_msg_warning(__func__,
"failed to load raw image, assuming 1x1 binning");
231 image->
data = cpl_image_new(kMuseOutputXRight, kMuseOutputYTop,
233 image->
header = cpl_propertylist_new();
234 cpl_propertylist_append_int(image->
header,
"ESO DET BINX", 1);
235 cpl_propertylist_append_int(image->
header,
"ESO DET BINY", 1);
242 MUSE_TAG_WAVECAL_TABLE, nifu);
244 MUSE_TAG_TRACE_TABLE, nifu);
250 if (binx != 1 || biny != 1) {
252 imunbinned->
data = cpl_image_new(kMuseOutputXRight, kMuseOutputYTop,
255 cpl_image *wavemap =
muse_wave_map(imunbinned, wavecaltable, tracetable);
258 if (binx != 1 || biny != 1) {
260 cpl_msg_info(__func__,
"Rebinning wavelength map %dx%d", binx, biny);
261 cpl_image *binned = cpl_image_rebin(wavemap, 1, 1, binx, biny);
262 cpl_image_delete(wavemap);
264 wavemap = cpl_image_divide_scalar_create(binned, binx * biny);
265 cpl_image_delete(binned);
269 cpl_mask *mask = cpl_mask_threshold_image_create(wavemap, wmin, wmax);
272 header = cpl_propertylist_new();
273 if (binx == 1 && biny == 1) {
274 muse_qi_mask_wavecal_polys(header, wavecaltable, tracetable);
281 int nx = cpl_mask_get_size_x(mask),
282 ny = cpl_mask_get_size_y(mask);
284 cpl_image *labeled = cpl_image_labelise_mask_create(mask, &ndet);
286 cpl_apertures *apertures = cpl_apertures_new_from_image(labeled, labeled);
287 int napertures = cpl_apertures_get_size(apertures);
291 cpl_matrix *mlabels = cpl_matrix_new(2, napertures);
293 for (n = 1; n <= napertures; n++) {
294 cpl_matrix_set(mlabels, 0, n - 1,
295 cpl_apertures_get_left(apertures, n));
296 cpl_matrix_set(mlabels, 1, n - 1, n);
298 cpl_matrix_sort_columns(mlabels, 1);
300 cpl_matrix_dump(mlabels, stdout);
304 for (m = 1; m <= ndet; m++) {
305 n = cpl_matrix_get(mlabels, 1, m - 1);
307 int x1 = cpl_apertures_get_left(apertures, n),
308 x2 = cpl_apertures_get_right(apertures, n),
309 y1 = cpl_apertures_get_bottom(apertures, n),
310 y2 = cpl_apertures_get_top(apertures, n);
311 if (x1 == x2 || y1 == y2) {
315 for (i = x1; i <= x2; i++) {
317 for (j = y1; j <= y2; j++) {
318 cpl_mask_set(mask, i, j, CPL_BINARY_0);
321 cpl_msg_debug(__func__,
"Excluding aperture [%d:%d,%d:%d]", x1, x2, y1, y2);
330 if (x1 > nx/2+32/binx) x1 += 64 / binx;
331 if (x2 > nx/2+32/binx) x2 += 64 / binx;
332 if (y1 > ny/2+32/biny) y1 += 64 / biny;
333 if (y2 > ny/2+32/biny) y2 += 64 / biny;
335 int xc = (x1 + x2) / 2,
339 cpl_msg_debug(__func__,
"Aperture %2d Slice %2d: [%d:%d,%d:%d] center %d,%d size %dx%d",
340 n, m, x1, x2, y1, y2, xc, yc, w, h);
342 char keyword[KEYWORD_LENGTH];
343 snprintf(keyword, KEYWORD_LENGTH,
"ESO DET SLICE%d XSTART", nslice);
344 cpl_propertylist_append_int(header, keyword, x1);
345 cpl_propertylist_set_comment(header, keyword,
"[pix] Start position of the slice along X");
346 snprintf(keyword, KEYWORD_LENGTH,
"ESO DET SLICE%d YSTART", nslice);
347 cpl_propertylist_append_int(header, keyword, y1);
348 cpl_propertylist_set_comment(header, keyword,
"[pix] Start position of the slice along Y");
349 snprintf(keyword, KEYWORD_LENGTH,
"ESO DET SLICE%d XEND", nslice);
350 cpl_propertylist_append_int(header, keyword, x2);
351 cpl_propertylist_set_comment(header, keyword,
"[pix] End position of the slice along X");
352 snprintf(keyword, KEYWORD_LENGTH,
"ESO DET SLICE%d YEND", nslice);
353 cpl_propertylist_append_int(header, keyword, y2);
354 cpl_propertylist_set_comment(header, keyword,
"[pix] End position of the slice along Y");
357 cpl_image_delete(labeled);
358 cpl_apertures_delete(apertures);
359 cpl_matrix_delete(mlabels);
360 if (nslice - 1 != kMuseSlicesPerCCD) {
361 cpl_msg_warning(__func__,
"Found %d slices (%d apertures) instead of %d",
362 nslice - 1, napertures, kMuseSlicesPerCCD);
366 cpl_mask *untrimmed = cpl_mask_new(nx + 4*32/binx, ny + 4*32/biny);
367 cpl_mask *m1 = cpl_mask_extract(mask, 1, 1, nx/2-1, ny/2-1),
368 *m2 = cpl_mask_extract(mask, 1, ny/2, nx/2-1, ny),
369 *m3 = cpl_mask_extract(mask, nx/2, 1, nx, ny/2-1),
370 *m4 = cpl_mask_extract(mask, nx/2, ny/2, nx, ny);
371 cpl_mask_copy(untrimmed, m1, 32/binx+1, 32/biny+1);
372 cpl_mask_copy(untrimmed, m2, 32/binx+1, ny/2+3*32/biny);
373 cpl_mask_copy(untrimmed, m3, nx/2+3*32/binx, 32/biny+1);
374 cpl_mask_copy(untrimmed, m4, nx/2+3*32/binx, ny/2+3*32/biny);
379 cpl_mask_delete(mask);
385 cpl_propertylist_copy_property_regexp(header, image->
header,
386 "ESO DET (CHIP |OUT)|EXTNAME", 0);
389 char *extname = cpl_sprintf(
"CHAN%02d", nifu);
390 cpl_propertylist_append_string(header,
"EXTNAME", extname);
393 cpl_mask_save(mask, fn, header, CPL_IO_EXTEND);
394 cpl_propertylist_delete(header);
395 cpl_image_delete(wavemap);
396 cpl_mask_delete(mask);
397 cpl_table_delete(tracetable);
398 cpl_table_delete(wavecaltable);
muse_imagelist * muse_basicproc_load(muse_processing *aProcessing, unsigned char aIFU, muse_basicproc_params *aBPars)
Load the raw input files from disk and do basic processing.
cpl_polynomial ** muse_trace_table_get_polys_for_slice(const cpl_table *aTable, const unsigned short aSlice)
construct polynomial from the trace table entry for the given slice
Structure definition for a collection of muse_images.
void muse_image_delete(muse_image *aImage)
Deallocate memory associated to a muse_image object.
cpl_polynomial * muse_wave_table_get_poly_for_slice(const cpl_table *aTable, const unsigned short aSlice)
Construct polynomial from the wavelength calibration table entry for the given slice.
cpl_image * data
the data extension
void muse_imagelist_delete(muse_imagelist *aList)
Free the memory of the MUSE image list.
Structure definition of MUSE three extension FITS file.
cpl_propertylist * header
the FITS header
unsigned int muse_imagelist_get_size(muse_imagelist *aList)
Return the number of stored images.
void muse_trace_polys_delete(cpl_polynomial *aPolys[])
Delete the multi-polynomial array created in relation to tracing.
cpl_error_code muse_processing_save_header(muse_processing *aProcessing, int aIFU, cpl_propertylist *aHeader, const char *aTag)
Save a FITS header to disk.
int muse_pfits_get_biny(const cpl_propertylist *aHeaders)
find out the binning factor in y direction
double wmax
Lower boundary of the wavelength range [Angstrom]. Only used when wrange=custom.
muse_image * muse_imagelist_get(muse_imagelist *aList, unsigned int aIdx)
Get the muse_image of given list index.
cpl_frameset * outputFrames
void muse_cplerrorstate_dump_some(unsigned aCurrent, unsigned aFirst, unsigned aLast)
Dump some CPL errors.
cpl_image * muse_wave_map(muse_image *aImage, const cpl_table *aWave, const cpl_table *aTrace)
Write out a wavelength map for visual checks.
const char * wrange_s
Wavelength range (filter name) of the setup. Set this to "custom" to set up a new wavelength range us...
void muse_processing_append_used(muse_processing *aProcessing, cpl_frame *aFrame, cpl_frame_group aGroup, int aDuplicate)
Add a frame to the set of used frames.
double wmin
Lower boundary of the wavelength range [Angstrom]. Only used when wrange=custom.
Structure to hold the parameters of the muse_qi_mask recipe.
int muse_pfits_get_binx(const cpl_propertylist *aHeaders)
find out the binning factor in x direction
muse_imagelist * muse_imagelist_new(void)
Create a new (empty) MUSE image list.
cpl_table * muse_table_load(muse_processing *aProcessing, const char *aTag, unsigned char aIFU)
load a table according to its tag and IFU/channel number
muse_image * muse_image_new(void)
Allocate memory for a new muse_image object.
cpl_frameset * inputFrames
cpl_error_code muse_imagelist_set(muse_imagelist *aList, muse_image *aImage, unsigned int aIdx)
Set the muse_image of given list index.
int nifu
IFU to handle. If set to 0, all IFUs are processed serially, which is the recommendation for this rec...