33 #include "muse_create_sky_z.h"
47 cpl_msg_error(__func__,
"no science exposures found in input");
50 int nexposures = cpl_table_get_nrow(exposures);
51 if (nexposures != 1) {
52 cpl_msg_error(__func__,
"More than one exposure (%i) in sky creation",
58 for (i = 0; i < nexposures; i++) {
59 cpl_table *thisexp = cpl_table_extract(exposures, i, 1);
63 cpl_table_delete(thisexp);
65 cpl_propertylist_erase_regexp(p->
header,
"ESO QC ", 0);
66 if (pixtable == NULL) {
70 cpl_table_get_nrow(pixtable->
table));
74 cpl_table_delete(exposures);
77 cpl_msg_error(__func__,
"Pixel table already sky subtracted");
82 cpl_table *response =
muse_table_load(aProcessing, MUSE_TAG_STD_RESPONSE, 0);
83 cpl_table *extinction =
muse_table_load(aProcessing, MUSE_TAG_EXTINCT_TABLE, 0);
84 cpl_table *telluric =
muse_table_load(aProcessing, MUSE_TAG_STD_TELLURIC, 0);
86 if ((pixtable != NULL) && (response != NULL)) {
88 cpl_msg_error(__func__,
89 "Pixel table already flux calibrated. Dont specify %s, %s, %s",
90 MUSE_TAG_STD_RESPONSE, MUSE_TAG_EXTINCT_TABLE,
91 MUSE_TAG_STD_TELLURIC);
96 if (rc != CPL_ERROR_NONE) {
97 cpl_msg_error(__func__,
"while muse_flux_calibrate");
104 cpl_table_delete(response);
105 cpl_table_delete(extinction);
106 cpl_table_delete(telluric);
109 cpl_msg_error(__func__,
"Pixel table not flux calibrated, cannot create "
115 if (pixtable != NULL) {
116 cpl_table_and_selected_int(pixtable->
table, MUSE_PIXTABLE_DQ,
117 CPL_NOT_EQUAL_TO, EURO3D_GOODPIXEL);
118 cpl_table_erase_selected(pixtable->
table);
123 cpl_msg_debug(__func__,
"WFM detected: starting DAR correction");
125 cpl_msg_debug(__func__,
"DAR correction returned rc=%d: %s", rc,
126 rc != CPL_ERROR_NONE ? cpl_error_get_message() :
"");
133 muse_create_sky_compute_master(cpl_table *spectrum,
muse_processing *aProcessing)
136 double lambda_low = cpl_array_get_min(lambda);
137 double lambda_high = cpl_array_get_max(lambda);
139 if (sky_lines != NULL) {
146 cpl_errorstate prestate = cpl_errorstate_get();
148 if (!cpl_errorstate_is_equal(prestate)) {
149 cpl_errorstate_dump(prestate, CPL_FALSE, NULL);
150 cpl_errorstate_set(prestate);
153 cpl_table_delete(sky_lines);
154 cpl_array_unwrap(lambda);
155 cpl_array_unwrap(data);
156 cpl_array_unwrap(stat);
157 cpl_table_delete(spectrum);
163 muse_create_sky_save_master(cpl_propertylist *aHeader,
169 "SKY_LINES", CPL_FRAME_TYPE_TABLE);
171 const char *filename = cpl_frame_get_filename(frame);
173 r = cpl_propertylist_save(aHeader, filename, CPL_IO_CREATE);
176 if (r == CPL_ERROR_NONE) {
177 cpl_frameset_insert(aProcessing->
outframes, frame);
179 cpl_frame_delete(frame);
183 "SKY_CONTINUUM", CPL_FRAME_TYPE_TABLE);
185 const char *filename = cpl_frame_get_filename(frame);
187 r = cpl_propertylist_save(aHeader, filename, CPL_IO_CREATE);
190 if (r == CPL_ERROR_NONE) {
191 cpl_frameset_insert(aProcessing->
outframes, frame);
193 cpl_frame_delete(frame);
205 static cpl_error_code
206 muse_create_sky_qc_sky(cpl_propertylist *aHeader,
209 cpl_ensure_code(aHeader && aMaster, CPL_ERROR_NULL_INPUT);
211 cpl_ensure_code(aMaster->
lines && cpl_table_get_nrow(aMaster->
lines) > 0,
212 CPL_ERROR_DATA_NOT_FOUND);
213 char keyword[KEYWORD_LENGTH];
214 int i, ngroups = cpl_table_get_column_max(aMaster->
lines,
"group") + 1;
215 for (i = 0; i < ngroups; i++) {
216 cpl_table_unselect_all(aMaster->
lines);
217 cpl_table_or_selected_int(aMaster->
lines,
"group", CPL_EQUAL_TO, i);
218 cpl_table *gtable = cpl_table_extract_selected(aMaster->
lines);
220 cpl_table_get_column_maxpos(gtable,
"flux", &row);
221 const char *name = cpl_table_get_string(gtable,
"name", row);
222 double wavelength = cpl_table_get_double(gtable,
"lambda", row, NULL),
223 flux = cpl_table_get_double(gtable,
"flux", row, NULL);
224 snprintf(keyword, KEYWORD_LENGTH,
"ESO QC SKY LINE%i NAME", i+1);
225 cpl_propertylist_append_string(aHeader, keyword, name);
226 snprintf(keyword, KEYWORD_LENGTH,
"ESO QC SKY LINE%i AWAV", i+1);
227 cpl_propertylist_append_double(aHeader, keyword, wavelength);
228 snprintf(keyword, KEYWORD_LENGTH,
"ESO QC SKY LINE%i FLUX", i+1);
229 if (!isfinite(flux)) {
232 cpl_propertylist_append_double(aHeader, keyword, -9999.999);
233 cpl_msg_error(__func__,
"Sky-line fit failed for group %d, computed "
234 "flux is infinite!", i+1);
236 cpl_propertylist_append_double(aHeader, keyword, flux);
238 cpl_table_delete(gtable);
239 double offset = aMaster->
lsf[0]->offset
240 + (aMaster->
lsf[0]->refraction - 1) * wavelength;
241 snprintf(keyword, KEYWORD_LENGTH,
"ESO QC SKY LINE%i OFFSET", i+1);
242 cpl_propertylist_append_double(aHeader, keyword, offset);
244 cpl_table_unselect_all(aMaster->
lines);
247 CPL_ERROR_DATA_NOT_FOUND);
248 cpl_size row, nrows = cpl_table_get_nrow(aMaster->
continuum);
250 for (row = 0; row < nrows; row++) {
251 flux += cpl_table_get_double(aMaster->
continuum,
"flux", row, NULL);
253 snprintf(keyword, KEYWORD_LENGTH,
"ESO QC SKY CONT FLUX");
254 if (!isfinite(flux)) {
256 cpl_propertylist_append_double(aHeader, keyword, -9999.999);
257 cpl_msg_error(__func__,
"Sky-continuum contains infinite values, fit may "
260 cpl_propertylist_append_double(aHeader, keyword, flux);
263 prev = cpl_table_get_double(aMaster->
continuum,
"flux", 0, NULL),
264 l_prev = cpl_table_get_double(aMaster->
continuum,
"lambda", 0, NULL);
265 for (row = 1; row < nrows; row++) {
266 double cur = cpl_table_get_double(aMaster->
continuum,
"flux", row, NULL),
267 l_cur = cpl_table_get_double(aMaster->
continuum,
"lambda", row, NULL),
268 dev = fabs((cur - prev)/ (l_cur - l_prev));
275 snprintf(keyword, KEYWORD_LENGTH,
"ESO QC SKY CONT MAXDEV");
276 cpl_propertylist_append_double(aHeader, keyword, maxdev);
278 return CPL_ERROR_NONE;
291 muse_create_sky_whitelight_image(
muse_pixtable *aPixtable,
int aCr)
293 cpl_boolean usegrid = getenv(
"MUSE_COLLAPSE_PIXTABLE")
294 && atoi(getenv(
"MUSE_COLLAPSE_PIXTABLE")) > 0;
304 usegrid ? &grid : NULL);
306 cpl_msg_error(__func__,
"Could not create cube for whitelight image");
316 cube, fwhite, params);
323 cpl_table_delete(fwhite);
349 cpl_table_erase_column(aMaster->
continuum,
"stat");
350 cpl_table_erase_column(aMaster->
continuum,
"dq");
351 cpl_table_name_column(aMaster->
continuum,
"data",
"flux");
366 muse_pixtable *pixtable = muse_create_sky_load_pixtable(aProcessing, aParams);
367 if (pixtable == NULL) {
368 cpl_msg_error(__func__,
"Could not load pixel table");
381 cpl_table_select_all(pixtable->
table);
386 int cube_cr = (!strncmp(aParams->
cr_s,
"cube", 5));
387 muse_image *whitelight = muse_create_sky_whitelight_image(pixtable, cube_cr);
388 if (whitelight == NULL) {
389 cpl_msg_error(__func__,
"Could not create whitelight image");
398 cpl_table_select_all(pixtable->
table);
405 if (!strncmp(aParams->
cr_s,
"spectrum", 9)) {
407 cpl_table_delete(spectrum);
411 if (spectrum == NULL) {
423 cpl_msg_info(__func__,
"Creating master sky spectrum using fits to lines "
424 "(fluxes) and residual continuum");
426 = muse_create_sky_compute_master(spectrum, aProcessing);
427 if (master == NULL) {
432 cpl_errorstate prestate = cpl_errorstate_get();
437 if (continuum != NULL) {
440 }
else if (lsfParam != NULL) {
441 muse_create_sky_create_continuum(pixtable, master,
446 cpl_propertylist *qc_header = cpl_propertylist_new();
447 muse_create_sky_qc_sky(qc_header, master);
449 muse_create_sky_save_master(qc_header, master, aProcessing);
453 cpl_propertylist_delete(qc_header);
455 return cpl_errorstate_is_equal(prestate) ? 0 : -1;
Structure definition of a MUSE datacube.
void muse_image_delete(muse_image *aImage)
Deallocate memory associated to a muse_image object.
int muse_processing_save_mask(muse_processing *aProcessing, int aIFU, muse_mask *aMask, const char *aTag)
Save a computed MUSE mask to disk.
cpl_error_code muse_dar_correct(muse_pixtable *aPixtable, double aLambdaRef)
Correct the pixel coordinates of all pixels of a given pixel table for differential atmospheric refra...
cpl_error_code muse_pixtable_and_selected_mask(muse_pixtable *aPixtable, muse_mask *aMask)
Select all pixels where the (x,y) positions are enabled in the given mask.
cpl_table * muse_sky_lines_load(muse_processing *)
Load the sky data files.
Structure to hold the MASTER SKY result.
double csampling
Spectral sampling of the continuum spectrum [Angstrom].
void muse_datacube_delete(muse_datacube *aCube)
Deallocate memory associated to a muse_datacube object.
muse_image * muse_datacube_collapse(muse_datacube *aCube, cpl_table *aFilter)
Integrate a FITS NAXIS=3 datacube along the wavelength direction.
muse_mask * muse_sky_create_skymask(muse_image *, double, const char *)
Select spaxels to be considered as sky.
Structure definition of MUSE three extension FITS file.
muse_mask * muse_processing_mask_load(muse_processing *aProcessing, const char *aTag)
Load a mask file and its FITS header.
cpl_table * table
The pixel table.
cpl_table * muse_table_load_filter(muse_processing *aProcessing, const char *aFilterName)
Load a table for a given filter name.
void muse_sky_mark_cosmic(cpl_table *aSpectrum, muse_pixtable *aPixtable)
Mark all pixel above a certain limit as COSMIC.
muse_resampling_crstats_type crtype
cpl_boolean muse_pixtable_is_skysub(muse_pixtable *aPixtable)
Determine whether the pixel table is sky subtracted.
cpl_table * muse_sky_continuum_load(muse_processing *)
Load the SKY_CONTINUUM spectrum.
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.
cpl_array * muse_cpltable_extract_column(cpl_table *aTable, const char *aColumn)
Create an array from a section of a column.
cpl_table * lines
Table of Atmospheric emission lines and their intensities.
muse_resampling_params * muse_resampling_params_new(muse_resampling_type aMethod)
Create the resampling parameters structure.
cpl_boolean muse_pixtable_is_fluxcal(muse_pixtable *aPixtable)
Determine whether the pixel table is flux calibrated.
cpl_error_code muse_flux_calibrate(muse_pixtable *aPixtable, const cpl_table *aResponse, const cpl_table *aExtinction, const cpl_table *aTelluric)
Convert the input pixel table from counts to fluxes.
const muse_cpltable_def muse_fluxspectrum_def[]
Definition of the flux spectrum table structure.
cpl_error_code muse_sky_lines_set_range(cpl_table *, double, double)
Limit the lines in the table to a wavelength range.
void muse_sky_master_delete(muse_sky_master *)
Delete a MASTER SKY structure.
muse_datacube * muse_resampling_cube(muse_pixtable *aPixtable, muse_resampling_params *aParams, muse_pixgrid **aPixgrid)
Resample a pixel table onto a regular grid structure representing a FITS NAXIS=3 datacube.
muse_sky_master * muse_sky_master_fit(const cpl_array *, const cpl_array *, const cpl_array *, const cpl_table *)
Fit all entries of the pixel table to the master sky.
muse_image * muse_resampling_collapse_pixgrid(muse_pixtable *aPixtable, muse_pixgrid *aPixgrid, muse_datacube *aCube, cpl_table *aFilter, muse_resampling_params *aParams)
Integrate a pixel table / pixel grid along the wavelength direction.
void muse_pixgrid_delete(muse_pixgrid *aPixels)
Delete a pixgrid and remove its memory.
int muse_processing_save_image(muse_processing *aProcessing, int aIFU, muse_image *aImage, const char *aTag)
Save a computed MUSE image to disk.
muse_pixtable * muse_pixtable_load_merge_channels(cpl_table *aExposureList, double aLambdaMin, double aLambdaMax)
Load and merge the pixel tables of the 24 MUSE sub-fields.
Handling of "mask" files.
double lambdamin
Cut off the data below this wavelength after loading the pixel table(s).
double sampling
Spectral sampling of the sky spectrum [Angstrom].
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
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.
double fraction
Fraction of the image to be considered as sky. If an input sky mask is provided, the fraction is appl...
muse_resampling_type
Resampling types.
double lambdamax
Cut off the data above this wavelength after loading the pixel table(s).
double lambdaref
Reference wavelength used for correction of differential atmospheric refraction. The R-band (peak wav...
void muse_resampling_params_delete(muse_resampling_params *aParams)
Delete a resampling parameters structure.
muse_resampling_type method
muse_lsf_params ** muse_processing_lsf_params_load(muse_processing *aProcessing, int aIFU)
Load slice LSF parameters.
void muse_mask_delete(muse_mask *aMask)
Deallocate memory associated to a muse_mask object.
const char * cr_s
Type of cosmic ray cleaning to use. "Cube" is the standard CR cleaning which works on a datacube...
cpl_table * continuum
Continuum flux table
cpl_table * muse_resampling_spectrum(muse_pixtable *aPixtable, double aBinwidth)
Resample the selected pixels of a pixel table into a spectrum.
cpl_table * muse_processing_sort_exposures(muse_processing *aProcessing)
Sort input frames (containing lists of pixel table filenames) into different exposures.
Structure definition of detector (slice) parameters.
void muse_pixtable_delete(muse_pixtable *aPixtable)
Deallocate memory associated to a pixel table object.
Structure to hold the parameters of the muse_create_sky recipe.
cpl_error_code muse_sky_subtract_pixtable(muse_pixtable *a, muse_sky_master *, muse_lsf_params **)
Subtract the sky spectrum from the "data" column of a pixel table.
muse_lsf_params ** lsf
LSF parameter for the resampled spectrum.
muse_ins_mode muse_pfits_get_mode(const cpl_propertylist *aHeaders)
find out the observation mode
void muse_lsf_params_delete(muse_lsf_params **aParams)
Delete an allocated array of muse_lsf_params structure.
cpl_error_code muse_cpltable_append_file(const cpl_table *aTable, const char *aFile, const char *aExtension, const muse_cpltable_def aDefinition[])
Save a table to disk (into a FITS extension)
cpl_propertylist * header
The FITS header.