MUSE Pipeline Reference Manual  0.18.1
muse_wavecal.c
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set sw=2 sts=2 et cin: */
3 /*
4  *
5  * This file is part of the MUSE Instrument Pipeline
6  * Copyright (C) 2005-2011 European Southern Observatory
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 /*----------------------------------------------------------------------------*
28  * Includes *
29  *----------------------------------------------------------------------------*/
30 #include <stdio.h>
31 #include <float.h>
32 #include <math.h>
33 #include <string.h>
34 #include <cpl.h>
35 #include <muse.h>
36 #include "muse_wavecal_z.h"
37 
38 /*---------------------------------------------------------------------------*
39  * Functions code *
40  *---------------------------------------------------------------------------*/
41 static cpl_error_code
42 muse_wavecal_save_lsf_params(cpl_propertylist *aHeader,
43  const muse_lsf_params **aSlicePars,
44  muse_processing *aProcessing, int aIFU)
45 {
46  cpl_error_code r = CPL_ERROR_NONE;
47  if (aSlicePars != NULL) {
48  cpl_frame *frame
49  = muse_processing_new_frame(aProcessing, aIFU, aHeader,
50  "LSF_TABLE", CPL_FRAME_TYPE_TABLE);
51  if (frame != NULL) {
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);
56  cpl_free(channel);
57  r = cpl_propertylist_save(aHeader, filename, CPL_IO_CREATE);
58  r = muse_lsf_params_save(aSlicePars, filename);
59  if (r == CPL_ERROR_NONE) {
60  cpl_frameset_insert(aProcessing->outputFrames, frame);
61  } else {
62  cpl_frame_delete(frame);
63  }
64  }
65  }
66  return r;
67 } /* muse_wavecal_save_lsf_params() */
68 
69 static muse_lsf_params *
70 muse_wavecal_compute_slice_lsf(cpl_table *aLines,
71  muse_pixtable *aPixtable,
72  muse_lsf_params *aFirstguess,
73  int max_iterations,
74  const muse_sky_fit_params *slice_fit_params)
75 
76 {
77  uint32_t origin = (uint32_t)cpl_table_get_int(aPixtable->table,
78  MUSE_PIXTABLE_ORIGIN, 0, NULL);
79  unsigned short i_ifu = muse_pixtable_origin_get_ifu(origin),
80  i_slice = muse_pixtable_origin_get_slice(origin);
81  cpl_size nrows = muse_pixtable_get_nrow(aPixtable);
82 
83  cpl_msg_info(__func__, "processing slice %hu.%hu with %"CPL_SIZE_FORMAT" rows",
84  i_ifu, i_slice, nrows);
85 
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);
90 
91  cpl_array *lambda = NULL;
92  if (cpl_table_get_column_type(aPixtable->table, MUSE_PIXTABLE_LAMBDA)
93  == CPL_TYPE_DOUBLE) {
94  lambda = muse_cpltable_extract_column(aPixtable->table,
95  MUSE_PIXTABLE_LAMBDA);
96  } else {
97  cpl_table_cast_column(aPixtable->table, MUSE_PIXTABLE_LAMBDA,
98  "lambda_double", CPL_TYPE_DOUBLE);
99  lambda = muse_cpltable_extract_column(aPixtable->table, "lambda_double");
100  }
101  cpl_array *data = muse_cpltable_extract_column(aPixtable->table,
102  MUSE_PIXTABLE_DATA);
103  cpl_array *stat = muse_cpltable_extract_column(aPixtable->table,
104  MUSE_PIXTABLE_STAT);
105 
106  muse_lsf_params *lsf
107  = muse_lsf_params_fit(lambda, data, stat, aLines, aFirstguess,
108  max_iterations, slice_fit_params);
109  lsf->slice = i_slice;
110  lsf->ifu = i_ifu;
111 
112  if (cpl_table_has_column(aPixtable->table, "lambda_double")) {
113  cpl_table_erase_column(aPixtable->table, "lambda_double");
114  }
115 
116  cpl_array_unwrap(lambda);
117  cpl_array_unwrap(data);
118  cpl_array_unwrap(stat);
119 
120  return lsf;
121 } /* muse_wavecal_compute_slice_lsf() */
122 
123 static muse_lsf_params **
124 muse_wavecal_compute_lsf(cpl_table *aLines,
125  muse_pixtable *aPixtable,
126  muse_lsf_params **aFirstguess,
127  int max_iterations,
128  const muse_sky_fit_params *slice_fit_params)
129 {
130  muse_pixtable **slice_pixtable = muse_pixtable_extracted_get_slices(aPixtable);
131  int n_slices = muse_pixtable_extracted_get_size(slice_pixtable);
132  int i_slice;
133 
134  muse_lsf_params **lsfParams
135  = cpl_calloc(n_slices+1, sizeof(muse_lsf_params *));
136  #pragma omp parallel for default(none) num_threads(2) /* as req. by Ralf */ \
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++) {
140  uint32_t origin
141  = (uint32_t)cpl_table_get_int(slice_pixtable[i_slice]->table,
142  MUSE_PIXTABLE_ORIGIN, 0, NULL);
143  unsigned short ifu = muse_pixtable_origin_get_ifu(origin),
144  slice = muse_pixtable_origin_get_slice(origin);
145  muse_lsf_params *firstguess_slice
146  = muse_lsf_params_get(aFirstguess, ifu, slice);
147 
148  cpl_errorstate prestate = cpl_errorstate_get();
149  lsfParams[i_slice]
150  = muse_wavecal_compute_slice_lsf(aLines, slice_pixtable[i_slice],
151  firstguess_slice, max_iterations,
152  slice_fit_params);
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);
157  }
158  }
159  muse_pixtable_extracted_delete(slice_pixtable);
160  return lsfParams;
161 } /* muse_wavecal_compute_lsf() */
162 
163 /*----------------------------------------------------------------------------*/
169 /*----------------------------------------------------------------------------*/
170 static cpl_error_code
171 muse_wavecal_qc_lsf(cpl_propertylist *aHeader,
172  const muse_lsf_params **aSlicePars)
173 {
174  double wavelength[] = { 5577.35, 8827.25, -1. };
175 
176  char keyword[KEYWORD_LENGTH];
177  int i;
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]);
181  const muse_lsf_params **slice;
182  for (slice = aSlicePars; *slice != NULL; slice++) {
183  double width
184  = muse_cplarray_poly1d_double(wavelength[i] - (*slice)->lambda_ref,
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);
190  }
191 
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);
199  }
200  for (slice = aSlicePars; *slice != NULL; slice++) {
201  double fwhm = muse_lsf_fwhm_lambda(*slice, wavelength[i],
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);
207  }
208  }
209  const muse_lsf_params **slice;
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);
216  }
217 
218  return CPL_ERROR_NONE;
219 } /* muse_wavecal_qc_lsf() */
220 
221 /*---------------------------------------------------------------------------*/
231 /*---------------------------------------------------------------------------*/
232 static muse_image *
233 muse_wavecal_sum_and_save(muse_imagelist *aImages, muse_processing *aProcessing,
234  int aIFU)
235 {
236  cpl_ensure(aImages && aProcessing, CPL_ERROR_NULL_INPUT, NULL);
237 
238  /* do the final (sum!) image combination if requested */
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");
243  cpl_free(pname);
244  muse_combinepar *cpars = muse_combinepar_new(aProcessing->parameters,
245  "muse.muse_wavecal");
246  cpl_parameter_set_string(param, porig);
247  cpl_free(porig);
248  muse_image *image = muse_combine_images(cpars, aImages);
249  muse_combinepar_delete(cpars);
250  if (!image) {
251  cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_OUTPUT,
252  "summing per-lamp images did not work");
253  return NULL;
254  }
255 
256  /* transfer NSATURATION headers from lamp-combined images to final combined image */
257  /* loop over lamps (entries in the imagelist) */
258  unsigned int k;
259  for (k = 0; k < muse_imagelist_get_size(aImages); k++) {
260  cpl_errorstate state = cpl_errorstate_get();
261  unsigned int i = 1;
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);
265  /* this will change the errorstate if the keyword doesn't exist: */
266  int nsaturated = cpl_propertylist_get_int(muse_imagelist_get(aImages, k)->header,
267  kwget);
268  if (cpl_errorstate_is_equal(state)) {
269  cpl_propertylist_update_int(image->header, kwout, nsaturated);
270  }
271  cpl_free(kwget);
272  cpl_free(kwout);
273  i++;
274  } /* while (errorstate is the same) */
275  /* reset the old errorstate, we don't want to leak *
276  * it outside, since it's not a real error */
277  cpl_errorstate_set(state);
278  } /* for k (all images in list) */
279  /* count saturated pixels in final combined image */
280  muse_basicproc_qc_saturated(image, QC_WAVECAL_PREFIX);
281 
282  /* save the pre-processed image to file *
283  * (this should be done, even if the wavelength calibration fails so *
284  * that the user can check what input files were used for the wavecal) */
285  muse_processing_save_image(aProcessing, aIFU, image,
286  MUSE_TAG_ARC_RED);
287 
288  return image;
289 } /* muse_wavecal_sum_and_save() */
290 
291 /*---------------------------------------------------------------------------*/
298 /*---------------------------------------------------------------------------*/
299 int
300 muse_wavecal_compute(muse_processing *aProcessing,
301  muse_wavecal_params_t *aParams)
302 {
304  if (aParams->fitweighting == MUSE_WAVECAL_PARAM_FITWEIGHTING_CERR) {
305  fweight = MUSE_WAVE_WEIGHTING_CERR;
306  } else if (aParams->fitweighting == MUSE_WAVECAL_PARAM_FITWEIGHTING_SCATTER) {
307  fweight = MUSE_WAVE_WEIGHTING_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\"",
312  aParams->fitweighting_s);
313  return -1;
314  }
315 
317  "muse.muse_wavecal");
318  cpl_frameset **labeledframes = NULL;
320  aParams->nifu,
321  bpars,
322  &labeledframes);
324  cpl_ensure(images, cpl_error_get_code(), -1);
325  /* save all resulting images, but only if there were different lamp *
326  * setups; otherwise we only save the combined image, see below */
327  cpl_frameset *used = aProcessing->usedFrames;
328  unsigned int k, kimages = muse_imagelist_get_size(images);
329  cpl_boolean needsum = !aParams->lampwise || aParams->resample || aParams->lsf;
330  for (k = 0; k < kimages; k++) {
331  /* only save individual files if different from combined one */
332  if (!(kimages == 1 && needsum)) {
333  muse_image *image = muse_imagelist_get(images, k);
334  if (labeledframes) { /* replace usedFrames with ones used for _this_ image */
335  aProcessing->usedFrames = labeledframes[k];
336  }
337  muse_basicproc_qc_saturated(image, QC_WAVECAL_PREFIX);
338  cpl_propertylist_erase_regexp(image->header, MUSE_WCS_KEYS, 0);
339  muse_processing_save_image(aProcessing, aParams->nifu, image,
340  MUSE_TAG_ARC_RED_LAMP);
341  }
342  /* delete the corresponding frameset in any case, if present */
343  if (labeledframes) {
344  cpl_frameset_delete(labeledframes[k]);
345  }
346  } /* for k (all images in list) */
347  cpl_free(labeledframes);
348  aProcessing->usedFrames = used;
349  muse_image *masterimage = NULL;
350  if (needsum) {
351  masterimage = muse_wavecal_sum_and_save(images, aProcessing, aParams->nifu);
352  } /* if !lampwise */
353 
354  /* line catalog is needed in any case */
355  cpl_table *linelist = muse_table_load(aProcessing, MUSE_TAG_LINE_CATALOG, 0);
356  cpl_propertylist *linehead = muse_propertylist_load(aProcessing,
357  MUSE_TAG_LINE_CATALOG);
358  int rc = muse_wave_lines_check(linelist, linehead) ? 0 : -1;
359  cpl_propertylist_delete(linehead);
360  if (rc) {
361  cpl_table_delete(linelist);
362  muse_image_delete(masterimage);
363  muse_imagelist_delete(images);
364  return rc;
365  }
366  /* trace table is needed in any case if we made it here */
367  cpl_table *tracetable = muse_table_load(aProcessing, MUSE_TAG_TRACE_TABLE,
368  aParams->nifu);
369 
370  /* the main step: compute the wavelength solution, add QC parameters *
371  * to the FITS headers of the input exposure(s), since the output *
372  * table doesn't carry headers, and create an output header for saving *
373  * by copying most of the input headers. */
374  cpl_table *wavecaltable = NULL;
375  cpl_propertylist *header = NULL;
377  p->xorder = aParams->xorder;
378  p->yorder = aParams->yorder;
379  p->detsigma = aParams->sigma;
380  p->ddisp = aParams->dres;
381  p->tolerance = aParams->tolerance;
382  p->linesigma = aParams->linesigma;
383  p->rflag = aParams->residuals; /* the residuals component itself stays NULL */
384  p->fitsigma = aParams->fitsigma;
385  p->fitweighting = fweight;
386  if (aParams->lampwise) { /* separate image handling (new method) */
387  wavecaltable = muse_wave_calib_lampwise(images, tracetable, linelist, p);
388  header = cpl_propertylist_duplicate(muse_imagelist_get(images, 0)->header);
389  } else { /* direct measurement and fit on single combined image (old method) */
390  wavecaltable = muse_wave_calib(masterimage, tracetable, linelist, p);
391  header = cpl_propertylist_duplicate(masterimage->header);
392  }
393  if (!wavecaltable) { /* failure of the main step, return now */
394  muse_image_delete(masterimage);
395  muse_imagelist_delete(images);
396  cpl_table_delete(tracetable);
397  cpl_table_delete(linelist);
398  cpl_propertylist_delete(header);
400  return -1;
401  }
402 
403  /* create table header by copying most of the image header *
404  * and save the wavelength solution in this 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);
411  muse_processing_save_table(aProcessing, aParams->nifu, wavecaltable, header,
412  MUSE_TAG_WAVECAL_TABLE, MUSE_TABLE_TYPE_CPL);
413  if (p->residuals) {
414  /* don't want to save QC headers with the residuals table: */
415  cpl_propertylist_erase_regexp(header, QC_WAVECAL_PREFIX, 0);
416  muse_processing_save_table(aProcessing, aParams->nifu, p->residuals, header,
417  MUSE_TAG_WAVECAL_DEBUG, MUSE_TABLE_TYPE_CPL);
418  }
420  cpl_propertylist_delete(header);
421 
422  /* now the extra steps: resampling, LSF determination, or wavemap creation */
423  muse_pixtable *pixtable = NULL;
424  if (aParams->resample || aParams->lsf) {
425  /* to visualize wavelength calibration, or for *
426  * LSF fitting, create the pixel table now */
427  pixtable = muse_pixtable_create(masterimage, tracetable, wavecaltable, NULL);
428  if (!pixtable) {
429  cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_INPUT, "pixel table "
430  "creation failed!");
431  if (!getenv("MUSE_EXPERT_USER")) {
432  muse_image_delete(masterimage);
433  cpl_table_delete(wavecaltable);
434  cpl_table_delete(tracetable);
435  muse_imagelist_delete(images);
436  cpl_table_delete(linelist);
437  return -1;
438  } /* if non-expert user */
439  } /* if no pixel table */
440  } /* if pixel table needed */
441 
442  if (aParams->resample) {
443  /* to visualize wavelength calibration, use the *
444  * pixel table to resample the data onto a 2D image */
445  muse_image *resampled = muse_resampling_image(pixtable,
447  1.0, 1.25);
448  if (resampled) {
449  /* don't want to save QC headers with the resampled image: */
450  cpl_propertylist_erase_regexp(resampled->header, QC_WAVECAL_PREFIX, 0);
451  muse_processing_save_cimage(aProcessing, aParams->nifu, resampled->data,
452  resampled->header, MUSE_TAG_ARC_RESAMP);
453  muse_image_delete(resampled);
454  }
455  } /* if resample */
456 
457  if (aParams->wavemap) {
458  muse_image *image = masterimage ? masterimage
459  : muse_imagelist_get(images, 0);
460  cpl_image *map = muse_wave_map(image, wavecaltable, tracetable);
461  /* simply use the header of the incoming image */
462  muse_processing_save_cimage(aProcessing, aParams->nifu, map, image->header,
463  MUSE_TAG_WAVE_MAP);
464  cpl_image_delete(map);
465  } /* if wavemap */
466 
467  if (aParams->lsf && pixtable) {
468  if (aParams->lsf_residuals) {
469  /* Duplicate to have access to original data after fit for residual calc */
470  cpl_table_duplicate_column(pixtable->table, "orig_data", pixtable->table,
471  "data");
472  }
473 
474  /* now we can throw away the original flux column and rename the one with *
475  * the measurements to "flux" as needed by the LSF fitting routines */
476  cpl_table_erase_column(linelist, MUSE_LINE_CATALOG_FLUX);
477  cpl_table_name_column(linelist, "Flux_for_LSF", "flux");
478  /* erase unused (flux == 0.) and non-isolated (quality < 3) lines */
479  cpl_table_unselect_all(linelist);
480  cpl_table_or_selected_int(linelist, MUSE_LINE_CATALOG_QUALITY,
481  CPL_LESS_THAN, 3);
482  cpl_table_or_selected_double(linelist, "flux", CPL_NOT_GREATER_THAN, 0.);
483  cpl_table_erase_selected(linelist);
484  /* sort list by decreasing flux and cut it to the 40 brightest lines */
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);
489  cpl_size nrows = 40;
490  if (nrows < cpl_table_get_nrow(linelist)) {
491  cpl_table_erase_window(linelist, nrows, cpl_table_get_nrow(linelist));
492  }
493 
494  muse_sky_fit_params *slice_fit_params = muse_sky_fit_params_new
495  (
496  0, // aParams->slice_fit_offset,
497  0, // aParams->slice_fit_refraction,
498  0, // sensitivity is not used here
499  1, // aParams->slice_fit_slit_width,
500  1, // aParams->slice_fit_bin_width,
501  3, // aParams->slice_fit_lsf_width + 1,
502  1, //1, // aParams->slice_fit_h3 + 1,
503  2, //2, // aParams->slice_fit_h4 + 1,
504  1, //1, // aParams->slice_fit_h5 + 1,
505  2 //2 // aParams->slice_fit_h6 + 1
506  );
507 
508  muse_lsf_params **firstguess
509  = muse_processing_lsf_params_load(aProcessing, aParams->nifu);
510  muse_lsf_params **lsf
511  = muse_wavecal_compute_lsf(linelist, pixtable, firstguess, 40,
512  slice_fit_params);
513 
514  muse_lsf_params_delete(firstguess);
515  muse_sky_fit_params_delete(slice_fit_params);
516 
517  cpl_propertylist *qc_header = cpl_propertylist_new();
518  muse_wavecal_qc_lsf(qc_header, (const muse_lsf_params **)lsf);
519  muse_wavecal_save_lsf_params(qc_header, (const muse_lsf_params **)lsf,
520  aProcessing, aParams->nifu);
522  cpl_propertylist_delete(qc_header);
523 
524  if (aParams->lsf_residuals) {
525  muse_processing_save_table(aProcessing, aParams->nifu, pixtable, NULL,
526  "LSF_RESIDUALS", MUSE_TABLE_TYPE_PIXTABLE);
527  }
528  } /* if lsf */
529 
530  /* clean up */
531  muse_pixtable_delete(pixtable);
532  cpl_table_delete(wavecaltable);
533  muse_image_delete(masterimage);
534  muse_imagelist_delete(images);
535  cpl_table_delete(tracetable);
536  cpl_table_delete(linelist);
537 
538  return rc; /* can only be 0 or -1 */
539 } /* muse_wavecal_compute() */
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.
Definition: muse_image.c:84
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
Definition: muse_image.h:47
cpl_boolean rflag
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.
Definition: muse_lsf.c:214
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.
Definition: muse_lsf_fit.c:131
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.
Definition: muse_lsf.c:456
void muse_imagelist_delete(muse_imagelist *aList)
Free the memory of the MUSE image list.
cpl_table * residuals
const char * recipeName
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.
Definition: muse_sky.h:87
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.
Definition: muse_combine.c:742
void muse_sky_fit_params_delete(muse_sky_fit_params *)
Delete the fit parameter structure.
Structure definition of MUSE three extension FITS file.
Definition: muse_image.h:41
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
Definition: muse_image.h:73
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.
Definition: muse_combine.c:716
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.
Definition: muse_lsf.c:708
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.
unsigned short xorder
muse_combinepar * muse_combinepar_new(cpl_parameterlist *aParameters, const char *aPrefix)
Create a new set of combination parameters.
Definition: muse_combine.c:673
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
Definition: muse_utils.c:452
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.
unsigned short yorder
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.
Definition: muse_lsf.c:392
cpl_propertylist * muse_propertylist_load(muse_processing *aProcessing, const char *aTag)
load a propertylist according to its tag
Definition: muse_utils.c:520
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.
Definition: muse_lsf.h:51
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.
Definition: muse_lsf.c:147
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.