36 #include "muse_wavecal_z.h"
42 muse_wavecal_save_lsf_params(cpl_propertylist *aHeader,
46 cpl_error_code r = CPL_ERROR_NONE;
47 if (aSlicePars != NULL) {
50 "LSF_TABLE", CPL_FRAME_TYPE_TABLE);
52 const char *filename = cpl_frame_get_filename(frame);
53 cpl_msg_info(__func__,
"Saving LSF table as %s", filename);
54 char *channel = cpl_sprintf(
"CHAN%02d", aIFU);
55 cpl_propertylist_update_string(aHeader,
"EXTNAME", channel);
57 r = cpl_propertylist_save(aHeader, filename, CPL_IO_CREATE);
59 if (r == CPL_ERROR_NONE) {
62 cpl_frame_delete(frame);
70 muse_wavecal_compute_slice_lsf(cpl_table *aLines,
77 uint32_t origin = (uint32_t)cpl_table_get_int(aPixtable->
table,
78 MUSE_PIXTABLE_ORIGIN, 0, NULL);
83 cpl_msg_info(__func__,
"processing slice %hu.%hu with %"CPL_SIZE_FORMAT
" rows",
84 i_ifu, i_slice, nrows);
86 cpl_propertylist *order = cpl_propertylist_new();
87 cpl_propertylist_append_bool(order, MUSE_PIXTABLE_LAMBDA, CPL_FALSE);
88 cpl_table_sort(aPixtable->
table, order);
89 cpl_propertylist_delete(order);
91 cpl_array *lambda = NULL;
92 if (cpl_table_get_column_type(aPixtable->
table, MUSE_PIXTABLE_LAMBDA)
95 MUSE_PIXTABLE_LAMBDA);
97 cpl_table_cast_column(aPixtable->
table, MUSE_PIXTABLE_LAMBDA,
98 "lambda_double", CPL_TYPE_DOUBLE);
108 max_iterations, slice_fit_params);
109 lsf->slice = i_slice;
112 if (cpl_table_has_column(aPixtable->
table,
"lambda_double")) {
113 cpl_table_erase_column(aPixtable->
table,
"lambda_double");
116 cpl_array_unwrap(lambda);
117 cpl_array_unwrap(data);
118 cpl_array_unwrap(stat);
124 muse_wavecal_compute_lsf(cpl_table *aLines,
136 #pragma omp parallel for default(none) num_threads(2) \
137 shared(aLines, n_slices, i_slice, lsfParams, slice_pixtable, \
138 aFirstguess, max_iterations, slice_fit_params)
139 for (i_slice = 0; i_slice < n_slices; i_slice++) {
141 = (uint32_t)cpl_table_get_int(slice_pixtable[i_slice]->table,
142 MUSE_PIXTABLE_ORIGIN, 0, NULL);
148 cpl_errorstate prestate = cpl_errorstate_get();
150 = muse_wavecal_compute_slice_lsf(aLines, slice_pixtable[i_slice],
151 firstguess_slice, max_iterations,
153 if (!cpl_errorstate_is_equal(prestate)) {
154 cpl_msg_error(__func__,
"While processing slice %hu.%hu:", ifu, slice);
155 cpl_errorstate_dump(prestate, CPL_FALSE, NULL);
156 cpl_errorstate_set(prestate);
170 static cpl_error_code
171 muse_wavecal_qc_lsf(cpl_propertylist *aHeader,
174 double wavelength[] = { 5577.35, 8827.25, -1. };
176 char keyword[KEYWORD_LENGTH];
178 for (i = 0; wavelength[i] > 0; i++) {
179 snprintf(keyword, KEYWORD_LENGTH,
"ESO QC LSF%i AWAV", i+1);
180 cpl_propertylist_append_double(aHeader, keyword, wavelength[i]);
182 for (slice = aSlicePars; *slice != NULL; slice++) {
185 (*slice)->lsf_width);
186 snprintf(keyword, KEYWORD_LENGTH,
187 "ESO QC IFU%i SLICE%i LSF%i WIDTH",
188 (*slice)->ifu, (*slice)->slice, i+1);
189 cpl_propertylist_append_double(aHeader, keyword, width);
192 for (slice = aSlicePars; *slice != NULL; slice++) {
193 double offset = (*slice)->offset +
194 ((*slice)->refraction - 1) * wavelength[i];
195 snprintf(keyword, KEYWORD_LENGTH,
196 "ESO QC IFU%i SLICE%i LSF%i OFFSET",
197 (*slice)->ifu, (*slice)->slice, i+1);
198 cpl_propertylist_append_double(aHeader, keyword, offset);
200 for (slice = aSlicePars; *slice != NULL; slice++) {
202 1000., 0.01, 1000., NULL);
203 snprintf(keyword, KEYWORD_LENGTH,
204 "ESO QC IFU%i SLICE%i LSF%i FWHM",
205 (*slice)->ifu, (*slice)->slice, i+1);
206 cpl_propertylist_append_float(aHeader, keyword, fwhm);
210 for (slice = aSlicePars; *slice != NULL; slice++) {
211 double wcal_error = (*slice)->refraction - 1;
212 snprintf(keyword, KEYWORD_LENGTH,
213 "ESO QC IFU%i SLICE%i WAVECAL ERROR",
214 (*slice)->ifu, (*slice)->slice);
215 cpl_propertylist_append_double(aHeader, keyword, wcal_error);
218 return CPL_ERROR_NONE;
236 cpl_ensure(aImages && aProcessing, CPL_ERROR_NULL_INPUT, NULL);
239 char *pname = cpl_sprintf(
"muse.%s.combine", aProcessing->
recipeName);
240 cpl_parameter *param = cpl_parameterlist_find(aProcessing->
parameters, pname);
241 char *porig = cpl_strdup(cpl_parameter_get_string(param));
242 cpl_parameter_set_string(param,
"sum");
245 "muse.muse_wavecal");
246 cpl_parameter_set_string(param, porig);
251 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_OUTPUT,
252 "summing per-lamp images did not work");
260 cpl_errorstate state = cpl_errorstate_get();
262 while (cpl_errorstate_is_equal(state)) {
263 char *kwget = cpl_sprintf(QC_WAVECAL_PREFIXi
" "QC_BASIC_NSATURATED, i),
264 *kwout = cpl_sprintf(QC_WAVECAL_PREFIXli
" "QC_BASIC_NSATURATED, k+1, i);
268 if (cpl_errorstate_is_equal(state)) {
269 cpl_propertylist_update_int(image->
header, kwout, nsaturated);
277 cpl_errorstate_set(state);
304 if (aParams->
fitweighting == MUSE_WAVECAL_PARAM_FITWEIGHTING_CERR) {
306 }
else if (aParams->
fitweighting == MUSE_WAVECAL_PARAM_FITWEIGHTING_SCATTER) {
308 }
else if (aParams->
fitweighting == MUSE_WAVECAL_PARAM_FITWEIGHTING_CERRSCATTER) {
310 }
else if (aParams->
fitweighting != MUSE_WAVECAL_PARAM_FITWEIGHTING_UNIFORM) {
311 cpl_msg_error(__func__,
"unknown fitweighting method \"%s\"",
317 "muse.muse_wavecal");
318 cpl_frameset **labeledframes = NULL;
324 cpl_ensure(images, cpl_error_get_code(), -1);
330 for (k = 0; k < kimages; k++) {
332 if (!(kimages == 1 && needsum)) {
338 cpl_propertylist_erase_regexp(image->
header, MUSE_WCS_KEYS, 0);
340 MUSE_TAG_ARC_RED_LAMP);
344 cpl_frameset_delete(labeledframes[k]);
347 cpl_free(labeledframes);
351 masterimage = muse_wavecal_sum_and_save(images, aProcessing, aParams->
nifu);
355 cpl_table *linelist =
muse_table_load(aProcessing, MUSE_TAG_LINE_CATALOG, 0);
357 MUSE_TAG_LINE_CATALOG);
359 cpl_propertylist_delete(linehead);
361 cpl_table_delete(linelist);
367 cpl_table *tracetable =
muse_table_load(aProcessing, MUSE_TAG_TRACE_TABLE,
374 cpl_table *wavecaltable = NULL;
375 cpl_propertylist *header = NULL;
391 header = cpl_propertylist_duplicate(masterimage->
header);
396 cpl_table_delete(tracetable);
397 cpl_table_delete(linelist);
398 cpl_propertylist_delete(header);
405 cpl_propertylist_erase_regexp(header,
406 "^SIMPLE$|^BITPIX$|^NAXIS|^EXTEND$|^XTENSION$|"
407 "^DATASUM$|^DATAMIN$|^DATAMAX$|^DATAMD5$|"
408 "^PCOUNT$|^GCOUNT$|^HDUVERS$|^BLANK$|"
409 "^BZERO$|^BSCALE$|^BUNIT$|^CHECKSUM$|^INHERIT$|"
410 "^PIPEFILE$|^ESO PRO ", 0);
415 cpl_propertylist_erase_regexp(header, QC_WAVECAL_PREFIX, 0);
420 cpl_propertylist_delete(header);
429 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_INPUT,
"pixel table "
431 if (!getenv(
"MUSE_EXPERT_USER")) {
433 cpl_table_delete(wavecaltable);
434 cpl_table_delete(tracetable);
436 cpl_table_delete(linelist);
450 cpl_propertylist_erase_regexp(resampled->
header, QC_WAVECAL_PREFIX, 0);
452 resampled->
header, MUSE_TAG_ARC_RESAMP);
460 cpl_image *map =
muse_wave_map(image, wavecaltable, tracetable);
464 cpl_image_delete(map);
467 if (aParams->
lsf && pixtable) {
470 cpl_table_duplicate_column(pixtable->
table,
"orig_data", pixtable->
table,
476 cpl_table_erase_column(linelist, MUSE_LINE_CATALOG_FLUX);
477 cpl_table_name_column(linelist,
"Flux_for_LSF",
"flux");
479 cpl_table_unselect_all(linelist);
480 cpl_table_or_selected_int(linelist, MUSE_LINE_CATALOG_QUALITY,
482 cpl_table_or_selected_double(linelist,
"flux", CPL_NOT_GREATER_THAN, 0.);
483 cpl_table_erase_selected(linelist);
485 cpl_propertylist *flux_sort = cpl_propertylist_new();
486 cpl_propertylist_append_bool(flux_sort,
"flux", CPL_TRUE);
487 cpl_table_sort(linelist, flux_sort);
488 cpl_propertylist_delete(flux_sort);
490 if (nrows < cpl_table_get_nrow(linelist)) {
491 cpl_table_erase_window(linelist, nrows, cpl_table_get_nrow(linelist));
511 = muse_wavecal_compute_lsf(linelist, pixtable, firstguess, 40,
517 cpl_propertylist *qc_header = cpl_propertylist_new();
520 aProcessing, aParams->
nifu);
522 cpl_propertylist_delete(qc_header);
532 cpl_table_delete(wavecaltable);
535 cpl_table_delete(tracetable);
536 cpl_table_delete(linelist);
int muse_processing_save_cimage(muse_processing *aProcessing, int aIFU, cpl_image *aImage, cpl_propertylist *aHeader, const char *aTag)
Save a computed FITS image to disk.
cpl_table * muse_wave_calib_lampwise(muse_imagelist *aImages, cpl_table *aTrace, cpl_table *aLinelist, muse_wave_params *aParams)
Find wavelength calibration solution using a list of arc images with different lamps.
cpl_table * muse_wave_calib(muse_image *aImage, cpl_table *aTrace, cpl_table *aLinelist, muse_wave_params *aParams)
Find wavelength calibration solution on an arc frame.
muse_image * muse_resampling_image(muse_pixtable *aPixtable, muse_resampling_type aMethod, double aDX, double aDLambda)
Resample a pixel table onto a two-dimensional regular grid.
Structure definition for a collection of muse_images.
void muse_image_delete(muse_image *aImage)
Deallocate memory associated to a muse_image object.
double fitsigma
Sigma level for iterative rejection of deviant datapoints during the final polynomial wavelength solu...
muse_wave_weighting_type fitweighting
void muse_pixtable_extracted_delete(muse_pixtable **aPixtables)
Delete a pixel table array.
unsigned short muse_pixtable_origin_get_slice(uint32_t aOrigin)
Get the slice number from the encoded 32bit origin number.
cpl_size muse_pixtable_extracted_get_size(muse_pixtable **aPixtables)
Get the size of an array of extracted pixel tables.
cpl_size muse_pixtable_get_nrow(muse_pixtable *aPixtable)
get the number of rows within the pixel table
void muse_wave_params_delete(muse_wave_params *aParams)
Deallocate memory associated to a wavelength parameters structure.
double linesigma
Sigma level for iterative rejection of deviant fits for each arc line within each slice...
muse_imagelist * muse_basicproc_combine_images_lampwise(muse_processing *aProcessing, unsigned char aIFU, muse_basicproc_params *aBPars, cpl_frameset ***aLabeledFrames)
Combine several images into a lampwise image list.
muse_pixtable ** muse_pixtable_extracted_get_slices(muse_pixtable *aPixtable)
Extract one pixel table per IFU and slice.
cpl_image * data
the data extension
cpl_error_code muse_lsf_params_save(const muse_lsf_params **aLsf, const char *aFile)
Save slice LSF parameters to the extension "slice" on disk.
muse_lsf_params * muse_lsf_params_fit(const cpl_array *aLambda, cpl_array *aData, const cpl_array *aStat, const cpl_table *aLines, muse_lsf_params *aFirstGuess, int aMaxIter, const muse_sky_fit_params *aFitParams)
Fit all entries of one slice.
double dres
The allowed range of resolutions for pattern matching (of detected arc lines to line list) in fractio...
muse_lsf_params * muse_lsf_params_get(muse_lsf_params **aParams, int aIFU, int aSlice)
Get the slice LSF parameters for one slice.
void muse_imagelist_delete(muse_imagelist *aList)
Free the memory of the MUSE image list.
int lsf
Fit the line spread function for each slice and save the result in the output LSF_TABLE.
Structure to define which slice parameters are fit.
muse_basicproc_params * muse_basicproc_params_new(cpl_parameterlist *aParameters, const char *aPrefix)
Create a new structure of basic processing parameters.
muse_image * muse_combine_images(muse_combinepar *aCPars, muse_imagelist *aImages)
Combine several images into one.
void muse_sky_fit_params_delete(muse_sky_fit_params *)
Delete the fit parameter structure.
Structure definition of MUSE three extension FITS file.
muse_wave_weighting_type
Type of weighting to use in the wavelength calibration fit.
cpl_table * table
The pixel table.
void muse_basicproc_params_delete(muse_basicproc_params *aBPars)
Free a structure of basic processing parameters.
cpl_propertylist * header
the FITS header
unsigned int muse_imagelist_get_size(muse_imagelist *aList)
Return the number of stored images.
void muse_combinepar_delete(muse_combinepar *aCPars)
Clear the combination parameters.
double muse_lsf_fwhm_lambda(const muse_lsf_params *aDP, double aLambda, double aFlux, double aSampling, unsigned int aLength, FILE *aOutstream)
Measure the FWHM of an LSF at a given wavelength.
Structure definition of MUSE pixel table.
cpl_frame * muse_processing_new_frame(muse_processing *aProcessing, int aIFU, cpl_propertylist *aHeader, const char *aTag, cpl_frame_type aType)
Create a new frame for a result file.
muse_image * muse_imagelist_get(muse_imagelist *aList, unsigned int aIdx)
Get the muse_image of given list index.
cpl_array * muse_cpltable_extract_column(cpl_table *aTable, const char *aColumn)
Create an array from a section of a column.
int nifu
IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in ...
Structure containing wavelength calibration parameters.
muse_combinepar * muse_combinepar_new(cpl_parameterlist *aParameters, const char *aPrefix)
Create a new set of combination parameters.
cpl_frameset * outputFrames
int wavemap
Create a wavelength map of the input images.
int lampwise
Identify and measure the arc emission lines on images separately for each lamp setup.
int residuals
Create a table containing residuals of the fits to the data of all arc lines. This is useful to asses...
cpl_image * muse_wave_map(muse_image *aImage, const cpl_table *aWave, const cpl_table *aTrace)
Write out a wavelength map for visual checks.
int resample
Resample the input arc images onto 2D images for a visual check using tracing and wavelength calibrat...
muse_sky_fit_params * muse_sky_fit_params_new(cpl_boolean, cpl_boolean, cpl_size, cpl_size, cpl_size, cpl_size, cpl_size, cpl_size, cpl_size, cpl_size)
Create a new fit parameter structure.
muse_pixtable * muse_pixtable_create(muse_image *aImage, cpl_table *aTrace, cpl_table *aWave, cpl_table *aGeoTable)
Create the pixel table for one CCD.
int yorder
Order of the polynomial used to fit the dispersion relation.
int lsf_residuals
Store the residual pixel table after the LSF fit.
unsigned short muse_pixtable_origin_get_ifu(uint32_t aOrigin)
Get the IFU number from the encoded 32bit origin number.
int muse_processing_save_image(muse_processing *aProcessing, int aIFU, muse_image *aImage, const char *aTag)
Save a computed MUSE image to disk.
int fitweighting
Type of weighting to use in the final polynomial wavelength solution fit, using centroiding error est...
cpl_table * muse_table_load(muse_processing *aProcessing, const char *aTag, unsigned char aIFU)
load a table according to its tag and IFU/channel number
cpl_error_code muse_processing_save_table(muse_processing *aProcessing, int aIFU, void *aTable, cpl_propertylist *aHeader, const char *aTag, muse_table_type aType)
Save a computed table to disk.
Structure of basic processing parameters.
Structure to hold the parameters of the muse_wavecal recipe.
muse_lsf_params ** muse_processing_lsf_params_load(muse_processing *aProcessing, int aIFU)
Load slice LSF parameters.
cpl_propertylist * muse_propertylist_load(muse_processing *aProcessing, const char *aTag)
load a propertylist according to its tag
cpl_boolean muse_wave_lines_check(cpl_table *aTable, cpl_propertylist *aHeader)
Check that a LINE_CATALOG has the expected format.
double tolerance
Tolerance for pattern matching (of detected arc lines to line list)
Structure definition of detector (slice) parameters.
cpl_frameset * usedFrames
double muse_cplarray_poly1d_double(double aDouble, const cpl_array *aCoeff)
Apply a polynomial to a double value.
void muse_pixtable_delete(muse_pixtable *aPixtable)
Deallocate memory associated to a pixel table object.
muse_wave_params * muse_wave_params_new(void)
Allocate a wavelength parameters structure and fill it with defaults.
const char * fitweighting_s
Type of weighting to use in the final polynomial wavelength solution fit, using centroiding error est...
double sigma
Sigma level used to detect arc emission lines above the median background level in the S/N image of t...
cpl_parameterlist * parameters
void muse_lsf_params_delete(muse_lsf_params **aParams)
Delete an allocated array of muse_lsf_params structure.
int xorder
Order of the polynomial for the horizontal curvature within each slice.
cpl_error_code muse_basicproc_qc_saturated(muse_image *aImage, const char *aPrefix)
Add QC parameter about saturated pixels to a muse_image.