ERIS Pipeline Reference Manual 1.8.15
eris_nix_flat_sky.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 <string.h>
36
37#include "eris_utils.h"
38#include "eris_nix_utils.h"
39#include "eris_pfits.h"
40#include "eris_dfs.h"
41#include "eris_nix_dfs.h"
42#include "eris_nix_master_bpm.h"
43#include "eris_nix_master_dark.h"
44#include "eris_nix_gain_linearity.h"
45#include <hdrl.h>
46
47#include <cpl.h>
48
49/*-----------------------------------------------------------------------------
50 Static variables
51 -----------------------------------------------------------------------------*/
52
53static const char eris_nix_flat_sky_description[] =
54"This recipe reduces either:\n"
55" a set of sky image frames taken at 2 different airmasses to produce\n"
56" "ERIS_NIX_MASTER_FLAT_SKY_HIFREQ_PRO_CATG", "
57ERIS_NIX_MASTER_FLAT_SKY_LOFREQ_PRO_CATG", and\n"
58" "ERIS_NIX_MASTER_BPM_SKY_PRO_CATG" results,\n"
59"or:\n"
60" a set of sky LSS frames taken at 2 different airmasses to produce\n"
61" "ERIS_NIX_MASTER_FLAT_LSS_HIFREQ_PRO_CATG" and "
62ERIS_NIX_MASTER_BPM_LSS_PRO_CATG" results.\n"
63"\n"
64"Input files:\n"
65" The recipe works with a set of sky frames, equal numbers taken at \n"
66" two different airmasses:\n"
67"\n"
68" DO CATG Explanation Req. #Frames\n"
69" ------- ----------- --- -------\n"
70" "ERIS_NIX_RAW_FLAT_SKY_DO_CATG
71 " sky frames Y >2*min-coadds\n"
72" or\n"
73" "ERIS_NIX_RAW_FLAT_SKY_LSS_DO_CATG
74 " sky LSS frames Y >2*min-coadds\n"
75" "ERIS_NIX_MASTER_DARK_IMG_PRO_CATG
76 " a MASTER_DARK with Y 1\n"
77" matching detector \n"
78" configuration\n"
79" "ERIS_NIX_GAIN_PRO_CATG
80 " DETMON gain N 0 or 1\n"
81" information e.g. in\n"
82" file \n"
83" detmon_ir_lg_gain_table.fits\n"
84" "ERIS_NIX_COEFFS_CUBE_PRO_CATG
85 " DETMON linearity N 0 or 1\n"
86" curves e.g. in file \n"
87" detmon_ir_coeffs_cube.fits\n"
88" "ERIS_NIX_NL_BPM_PRO_CATG
89 " DETMON non-linear N 0 or 1\n"
90" bpm e.g. in file \n"
91" detmon_ir_lg_bpm.fits\n"
92"\n"
93"Output files:\n"
94"\n"
95" DO CATG Explanation \n"
96" ------- ----------- \n"
97" "ERIS_NIX_MASTER_FLAT_SKY_HIFREQ_PRO_CATG
98 " The required sky HIFREQ flatfield.\n"
99" "ERIS_NIX_MASTER_FLAT_SKY_LOFREQ_PRO_CATG
100 " For imaging data only, the\n"
101" required sky LOFREQ flatfield.\n"
102"\n"
103" "ERIS_NIX_MASTER_BPM_SKY_PRO_CATG
104 " The required sky master BPM.\n"
105"\n"
106" The HIFREQ output will be a FITS file named \n"
107" 'master_flat_hifreq.fits', with extensions:\n"
108" - DATA, with the flatfield data.\n"
109" - ERR, with the flatfield error plane.\n"
110" - DQ, with the flatfield data quality plane.\n"
111" - COLD_BPM, with a bpm for the 'cold' pixels.\n"
112" - CONFIDENCE, with the flatfield confidence plane.\n"
113"\n"
114" The LOFREQ output will be a FITS file named \n"
115" 'master_flat_lofreq.fits', with extensions:\n"
116" - DATA, with the flatfield data.\n"
117" - ERR, with the flatfield error plane.\n"
118" - DQ, with the flatfield data quality plane.\n"
119" - CONFIDENCE, with the flatfield confidence plane.\n"
120"\n"
121" The master BPM output will be a FITS file named \n"
122" 'master_bpm.fits'. Common pixel values are:\n"
123" - 512, 'hot' pixel.\n"
124" - 1024, 'cold' pixel.\n"
125" - 32768, 'non-linear' pixel.\n"
126"\n";
127
128#define RECIPE_NAME "eris.eris_nix_flat_sky"
129#define CONTEXT "eris."RECIPE_NAME
130/*-----------------------------------------------------------------------------
131 Private function prototypes
132 -----------------------------------------------------------------------------*/
133
134cpl_recipe_define(eris_nix_flat_sky, ERIS_BINARY_VERSION, "John Lightfoot",
135 PACKAGE_BUGREPORT, "2017",
136 "Calculate a MASTER_FLAT_SKY_HIFREQ/LOFREQ and "
137 "MASTER_SKY_BPM", eris_nix_flat_sky_description);
138
139/*-----------------------------------------------------------------------------
140 Function code
141 -----------------------------------------------------------------------------*/
142
143/*----------------------------------------------------------------------------*/
151/*----------------------------------------------------------------------------*/
152
153static cpl_error_code eris_nix_flat_sky_fill_parameterlist(
154 cpl_parameterlist *self) {
155
156 if (cpl_error_get_code() != CPL_ERROR_NONE) return cpl_error_get_code();
157
158 cpl_parameterlist * bpm_parlist = NULL;
159 cpl_parameterlist * collapse_parlist = NULL;
160 hdrl_parameter * filter_defaults = NULL;
161 hdrl_parameter * flat_defaults = NULL;
162 cpl_parameterlist * flat_parlist = NULL;
163 hdrl_parameter * legendre_defaults = NULL;
164 hdrl_parameter * minmax_defaults = NULL;
165 hdrl_parameter * sigclip_defaults = NULL;
166
167 /* generate the general parameter list for the collapse */
168 hdrl_parameter * mode_def =
169 hdrl_collapse_mode_parameter_create(10., 1., 0., HDRL_MODE_MEDIAN, 0);
170 sigclip_defaults = hdrl_collapse_sigclip_parameter_create(10.0, 10.0, 3);
171 minmax_defaults = hdrl_collapse_minmax_parameter_create(50, 50);
172 collapse_parlist = hdrl_collapse_parameter_create_parlist(RECIPE_NAME,
173 "collapse", "MEDIAN", sigclip_defaults,
174 minmax_defaults, mode_def);
175
176 /* add the subset of parameters to be used, i.e. leave out 'minmax' */
177
178 for (const cpl_parameter * p =
179 cpl_parameterlist_get_first_const(collapse_parlist);
180 p != NULL;
181 p = cpl_parameterlist_get_next_const(collapse_parlist)) {
182
183 const char * pname = cpl_parameter_get_name(p);
184 if (strstr(pname, "minmax") == NULL) {
185 cpl_parameter * duplicate = cpl_parameter_duplicate(p);
186 cpl_parameterlist_append(self, duplicate);
187 }
188 }
189
190 /* generate the general parameter list for the flat-field calculation */
191
192 flat_defaults = hdrl_flat_parameter_create(21, 21, HDRL_FLAT_FREQ_HIGH);
193 flat_parlist = hdrl_flat_parameter_create_parlist(RECIPE_NAME, "flat",
194 flat_defaults);
195
196 for (const cpl_parameter * p =
197 cpl_parameterlist_get_first(flat_parlist);
198 p != NULL;
199 p = cpl_parameterlist_get_next(flat_parlist)) {
200 cpl_parameter * duplicate = cpl_parameter_duplicate(p);
201 cpl_parameterlist_append(self, duplicate);
202 }
203
204 /* Get the general parameter list for the cold-pixel bpm */
205
206 filter_defaults = hdrl_bpm_2d_parameter_create_filtersmooth(5.0, 20.0, 3,
207 CPL_FILTER_MEDIAN, CPL_BORDER_NOP, 21, 21);
208 legendre_defaults = hdrl_bpm_2d_parameter_create_legendresmooth(4, 5, 6,
209 20, 21, 11, 12, 2, 10);
210 bpm_parlist = hdrl_bpm_2d_parameter_create_parlist(RECIPE_NAME, "coldpix",
211 "FILTER", filter_defaults, legendre_defaults);
212
213 for (const cpl_parameter * p =
214 cpl_parameterlist_get_first_const(bpm_parlist);
215 p != NULL;
216 p = cpl_parameterlist_get_next_const(bpm_parlist)) {
217 cpl_parameter * duplicate = cpl_parameter_duplicate(p);
218 cpl_parameterlist_append(self, duplicate);
219 }
220
221 /* the minimum number of lamp_on - lamp_off images acceptable for the
222 calculation of the flat */
223
224 cpl_parameter * cp = NULL;
225 cp = cpl_parameter_new_value(RECIPE_NAME".min_coadds", CPL_TYPE_INT,
226 "minimum acceptable number of (lamp_on - "
227 "lamp_off) images", RECIPE_NAME, 1);
228 cpl_parameter_set_alias(cp, CPL_PARAMETER_MODE_CLI, "min-coadds");
229 cpl_parameter_disable(cp, CPL_PARAMETER_MODE_ENV);
230 cpl_parameterlist_append(self, cp);
231
232 /* coords of pixel whose value to be used for diagnostics during
233 reduction */
234
235 cp = cpl_parameter_new_value(RECIPE_NAME".x_probe", CPL_TYPE_INT,
236 "x coord of diagnostic pixel",
237 RECIPE_NAME, -1);
238 cpl_parameter_set_alias(cp, CPL_PARAMETER_MODE_CLI, "x-probe");
239 cpl_parameter_disable(cp, CPL_PARAMETER_MODE_ENV);
240 cpl_parameterlist_append(self, cp);
241
242 cp = cpl_parameter_new_value(RECIPE_NAME".y_probe", CPL_TYPE_INT,
243 "y coord of diagnostic pixel",
244 RECIPE_NAME, -1);
245 cpl_parameter_set_alias(cp, CPL_PARAMETER_MODE_CLI, "y-probe");
246 cpl_parameter_disable(cp, CPL_PARAMETER_MODE_ENV);
247 cpl_parameterlist_append(self, cp);
248
249
250
251 cp = cpl_parameter_new_value(CONTEXT".threshold", CPL_TYPE_DOUBLE,
252 "positive saturation level (for QC)",
253 CONTEXT, 60000.);
254 cpl_parameter_set_alias(cp, CPL_PARAMETER_MODE_CLI, "threshold");
255 cpl_parameter_disable(cp, CPL_PARAMETER_MODE_ENV);
256 cpl_parameterlist_append(self, cp);
257
258 cp = cpl_parameter_new_value(CONTEXT".saturation_neg", CPL_TYPE_DOUBLE,
259 "negative saturation level (for QC)", CONTEXT, -4.5e7);
260 cpl_parameter_set_alias(cp, CPL_PARAMETER_MODE_CLI, "saturation_neg");
261 cpl_parameter_disable(cp, CPL_PARAMETER_MODE_ENV);
262 cpl_parameterlist_append(self, cp);
263
264 /* cleanup */
265
266 cpl_parameterlist_delete(bpm_parlist);
267 cpl_parameterlist_delete(collapse_parlist);
268 hdrl_parameter_delete(filter_defaults);
269 hdrl_parameter_delete(flat_defaults);
270 cpl_parameterlist_delete(flat_parlist);
271 hdrl_parameter_delete(legendre_defaults);
272 hdrl_parameter_delete(minmax_defaults);
273 hdrl_parameter_delete(sigclip_defaults);
274 hdrl_parameter_delete(mode_def);
275 return 0;
276}
277/*----------------------------------------------------------------------------*/
291/*----------------------------------------------------------------------------*/
292static hdrl_value hdrl_get_airmass_young(hdrl_value hvaCosZt)
293{
294 double aCosZt = hvaCosZt.data,
295 aCosZtErr = hvaCosZt.error;
296
297 hdrl_value airmass = {(1.002432 * aCosZt * aCosZt + 0.148386 * aCosZt + 0.0096467)
298 / (aCosZt * aCosZt * aCosZt + 0.149864 * aCosZt * aCosZt + 0.0102963 * aCosZt
299 + 0.000303978),
300 aCosZtErr * fabs( ( (2. * 1.002432 * aCosZt + 0.148386) * (aCosZt * aCosZt * aCosZt + 0.149864 * aCosZt * aCosZt + 0.0102963 * aCosZt + 0.000303978)
301 - (3. * aCosZt * aCosZt + 2. * 0.149864 * aCosZt + 0.0102963) * (1.002432 * aCosZt * aCosZt + 0.148386 * aCosZt + 0.0096467)
302 ) / pow(aCosZt * aCosZt * aCosZt + 0.149864 * aCosZt * aCosZt + 0.0102963 * aCosZt + 0.000303978, 2) )};
303
304 return airmass;
305}
306
307
308
309/*----------------------------------------------------------------------------*/
321/*----------------------------------------------------------------------------*/
322
323static cpl_error_code eris_nix_flat_sky_bin_by_airmass(
324 cpl_frameset * frameset,
325 const int min_coadds,
326 cpl_frameset * used,
327 located_imagelist ** low_z_limlist,
328 located_imagelist ** high_z_limlist,
329 int * lss) {
330
331 if (cpl_error_get_code() != CPL_ERROR_NONE) return cpl_error_get_code();
332
333 cpl_ensure_code(frameset, CPL_ERROR_NULL_INPUT);
334 cpl_ensure_code(used, CPL_ERROR_NULL_INPUT);
335
336 cpl_vector * airmass = NULL;
337 cpl_vector * high_z_list = NULL;
338 cpl_vector * low_z_list = NULL;
339 located_imagelist * sky_limlist = NULL;
340 located_imagelist * sky_lss_limlist = NULL;
341
342 /* read in the sky data */
343
344 sky_limlist = enu_limlist_load_from_frameset(frameset,
345 ERIS_NIX_RAW_FLAT_SKY_DO_CATG, used);
346 sky_lss_limlist = enu_limlist_load_from_frameset(frameset,
347 ERIS_NIX_RAW_FLAT_SKY_LSS_DO_CATG, used);
348 enu_check_error_code("Failed to read sky data from frameset");
349
350 cpl_msg_info(cpl_func, "%d SKY frames read",
351 (int) sky_limlist->size);
352 cpl_msg_info(cpl_func, "%d SKY LSS frames read",
353 (int) sky_lss_limlist->size);
354
355 /* is this imaging or LSS data */
356
357 enu_check(!((sky_limlist->size > 0) && (sky_lss_limlist->size > 0)),
358 CPL_ERROR_ILLEGAL_INPUT, "cannot combine imaging and LSS data");
359 enu_check(!((sky_limlist->size == 0) && (sky_lss_limlist->size == 0)),
360 CPL_ERROR_ILLEGAL_INPUT, "no sky flat data found");
361
362 *lss = CPL_FALSE;
363 if (sky_lss_limlist->size > 0) {
364 *lss = CPL_TRUE;
365 enu_located_imagelist_delete(sky_limlist);
366 sky_limlist = sky_lss_limlist;
367 sky_lss_limlist = NULL;
368 }
369
370 /* get the airmass of each frame, stored in different places for
371 NIX and NACO */
372
373 airmass = cpl_vector_new(sky_limlist->size);
374 for (cpl_size i = 0; i < sky_limlist->size; i++) {
375 double air =0;
376 /*
377 air = enu_get_airmass(sky_limlist->limages[i]->plist);
378 // Alternative way to compute airmass using HDRL and FITS header info:
379 * method 1:
380 double dRA = cpl_propertylist_get_double(sky_limlist->limages[i]->plist, "RA");
381 double dDEC = cpl_propertylist_get_double(sky_limlist->limages[i]->plist, "DEC");
382 double dLST = cpl_propertylist_get_double(sky_limlist->limages[i]->plist, "LST");
383 double exptime = cpl_propertylist_get_double(sky_limlist->limages[i]->plist, "EXPTIME");
384 double geolat = cpl_propertylist_get_double(sky_limlist->limages[i]->plist, "ESO TEL GEOLAT");
385 //168.839579 -29.50799 34614.068 -24.627
386 //dRA=168.839579;
387 //dDEC=-29.50799;
388 //dLST=34614.068;
389 //geolat=-24.627;
390 //hdrl_airmass_approx type = HDRL_AIRMASS_APPROX_YOUNG;
391 hdrl_airmass_approx type = HDRL_AIRMASS_APPROX_HARDIE;
392 cpl_msg_info(cpl_func,"ra: %g dec: %g lst: %g exptime: %g geolat: %g",
393 dRA, dDEC, dLST, exptime, geolat);
394
395 double rel_err = 0.01;
396 hdrl_value hva_ra = {dRA, fabs(dRA * rel_err)};
397 hdrl_value hva_dec = {dDEC, fabs(dDEC * rel_err)};
398 hdrl_value hva_lst = {dLST, fabs(dLST * rel_err)};
399 hdrl_value hva_exptime = {exptime, fabs(exptime * rel_err)};
400 hdrl_value hva_geolat = {geolat, fabs(geolat * rel_err)};
401 hdrl_value hva_airmass = hdrl_utils_airmass(hva_ra, hva_dec, hva_lst,
402 hva_exptime, hva_geolat, type);
403 eris_print_rec_status(0);
404 air = hva_airmass.data;
405 END Method 1*/
406 /* Method 2, using HDRL
407 // Compute hour angle of the observation in degrees.
408 hdrl_value HA = {hva_ra.data * 15. / 3600. - hva_ra.data,
409 hva_lst.error * fabs(15. / 3600.) + hva_ra.error * fabs(-1.)};
410
411 // Range adjustments.Angle between line of sight and meridian is needed.
412 if (HA.data < -180.) HA.data += 360.;
413 if (HA.data > 180.) HA.data -= 360.;
414
415 // Convert angles from degrees to radians.
416
417 hdrl_value delta = {hva_dec.data * CPL_MATH_RAD_DEG,
418 hva_dec.error * fabs(CPL_MATH_RAD_DEG)};
419
420 hdrl_value latitude = {hva_geolat.data * CPL_MATH_RAD_DEG,
421 hva_geolat.error * fabs(CPL_MATH_RAD_DEG)};
422
423 hdrl_value hourangle = {HA.data * CPL_MATH_RAD_DEG,
424 HA.error * fabs(CPL_MATH_RAD_DEG)};
425
426 cpl_msg_warning(cpl_func,"delta: %g", delta.data);
427 cpl_msg_warning(cpl_func,"latitude: %g", latitude.data);
428 cpl_msg_warning(cpl_func,"hourangle: %g", hourangle.data);
429
430 END Method 2*/
431 /* Method 3:
432 * Calculate airmass of the observation using the approximation given *
433 * by Young (1994). For non-zero exposure times these airmass values are *
434 * averaged using the weights given by Stetson. */
435
436
437 /*
438 hdrl_value cosz = hdrl_get_zenith_distance(hourangle, delta, latitude);
439 hdrl_value z = {0., cosz.error};
440 double zlimit = 80.;
441
442 cpl_msg_info(cpl_func,"cosz: %g",cosz.data);
443 */
444 /* TODO: TEMPORARY SOLUTION. As previous methods still have problems
445 * in determining proper value of airmass and the the algorithm below
446 * is only used to separate frames in groups of same airmass (equivalent
447 * to groups of same tel.alt we use the next method 4, the simplest one
448 * even if also this is not accurate.
449 */
450 double tel_alt = enu_get_tel_alt(sky_limlist->limages[i]->plist);
451 double zenith_dist = 90.0 - tel_alt;
452 hdrl_value hvaCosZt = {cos(zenith_dist), 0};
453 hdrl_value hva_airm = hdrl_get_airmass_young(hvaCosZt);
454 //cpl_msg_info(cpl_func,"air1: %g",hva_airm.data);
455 air = hva_airm.data;
456 //cpl_msg_info(cpl_func,"airmass: %g",air);
457
458
459 cpl_vector_set(airmass, i, air);
460 }
461
462 /* assign frames to high and low airmass bins */
463
464 double max_z = cpl_vector_get_max(airmass);
465 double min_z = cpl_vector_get_min(airmass);
466 low_z_list = cpl_vector_new(sky_limlist->size);
467 cpl_vector_fill(low_z_list, -1.0);
468 cpl_size ilow = 0;
469 high_z_list = cpl_vector_new(sky_limlist->size);
470 cpl_vector_fill(high_z_list, -1.0);
471 cpl_size ihigh = 0;
472
473 for (cpl_size i = 0; i < cpl_vector_get_size(airmass); i++) {
474 if (fabs(cpl_vector_get(airmass, i) - min_z) < 0.1) {
475 cpl_vector_set(low_z_list, ilow, i);
476 ilow++;
477 } else if (fabs(cpl_vector_get(airmass, i) - max_z) < 0.1) {
478 cpl_vector_set(high_z_list, ihigh, i);
479 ihigh++;
480 }
481 }
482
483 cpl_msg_info(cpl_func, "Found %d frames at high airmass", (int)ihigh);
484 cpl_msg_info(cpl_func, "Found %d frames at low airmass", (int)ilow);
485
486 /* check bins are filled as we expect, half of frames in each */
487
488 enu_check(ilow >= min_coadds, CPL_ERROR_ILLEGAL_INPUT,
489 "SoF contains insufficient sky frames at lower airmass "
490 "%d < %d", (int) ilow, min_coadds);
491 enu_check(ilow == ihigh, CPL_ERROR_ILLEGAL_INPUT,
492 "SoF contains unequal numbers of high / low airmass frames "
493 "%d != %d", (int) ihigh, (int) ilow);
494
495 /* fill lists with the high and low z frames */
496
497 *low_z_limlist = enu_located_imagelist_new(ihigh);
498 for (cpl_size i = 0; i < ilow; i++) {
499 enu_located_imagelist_insert(*low_z_limlist,
501 sky_limlist->limages[(int)
502 cpl_vector_get(low_z_list, i)]), i);
503 }
504
505 *high_z_limlist = enu_located_imagelist_new(ilow);
506 for (cpl_size i = 0; i < ihigh; i++) {
507 enu_located_imagelist_insert(*high_z_limlist,
509 sky_limlist->limages[(int)
510 cpl_vector_get(high_z_list, i)]), i);
511 }
512
513cleanup:
514 cpl_vector_delete(airmass);
515 cpl_vector_delete(high_z_list);
516 cpl_vector_delete(low_z_list);
517 enu_located_imagelist_delete(sky_limlist);
518 enu_located_imagelist_delete(sky_lss_limlist);
519
520 if (cpl_error_get_code() != CPL_ERROR_NONE) {
521 enu_located_imagelist_delete(*high_z_limlist);
522 *high_z_limlist = NULL;
523 enu_located_imagelist_delete(*low_z_limlist);
524 *low_z_limlist = NULL;
525 }
526
527 return cpl_error_get_code();
528}
529
530
531/*----------------------------------------------------------------------------*/
542/*----------------------------------------------------------------------------*/
543
544static hdrl_imagelist * eris_nix_reduce_sky(located_imagelist * high_z_limlist,
545 located_imagelist * low_z_limlist,
546 const master_dark * mdark,
547 const gain_linearity * gain_lin,
548 const cpl_size x_probe,
549 const cpl_size y_probe) {
550
551
552 hdrl_imagelist * result = NULL;
553 cpl_ensure(high_z_limlist, CPL_ERROR_NULL_INPUT, NULL);
554 cpl_ensure(low_z_limlist, CPL_ERROR_NULL_INPUT, NULL);
555 cpl_ensure(mdark, CPL_ERROR_NULL_INPUT, NULL);
556
557 enu_check(high_z_limlist->size == low_z_limlist->size,
558 CPL_ERROR_INCOMPATIBLE_INPUT,
559 "different number of high z and low z frames");
560
561 result = hdrl_imagelist_new();
562
563/*
564 const int debug = x_probe > 0 &&
565 x_probe <= hdrl_image_get_size_x(
566 high_z_limlist->limages[0]->himage) &&
567 y_probe > 0 &&
568 y_probe <= hdrl_image_get_size_y(
569 high_z_limlist->limages[0]->himage);
570*/
571
572
573
574 for (int i = 0; i < high_z_limlist->size; i++) {
575
576 /* do basic calibration: linearize, calculate error plane */
577
578 enu_basic_calibrate(high_z_limlist->limages[i],
579 CPL_TRUE,
580 NULL,
581 mdark,
582 gain_lin,
583 NULL,
584 NULL,
585 NULL,
586 0,
587 "noop",
588 0.0,
589 x_probe,
590 y_probe);
591 enu_basic_calibrate(low_z_limlist->limages[i],
592 CPL_TRUE,
593 NULL,
594 mdark,
595 gain_lin,
596 NULL,
597 NULL,
598 NULL,
599 0,
600 "noop",
601 0.0,
602 x_probe,
603 y_probe);
604 enu_check_error_code("error performing basic calibration of sky "
605 "frames");
606
607 /* difference the high and low airmass images */
608
609 hdrl_image_sub_image(high_z_limlist->limages[i]->himage,
610 low_z_limlist->limages[i]->himage);
611 hdrl_imagelist_set(result,
613 high_z_limlist->limages[i]->himage),
615 }
616
617 cleanup:
618 if (cpl_error_get_code() != CPL_ERROR_NONE) {
619 if(result != NULL) {
620 hdrl_imagelist_delete(result);
621 result = NULL;
622 }
623 }
624 return result;
625}
626
627
628/*----------------------------------------------------------------------------*/
635/*----------------------------------------------------------------------------*/
636
637static int eris_nix_flat_sky(cpl_frameset * frameset,
638 const cpl_parameterlist * parlist) {
639 cpl_mask * bpm_mask = NULL;
640 hdrl_parameter * bpm_params = NULL;
641 cpl_propertylist * bpm_plist = NULL;
642 cpl_mask * cold_bpm = NULL;
643 hdrl_parameter * collapse_params = NULL;
644 cpl_image * confidence_hi = NULL;
645 cpl_image * confidence_lo = NULL;
646 hdrl_parameter * flat_params = NULL;
647 cpl_propertylist * flat_plist = NULL;
648 const gain_linearity * gain_lin = NULL;
649 located_imagelist * high_z_limlist = NULL;
650 located_imagelist * low_z_limlist = NULL;
651 master_bpm * mbad_pix_map = NULL;
652 master_dark * mdark = NULL;
653 hdrl_image * master_flat_hifreq = NULL;
654 hdrl_image * master_flat_lofreq = NULL;
655 const cpl_parameter * param = NULL;
656 hdrl_imagelist * sky_reduced_data = NULL;
657 cpl_frameset * used = NULL;
658
659 enu_check_error_code("%s():%d: An error is already set: %s",
660 cpl_func, __LINE__, cpl_error_get_where());
661
662 /* check input parameters */
663
664 cpl_ensure_code(frameset, CPL_ERROR_NULL_INPUT);
665 cpl_ensure_code(parlist, CPL_ERROR_NULL_INPUT);
666
667 /* set the msg verbosity level from environment variable CPL_MSG_LEVEL */
668
669 cpl_msg_set_level_from_env();
670 cpl_msg_severity severity = cpl_msg_get_level();
671 cpl_msg_info(cpl_func, "level %d", (int) severity);
672
673 /* check required input tags are present */
674 const int ntags = 5;
675 const char* required_tags[5] = {
676 ERIS_NIX_RAW_FLAT_SKY_DO_CATG,
677 ERIS_NIX_NL_BPM_PRO_CATG,
678 ERIS_NIX_COEFFS_CUBE_PRO_CATG,
679 ERIS_NIX_GAIN_PRO_CATG,
680 ERIS_NIX_MASTER_DARK_IMG_PRO_CATG
681 };
682 cpl_ensure_code(CPL_ERROR_NONE ==
683 eris_dfs_check_input_tags(frameset, required_tags, ntags, 1),
684 CPL_ERROR_ILLEGAL_INPUT);
685 /* retrieve input parameters for collapse */
686
687 collapse_params = hdrl_collapse_parameter_parse_parlist(parlist,
688 RECIPE_NAME".collapse");
689
690 /* retrieve input filter parameters for HI and LO flat-field */
691
692 flat_params = hdrl_flat_parameter_parse_parlist(parlist,
693 RECIPE_NAME".flat");
694 cpl_size filter_size_x = hdrl_flat_parameter_get_filter_size_x(
695 flat_params);
696 cpl_size filter_size_y = hdrl_flat_parameter_get_filter_size_y(
697 flat_params);
698
699 /* retrieve input parameters for 'cold-pixel' bpm */
700
701 bpm_params = hdrl_bpm_2d_parameter_parse_parlist(parlist,
702 RECIPE_NAME".coldpix");
703
704 /* retrieve minimum acceptable number of coadds */
705
706 param = cpl_parameterlist_find_const(parlist, RECIPE_NAME".min_coadds");
707 int min_coadds = cpl_parameter_get_int(param);
708
709 /* retrieve probe pixel coords */
710
711 param = cpl_parameterlist_find_const(parlist, RECIPE_NAME".x_probe");
712 cpl_size x_probe = (cpl_size) cpl_parameter_get_int(param);
713 param = cpl_parameterlist_find_const(parlist, RECIPE_NAME".y_probe");
714 cpl_size y_probe = (cpl_size) cpl_parameter_get_int(param);
715
716 enu_check_error_code("Could not retrieve input parameters");
717
718 /* identify the RAW and CALIB frames in the input frameset */
719
720 eris_nix_dfs_set_groups(frameset);
721 enu_check_error_code("Could not identify RAW and CALIB frames");
722
723 used = cpl_frameset_new();
724
725 /* read the gain and linearity information, if available */
726
727 int required = CPL_FALSE;
728 gain_lin = engl_gain_linearity_load_from_frameset(frameset,
729 ERIS_NIX_GAIN_PRO_CATG, ERIS_NIX_COEFFS_CUBE_PRO_CATG,
730 ERIS_NIX_NL_BPM_PRO_CATG, required, used);
731 enu_check_error_code("failed to read gain/linearity information from SoF");
732
733 /* read the mdark */
734
735 mdark = en_master_dark_load_from_frameset(frameset,
736 ERIS_NIX_MASTER_DARK_IMG_PRO_CATG, used);
737 enu_check_error_code("failed to read master dark from SoF");
738
739 /* read the SoF sky data into high and low airmass bins */
740
741 int lss = CPL_FALSE;
742 eris_nix_flat_sky_bin_by_airmass(frameset,
743 min_coadds,
744 used,
745 &low_z_limlist,
746 &high_z_limlist,
747 &lss);
748
749 /* reduce raw data to get input to flatfield calculation */
750
751 sky_reduced_data = eris_nix_reduce_sky(high_z_limlist,
752 low_z_limlist,
753 mdark,
754 gain_lin,
755 x_probe,
756 y_probe);
757
758 /* get the HI freq flatfield */
759
760 for (cpl_size i = 0; i < hdrl_imagelist_get_size(sky_reduced_data); i++) {
761 char * fname = cpl_sprintf("sky%d.fits", (int)i);
762 cpl_mask_save(cpl_image_get_bpm(hdrl_image_get_image(hdrl_imagelist_get(sky_reduced_data, i))),
763 fname, NULL, CPL_IO_CREATE);
764 cpl_free(fname);
765 }
766
767
768 master_flat_hifreq = enu_calc_flat(sky_reduced_data,
769 min_coadds,
770 collapse_params,
771 filter_size_x,
772 filter_size_y,
773 HDRL_FLAT_FREQ_HIGH);
774 enu_check_error_code("error computing hi-freq flatfield");
775
776 /* compute the 'cold-pixel' BPM, the output will not include
777 pixels already set bad in the input image */
778
779 cpl_image_save(hdrl_image_get_image(master_flat_hifreq), "hifreq.fits",
780 CPL_TYPE_UNSPECIFIED, NULL, CPL_IO_CREATE);
781 cpl_image_save(hdrl_image_get_error(master_flat_hifreq), "hifreq_error.fits",
782 CPL_TYPE_UNSPECIFIED, NULL, CPL_IO_CREATE);
783
784 cold_bpm = hdrl_bpm_2d_compute(master_flat_hifreq, bpm_params);
785 enu_check_error_code("error computing cold-pixel bpm");
786
787 /* construct the MASTER_BPM */
788
789 mbad_pix_map = en_master_bpm_create("eris_nix_flat_sky", cold_bpm,
790 BPM_DARK, NULL);
791 en_master_bpm_set(mbad_pix_map, mdark->hot_bpm, BPM_HOT);
792 if (gain_lin) {
793 en_master_bpm_set(mbad_pix_map, gain_lin->bpm, BPM_NON_LINEAR);
794 }
795
796 /* create a bpm mask, find how many bad pixels overall */
797 //bpm_plist = cpl_propertylist_new();
798 //eris_nix_get_badpix_qc_from_ima(mbad_pix_map, bpm_plist, "FLATSKY");
799
800 int flag_mask = 0;
801 flag_mask = ~flag_mask;
802 bpm_mask = en_master_bpm_get_mask(mbad_pix_map, flag_mask);
803 bpm_plist = cpl_propertylist_new();
804 int nbad = cpl_mask_count(bpm_mask);
805 cpl_propertylist_append_int(bpm_plist, "ESO QC NUMBER BAD PIXELS", nbad);
806 cpl_size sx = cpl_mask_get_size_x(bpm_mask);
807 cpl_size sy = cpl_mask_get_size_y(bpm_mask);
808 double fraction = (double) nbad / (sx * sy);
809 cpl_propertylist_append_double(bpm_plist, "ESO QC FRACTION BAD PIXELS",fraction);
810 /* and save it */
811
812 enu_dfs_save_bpm(ERIS_NIX_MASTER_BPM_SKY_PRO_CATG,
813 frameset, parlist, used, mbad_pix_map,
814 RECIPE_NAME, bpm_plist, PACKAGE "/" PACKAGE_VERSION,
815 "master_bpm.fits");
816 enu_check_error_code("Failed to save MASTER_BPM");
817
818 /* create a HIFREQ confidence array, essentially the flat field with
819 bad pixels set to 0 and median pixel value normalised to 100 */
820
821 confidence_hi = cpl_image_duplicate(hdrl_image_get_image_const(
822 master_flat_hifreq));
823 cpl_image_fill_rejected(confidence_hi, 0.0);
824 cpl_image_accept_all(confidence_hi);
825 enu_normalise_confidence(confidence_hi);
826 enu_check_error_code("error computing HIFREQ confidence map");
827
828 /* now save the HIFREQ flat */
829
830 enu_flat_save(ERIS_NIX_MASTER_FLAT_SKY_HIFREQ_PRO_CATG,
831 master_flat_hifreq,
832 confidence_hi,
833 cold_bpm,
834 frameset,
835 parlist,
836 "master_flat_hifreq.fits",
837 RECIPE_NAME, NULL);
838 enu_check_error_code("Failed to save HIFREQ flat");
839
840 if (!lss) {
841
842 /* similar for LOFREQ flat */
843
844 /* except reject pixels flagged by the master bpm first */
845
846 for (cpl_size i = 0; i < hdrl_imagelist_get_size(sky_reduced_data);
847 i++) {
848 cpl_mask * current_mask = hdrl_image_get_mask(
849 hdrl_imagelist_get(sky_reduced_data, i));
850 cpl_mask_or(current_mask, bpm_mask);
851 }
852
853 /* get the LO freq flatfield */
854
855 master_flat_lofreq = enu_calc_flat(sky_reduced_data,
856 min_coadds,
857 collapse_params,
858 filter_size_x,
859 filter_size_y,
860 HDRL_FLAT_FREQ_LOW);
861
862 confidence_lo = cpl_image_duplicate(hdrl_image_get_image_const(
863 master_flat_lofreq));
864 cpl_image_fill_rejected(confidence_lo, 0.0);
865 cpl_image_accept_all(confidence_lo);
866 enu_normalise_confidence(confidence_lo);
867 enu_check_error_code("error computing LOFREQ confidence map");
868
869 /* QC on FLAT_ON frames not using information from pixels of mbad_pix_map */
870 const char* saturation_limit = cpl_propertylist_get_string(gain_lin->plist,
871 "ESO PRO REC1 PARAM25 VALUE");
872 double saturation = atof(saturation_limit);
873
874 located_imagelist * sky_limlist = enu_limlist_load_from_frameset(frameset,
875 ERIS_NIX_RAW_FLAT_SKY_DO_CATG, used);
876
877
878 cpl_propertylist* qclog = enu_raw_flats_qc(sky_limlist, gain_lin->bpm,
879 parlist, CONTEXT, saturation, CPL_FALSE, CPL_FALSE);
880 enu_located_imagelist_delete(sky_limlist);
881
882
883 enu_flat_save(ERIS_NIX_MASTER_FLAT_SKY_LOFREQ_PRO_CATG,
884 master_flat_lofreq,
885 confidence_lo,
886 NULL,
887 frameset,
888 parlist,
889 "master_flat_lofreq.fits",
890 RECIPE_NAME, qclog);
891 cpl_propertylist_delete(qclog);
892
893
894 enu_check_error_code("Failed to save LOFREQ flat");
895
896 }
897
898cleanup:
899 cpl_mask_delete(bpm_mask);
900 cpl_propertylist_delete(bpm_plist);
901 hdrl_parameter_delete(bpm_params);
902 cpl_mask_delete(cold_bpm);
903 hdrl_parameter_delete(collapse_params);
904 cpl_image_delete(confidence_hi);
905 cpl_image_delete(confidence_lo);
906 hdrl_parameter_delete(flat_params);
907 cpl_propertylist_delete(flat_plist);
908 engl_gain_linearity_delete((gain_linearity *) gain_lin);
909 enu_located_imagelist_delete(high_z_limlist);
910 enu_located_imagelist_delete(low_z_limlist);
911 en_master_bpm_delete(mbad_pix_map);
913 hdrl_image_delete(master_flat_hifreq);
914 hdrl_image_delete(master_flat_lofreq);
915 hdrl_imagelist_delete(sky_reduced_data);
916 cpl_frameset_delete(used);
917
918 return (int)cpl_error_get_code();
919}
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
cpl_error_code enu_dfs_save_bpm(const char *procat, cpl_frameset *allframes, const cpl_parameterlist *parlist, const cpl_frameset *usedframes, const master_bpm *mbad_pix_map, const char *recipe, const cpl_propertylist *applist, const char *pipe_id, const char *filename)
Save a master_bpm as a DFS-compliant pipeline product.
Definition: eris_nix_dfs.c:218
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.
located_image * enu_located_image_duplicate(const located_image *limage)
Make a deep copy of a located_image and its contents.
void enu_located_imagelist_delete(located_imagelist *limlist)
Delete a located_imagelist and its contents.
cpl_error_code enu_located_imagelist_insert(located_imagelist *limlist, located_image *limage, cpl_size position)
Insert a located_image at a specified point in a located_imagelist.
cpl_propertylist * enu_raw_flats_qc(located_imagelist *lamp_on_limlist, cpl_mask *bp_map_nl_mask, const cpl_parameterlist *parlist, const char *context, const double threshold_pos, const cpl_boolean verbose, const cpl_boolean rescale_by_dit)
Compute QC on input raw flats.
cpl_error_code enu_flat_save(const char *pro_catg, const hdrl_image *flat, const cpl_image *confidence, const cpl_mask *cold_bpm, cpl_frameset *frameset, const cpl_parameterlist *parlist, const char *filename, const char *recipe_name, const cpl_propertylist *qclog)
Save a flatfield result.
double enu_get_tel_alt(const cpl_propertylist *plist)
Get telescope altitude of an observation.
hdrl_image * enu_calc_flat(hdrl_imagelist *himlist, const int min_coadds, const hdrl_parameter *collapse_params, const cpl_size filter_size_x, const cpl_size filter_size_y, const hdrl_flat_method method)
Calculate a flatfield result.
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)
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.
cpl_error_code enu_normalise_confidence(cpl_image *confidence)
Normalise confidence array so that mean of good pixels is 100.
located_imagelist * enu_located_imagelist_new(cpl_size size)
Return a pointer to a new located_imagelist.
cpl_mask * hdrl_bpm_2d_compute(const hdrl_image *img_in, const hdrl_parameter *params)
Detect bad pixels on a single image with an iterative process.
Definition: hdrl_bpm_2d.c:1136
hdrl_parameter * hdrl_bpm_2d_parameter_parse_parlist(const cpl_parameterlist *parlist, const char *prefix)
Parse parameter list to create input parameters for the BPM_2D.
Definition: hdrl_bpm_2d.c:896
hdrl_parameter * hdrl_bpm_2d_parameter_create_filtersmooth(double kappa_low, double kappa_high, int maxiter, cpl_filter_mode filter, cpl_border_mode border, int smooth_x, int smooth_y)
Creates BPM_2D Parameters object for HDRL_BPM_2D_FILTERSMOOTH.
Definition: hdrl_bpm_2d.c:137
cpl_parameterlist * hdrl_bpm_2d_parameter_create_parlist(const char *base_context, const char *prefix, const char *method_def, const hdrl_parameter *filtersmooth_def, const hdrl_parameter *legendresmooth_def)
Create parameter list for the BPM_2D computation.
Definition: hdrl_bpm_2d.c:798
hdrl_parameter * hdrl_bpm_2d_parameter_create_legendresmooth(double kappa_low, double kappa_high, int maxiter, int steps_x, int steps_y, int filter_size_x, int filter_size_y, int order_x, int order_y)
Creates BPM_2D Parameters object for HDRL_BPM_2D_LEGENDRESMOOTH.
Definition: hdrl_bpm_2d.c:191
hdrl_parameter * hdrl_collapse_sigclip_parameter_create(double kappa_low, double kappa_high, int niter)
create a parameter object for sigclipped mean
hdrl_parameter * hdrl_collapse_mode_parameter_create(double histo_min, double histo_max, double bin_size, hdrl_mode_type mode_method, cpl_size error_niter)
create a parameter object for the mode
cpl_parameterlist * hdrl_collapse_parameter_create_parlist(const char *base_context, const char *prefix, const char *method_def, hdrl_parameter *sigclip_def, hdrl_parameter *minmax_def, hdrl_parameter *mode_def)
Create parameters for the collapse.
hdrl_parameter * hdrl_collapse_minmax_parameter_create(double nlow, double nhigh)
create a parameter object for min-max rejected mean
hdrl_parameter * hdrl_collapse_parameter_parse_parlist(const cpl_parameterlist *parlist, const char *prefix)
parse parameterlist for imagelist reduction method
cpl_size hdrl_flat_parameter_get_filter_size_x(const hdrl_parameter *p)
Access the filter_size_x in the FLAT parameter.
Definition: hdrl_flat.c:209
hdrl_parameter * hdrl_flat_parameter_create(cpl_size filter_size_x, cpl_size filter_size_y, hdrl_flat_method method)
Creates FLAT Parameters object.
Definition: hdrl_flat.c:173
cpl_size hdrl_flat_parameter_get_filter_size_y(const hdrl_parameter *p)
Access the filter_size_y in the FLAT parameter.
Definition: hdrl_flat.c:223
hdrl_parameter * hdrl_flat_parameter_parse_parlist(const cpl_parameterlist *parlist, const char *prefix)
Parse a parameterlist to create input parameters for the FLAT.
Definition: hdrl_flat.c:331
cpl_parameterlist * hdrl_flat_parameter_create_parlist(const char *base_context, const char *prefix, const hdrl_parameter *defaults)
Create a parameter list for the FLAT computation.
Definition: hdrl_flat.c:258
cpl_error_code hdrl_image_sub_image(hdrl_image *self, const hdrl_image *other)
Subtract two images, store the result in the first image.
hdrl_image * hdrl_image_duplicate(const hdrl_image *himg)
copy hdrl_image
Definition: hdrl_image.c:391
cpl_mask * hdrl_image_get_mask(hdrl_image *himg)
get cpl bad pixel mask from image
Definition: hdrl_image.c:157
cpl_image * hdrl_image_get_error(hdrl_image *himg)
get error as cpl image
Definition: hdrl_image.c:131
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
cpl_error_code hdrl_imagelist_set(hdrl_imagelist *himlist, hdrl_image *himg, cpl_size pos)
Insert an image into an imagelist.
void hdrl_imagelist_delete(hdrl_imagelist *himlist)
Free all memory used by a hdrl_imagelist object including the images.
cpl_size hdrl_imagelist_get_size(const hdrl_imagelist *himlist)
Get the number of images in the imagelist.
hdrl_imagelist * hdrl_imagelist_new(void)
Create an empty imagelist.
hdrl_image * hdrl_imagelist_get(const hdrl_imagelist *himlist, cpl_size inum)
Get an image from a list of images.
void hdrl_parameter_delete(hdrl_parameter *obj)
shallow delete of a parameter
double fraction(double x, double y, double r_out)
Fraction of pixel bounded.