MUSE Pipeline Reference Manual  2.1.1
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-2015 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 <math.h>
30 
31 #include "muse_sky.h"
32 
33 #include "muse_cplwrappers.h"
34 #include "muse_data_format_z.h"
35 #include "muse_quality.h"
36 #include "muse_mask.h"
37 #include "muse_pfits.h"
38 
39 /*----------------------------------------------------------------------------*
40  * Special variable types *
41  *----------------------------------------------------------------------------*/
45 /*----------------------------------------------------------------------------*/
54 /*----------------------------------------------------------------------------*/
56  {"lambda", CPL_TYPE_DOUBLE, "Angstrom", "%7.2f", "wavelength", CPL_TRUE},
57  {"flux", CPL_TYPE_DOUBLE, "erg/(s cm^2 arcsec^2)", "%e", "Flux", CPL_TRUE},
58  { NULL, 0, NULL, NULL, NULL, CPL_FALSE }
59 };
60 
61 /*----------------------------------------------------------------------------*/
68 /*----------------------------------------------------------------------------*/
69 cpl_table *
70 muse_sky_spectrum_from_cube(muse_datacube *aCube, const cpl_mask *aMask) {
71  unsigned count = cpl_imagelist_get_size(aCube->data);
72  cpl_table *spectrum = muse_cpltable_new(muse_dataspectrum_def, count);
73  double crval3 = muse_pfits_get_crval(aCube->header, 3);
74  double crpix3 = muse_pfits_get_crpix(aCube->header, 3);
75  double cdelt3 = muse_pfits_get_cd(aCube->header, 3, 3);
76  unsigned i;
77  cpl_mask *nmask = cpl_mask_duplicate(aMask);
78  cpl_mask_not(nmask);
79  for (i = 0; i < count; i++) {
80  cpl_table_set(spectrum, "lambda", i, crval3 + (i + 1 - crpix3) * cdelt3);
81 
82  cpl_image *img = cpl_imagelist_get(aCube->data, i);
83  cpl_mask *bpm = cpl_image_get_bpm(img);
84  cpl_mask_or(bpm, nmask);
85  if (aCube->dq != NULL) {
86  cpl_image *dq = cpl_imagelist_get(aCube->dq, i);
87  cpl_mask *dq_mask = cpl_mask_threshold_image_create(dq, -0.5, 0.5);
88  cpl_mask_not(dq_mask);
89  cpl_mask_or(bpm, dq_mask);
90  cpl_mask_delete(dq_mask);
91  }
92  double dev = cpl_image_get_stdev(img);
93  double mean = cpl_image_get_mean(img);
94  cpl_table_set(spectrum, "data", i, mean);
95  cpl_table_set(spectrum, "stat", i, dev / sqrt(cpl_mask_count(bpm)));
96  cpl_table_set(spectrum, "dq", i, (cpl_mask_count(bpm) < 3));
97  }
98  cpl_mask_delete(nmask);
99 
100  return spectrum;
101 }
102 
103 /*----------------------------------------------------------------------------*/
118 /*----------------------------------------------------------------------------*/
119 muse_mask *
120 muse_sky_create_skymask(muse_image *aImage, double aMinFraction, double aFraction,
121  const char *aQCPrefix)
122 {
123  cpl_ensure(aImage, CPL_ERROR_NULL_INPUT, NULL);
124 
125  /* Re-normalize fraction: as parameter, it means the fraction of the remaining image,
126  while we need the absolute number here. Example: if
127  minFraction = 0.2, Fraction = 0.8 means: throw away the lowest 20% and then take the
128  lowest 80% of the remaining image. This converts to 84 % of the total image. */
129  aFraction = aMinFraction + aFraction * (1-aMinFraction);
130 
131  /* do statistics */
133  double t0 = muse_cplimage_get_percentile(aImage->data, aMinFraction);
134  double t1 = muse_cplimage_get_percentile(aImage->data, aFraction);
135  cpl_msg_info(__func__, "Creating sky mask for pixels between minimum (%g) and"
136  " threshold (%g)", t0, t1);
137 
138  /* create output mask with pixels between min and threshold */
139  muse_mask *selectedRegions = muse_mask_new();
140  selectedRegions->mask = cpl_mask_threshold_image_create(aImage->data, t0, t1);
141  cpl_mask_not(selectedRegions->mask);
142  cpl_mask_or(selectedRegions->mask, cpl_image_get_bpm(aImage->data));
143  cpl_mask_not(selectedRegions->mask);
144 
145  /* add threshold as QC parameter */
146  selectedRegions->header = cpl_propertylist_duplicate(aImage->header);
147  char keyword[KEYWORD_LENGTH];
148  snprintf(keyword, KEYWORD_LENGTH, "%s THRESHOLD", aQCPrefix);
149  cpl_propertylist_append_double(selectedRegions->header, keyword, t1);
150 
151  return selectedRegions;
152 }
153 
154 /*----------------------------------------------------------------------------*/
167 /*----------------------------------------------------------------------------*/
168 cpl_error_code
170  const cpl_table *aContinuum, cpl_propertylist *aHeader)
171 {
172  cpl_ensure_code(aProcessing && aContinuum && aHeader, CPL_ERROR_NULL_INPUT);
173  cpl_frame *frame = muse_processing_new_frame(aProcessing, -1, aHeader,
174  MUSE_TAG_SKY_CONT,
175  CPL_FRAME_TYPE_TABLE);
176  cpl_ensure_code(frame, CPL_ERROR_ILLEGAL_INPUT);
177  const char *filename = cpl_frame_get_filename(frame);
178  cpl_error_code rc = cpl_propertylist_save(aHeader, filename, CPL_IO_CREATE);
179  rc = muse_cpltable_append_file(aContinuum, filename,
180  "CONTINUUM", muse_fluxspectrum_def);
181  if (rc == CPL_ERROR_NONE) {
182 #pragma omp critical(muse_processing_output_frames)
183  cpl_frameset_insert(aProcessing->outframes, frame);
184  } else {
185  cpl_frame_delete(frame);
186  }
187  return rc;
188 } /* muse_sky_save_continuum() */
189 
Structure definition of a MUSE datacube.
Definition: muse_datacube.h:48
double muse_pfits_get_cd(const cpl_propertylist *aHeaders, unsigned int aAxisI, unsigned int aAxisJ)
find out the WCS coordinate at the reference point
Definition: muse_pfits.c:446
double muse_pfits_get_crval(const cpl_propertylist *aHeaders, unsigned int aAxis)
find out the WCS coordinate at the reference point
Definition: muse_pfits.c:423
cpl_image * data
the data extension
Definition: muse_image.h:46
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[]
Structure definition of MUSE three extension FITS file.
Definition: muse_image.h:40
cpl_propertylist * header
the FITS header
Definition: muse_image.h:72
cpl_table * muse_cpltable_new(const muse_cpltable_def *aDef, cpl_size aLength)
Create an empty table according to the specified definition.
double muse_pfits_get_crpix(const cpl_propertylist *aHeaders, unsigned int aAxis)
find out the WCS reference point
Definition: muse_pfits.c:401
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_frameset * outframes
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
muse_mask * muse_mask_new(void)
Allocate memory for a new muse object.
Definition: muse_mask.c:61
cpl_propertylist * header
the FITS header
Definition: muse_datacube.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:863
muse_mask * muse_sky_create_skymask(muse_image *aImage, double aMinFraction, double aFraction, const char *aQCPrefix)
Select spaxels to be considered as sky.
cpl_propertylist * header
the FITS header
Definition: muse_mask.h:56
Definition of a cpl table structure.
cpl_mask * mask
The mask data.
Definition: muse_mask.h:49
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_error_code muse_sky_save_continuum(muse_processing *aProcessing, const cpl_table *aContinuum, cpl_propertylist *aHeader)
Save sky continuum table to file.