MUSE Pipeline Reference Manual  0.18.5
muse_sky_common.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) 2008-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 #include <math.h>
27 
28 #include "muse_sky.h"
29 #include "muse_quality.h"
30 #include "muse_cplwrappers.h"
31 #include "muse_mask.h"
32 #include "muse_data_format_z.h"
33 
48  {"lambda", CPL_TYPE_DOUBLE, "Angstrom", "%7.2f", "wavelength", CPL_TRUE},
49  {"flux", CPL_TYPE_DOUBLE, "erg/(s cm^2 arcsec^2)", "%e", "Flux", CPL_TRUE},
50  { NULL, 0, NULL, NULL, NULL, CPL_FALSE }
51 };
52 
53 /*----------------------------------------------------------------------------*/
60 /*----------------------------------------------------------------------------*/
61 cpl_table *
62 muse_sky_spectrum_from_cube(muse_datacube *aCube, const cpl_mask *aMask) {
63  unsigned count = cpl_imagelist_get_size(aCube->data);
64  cpl_table *spectrum = muse_cpltable_new(muse_dataspectrum_def, count);
65  double crval3 = cpl_propertylist_get_float(aCube->header, "CRVAL3");
66  double crpix3 = cpl_propertylist_get_float(aCube->header, "CRPIX3");
67  double cdelt3 = cpl_propertylist_get_float(aCube->header, "CD3_3");
68  unsigned i;
69  cpl_mask *nmask = cpl_mask_duplicate(aMask);
70  cpl_mask_not(nmask);
71  for (i = 0; i < count; i++) {
72  cpl_table_set(spectrum, "lambda", i, crval3 + (i + 1 - crpix3) * cdelt3);
73 
74  cpl_image *img = cpl_imagelist_get(aCube->data, i);
75  cpl_mask *bpm = cpl_image_get_bpm(img);
76  cpl_mask_or(bpm, nmask);
77  if (aCube->dq != NULL) {
78  cpl_image *dq = cpl_imagelist_get(aCube->dq, i);
79  cpl_mask *dq_mask = cpl_mask_threshold_image_create(dq, -0.5, 0.5);
80  cpl_mask_not(dq_mask);
81  cpl_mask_or(bpm, dq_mask);
82  cpl_mask_delete(dq_mask);
83  }
84  double dev = cpl_image_get_stdev(img);
85  double mean = cpl_image_get_mean(img);
86  cpl_table_set(spectrum, "data", i, mean);
87  cpl_table_set(spectrum, "stat", i, dev / sqrt(cpl_mask_count(bpm)));
88  cpl_table_set(spectrum, "dq", i, (cpl_mask_count(bpm) < 3));
89  }
90  cpl_mask_delete(nmask);
91 
92  return spectrum;
93 }
94 
95 /*----------------------------------------------------------------------------*/
104 /*----------------------------------------------------------------------------*/
105 muse_mask *
106 muse_sky_create_skymask(muse_image *aImage, double aFraction)
107 {
109 
110  double t0 = cpl_image_get_min(aImage->data);
111  double t1 = muse_cplimage_get_percentile(aImage->data, aFraction);
112  cpl_msg_info(__func__, "minimum = %g, threshold = %g", t0, t1);
113 
114  muse_mask *selectedRegions = muse_mask_new();
115  selectedRegions->mask = cpl_mask_threshold_image_create(aImage->data, t0, t1);
116  cpl_mask_not(selectedRegions->mask);
117  cpl_mask_or(selectedRegions->mask, cpl_image_get_bpm(aImage->data));
118  cpl_mask_not(selectedRegions->mask);
119 
120  selectedRegions->header = cpl_propertylist_duplicate(aImage->header);
121 
122  const char *keyword = "ESO QC SKY THRESHOLD";
123  cpl_propertylist_append_double(selectedRegions->header, keyword, t1);
124 
125  return selectedRegions;
126 }
127 
147 cpl_array *
148 muse_sky_apply_lsf(const cpl_array *aLambda, const cpl_table *aLines,
149  const muse_lsf_params *aLsf)
150 {
151  cpl_ensure(aLambda, CPL_ERROR_NULL_INPUT, NULL);
152  cpl_ensure(aLsf, CPL_ERROR_NULL_INPUT, NULL);
153 
154  cpl_array *linesLambda = muse_cpltable_extract_column((cpl_table *)aLines,
155  "lambda");
156  cpl_array *linesFlux = muse_cpltable_extract_column((cpl_table *)aLines,
157  "flux");
158  cpl_array *spectrum
159  = muse_lsf_spectrum_get_lines(aLambda, linesLambda, linesFlux, aLsf);
160  cpl_array_unwrap(linesLambda);
161  cpl_array_unwrap(linesFlux);
162 
163  cpl_array *sensitivity = cpl_array_duplicate(aLambda);
164  cpl_array_subtract_scalar(sensitivity, aLsf->lambda_ref);
165  muse_cplarray_poly1d(sensitivity, aLsf->sensitivity);
166 
167  cpl_array_multiply(spectrum, sensitivity);
168 
169  cpl_array_delete(sensitivity);
170 
171  return spectrum;
172 }
173 
174 /*----------------------------------------------------------------------------*/
186 /*----------------------------------------------------------------------------*/
187 void
188 muse_sky_mark_cosmic(cpl_table *aSpectrum, muse_pixtable *aPixtable) {
189  float *lbda = cpl_table_get_data_float(aPixtable->table, MUSE_PIXTABLE_LAMBDA);
190  float *data = cpl_table_get_data_float(aPixtable->table, MUSE_PIXTABLE_DATA);
191  int *dq = cpl_table_get_data_int(aPixtable->table, MUSE_PIXTABLE_DQ);
192 
193  cpl_size spec_nrows = cpl_table_get_nrow(aSpectrum);
194  double *spec_data = cpl_table_get_data_double(aSpectrum, "data");
195  double *spec_stat = cpl_table_get_data_double(aSpectrum, "stat");
196  double *spec_std = cpl_malloc(spec_nrows * sizeof(double));
197  cpl_size i_spec;
198  for (i_spec = 0; i_spec < spec_nrows; i_spec++) {
199  spec_std[i_spec] = sqrt(spec_stat[i_spec]);
200  }
201 
202  /* loop through all selected pixel table rows */
203  cpl_array *asel = cpl_table_where_selected(aPixtable->table);
204  const cpl_size *sel = cpl_array_get_data_cplsize_const(asel);
205  cpl_size isel, nsel = cpl_array_get_size(asel);
206  cpl_size n_cosmic = 0;
207  for (isel = 0; isel < nsel; isel++) {
208  cpl_size i_row = sel[isel];
209  if ((dq[i_row] != EURO3D_GOODPIXEL)) {
210  continue;
211  }
212  double l = lbda[i_row];
213  i_spec = muse_cpltable_find_sorted(aSpectrum, "lambda", l);
214  if ((i_spec < spec_nrows - 1) && (spec_data[i_spec] < spec_data[i_spec+1])) {
215  i_spec++;
216  }
217  if (spec_data[i_spec] + 5 * spec_std[i_spec] < data[i_row]) {
218  dq[i_row] = EURO3D_COSMICRAY;
219  n_cosmic++;
220  }
221  }
222  cpl_msg_info(__func__, "Marked %"CPL_SIZE_FORMAT" pixels of %"CPL_SIZE_FORMAT" as cosmic (one of %i)",
223  n_cosmic, nsel, (int)(nsel/n_cosmic));
224 
225  cpl_array_delete(asel);
226  cpl_free(spec_std);
227 }
228 
Structure definition of a MUSE datacube.
Definition: muse_datacube.h:48
cpl_image * data
the data extension
Definition: muse_image.h:47
cpl_table * muse_sky_spectrum_from_cube(muse_datacube *aCube, const cpl_mask *aMask)
Create a spectrum out of a cube by applying a mask.
const muse_cpltable_def muse_dataspectrum_def[]
muse_mask * muse_mask_new(void)
Allocate memory for a new muse object.
Definition: muse_mask.c:53
muse_mask * muse_sky_create_skymask(muse_image *aImage, double aFraction)
Select spaxels to be considered as sky.
cpl_error_code muse_cplarray_poly1d(cpl_array *aArray, const cpl_array *aCoeff)
Apply a polynomial to an array.
Structure definition of MUSE three extension FITS file.
Definition: muse_image.h:41
cpl_table * table
The pixel table.
cpl_propertylist * header
the FITS header
Definition: muse_image.h:73
cpl_array * muse_lsf_spectrum_get_lines(const cpl_array *aLambda, const cpl_array *aLinesLambda, const cpl_array *aLinesFlux, const muse_lsf_params *aLsf)
Set the lines spectrum from the lines table and the detector LSF.
Definition: muse_lsf.c:653
void muse_sky_mark_cosmic(cpl_table *aSpectrum, muse_pixtable *aPixtable)
Mark all pixel above a certain limit as COSMIC.
cpl_table * muse_cpltable_new(const muse_cpltable_def *aDef, cpl_size aLength)
Create an empty table according to the specified definition.
cpl_array * sensitivity
Relative detector sensitivity parametrization.
Definition: muse_lsf.h:59
Structure definition of MUSE pixel table.
cpl_array * muse_cpltable_extract_column(cpl_table *aTable, const char *aColumn)
Create an array from a section of a column.
double muse_cplimage_get_percentile(const cpl_image *aImage, double aFraction)
Get the percentile of an image.
cpl_imagelist * data
the cube containing the actual data values
Definition: muse_datacube.h:76
const muse_cpltable_def muse_fluxspectrum_def[]
Definition of the flux spectrum table structure.
cpl_imagelist * dq
the optional cube containing the bad pixel status
Definition: muse_datacube.h:81
cpl_size muse_cpltable_find_sorted(const cpl_table *aTable, const char *aColumn, double aValue)
Find a row in a table.
cpl_propertylist * header
the FITS header
Definition: muse_datacube.h:57
double lambda_ref
Reference wavelength for polynomial parametrizations.
Definition: muse_lsf.h:57
Handling of "mask" files.
Definition: muse_mask.h:43
cpl_error_code muse_image_reject_from_dq(muse_image *aImage)
Reject pixels of a muse_image depending on its DQ data.
Definition: muse_image.c:848
cpl_propertylist * header
the FITS header
Definition: muse_mask.h:56
Definition of a cpl table structure.
cpl_array * muse_sky_apply_lsf(const cpl_array *aLambda, const cpl_table *aLines, const muse_lsf_params *aLsf)
Apply the LSF parameters to a spectrum.
cpl_mask * mask
The mask data.
Definition: muse_mask.h:49
Structure definition of detector (slice) parameters.
Definition: muse_lsf.h:51