ERIS Pipeline Reference Manual 1.9.2
eris_nix_spec_cal_and_stack.c
1/* $Id$
2 *
3 * This file is part of the ERIS Pipeline
4 * Copyright (C) 2017 European Southern Observatory
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/*
22 * $Author$
23 * $Date$
24 * $Revision$
25 */
26
27#ifdef HAVE_CONFIG_H
28#include <config.h>
29#endif
30
31/*-----------------------------------------------------------------------------
32 Includes
33 -----------------------------------------------------------------------------*/
34
35#include <libgen.h>
36#include <math.h>
37#include <string.h>
38
39#include "casu_utils.h"
40#include "casu_mods.h"
41
42#include "eris_utils.h"
43#include "eris_nix_utils.h"
44#include "eris_pfits.h"
45#include "eris_dfs.h"
46#include "eris_nix_dfs.h"
47#include "eris_nix_master_bpm.h"
48#include "eris_nix_master_dark.h"
49#include "eris_nix_gain_linearity.h"
50#include <hdrl.h>
51
52#include <cpl.h>
53
54/*-----------------------------------------------------------------------------
55 Static variables
56 -----------------------------------------------------------------------------*/
57
58static const char eris_nix_spec_cal_and_stack_description[] =
59"This recipe calibrates a set of OBJECT_SPEC_JITTER frames to \n"
60"produce:\n"
61"- OBJECT_SPEC_JITTER_CALIB frames.\n"
62"- TBD\n"
63"The recipes needs:\n"
64"- a series of tagged OBJECT_SPEC_JITTER frames.\n"
65"- a tagged DETMON coefficients cube file, e.g.\n"
66"-- detmon_ir_lg_coeffs_cube.fits "ERIS_NIX_COEFFS_CUBE_PRO_CATG "\n"
67"- a tagged MASTER_DARK for matching detector configuration.\n"
68"- a tagged MASTER_FLAT_HIFREQ for matching detector configuration.\n"
69"The output will be fits files containing:\n"
70"- OBJECT_SPEC_JITTER_CALIBRATED frames.\n"
71"- TBD.\n"
72"\n";
73
74#define RECIPE_NAME "eris.eris_nix_spec_cal_and_stack"
75
76/*-----------------------------------------------------------------------------
77 Private function prototypes
78 -----------------------------------------------------------------------------*/
79
80cpl_recipe_define(eris_nix_spec_cal_and_stack, ERIS_BINARY_VERSION,
81 "John Lightfoot",
82 PACKAGE_BUGREPORT, "2017",
83 "Calibrate OBJECT_SPEC_JITTER frames",
84 eris_nix_spec_cal_and_stack_description);
85
86/*-----------------------------------------------------------------------------
87 Function code
88 -----------------------------------------------------------------------------*/
89
90/*----------------------------------------------------------------------------*/
98/*----------------------------------------------------------------------------*/
99
100static cpl_error_code eris_nix_spec_cal_and_stack_fill_parameterlist(
101 cpl_parameterlist * self) {
102
103 if (cpl_error_get_code() != CPL_ERROR_NONE) return cpl_error_get_code();
104
105 cpl_parameter * p = NULL;
106
107 p = cpl_parameter_new_value(RECIPE_NAME".debug_data",
108 CPL_TYPE_BOOL,
109 "write additional data for debugging",
110 RECIPE_NAME, CPL_TRUE);
111 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "debug_data");
112 cpl_parameterlist_append(self, p);
113
114 p = cpl_parameter_new_value(RECIPE_NAME".zero_rejected",
115 CPL_TYPE_BOOL,
116 "set rejected pixels to 0",
117 RECIPE_NAME, CPL_TRUE);
118 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "zero_rejected");
119 cpl_parameterlist_append(self, p);
120
121 p = cpl_parameter_new_value(RECIPE_NAME".premask_objects",
122 CPL_TYPE_BOOL,
123 "create object masks before background estimation",
124 RECIPE_NAME, CPL_TRUE);
125 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "premask_objects");
126 cpl_parameterlist_append(self, p);
127
128 p = cpl_parameter_new_value(RECIPE_NAME".premask_nsigma",
129 CPL_TYPE_DOUBLE,
130 "sigma cutoff for premask object detection",
131 RECIPE_NAME, 5.0);
132 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "premask_nsigma");
133 cpl_parameterlist_append(self, p);
134
135 /* tidy up */
136
137 return 0;
138}
139
140/*----------------------------------------------------------------------------*/
147/*----------------------------------------------------------------------------*/
148
149static int eris_nix_spec_cal_and_stack(cpl_frameset * frameset,
150 const cpl_parameterlist * parlist) {
151
152 cpl_table * astrom_ref_cat = NULL;
153 located_imagelist * cal_sky_jitters1 = NULL;
154 located_imagelist * cal_sky_jitters2 = NULL;
155 located_imagelist * cal_jitters1 = NULL;
156 located_imagelist * cal_jitters2 = NULL;
157/* located_imagelist * cal_jitters_final = NULL; */
158 hdrl_parameter * cat_params = NULL;
159 const gain_linearity * gain_lin = NULL;
160 master_bpm * master_bpm = NULL;
161 master_dark * master_dark = NULL;
162 master_flat * master_flat_hifreq = NULL;
163 master_flat * master_flat_lofreq = NULL;
164 mef_extension_list * mefs = NULL;
165 hdrl_image * object_photom = NULL;
166 const cpl_parameter * p = NULL;
167 cpl_table * photom_ref_cat = NULL;
168 cpl_vector * profile = NULL;
169 located_imagelist * raw_sky_jitters = NULL;
170 located_imagelist * raw_jitters = NULL;
171 located_image * sky_stack = NULL;
172 located_image * sky_stack2 = NULL;
173 cpl_polynomial * startrace_poly = NULL;
174 located_image * target_stack = NULL;
175 located_image * target_stack2 = NULL;
176 cpl_frameset * used_frameset = NULL;
177 cpl_polynomial * wave_poly = NULL;
178
179 enu_check_error_code("%s():%d: An error is already set: %s",
180 cpl_func, __LINE__, cpl_error_get_where());
181
182 /* Check input parameters */
183
184 cpl_ensure_code(frameset, CPL_ERROR_NULL_INPUT);
185 cpl_ensure_code(parlist, CPL_ERROR_NULL_INPUT);
186
187 /* Set the msg verbosity level from environment variable CPL_MSG_LEVEL */
188
189 cpl_msg_set_level_from_env();
190 cpl_msg_severity severity = cpl_msg_get_level();
191 cpl_msg_info(cpl_func, "level %d", (int) severity);
192
193 /* Retrieve input parameters */
194
195 p = cpl_parameterlist_find_const(parlist, RECIPE_NAME".debug_data");
196 int debug_data = cpl_parameter_get_bool(p);
197 cpl_msg_info(cpl_func, "debug_data %d", debug_data);
198
199 p = cpl_parameterlist_find_const(parlist, RECIPE_NAME".zero_rejected");
200 int zero_rejected = cpl_parameter_get_bool(p);
201
202 p = cpl_parameterlist_find_const(parlist, RECIPE_NAME".premask_objects");
203 int premask_objects = cpl_parameter_get_bool(p);
204
205 p = cpl_parameterlist_find_const(parlist, RECIPE_NAME".premask_nsigma");
206 double premask_nsigma = cpl_parameter_get_double(p);
207
208 cpl_size x_probe = 1024;
209 cpl_size y_probe = 1024;
210
211 enu_check_error_code("Could not retrieve input parameters");
212
213 /* Identify the RAW and CALIB frames in the input frameset */
214
215 eris_nix_dfs_set_groups(frameset);
216 enu_check_error_code("Could not identify RAW and CALIB frames");
217 used_frameset = cpl_frameset_new();
218
219 /* read the gain and linearity information */
220
221 gain_lin = engl_gain_linearity_load_from_frameset(frameset,
222 ERIS_NIX_GAIN_PRO_CATG, ERIS_NIX_COEFFS_CUBE_PRO_CATG,
223 ERIS_NIX_NL_BPM_PRO_CATG, 0, used_frameset);
224 enu_check_error_code("failed to read gain/linearity information from SoF");
225
226 /* read the master_dark */
227
228 master_dark = en_master_dark_load_from_frameset(frameset,
229 ERIS_NIX_MASTER_DARK_IMG_PRO_CATG, used_frameset);
230 enu_check_error_code("failed to read master dark from SoF");
231
232 /* read the master_bpm */
233
234 master_bpm = en_master_bpm_load_from_frameset(frameset,
235 ERIS_NIX_MASTER_BPM_PRO_CATG,
236 used_frameset);
237 enu_check_error_code("failed to read master BPM from SoF");
238
239 /* read the high-freq flatfield */
240
241 master_flat_hifreq = en_master_flat_load_from_frameset(
242 frameset, ERIS_NIX_MASTER_FLAT_HIFREQ_PRO_CATG,
243 used_frameset, CPL_FALSE);
244
245 /* get the wavelength cal and dispersion direction polynomials */
246 /* p2(x,y) = p0 + p1.x + p2.y + p3.x.y + p4.x^2 + p5.y^2 */
247
248 wave_poly = cpl_polynomial_new(2);
249 cpl_size pows[] = {0, 1};
250 cpl_polynomial_set_coeff(wave_poly, pows, 1.0);
251 cpl_polynomial_dump(wave_poly, stdout);
252
253 startrace_poly = cpl_polynomial_new(2);
254 pows[0] = 1;
255 pows[1] = 0;
256 cpl_polynomial_set_coeff(startrace_poly, pows, 1.0);
257 cpl_polynomial_dump(startrace_poly, stdout);
258
259 /* Read in OBJECT_SPEC_JITTER data */
260
261 raw_jitters = enu_limlist_load_from_frameset(frameset,
262 ERIS_NIX_RAW_OBJECT_LSS_JITTER_DO_CATG, used_frameset);
263 cpl_msg_info(cpl_func, "read %d OBJECT_LSS_JITTER frames",
264 (int) raw_jitters->size);
265
266 /* Do 'detector calibration': dark subtraction, linearize,
267 calculate error plane, flatfield, associate with bpm */
268
269 int flag_mask = ~(int)0;
270 enu_basic_calibrate(raw_jitters, master_dark, gain_lin, master_flat_hifreq,
271 NULL, NULL, flag_mask, zero_rejected, x_probe,
272 y_probe);
273 enu_check_error_code("error performing basic calibration of frames");
274 enu_debug_limlist_save(debug_data, raw_jitters, "target_basic_cal_",
275 RECIPE_NAME, frameset, parlist, used_frameset);
276 cal_jitters1 = enu_located_imagelist_duplicate(raw_jitters);
277
278 /* Use the target calibrated jitters to estimate the sky background.
279
280 This would work for a spread-out jitter pattern. NACO data switches
281 between 2 nod positions on the slit, so a straight median does not
282 work, instead have to mask out the objects first. */
283
284 cpl_msg_info(cpl_func, "Estimating sky background:");
285
286 if (premask_objects) {
287 enu_opm_spectrum_limlist(cal_jitters1, premask_nsigma);
288 }
289 enu_sky_subtract_limlist("median", "bracket", 600.0, cal_jitters1,
290 -1, -1, cal_jitters1);
291 enu_check_error_code("error in sky background first iteration: sky-subtract");
292 cpl_msg_info(cpl_func, "here0 %s", cpl_error_get_message());
293
294 /* in debug mode, save the sky-subtracted images */
295
296 enu_debug_limlist_save(debug_data, cal_jitters1, "target_skysub_1_",
297 RECIPE_NAME, frameset, parlist, used_frameset);
298
299 /* correct the frames for spectral and startrace distortion */
300
301 /* profile is Lanczos2, which works well for images, not sure about
302 spectral direction. ISAAC uses default profile, tanh.
303
304 Also can use different profiles for spatial and spectral, should
305 examine this when we get some real data */
306
307 cpl_msg_info(cpl_func, "here0 %s", cpl_error_get_message());
308 cal_jitters2 = enu_located_imagelist_duplicate(cal_jitters1);
309 cpl_msg_info(cpl_func, "here1 %s", cpl_error_get_message());
310
311 cpl_msg_info(cpl_func, "note: check warping profile when have real data");
312 cpl_msg_info(cpl_func, "here0 %s", cpl_error_get_message());
313 profile = cpl_vector_new(CPL_KERNEL_DEF_SAMPLES);
314 cpl_vector_fill_kernel_profile(profile, CPL_KERNEL_LANCZOS,
315 CPL_KERNEL_DEF_WIDTH);
316 for (cpl_size j = 0; j < cal_jitters2->size; j++) {
317 cpl_msg_info(cpl_func, "here0 %s", cpl_error_get_message());
318 cpl_image_warp_polynomial(hdrl_image_get_image(
319 cal_jitters2->limages[j]->himage),
321 cal_jitters1->limages[j]->himage),
322 startrace_poly, wave_poly,
323 profile, CPL_KERNEL_DEF_WIDTH,
324 profile, CPL_KERNEL_DEF_WIDTH);
325 }
326
327 /* in debug mode, save the distortion corrected images */
328
329 enu_debug_limlist_save(debug_data, cal_jitters2, "target_warp_",
330 RECIPE_NAME, frameset, parlist, used_frameset);
331
332/*
333 enu_stack(cal_jitters2, stk_lthr, stk_hthr, stk_method, stk_fast,
334 &target_stack);
335 enu_check_error_code("error in target reduction: stack");
336 target_stack->objects = enu_catalogue_compute(target_stack->himage,
337 target_stack->confidence,
338 cpl_wcs_new_from_propertylist(
339 target_stack->plist),
340 cat_params);
341 enu_check_error_code("error in target reduction: stack catalogue");
342*/
343 /* cal_jitters2 holds the final calibrated jitter images */
344/*
345 cal_jitters_final = cal_jitters2;
346*/
347 /* save the calibrated jitter images to FITS files */
348/*
349 for (cpl_size i = 0; i < cal_jitters_final->size; i++) {
350*/
351 /* the propertylist to be saved with the calibrated jitter
352 image is that of the raw data - NOT with recalibrated wcs.
353 The wcs calibration is done by whatever task does the
354 stacking into the final image */
355/*
356 cpl_propertylist_delete(cal_jitters_final->limages[i]->plist);
357 cal_jitters_final->limages[i]->plist = cpl_propertylist_duplicate(
358 raw_jitters->limages[i]->plist);
359*/
360/*
361 cpl_msg_info(cpl_func, "using raw plist");
362 const char * tname = cpl_frame_get_filename(cal_jitters_final->
363 limages[i]->frame);
364 cpl_propertylist * out_plist = cpl_propertylist_load(tname, 0);
365*/
366/*
367 cpl_propertylist_append_string(cal_jitters_final->limages[i]->plist,
368 CPL_DFS_PRO_CATG,
369 ERIS_NIX_CALIB_OBJECT_JITTER_PRO_CATG);
370*/
371 /* Add QC parameters */
372/*
373 hdrl_value flat_median = hdrl_image_get_median(master_flat_hifreq);
374 cpl_propertylist_append_double(flat_plist, "ESO QC FLAT MED",
375 (double) flat_median.data);
376 hdrl_value flat_mean = hdrl_image_get_mean(master_flat_hifreq);
377 cpl_propertylist_append_double(flat_plist, "ESO QC FLAT MEAN",
378 (double) flat_mean.data);
379 double flat_rms = hdrl_image_get_stdev(master_flat_hifreq);
380 cpl_propertylist_append_double(flat_plist, "ESO QC FLAT RMS", flat_rms);
381*/
382 /* generate name of output file */
383/*
384 const char * in_fname = cpl_frame_get_filename(cal_jitters_final->
385 limages[i]->frame);
386 char * in_fname_copy = cpl_strdup(in_fname);
387 char * out_fname = cpl_sprintf("calib.%s", basename(in_fname_copy));
388*/
389 /* extension to hold confidence array */
390/*
391 mefs = enu_mef_extension_list_new(1);
392 mefs->mef[0] = enu_mef_new_image("CONFIDENCE",
393 cal_jitters_final->limages[i]->
394 confidence);
395 cpl_msg_info(cpl_func, "..writing %s", out_fname);
396 enu_dfs_save_himage(frameset, parlist, used_frameset,
397 cal_jitters_final->limages[i]->himage,
398 cal_jitters_final->limages[i]->frame,
399 mefs, RECIPE_NAME,
400 cal_jitters_final->limages[i]->plist,
401 PACKAGE "/" PACKAGE_VERSION, out_fname);
402 cpl_free(in_fname_copy);
403 cpl_free(out_fname);
404 }
405*/
406 /* Save the stacked image as an IMG_OBS_COMBINED data product.
407 An attempt is made to erase all no longer relevant keywords
408 from the propertylist, but some ESO ... keywords remain for some
409 unknown reason */
410/*
411 cpl_propertylist * stack_plist = cpl_propertylist_duplicate(
412 target_stack->plist);
413 cpl_propertylist_erase_regexp(stack_plist,
414 "SIMPLE|BITPIX|NAXIS|NAXIS1|NAXIS2|"
415 "EXTEND|DATE|ORIGIN|TELESCOP|"
416 "INSTRUME|OBJECT|RA|DEC|EQUINOX|"
417 "RADECSYS|CTYPE1|CTYPE2|CRVAL1|"
418 "CRVAL2|CRPIX1|CRPIX2|CD1_1|CD1_2|"
419 "CD2_1|CD2_2|CHECKSUM|DATASUM|"
420 "ESO OBS DID", 1);
421 cpl_propertylist_append_string(stack_plist, CPL_DFS_PRO_CATG,
422 ERIS_NIX_IMG_OBS_COMBINED_PRO_CATG);
423*/
424 /* add QC parameters ..tbd */
425/*
426 const char * ob_name = cpl_propertylist_get_string(cal_jitters_final->
427 limages[0]->plist,
428 "ESO OBS START");
429 char * stack_fname = cpl_sprintf("stack_image_%s.fits", ob_name);
430 enu_mef_extension_list_delete(mefs);
431 mefs = enu_mef_extension_list_new(2);
432 mefs->mef[0] = enu_mef_new_image("CONFIDENCE", target_stack->confidence);
433 mefs->mef[1] = enu_mef_new_table("OBJECT_CATALOGUE",
434 target_stack->objects->catalogue);
435 enu_dfs_save_himage(frameset, parlist, used_frameset, target_stack->himage,
436 raw_jitters->limages[0]->frame, mefs, RECIPE_NAME,
437 stack_plist, PACKAGE "/" PACKAGE_VERSION, stack_fname);
438 cpl_free(stack_fname);
439 cpl_propertylist_delete(stack_plist);
440 enu_check_error_code("Failed to save IMG_OBS_COMBINED product");
441*/
442/*
443 cpl_image_save(hdrl_image_get_image(object_photom), "photom_test.fits",
444 CPL_TYPE_UNSPECIFIED, NULL, CPL_IO_CREATE);
445*/
446
447cleanup:
448 cpl_table_delete(astrom_ref_cat);
449 enu_located_imagelist_delete(cal_sky_jitters1);
450 enu_located_imagelist_delete(cal_sky_jitters2);
451 enu_located_imagelist_delete(cal_jitters1);
452 enu_located_imagelist_delete(cal_jitters2);
453 hdrl_parameter_delete(cat_params);
454 engl_gain_linearity_delete((gain_linearity *) gain_lin);
455 en_master_bpm_delete(master_bpm);
456 en_master_dark_delete(master_dark);
457 en_master_flat_delete(master_flat_hifreq);
458 en_master_flat_delete(master_flat_lofreq);
460 hdrl_image_delete(object_photom);
461 cpl_table_delete(photom_ref_cat);
462 cpl_vector_delete(profile);
463 enu_located_imagelist_delete(raw_sky_jitters);
464 enu_located_imagelist_delete(raw_jitters);
465 enu_located_image_delete(sky_stack);
466 enu_located_image_delete(sky_stack2);
467 cpl_polynomial_delete(startrace_poly);
468 enu_located_image_delete(target_stack);
469 enu_located_image_delete(target_stack2);
470 cpl_frameset_delete(used_frameset);
471 cpl_polynomial_delete(wave_poly);
472
473 return (int) cpl_error_get_code();
474}
cpl_error_code eris_nix_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
Definition: eris_nix_dfs.c:58
void en_master_bpm_delete(master_bpm *target)
Delete a 'master_bpm' struct.
master_dark * en_master_dark_load_from_frameset(const cpl_frameset *frameset, const char *tag, cpl_frameset *used)
Load a 'master_dark' struct from a frameset.
void en_master_dark_delete(master_dark *target)
Delete a 'master_dark' struct.
void enu_located_imagelist_delete(located_imagelist *limlist)
Delete a located_imagelist and its contents.
located_imagelist * enu_located_imagelist_duplicate(const located_imagelist *limlist)
Make a deep copy of a located_imagelist and its contents.
cpl_error_code enu_basic_calibrate(located_image *limage, const int read_offsets, const cpl_table *refine_wcs, const master_dark *mdark, const gain_linearity *gain_lin, const master_flat *flatfield_1, const master_flat *flatfield_2, const master_bpm *mbad_pix_map, const int flag_mask, const char *fill_rejected, const double fill_value, const cpl_size x_probe, const cpl_size y_probe)
Do basic calibration of located_image (single or cube)
cpl_error_code enu_sky_subtract_limlist(const char *method, const char *select_method, const double timerange, const located_imagelist *sky_data, const cpl_size x_probe, const cpl_size y_probe, located_imagelist *target_data)
Estimate and subtract sky backgrounds for a list of target images.
cpl_error_code enu_debug_limlist_save(const int debug, const located_imagelist *limlist, const char *nameroot, const char *recipename, cpl_frameset *frameset, const cpl_parameterlist *parlist, const cpl_frameset *used)
Save a list of intermediate image results for use in debugging.
located_imagelist * enu_limlist_load_from_frameset(cpl_frameset *frameset, const char *tag, cpl_frameset *used)
Load tagged data from a frameset into a located_imagelist.
void enu_located_image_delete(located_image *limage)
Delete a located_image and its contents.
void enu_mef_extension_list_delete(mef_extension_list *list)
Delete a mef_extension_list and its contents.
cpl_image * hdrl_image_get_image(hdrl_image *himg)
get data as cpl image
Definition: hdrl_image.c:105
const cpl_image * hdrl_image_get_image_const(const hdrl_image *himg)
get data as cpl image
Definition: hdrl_image.c:118
void hdrl_image_delete(hdrl_image *himg)
delete hdrl_image
Definition: hdrl_image.c:379
void hdrl_parameter_delete(hdrl_parameter *obj)
shallow delete of a parameter