MUSE Pipeline Reference Manual  1.0.2
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  cpl_table *linelist = muse_table_load(aProcessing, MUSE_TAG_LINE_CATALOG, 0);
176  cpl_propertylist *linehead = muse_propertylist_load(aProcessing,
177  MUSE_TAG_LINE_CATALOG);
178  int rc = muse_wave_lines_check(linelist, linehead) ? 0 : -1;
179  cpl_propertylist_delete(linehead);
180  if (rc) {
181  cpl_table_delete(linelist);
182  muse_image_delete(masterimage);
183  muse_imagelist_delete(images);
184  return rc;
185  }
186  /* trace table is needed in any case if we made it here */
187  cpl_table *tracetable = muse_table_load(aProcessing, MUSE_TAG_TRACE_TABLE,
188  aParams->nifu);
189 
190  /* the main step: compute the wavelength solution, add QC parameters *
191  * to the FITS headers of the input exposure(s), since the output *
192  * table doesn't carry headers, and create an output header for saving *
193  * by copying most of the input headers. */
194  cpl_table *wavecaltable = NULL;
195  cpl_propertylist *header = NULL;
197  p->xorder = aParams->xorder;
198  p->yorder = aParams->yorder;
199  p->detsigma = aParams->sigma;
200  p->ddisp = aParams->dres;
201  p->tolerance = aParams->tolerance;
202  p->linesigma = aParams->linesigma;
203  p->rflag = aParams->residuals; /* the residuals component itself stays NULL */
204  p->fitsigma = aParams->fitsigma;
205  p->fitweighting = fweight;
206  if (aParams->lampwise) { /* separate image handling (new method) */
207  wavecaltable = muse_wave_calib_lampwise(images, tracetable, linelist, p);
208  header = cpl_propertylist_duplicate(muse_imagelist_get(images, 0)->header);
209  } else { /* direct measurement and fit on single combined image (old method) */
210  wavecaltable = muse_wave_calib(masterimage, tracetable, linelist, p);
211  header = cpl_propertylist_duplicate(masterimage->header);
212  }
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_table_delete(linelist);
218  cpl_propertylist_delete(header);
220  return -1;
221  }
222 
223  /* create table header by copying most of the image header *
224  * and save the wavelength solution in this header */
225  cpl_propertylist_erase_regexp(header,
226  "^SIMPLE$|^BITPIX$|^NAXIS|^EXTEND$|^XTENSION$|"
227  "^DATASUM$|^DATAMIN$|^DATAMAX$|^DATAMD5$|"
228  "^PCOUNT$|^GCOUNT$|^HDUVERS$|^BLANK$|"
229  "^BZERO$|^BSCALE$|^BUNIT$|^CHECKSUM$|^INHERIT$|"
230  "^PIPEFILE$|^ESO PRO ", 0);
231  muse_processing_save_table(aProcessing, aParams->nifu, wavecaltable, header,
232  MUSE_TAG_WAVECAL_TABLE, MUSE_TABLE_TYPE_CPL);
233  if (p->residuals) {
234  /* don't want to save QC headers with the residuals table: */
235  cpl_propertylist_erase_regexp(header, QC_WAVECAL_PREFIX, 0);
236  muse_processing_save_table(aProcessing, aParams->nifu, p->residuals, header,
237  MUSE_TAG_WAVECAL_DEBUG, MUSE_TABLE_TYPE_CPL);
238  }
240  cpl_propertylist_delete(header);
241 
242  /* now the extra steps: resampling, and/or wavemap creation */
243  if (aParams->resample) {
244  /* to visualize wavelength calibration, use the *
245  * pixel table to resample the data onto a 2D image */
246  muse_pixtable *pixtable = muse_pixtable_create(masterimage, tracetable,
247  wavecaltable, NULL);
248  muse_image *resampled = muse_resampling_image(pixtable,
250  1.0, 1.25);
251  muse_pixtable_delete(pixtable);
252  if (resampled) {
253  /* don't want to save QC headers with the resampled image: */
254  cpl_propertylist_erase_regexp(resampled->header, QC_WAVECAL_PREFIX, 0);
255  muse_processing_save_cimage(aProcessing, aParams->nifu, resampled->data,
256  resampled->header, MUSE_TAG_ARC_RESAMP);
257  muse_image_delete(resampled);
258  }
259  } /* if resample */
260 
261  if (aParams->wavemap) {
262  muse_image *image = masterimage ? masterimage
263  : muse_imagelist_get(images, 0);
264  cpl_image *map = muse_wave_map(image, wavecaltable, tracetable);
265  /* simply use the header of the incoming image */
266  muse_processing_save_cimage(aProcessing, aParams->nifu, map, image->header,
267  MUSE_TAG_WAVE_MAP);
268  cpl_image_delete(map);
269  } /* if wavemap */
270 
271  /* clean up */
272  cpl_table_delete(wavecaltable);
273  muse_image_delete(masterimage);
274  muse_imagelist_delete(images);
275  cpl_table_delete(tracetable);
276  cpl_table_delete(linelist);
277 
278  return rc; /* can only be 0 or -1 */
279 } /* 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: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
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.
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
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...
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 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:721
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.
cpl_propertylist * muse_propertylist_load(muse_processing *aProcessing, const char *aTag)
load a propertylist according to its tag
Definition: muse_utils.c:789
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)
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
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.