MUSE Pipeline Reference Manual  2.1.1
muse_sky_subtract.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 "muse_sky.h"
27 #include "muse_cplwrappers.h"
28 #include "muse_data_format_z.h"
29 
30 /*----------------------------------------------------------------------------*/
47 /*----------------------------------------------------------------------------*/
50 /*----------------------------------------------------------------------------*/
62 /*----------------------------------------------------------------------------*/
63 cpl_array *
64 muse_sky_lines_spectrum(const cpl_array *aLambda, cpl_table *aLines,
65  const cpl_image *aLsfImage,
66  const muse_wcs *aLsfWCS)
67 {
68  cpl_size n_lines = cpl_table_get_nrow(aLines);
69  cpl_size i_line;
70  double l_min = aLsfWCS->crval1 + aLsfWCS->cd11 * (1 - aLsfWCS->crpix1),
71  l_max = aLsfWCS->crval1
72  + aLsfWCS->cd11 * (cpl_image_get_size_x(aLsfImage) - aLsfWCS->crpix1);
73  cpl_array *spectrum = cpl_array_new(cpl_array_get_size(aLambda),
74  CPL_TYPE_DOUBLE);
75  cpl_array_fill_window(spectrum, 0, cpl_array_get_size(aLambda), 0.0);
76  for (i_line = 0; i_line < n_lines; i_line++) {
77  double l_lambda = cpl_table_get(aLines, "lambda", i_line, NULL);
78  double l_flux = cpl_table_get(aLines, "flux", i_line, NULL);
79  cpl_size imin = muse_cplarray_find_sorted(aLambda, l_lambda + l_min);
80  cpl_size imax = muse_cplarray_find_sorted(aLambda, l_lambda + l_max);
81  if (imax <= imin) {
82  continue;
83  }
84  cpl_array *l0 = cpl_array_extract(aLambda, imin, imax-imin+1);
85  cpl_array_subtract_scalar(l0, l_lambda);
86  muse_lsf_apply(aLsfImage, aLsfWCS, l0, l_lambda);
87  cpl_array_multiply_scalar(l0, l_flux);
88  muse_cplarray_add_window(spectrum, imin, l0);
89  cpl_array_delete(l0);
90  }
91  return spectrum;
92 }
93 
94 /*----------------------------------------------------------------------------*/
100 /*----------------------------------------------------------------------------*/
101 static cpl_error_code
102 muse_sky_subtract_lines_slice(muse_pixtable *aPixtable, cpl_table *aLines,
103  cpl_image *aLsfImage, muse_wcs *aLsfWCS)
104 {
105  cpl_propertylist *order = cpl_propertylist_new();
106  cpl_propertylist_append_bool(order, MUSE_PIXTABLE_LAMBDA, CPL_FALSE);
107  cpl_table_sort(aPixtable->table, order);
108  cpl_propertylist_delete(order);
109 
110  cpl_array *data = muse_cpltable_extract_column(aPixtable->table,
112 
113  cpl_array *lambda = NULL;
114  if (cpl_table_get_column_type(aPixtable->table, MUSE_PIXTABLE_LAMBDA)
115  == CPL_TYPE_DOUBLE) {
116  lambda = muse_cpltable_extract_column(aPixtable->table,
118  } else {
119  cpl_table_cast_column(aPixtable->table, MUSE_PIXTABLE_LAMBDA,
120  "lambda_double", CPL_TYPE_DOUBLE);
121  lambda = muse_cpltable_extract_column(aPixtable->table, "lambda_double");
122  }
123 
124  if ((aLines != NULL) && (aLsfImage != NULL) && (aLsfWCS != NULL)) {
125  cpl_array *spectrum = muse_sky_lines_spectrum(lambda, aLines,
126  aLsfImage, aLsfWCS);
127  cpl_array_subtract(data, spectrum);
128  cpl_array_delete(spectrum);
129  }
130 
131  cpl_array_unwrap(data);
132  cpl_array_unwrap(lambda);
133  if (cpl_table_has_column(aPixtable->table, "lambda_double")) {
134  cpl_table_erase_column(aPixtable->table, "lambda_double");
135  }
136 
137  return CPL_ERROR_NONE;
138 }
139 
140 /*----------------------------------------------------------------------------*/
148 /*----------------------------------------------------------------------------*/
149 cpl_error_code
151  cpl_table *aLines, muse_lsf_cube **aLsfCube)
152 {
153  cpl_ensure_code(aPixtable != NULL, CPL_ERROR_NULL_INPUT);
154  cpl_ensure_code(aPixtable->table != NULL, CPL_ERROR_NULL_INPUT);
155  cpl_ensure_code(muse_cpltable_check(aPixtable->table, muse_pixtable_def) == CPL_ERROR_NONE,
156  CPL_ERROR_DATA_NOT_FOUND);
157  cpl_ensure_code(aLines != NULL, CPL_ERROR_NULL_INPUT);
158  cpl_ensure_code(aLsfCube != NULL, CPL_ERROR_NULL_INPUT);
159 
160  muse_pixtable **slice_pixtable =
162  cpl_size n_slices = muse_pixtable_extracted_get_size(slice_pixtable);
163  cpl_size i_slice;
164  cpl_error_code rc[n_slices];
165  cpl_msg_info(__func__, "Starting sky subtraction of %"CPL_SIZE_FORMAT
166  " slices", n_slices);
167  cpl_boolean debug = getenv("MUSE_DEBUG_SKY")
168  && atoi(getenv("MUSE_DEBUG_SKY")) > 0;
169  #pragma omp parallel for default(none) \
170  shared(aLsfCube, aLines, debug, n_slices, slice_pixtable, rc)
171  for (i_slice = 0; i_slice < n_slices; i_slice++) {
172  muse_pixtable *slice_pt = slice_pixtable[i_slice];
173  uint32_t origin =
174  (uint32_t) cpl_table_get_int(slice_pt->table,
175  MUSE_PIXTABLE_ORIGIN, 0, NULL);
176  int ifu = muse_pixtable_origin_get_ifu(origin);
177  int slice = muse_pixtable_origin_get_slice(origin);
178  if ((aLsfCube[ifu-1] == NULL) && (aLines != NULL)) {
179  cpl_msg_warning(__func__,
180  "No LSF params for slice #%i.%i."
181  " Ignoring lines in sky subtraction for this slice.",
182  ifu, slice);
183  rc[i_slice] = CPL_ERROR_NONE;
184  continue;
185  }
186 
187  cpl_size nrows = muse_pixtable_get_nrow(slice_pt);
188  if (debug) {
189  cpl_msg_debug(__func__, "Sky subtraction of %"CPL_SIZE_FORMAT" pixels for"
190  " slice #%i.%i (%i)", nrows, ifu, slice, (int)i_slice+1);
191  }
192  cpl_image *lsfImage = cpl_imagelist_get(aLsfCube[ifu-1]->img, slice-1);
193  rc[i_slice] = muse_sky_subtract_lines_slice(slice_pt,
194  aLines, lsfImage,
195  aLsfCube[ifu-1]->wcs);
196  }
197  muse_pixtable_extracted_delete(slice_pixtable);
198 
199  for (i_slice = 0; i_slice < n_slices; i_slice++) {
200  if (rc[i_slice] != CPL_ERROR_NONE) {
201  return rc[i_slice];
202  }
203  }
204  return CPL_ERROR_NONE;
205 }
206 
207 /*----------------------------------------------------------------------------*/
214 /*----------------------------------------------------------------------------*/
215 cpl_error_code
216 muse_sky_subtract_continuum(muse_pixtable *aPixtable, cpl_table *aSpectrum)
217 {
218  cpl_ensure_code(aPixtable != NULL, CPL_ERROR_NULL_INPUT);
219  cpl_ensure_code(aPixtable->table != NULL, CPL_ERROR_NULL_INPUT);
220  cpl_ensure_code(muse_cpltable_check(aPixtable->table, muse_pixtable_def)
221  == CPL_ERROR_NONE, CPL_ERROR_DATA_NOT_FOUND);
222  cpl_ensure_code(aSpectrum != NULL, CPL_ERROR_NULL_INPUT);
223  cpl_ensure_code(cpl_table_has_column(aSpectrum, "lambda") &&
224  cpl_table_has_column(aSpectrum, "flux"),
225  CPL_ERROR_DATA_NOT_FOUND);
226 
227  /* cut input pixel table to the length of the continuum in the sky master */
228  double lmin = cpl_table_get_column_min(aSpectrum, "lambda");
229  double lmax = cpl_table_get_column_max(aSpectrum, "lambda");
230  cpl_msg_info(__func__, "Cutting data to %.3f...%.3f Angstrom for sky "
231  "subtraction (range of continuum)", lmin, lmax);
232  muse_pixtable_restrict_wavelength(aPixtable, lmin, lmax);
233 
234  cpl_array *lambda = muse_cpltable_extract_column(aSpectrum, "lambda"),
235  *flux = muse_cpltable_extract_column(aSpectrum, "flux");
236  muse_pixtable_spectrum_apply(aPixtable, lambda, flux,
237  MUSE_PIXTABLE_OPERATION_SUBTRACT);
238  cpl_array_unwrap(lambda);
239  cpl_array_unwrap(flux);
240 
241  return CPL_ERROR_NONE;
242 } /* muse_sky_subtract_continuum() */
243 
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.
A structure containing a spatial two-axis WCS.
Definition: muse_wcs.h:105
muse_pixtable ** muse_pixtable_extracted_get_slices(muse_pixtable *aPixtable)
Extract one pixel table per IFU and slice.
cpl_size muse_pixtable_get_nrow(const muse_pixtable *aPixtable)
get the number of rows within the pixel table
Data cube/stacked image list containing the LSF for one IFU.
Definition: muse_lsf.h:49
cpl_table * table
The pixel table.
cpl_error_code muse_cpltable_check(const cpl_table *aTable, const muse_cpltable_def *aDef)
Check whether the table contains the fields of the definition.
#define MUSE_PIXTABLE_DATA
Definition: muse_pixtable.h:48
cpl_error_code muse_pixtable_restrict_wavelength(muse_pixtable *aPixtable, double aLow, double aHigh)
Restrict a pixel table to a certain wavelength range.
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.
cpl_error_code muse_sky_subtract_continuum(muse_pixtable *aPixtable, cpl_table *aSpectrum)
Subtract sky continuum from pixel table.
cpl_error_code muse_lsf_apply(const cpl_image *aLsfImage, const muse_wcs *aWCS, cpl_array *aVal, double aLambda)
Apply the LSF to a number of data points of one slice.
cpl_error_code muse_cplarray_add_window(cpl_array *aDest, cpl_size aStart, const cpl_array *aArray)
Add the value of an array to a window of a table column.
#define MUSE_PIXTABLE_ORIGIN
Definition: muse_pixtable.h:54
cpl_array * muse_sky_lines_spectrum(const cpl_array *aLambda, cpl_table *aLines, const cpl_image *aLsfImage, const muse_wcs *aLsfWCS)
Create spectrum for a single slice.
unsigned short muse_pixtable_origin_get_ifu(uint32_t aOrigin)
Get the IFU number from the encoded 32bit origin number.
const muse_cpltable_def muse_pixtable_def[]
MUSE pixel table definition.
#define MUSE_PIXTABLE_LAMBDA
Definition: muse_pixtable.h:53
cpl_error_code muse_sky_subtract_lines(muse_pixtable *aPixtable, cpl_table *aLines, muse_lsf_cube **aLsfCube)
Subtract sky lines from a pixtable.
cpl_error_code muse_pixtable_spectrum_apply(muse_pixtable *aPixtable, const cpl_array *aLambdas, const cpl_array *aFlux, muse_pixtable_operation aOperation)
Apply a spectrum given by two arrays with an operation to a pixel table.
cpl_size muse_cplarray_find_sorted(const cpl_array *aArray, double aValue)
Find a row in an array.