MUSE Pipeline Reference Manual  2.1.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  * This file is part of the MUSE Instrument Pipeline
5  * Copyright (C) 2005-2014 European Southern Observatory
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 /*----------------------------------------------------------------------------*
27  * Includes *
28  *----------------------------------------------------------------------------*/
29 #include <stdio.h>
30 #include <float.h>
31 #include <math.h>
32 #include <string.h>
33 #include <cpl.h>
34 #include <muse.h>
35 #include "muse_wavecal_z.h"
36 
37 /*---------------------------------------------------------------------------*
38  * Functions code *
39  *---------------------------------------------------------------------------*/
40 
41 /*---------------------------------------------------------------------------*/
51 /*---------------------------------------------------------------------------*/
52 static muse_image *
53 muse_wavecal_sum_and_save(muse_imagelist *aImages, muse_processing *aProcessing,
54  int aIFU)
55 {
56  cpl_ensure(aImages && aProcessing, CPL_ERROR_NULL_INPUT, NULL);
57 
58  /* do the final (sum!) image combination if requested */
59  char *pname = cpl_sprintf("muse.%s.combine", aProcessing->name);
60  cpl_parameter *param = cpl_parameterlist_find(aProcessing->parameters, pname);
61  char *porig = cpl_strdup(cpl_parameter_get_string(param));
62  cpl_parameter_set_string(param, "sum");
63  cpl_free(pname);
64  muse_combinepar *cpars = muse_combinepar_new(aProcessing->parameters,
65  "muse.muse_wavecal");
66  cpl_parameter_set_string(param, porig);
67  cpl_free(porig);
68  muse_image *image = muse_combine_images(cpars, aImages);
70  if (!image) {
71  cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_OUTPUT,
72  "summing per-lamp images did not work");
73  return NULL;
74  }
75 
76  /* transfer NSATURATION headers from lamp-combined images to final combined image */
77  /* loop over lamps (entries in the imagelist) */
78  unsigned int k;
79  for (k = 0; k < muse_imagelist_get_size(aImages); k++) {
80  cpl_errorstate state = cpl_errorstate_get();
81  unsigned int i = 1;
82  while (cpl_errorstate_is_equal(state)) {
83  char *kwget = cpl_sprintf(QC_WAVECAL_PREFIXi" "QC_BASIC_NSATURATED, i),
84  *kwout = cpl_sprintf(QC_WAVECAL_PREFIXli" "QC_BASIC_NSATURATED, k+1, i);
85  /* this will change the errorstate if the keyword doesn't exist: */
86  int nsaturated = cpl_propertylist_get_int(muse_imagelist_get(aImages, k)->header,
87  kwget);
88  if (cpl_errorstate_is_equal(state)) {
89  cpl_propertylist_update_int(image->header, kwout, nsaturated);
90  }
91  cpl_free(kwget);
92  cpl_free(kwout);
93  i++;
94  } /* while (errorstate is the same) */
95  /* reset the old errorstate, we don't want to leak *
96  * it outside, since it's not a real error */
97  cpl_errorstate_set(state);
98  } /* for k (all images in list) */
99  /* count saturated pixels in final combined image */
100  muse_basicproc_qc_saturated(image, QC_WAVECAL_PREFIX);
101 
102  /* save the pre-processed image to file *
103  * (this should be done, even if the wavelength calibration fails so *
104  * that the user can check what input files were used for the wavecal) */
105  muse_processing_save_image(aProcessing, aIFU, image,
106  MUSE_TAG_ARC_RED);
107 
108  return image;
109 } /* muse_wavecal_sum_and_save() */
110 
111 /*---------------------------------------------------------------------------*/
118 /*---------------------------------------------------------------------------*/
119 int
120 muse_wavecal_compute(muse_processing *aProcessing,
121  muse_wavecal_params_t *aParams)
122 {
124  if (aParams->fitweighting == MUSE_WAVECAL_PARAM_FITWEIGHTING_CERR) {
125  fweight = MUSE_WAVE_WEIGHTING_CERR;
126  } else if (aParams->fitweighting == MUSE_WAVECAL_PARAM_FITWEIGHTING_SCATTER) {
127  fweight = MUSE_WAVE_WEIGHTING_SCATTER;
128  } else if (aParams->fitweighting == MUSE_WAVECAL_PARAM_FITWEIGHTING_CERRSCATTER) {
130  } else if (aParams->fitweighting != MUSE_WAVECAL_PARAM_FITWEIGHTING_UNIFORM) {
131  cpl_msg_error(__func__, "unknown fitweighting method \"%s\"",
132  aParams->fitweighting_s);
133  return -1;
134  }
135 
137  "muse.muse_wavecal");
138  cpl_frameset **labeledframes = NULL;
140  aParams->nifu,
141  bpars,
142  &labeledframes);
144  cpl_ensure(images, cpl_error_get_code(), -1);
145  /* save all resulting images, but only if there were different lamp *
146  * setups; otherwise we only save the combined image, see below */
147  cpl_frameset *used = aProcessing->usedframes;
148  unsigned int k, kimages = muse_imagelist_get_size(images);
149  cpl_boolean needsum = !aParams->lampwise || aParams->resample;
150  for (k = 0; k < kimages; k++) {
151  /* only save individual files if different from combined one */
152  if (!(kimages == 1 && needsum)) {
153  muse_image *image = muse_imagelist_get(images, k);
154  if (labeledframes) { /* replace usedframes with ones used for _this_ image */
155  aProcessing->usedframes = labeledframes[k];
156  }
157  muse_basicproc_qc_saturated(image, QC_WAVECAL_PREFIX);
158  cpl_propertylist_erase_regexp(image->header, MUSE_WCS_KEYS, 0);
159  muse_processing_save_image(aProcessing, aParams->nifu, image,
160  MUSE_TAG_ARC_RED_LAMP);
161  }
162  /* delete the corresponding frameset in any case, if present */
163  if (labeledframes) {
164  cpl_frameset_delete(labeledframes[k]);
165  }
166  } /* for k (all images in list) */
167  cpl_free(labeledframes);
168  aProcessing->usedframes = used;
169  muse_image *masterimage = NULL;
170  if (needsum) {
171  masterimage = muse_wavecal_sum_and_save(images, aProcessing, aParams->nifu);
172  } /* if !lampwise */
173 
174  /* line catalog is needed in any case */
175  muse_table *linelist = muse_processing_load_table(aProcessing,
176  MUSE_TAG_LINE_CATALOG, 0);
177  int rc = muse_wave_lines_check(linelist) ? 0 : -1;
178  if (rc) {
179  muse_table_delete(linelist);
180  muse_image_delete(masterimage);
181  muse_imagelist_delete(images);
182  return rc;
183  }
184  /* trace table is needed in any case if we made it here */
185  cpl_table *tracetable = muse_processing_load_ctable(aProcessing, MUSE_TAG_TRACE_TABLE,
186  aParams->nifu);
187 
188  /* the main step: compute the wavelength solution, add QC parameters *
189  * to the FITS headers of the input exposure(s), since the output *
190  * table doesn't carry headers, and create an output header for saving *
191  * by copying most of the input headers. */
192  cpl_table *wavecaltable = NULL;
193  cpl_propertylist *header = NULL;
195  p->xorder = aParams->xorder;
196  p->yorder = aParams->yorder;
197  p->detsigma = aParams->sigma;
198  p->ddisp = aParams->dres;
199  p->tolerance = aParams->tolerance;
200  p->linesigma = aParams->linesigma;
201  p->rflag = aParams->residuals; /* the residuals component itself stays NULL */
202  p->fitsigma = aParams->fitsigma;
203  p->fitweighting = fweight;
204  if (aParams->lampwise) { /* separate image handling (new method) */
205  wavecaltable = muse_wave_calib_lampwise(images, tracetable, linelist->table,
206  p);
207  header = cpl_propertylist_duplicate(muse_imagelist_get(images, 0)->header);
208  } else { /* direct measurement and fit on single combined image (old method) */
209  wavecaltable = muse_wave_calib(masterimage, tracetable, linelist->table, p);
210  header = cpl_propertylist_duplicate(masterimage->header);
211  }
212  muse_table_delete(linelist);
213  if (!wavecaltable) { /* failure of the main step, return now */
214  muse_image_delete(masterimage);
215  muse_imagelist_delete(images);
216  cpl_table_delete(tracetable);
217  cpl_propertylist_delete(header);
219  return -1;
220  }
221 
222  /* create table header by copying most of the image header *
223  * and save the wavelength solution in this header */
224  cpl_propertylist_erase_regexp(header,
225  "^SIMPLE$|^BITPIX$|^NAXIS|^EXTEND$|^XTENSION$|"
226  "^DATASUM$|^DATAMIN$|^DATAMAX$|^DATAMD5$|"
227  "^PCOUNT$|^GCOUNT$|^HDUVERS$|^BLANK$|"
228  "^BZERO$|^BSCALE$|^BUNIT$|^CHECKSUM$|^INHERIT$|"
229  "^PIPEFILE$|^ESO PRO ", 0);
230  muse_processing_save_table(aProcessing, aParams->nifu, wavecaltable, header,
231  MUSE_TAG_WAVECAL_TABLE, MUSE_TABLE_TYPE_CPL);
232  if (p->residuals) {
233  /* don't want to save QC headers with the residuals table: */
234  cpl_propertylist_erase_regexp(header, QC_WAVECAL_PREFIX, 0);
235  muse_processing_save_table(aProcessing, aParams->nifu, p->residuals, header,
236  MUSE_TAG_WAVECAL_DEBUG, MUSE_TABLE_TYPE_CPL);
237  }
239  cpl_propertylist_delete(header);
240 
241  /* now the extra steps: resampling, and/or wavemap creation */
242  if (aParams->resample) {
243  /* to visualize wavelength calibration, use the *
244  * pixel table to resample the data onto a 2D image */
245  muse_pixtable *pixtable = muse_pixtable_create(masterimage, tracetable,
246  wavecaltable, NULL);
247  muse_image *resampled = muse_resampling_image(pixtable,
249  1.0, 1.25);
250  muse_pixtable_delete(pixtable);
251  if (resampled) {
252  /* don't want to save QC headers with the resampled image: */
253  cpl_propertylist_erase_regexp(resampled->header, QC_WAVECAL_PREFIX, 0);
254  muse_processing_save_cimage(aProcessing, aParams->nifu, resampled->data,
255  resampled->header, MUSE_TAG_ARC_RESAMP);
256  muse_image_delete(resampled);
257  }
258  } /* if resample */
259 
260  if (aParams->wavemap) {
261  muse_image *image = masterimage ? masterimage
262  : muse_imagelist_get(images, 0);
263  cpl_image *map = muse_wave_map(image, wavecaltable, tracetable);
264  /* simply use the header of the incoming image */
265  muse_processing_save_cimage(aProcessing, aParams->nifu, map, image->header,
266  MUSE_TAG_WAVE_MAP);
267  cpl_image_delete(map);
268  } /* if wavemap */
269 
270  /* clean up */
271  cpl_table_delete(wavecaltable);
272  muse_image_delete(masterimage);
273  muse_imagelist_delete(images);
274  cpl_table_delete(tracetable);
275 
276  return rc; /* can only be 0 or -1 */
277 } /* 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.
muse_wave_params * muse_wave_params_new(cpl_propertylist *aHeader)
Allocate a wavelength parameters structure and fill it with defaults.
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:85
double fitsigma
Sigma level for iterative rejection of deviant datapoints during the final polynomial wavelength solu...
muse_wave_weighting_type fitweighting
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...
const char * name
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.
cpl_image * data
the data extension
Definition: muse_image.h:46
cpl_boolean rflag
double dres
The allowed range of resolutions for pattern matching (of detected arc lines to line list) in fractio...
void muse_imagelist_delete(muse_imagelist *aList)
Free the memory of the MUSE image list.
cpl_table * residuals
cpl_boolean muse_wave_lines_check(muse_table *aTable)
Check that a LINE_CATALOG has the expected format.
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:741
Structure definition of MUSE three extension FITS file.
Definition: muse_image.h:40
muse_wave_weighting_type
Type of weighting to use in the wavelength calibration fit.
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:72
unsigned int muse_imagelist_get_size(muse_imagelist *aList)
Return the number of stored images.
cpl_frameset * usedframes
void muse_combinepar_delete(muse_combinepar *aCPars)
Clear the combination parameters.
Definition: muse_combine.c:715
Structure definition of MUSE pixel table.
#define MUSE_WCS_KEYS
regular expression for WCS properties
Definition: muse_wcs.h:48
muse_image * muse_imagelist_get(muse_imagelist *aList, unsigned int aIdx)
Get the muse_image of given list index.
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
cpl_table * table
The table.
Definition: muse_table.h:49
muse_table * muse_processing_load_table(muse_processing *aProcessing, const char *aTag, unsigned char aIFU)
Load a MUSE table according to its tag and IFU/channel number.
muse_combinepar * muse_combinepar_new(cpl_parameterlist *aParameters, const char *aPrefix)
Create a new set of combination parameters.
Definition: muse_combine.c:672
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...
Structure to store a table together with a property list.
Definition: muse_table.h:43
muse_pixtable * muse_pixtable_create(muse_image *aImage, cpl_table *aTrace, cpl_table *aWave, cpl_table *aGeoTable)
Create the pixel table for one CCD.
void muse_table_delete(muse_table *aTable)
Deallocate memory associated to a muse_table object.
Definition: muse_table.c:80
int yorder
Order of the polynomial used to fit the dispersion relation.
int muse_processing_save_image(muse_processing *aProcessing, int aIFU, muse_image *aImage, const char *aTag)
Save a computed MUSE image to disk.
cpl_table * muse_processing_load_ctable(muse_processing *aProcessing, const char *aTag, unsigned char aIFU)
Load a CPL table according to its tag and IFU/channel number.
int fitweighting
Type of weighting to use in the final polynomial wavelength solution fit, using centroiding error est...
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.
double tolerance
Tolerance for pattern matching (of detected arc lines to line list)
void muse_pixtable_delete(muse_pixtable *aPixtable)
Deallocate memory associated to a pixel table object.
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
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.