35 #include "muse_flat_z.h" 51 cpl_msg_debug(__func__,
"Adding QC keywords");
53 unsigned stats = CPL_STATS_MEDIAN | CPL_STATS_MEAN | CPL_STATS_STDEV
54 | CPL_STATS_MIN | CPL_STATS_MAX;
59 char *keyword = cpl_sprintf(QC_FLAT_PREFIXi, k+1);
61 aImage->
header, keyword, stats);
63 keyword = cpl_sprintf(QC_FLAT_PREFIXi
" "QC_BASIC_NSATURATED, k+1);
66 cpl_propertylist_update_int(aImage->
header, keyword, nsaturated);
71 stats |= CPL_STATS_FLUX;
73 QC_FLAT_MASTER_PREFIX, stats);
84 muse_flat_qc_trace_header(cpl_propertylist *aHeader,
const cpl_table *aTrace)
86 if (!aHeader || !aTrace) {
90 cpl_msg_debug(__func__,
"Adding tracing QC keywords for IFU %hhu", ifu);
93 cpl_array *gaps = cpl_array_new(kMuseSlicesPerCCD - 1, CPL_TYPE_DOUBLE);
96 for (nslice = 1; nslice <= kMuseSlicesPerCCD; nslice++) {
100 cpl_msg_warning(__func__,
"slice %2d of IFU %hhu: tracing polynomials " 101 "missing!", nslice, ifu);
106 float xpos = cpl_polynomial_eval_1d(ptrace[MUSE_TRACE_CENTER],
107 kMuseOutputYTop/2, NULL);
108 if (xpos < 1 || xpos > kMuseOutputXRight || !isnormal(xpos)) {
109 cpl_msg_warning(__func__,
"slice %2d of IFU %hhu: faulty polynomial " 110 "detected at y=%d (center: %f)", nslice, ifu,
111 kMuseOutputYTop/2, xpos);
117 double x1 = cpl_polynomial_eval_1d(ptrace[MUSE_TRACE_CENTER], 1, NULL),
118 x2 = cpl_polynomial_eval_1d(ptrace[MUSE_TRACE_CENTER],
119 kMuseOutputYTop, NULL);
120 float tilt = atan((x2 - x1) / (kMuseOutputYTop - 1)) * CPL_MATH_DEG_RAD;
122 cpl_propertylist_append_float(aHeader, QC_TRACE_L_XPOS, xpos);
123 cpl_propertylist_append_float(aHeader, QC_TRACE_L_TILT, tilt);
124 }
else if (nslice == kMuseSlicesPerCCD) {
125 cpl_propertylist_append_float(aHeader, QC_TRACE_R_XPOS, xpos);
126 cpl_propertylist_append_float(aHeader, QC_TRACE_R_TILT, tilt);
131 double gap = cpl_polynomial_eval_1d(ptrace[MUSE_TRACE_LEFT],
132 kMuseOutputYTop/2, NULL)
134 cpl_array_set_double(gaps, nslice - 2, gap);
137 redge = cpl_polynomial_eval_1d(ptrace[MUSE_TRACE_RIGHT], kMuseOutputYTop/2,
142 double maxslope = 0.;
143 int ipoly, j, jmax = -1, ipolymax = -1;
144 for (ipoly = MUSE_TRACE_CENTER; ipoly <= MUSE_TRACE_RIGHT; ipoly++) {
145 cpl_polynomial_derivative(ptrace[ipoly], 0);
148 for (j = 1; j <= kMuseOutputYTop; j++) {
149 double slope = cpl_polynomial_eval_1d(ptrace[ipoly], j, NULL);
150 if (fabs(slope) > fabs(maxslope)) {
157 #define MAX_NORMAL_SLOPE 0.015 158 if (fabs(maxslope) > MAX_NORMAL_SLOPE) {
159 cpl_msg_warning(__func__,
"Slope in slice %2d of IFU %hhu is unusually " 160 "high (maximum in polynomial %d at y=%d is |%f| > %f)",
161 nslice, ifu, ipolymax, jmax, maxslope, MAX_NORMAL_SLOPE);
163 char *kw = cpl_sprintf(QC_TRACE_SLICEj_MXSLOP, nslice);
164 cpl_propertylist_append_float(aHeader, kw, maxslope);
169 if (nslice == 10 || nslice == 46 || nslice == 3 || nslice == 39) {
171 int irow, err, nrow = cpl_table_get_nrow(aTrace);
172 for (irow = 0; irow < nrow; irow++) {
173 int slice = cpl_table_get_int(aTrace, MUSE_TRACE_TABLE_COL_SLICE_NO,
175 if (slice == nslice && !err) {
180 cpl_msg_warning(__func__,
"Slice %d not found in trace table!", nslice);
183 float width = cpl_table_get(aTrace, MUSE_TRACE_TABLE_COL_WIDTH, irow, &err);
184 kw = cpl_sprintf(QC_TRACE_SLICEj_WIDTH, nslice);
185 cpl_propertylist_append_float(aHeader, kw, width);
190 float median, mean, stdev, min, max;
192 median = cpl_array_get_median(gaps);
193 mean = cpl_array_get_mean(gaps);
194 stdev = cpl_array_get_stdev(gaps);
195 min = cpl_array_get_min(gaps);
196 max = cpl_array_get_max(gaps);
197 cpl_propertylist_append_float(aHeader, QC_TRACE_GAPS_MEDIAN, median);
198 cpl_propertylist_append_float(aHeader, QC_TRACE_GAPS_MEAN, mean);
199 cpl_propertylist_append_float(aHeader, QC_TRACE_GAPS_STDEV, stdev);
200 cpl_propertylist_append_float(aHeader, QC_TRACE_GAPS_MIN, min);
201 cpl_propertylist_append_float(aHeader, QC_TRACE_GAPS_MAX, max);
202 cpl_array_delete(gaps);
205 median = cpl_table_get_column_median(aTrace, MUSE_TRACE_TABLE_COL_WIDTH);
206 mean = cpl_table_get_column_mean(aTrace, MUSE_TRACE_TABLE_COL_WIDTH);
207 stdev = cpl_table_get_column_stdev(aTrace, MUSE_TRACE_TABLE_COL_WIDTH);
208 min = cpl_table_get_column_min(aTrace, MUSE_TRACE_TABLE_COL_WIDTH);
209 max = cpl_table_get_column_max(aTrace, MUSE_TRACE_TABLE_COL_WIDTH);
210 cpl_propertylist_append_float(aHeader, QC_TRACE_WIDTHS_MEDIAN, median);
211 cpl_propertylist_append_float(aHeader, QC_TRACE_WIDTHS_MEAN, mean);
212 cpl_propertylist_append_float(aHeader, QC_TRACE_WIDTHS_STDEV, stdev);
213 cpl_propertylist_append_float(aHeader, QC_TRACE_WIDTHS_MIN, min);
214 cpl_propertylist_append_float(aHeader, QC_TRACE_WIDTHS_MAX, max);
225 muse_flat_qc_per_slice(
muse_image *aImage,
const cpl_table *aTrace)
227 if (!aImage->
header || !aTrace) {
231 cpl_msg_debug(__func__,
"Adding per-slice QC statistics for IFU %hhu", ifu);
234 const int y1 = kMuseOutputYTop/2 - 100,
235 y2 = kMuseOutputYTop/2 + 100;
237 for (nslice = 1; nslice <= kMuseSlicesPerCCD; nslice++) {
241 cpl_msg_warning(__func__,
"slice %2d of IFU %hhu: tracing polynomials " 242 "missing!", nslice, ifu);
245 char *kwmean = cpl_sprintf(QC_FLAT_MASTER_SLICEj_MEAN, nslice),
246 *kwstdev = cpl_sprintf(QC_FLAT_MASTER_SLICEj_STDEV, nslice);
248 int x1 = lround(cpl_polynomial_eval_1d(ptrace[MUSE_TRACE_LEFT],
249 kMuseOutputYTop/2, NULL)) + 1,
250 x2 = lround(cpl_polynomial_eval_1d(ptrace[MUSE_TRACE_RIGHT],
251 kMuseOutputYTop/2, NULL)) - 1;
252 if (x1 < 1 || x2 > kMuseOutputXRight || x1 > x2) {
253 cpl_msg_warning(__func__,
"slice %2d of IFU %hhu: faulty polynomial " 254 "detected at y=%d (borders: %d ... %d)", nslice, ifu,
255 kMuseOutputYTop/2, x1, x2);
259 double mean = cpl_image_get_mean_window(aImage->
data, x1, y1, x2, y2),
260 stdev = cpl_image_get_stdev_window(aImage->
data, x1, y1, x2, y2);
261 cpl_propertylist_update_float(aImage->
header, kwmean, mean);
262 cpl_propertylist_update_float(aImage->
header, kwstdev, stdev);
279 static cpl_error_code
283 cpl_table *samples = NULL;
286 aParams->
samples ? &samples : NULL);
288 cpl_table_delete(samples);
289 return cpl_error_get_code();
293 cpl_propertylist *header = cpl_propertylist_duplicate(aImage->
header);
294 cpl_propertylist_erase_regexp(header,
295 "^SIMPLE$|^BITPIX$|^NAXIS|^EXTEND$|^XTENSION$|" 296 "^DATASUM$|^DATAMIN$|^DATAMAX$|^DATAMD5$|" 297 "^PCOUNT$|^GCOUNT$|^HDUVERS$|^BLANK$|" 298 "^BZERO$|^BSCALE$|^BUNIT$|^CHECKSUM$|^INHERIT$|" 299 "^PIPEFILE$|^ESO QC |^ESO PRO ", 0);
301 muse_flat_qc_trace_header(header, tracetable);
304 MUSE_TAG_TRACE_TABLE,
308 cpl_propertylist_erase_regexp(header, QC_TRACE_PREFIX, 0);
311 cpl_table_delete(samples);
313 cpl_propertylist_delete(header);
314 if (rc != CPL_ERROR_NONE) {
315 cpl_table_delete(tracetable);
323 cpl_msg_info(__func__,
"Found %d bad pixels in the flat-field image of IFU %d",
324 nbad, aParams->
nifu);
327 muse_flat_qc_per_slice(aImage, tracetable);
329 cpl_table_delete(tracetable);
348 cpl_ensure(images, cpl_error_get_code(), -1);
355 cpl_msg_error(__func__,
"Combining input frames failed for IFU %d!",
362 muse_flat_qc_header(masterimage, images);
365 cpl_error_code rc1 = CPL_ERROR_NONE;
366 if (aParams->
trace) {
369 rc1 = muse_flat_trace_badpix(aProcessing, aParams, masterimage);
370 if (rc1 != CPL_ERROR_NONE) {
373 cpl_msg_error(__func__,
"Tracing/bad pixel search failed in IFU %d",
380 double mean = cpl_propertylist_get_float(masterimage->
header,
381 QC_FLAT_MASTER_PREFIX
" MEAN");
388 MUSE_TAG_MASTER_FLAT);
390 return rc1 == CPL_ERROR_NONE && rc2 == CPL_ERROR_NONE ? 0 : -1;
muse_imagelist * muse_basicproc_load(muse_processing *aProcessing, unsigned char aIFU, muse_basicproc_params *aBPars)
Load the raw input files from disk and do basic processing.
cpl_polynomial ** muse_trace_table_get_polys_for_slice(const cpl_table *aTable, const unsigned short aSlice)
construct polynomial from the trace table entry for the given slice
int nifu
IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in ...
int order
Order of polynomial fit to the trace.
Structure definition for a collection of muse_images.
void muse_image_delete(muse_image *aImage)
Deallocate memory associated to a muse_image object.
int muse_quality_flat_badpix(muse_image *aFlat, cpl_table *aTrace, double aSigmaLo, double aSigmaHi)
Find bad (especially dark) pixels (in a master flat).
int muse_image_scale(muse_image *aImage, double aScale)
Scale a muse_image with correct treatment of variance.
cpl_table * muse_trace(const muse_image *aImage, int aNSum, double aEdgeFrac, int aFitorder, cpl_table **aSamples)
carry out the tracing of the slices on CCD, save parameters in table
unsigned char muse_utils_get_ifu(const cpl_propertylist *aHeaders)
Find out the IFU/channel from which this header originated.
cpl_image * data
the data extension
int normalize
Normalize the master flat to the average flux.
Structure to hold the parameters of the muse_flat recipe.
void muse_imagelist_delete(muse_imagelist *aList)
Free the memory of the MUSE image list.
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.
Structure definition of MUSE three extension FITS file.
void muse_basicproc_params_delete(muse_basicproc_params *aBPars)
Free a structure of basic processing parameters.
cpl_propertylist * header
the FITS header
unsigned int muse_imagelist_get_size(muse_imagelist *aList)
Return the number of stored images.
void muse_trace_polys_delete(cpl_polynomial *aPolys[])
Delete the multi-polynomial array created in relation to tracing.
void muse_combinepar_delete(muse_combinepar *aCPars)
Clear the combination parameters.
#define MUSE_WCS_KEYS
regular expression for WCS properties
muse_image * muse_imagelist_get(muse_imagelist *aList, unsigned int aIdx)
Get the muse_image of given list index.
int nsum
Number of lines over which to average when tracing.
int samples
Create a table containing all tracing sample points.
muse_combinepar * muse_combinepar_new(cpl_parameterlist *aParameters, const char *aPrefix)
Create a new set of combination parameters.
cpl_error_code muse_basicproc_stats_append_header(cpl_image *aImage, cpl_propertylist *aHeader, const char *aPrefix, unsigned aStats)
Compute image statistics of an image and add them to a header.
int muse_processing_save_image(muse_processing *aProcessing, int aIFU, muse_image *aImage, const char *aTag)
Save a computed MUSE image to disk.
double edgefrac
Fractional change required to identify edge when tracing.
double losigmabadpix
Low sigma to find dark pixels in the master flat.
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.
int trace
Trace the position of the slices on the master flat.
Structure of basic processing parameters.
cpl_parameterlist * parameters
double hisigmabadpix
High sigma to find bright pixels in the master flat.
cpl_error_code muse_basicproc_qc_saturated(muse_image *aImage, const char *aPrefix)
Add QC parameter about saturated pixels to a muse_image.