ERIS Pipeline Reference Manual 1.9.2
eris_nix_dark.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#include <eris_utils.h>
31/*-----------------------------------------------------------------------------
32 Includes
33 -----------------------------------------------------------------------------*/
34
35#include <math.h>
36#include <string.h>
37#include <cpl.h>
38
39#include "eris_nix_defs.h"
40#include "eris_nix_utils.h"
41#include "eris_pfits.h"
42#include "eris_nix_dfs.h"
43#include <hdrl.h>
44
45/*-----------------------------------------------------------------------------
46 Static variables
47 -----------------------------------------------------------------------------*/
48
49static const char eris_nix_dark_description[] =
50"This recipe reduces a set of DARK frames to produce a MASTER_DARK image,\n"
51"a bad pixel mask of `hot' pixels, and a measurement of the read-out noise.\n"
52"\n"
53"Input files:\n"
54"\n"
55" DO CATG Explanation Req. #Frames\n"
56" ------- ----------- --- -------\n"
57" "ERIS_NIX_RAW_DARK_DO_CATG
58 " The raw DARK frames. Y 2-n\n"
59" "ERIS_NIX_GAIN_PRO_CATG
60 " Gain information in Y 1\n"
61" file \n"
62" detmon_ir_lg_gain_table.fits\n"
63" output by recipe\n"
64" detmon_ir_lg.\n"
65"\n"
66"Output files:\n"
67"\n"
68" DO CATG Explanation \n"
69" ------- ----------- \n"
70" "ERIS_NIX_MASTER_DARK_IMG_PRO_CATG
71 " Master DARK result.\n"
72"\n"
73" The output will be a FITS file named 'master_dark.fits',\n"
74" containing extensions:\n"
75" - DATA Dark data\n"
76" - ERR Error on the data\n"
77" - DQ Data quality\n"
78" - HOT_BPM hot pixels\n"
79" Relevant FITS keywords are:\n"
80" - QC.READ.NOISE the measured readout noise\n"
81" of the array [electrons].\n"
82" - QC.READ.NOISE.VAR the variance on the readout\n"
83" noise [electrons^2].\n"
84" - QC.DARK.MED the median value of DARK \n"
85" good pixels [ADU].\n"
86" - QC.DARK.MEAN the mean value of DARK good\n"
87" pixels [ADU].\n"
88" - QC.DARK.RMS the r.m.s. of the DARK \n"
89" good pixels [ADU].\n"
90" - QC.NUMBER.HOT.PIXEL the number of hot pixels\n"
91" detected.\n"
92" - QC.PARTICLE.RATE the number of cosmic rays\n"
93" detected divided by the total\n"
94" integration time.\n"
95"\n";
96
97/*-----------------------------------------------------------------------------
98 Private function prototypes
99 -----------------------------------------------------------------------------*/
100#define RECIPE_NAME "eris_nix_dark"
101#define CONTEXT "eris."RECIPE_NAME
102#define ERIS_NIX_DETECTOR_SIZE 2048
103#define ERIS_NIX_DETECTOR_SIZE_X 2048
104#define ERIS_NIX_DETECTOR_SIZE_Y 2048
105cpl_recipe_define(eris_nix_dark, ERIS_BINARY_VERSION, "John Lightfoot",
106 PACKAGE_BUGREPORT, "2017",
107 "Calculate MASTER_DARK and 'hot-pixel' BPM",
108 eris_nix_dark_description);
109
110/*-----------------------------------------------------------------------------
111 Function code
112 -----------------------------------------------------------------------------*/
113
114/*----------------------------------------------------------------------------*/
122/*----------------------------------------------------------------------------*/
123static cpl_error_code eris_nix_dark_fill_parameterlist(cpl_parameterlist
124 *self)
125{
126 cpl_parameterlist * bpm_parlist = NULL;
127 cpl_parameterlist * collapse_parlist = NULL;
128 hdrl_parameter * filter_defaults = NULL;
129 hdrl_parameter * legendre_defaults = NULL;
130 hdrl_parameter * minmax_defaults = NULL;
131 hdrl_parameter * sigclip_defaults = NULL;
132
133 if (cpl_error_get_code() != CPL_ERROR_NONE) return cpl_error_get_code();
134
135 /* generate the general parameter list for the collapse */
136 hdrl_parameter * mode_def =
137 hdrl_collapse_mode_parameter_create(10., 1., 0., HDRL_MODE_MEDIAN, 0);
138 sigclip_defaults = hdrl_collapse_sigclip_parameter_create(10.0, 10.0, 3);
139 minmax_defaults = hdrl_collapse_minmax_parameter_create(50, 50);
141 "eris.eris_nix_dark", "collapse", "MEDIAN", sigclip_defaults,
142 minmax_defaults, mode_def);
143
144 /* add the subset of parameters to be used, leaving out 'minmax' */
145
146 for (const cpl_parameter * p =
147 cpl_parameterlist_get_first_const(collapse_parlist);
148 p != NULL;
149 p = cpl_parameterlist_get_next_const(collapse_parlist)) {
150 const char * pname = cpl_parameter_get_name(p);
151 if (strstr(pname, "minmax") == NULL) {
152 cpl_parameter * duplicate = cpl_parameter_duplicate(p);
153 cpl_parameterlist_append(self, duplicate);
154 }
155 }
156
157 /* get the general parameter list for the hot-pixel bpm */
158
159 /* hot (and cold) pixels flagged at 10.0 sigma - see HDRL docs */
160 filter_defaults = hdrl_bpm_2d_parameter_create_filtersmooth(10.0, 10.0, 3,
161 CPL_FILTER_MEDIAN, CPL_BORDER_FILTER, 21, 21);
162 legendre_defaults = hdrl_bpm_2d_parameter_create_legendresmooth(4, 5, 6,
163 20, 21, 11, 12, 2, 10);
164 bpm_parlist = hdrl_bpm_2d_parameter_create_parlist("eris.eris_nix_dark",
165 "hotpix", "FILTER", filter_defaults, legendre_defaults);
166
167 /* add the parameters to be used */
168
169 for (const cpl_parameter * p =
170 cpl_parameterlist_get_first(bpm_parlist);
171 p != NULL; p = cpl_parameterlist_get_next_const(bpm_parlist)) {
172 cpl_parameter * duplicate = cpl_parameter_duplicate(p);
173 cpl_parameterlist_append(self, duplicate);
174 }
175
176
177
178 /* FPN parameters */
179 cpl_parameter * p;
180 p = cpl_parameter_new_range("eris.eris_nix_dark.qc_fpn_xmin",
181 CPL_TYPE_INT,
182 "qc_fpn_xmin",
183 "eris.eris_nix_dark",
184 7,1,ERIS_NIX_DETECTOR_SIZE);
185
186 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"qc_fpn_xmin");
187
188 cpl_parameterlist_append(self, p);
189
190
191 p = cpl_parameter_new_range("eris.eris_nix_dark.qc_fpn_xmax",
192 CPL_TYPE_INT,
193 "qc_fpn_xmax",
194 "eris.eris_nix_dark",
195 2042,1,ERIS_NIX_DETECTOR_SIZE);
196
197 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"qc_fpn_xmax");
198
199 cpl_parameterlist_append(self, p);
200
201 p = cpl_parameter_new_range("eris.eris_nix_dark.qc_fpn_ymin",
202 CPL_TYPE_INT,
203 "qc_fpn_ymin",
204 "eris.eris_nix_dark",
205 7,1,ERIS_NIX_DETECTOR_SIZE);
206
207 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"qc_fpn_ymin");
208
209 cpl_parameterlist_append(self, p);
210
211
212 p = cpl_parameter_new_range("eris.eris_nix_dark.qc_fpn_ymax",
213 CPL_TYPE_INT,
214 "qc_fpn_ymax",
215 "eris.eris_nix_dark",
216 2042,1,ERIS_NIX_DETECTOR_SIZE);
217
218 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"qc_fpn_ymax");
219
220 cpl_parameterlist_append(self, p);
221
222
223 p = cpl_parameter_new_value("eris.eris_nix_dark.qc_fpn_hsize",
224 CPL_TYPE_INT,
225 "qc_fpn_hsize",
226 "eris.eris_nix_dark",
227 10);
228
229 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"qc_fpn_hsize");
230
231 cpl_parameterlist_append(self, p);
232
233
234 p = cpl_parameter_new_value("eris.eris_nix_dark.qc_fpn_nsamp",
235 CPL_TYPE_INT,
236 "qc_fpn_nsamp",
237 "eris.eris_nix_dark",
238 1000);
239
240 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"qc_fpn_nsamp");
241
242 cpl_parameterlist_append(self, p);
243
244
245
246
247 /* cleanup */
248
249 hdrl_parameter_delete(sigclip_defaults);
250 hdrl_parameter_delete(minmax_defaults);
251 cpl_parameterlist_delete(collapse_parlist);
252 hdrl_parameter_delete(mode_def);
253 hdrl_parameter_delete(filter_defaults);
254 hdrl_parameter_delete(legendre_defaults);
255 cpl_parameterlist_delete(bpm_parlist);
256
257 return cpl_error_get_code();
258}
259
260/*----------------------------------------------------------------------------*/
267/*----------------------------------------------------------------------------*/
268
269static int eris_nix_dark(cpl_frameset * frameset,
270 const cpl_parameterlist * parlist) {
271
272 cpl_propertylist * applist = NULL;
273 hdrl_parameter * bpm_params = NULL;
274 hdrl_image * mdark = NULL;
275 cpl_image * contribution = NULL;
276 hdrl_parameter * collapse_params = NULL;
277 cpl_frameset * dark_frameset = NULL;
278 hdrl_image * diff = NULL;
279 const char * filename = NULL;
280 cpl_frameset_iterator * frame_iter = NULL;
281 cpl_propertylist * gain_propertylist = NULL;
282 cpl_mask * hot_bpm = NULL;
283 cpl_frame * inherit = NULL;
284 mef_extension_list * mefs = NULL;
285 const cpl_frame * rawframe = NULL;
286 hdrl_imagelist * dark_himlist = NULL;
287 cpl_propertylist * plist0 = NULL;
288
289 /* Return immediately if an error code is already set */
290
291 enu_check_error_code("%s():%d: An error is already set: %s",
292 cpl_func, __LINE__, cpl_error_get_where());
293
294 /* Check input parameters */
295
296 cpl_ensure_code(frameset, CPL_ERROR_NULL_INPUT);
297 cpl_ensure_code(parlist, CPL_ERROR_NULL_INPUT);
298
299 /* Set the msg verbosity level from environment variable CPL_MSG_LEVEL */
300 /* --can't get this to work */
301
302 cpl_msg_set_level_from_env();
303 cpl_msg_severity severity = cpl_msg_get_level();
304 cpl_msg_info(cpl_func, "level %d", (int) severity);
305
306 /* check required input tags are present */
307 const int ntags = 2;
308 const char* required_tags[2] = {ERIS_NIX_RAW_DARK_DO_CATG,
309 ERIS_NIX_GAIN_PRO_CATG,
310 };
311
312 cpl_ensure_code(CPL_ERROR_NONE ==
313 eris_dfs_check_input_tags(frameset, required_tags, ntags, 1),
314 CPL_ERROR_ILLEGAL_INPUT);
315
316
317 /* Retrieve input parameters for collapse */
318
319 collapse_params = hdrl_collapse_parameter_parse_parlist(parlist,
320 "eris.eris_nix_dark.collapse");
321
322 /* Retrieve input parameters for 'hot-pixel' bpm */
323
324 bpm_params = hdrl_bpm_2d_parameter_parse_parlist(parlist,
325 "eris.eris_nix_dark.hotpix");
326
327 enu_check(cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
328 "Could not retrieve input parameters");
329
330 /* Identify the RAW and CALIB frames in the input frameset */
331
332 eris_nix_dfs_set_groups(frameset);
333 enu_check(cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
334 "Could not identify RAW and CALIB frames");
335
336 /* Check at least one DARK frame is present in SoF */
337
338 rawframe = cpl_frameset_find_const(frameset, ERIS_NIX_RAW_DARK_DO_CATG);
339 enu_check(rawframe != NULL, CPL_ERROR_DATA_NOT_FOUND,
340 "SOF does not have any file tagged with %s",
341 ERIS_NIX_RAW_DARK_DO_CATG);
342
343 /* Check GAIN file is present in SoF */
344
345 const cpl_frame * gainframe = cpl_frameset_find_const(frameset,
346 ERIS_NIX_GAIN_PRO_CATG);
347 enu_check(gainframe != NULL, CPL_ERROR_DATA_NOT_FOUND,
348 "SOF does not have any file tagged with %s",
349 ERIS_NIX_GAIN_PRO_CATG);
350
351 /* Construct a frameset with just the DARK frames */
352
353 dark_frameset = cpl_frameset_new();
354 frame_iter = cpl_frameset_iterator_new(frameset);
355
356 while (cpl_frameset_iterator_get(frame_iter) != NULL) {
357 cpl_frame * frame = cpl_frameset_iterator_get(frame_iter);
358 const char * tag = cpl_frame_get_tag(frame);
359 filename = cpl_frame_get_filename(frame);
360 cpl_msg_debug(cpl_func, "filename %s tag %s", filename, tag);
361 if (!strcmp(tag, ERIS_NIX_RAW_DARK_DO_CATG)) {
362 cpl_frameset_insert(dark_frameset, cpl_frame_duplicate(frame));
363 }
364 cpl_frameset_iterator_advance(frame_iter, 1);
365 }
366
367 /* How many DARKS do we have */
368
369 const int ndarks = cpl_frameset_get_size(dark_frameset);
370 cpl_msg_info(cpl_func, "Number of DARK frames: %d", ndarks);
371
372 /* Construct an imagelist containing the DARK images */
373 dark_himlist = hdrl_imagelist_new();
374
375 for (int idark=0; idark < ndarks; idark++) {
376
377 /* Check that the DARK frames all match */
378
379 const cpl_frame * frame = cpl_frameset_get_position_const(
380 dark_frameset, idark);
381 filename = cpl_frame_get_filename(frame);
382
383 if (idark == 0) {
384 plist0 = cpl_propertylist_load(filename, 0);
385 inherit = cpl_frame_duplicate(frame);
386 } else {
387 cpl_propertylist * plist = cpl_propertylist_load(filename, 0);
388
389 /* following should work for both ERIS and NACO-style data */
390 enu_check_conformance(plist0, plist,
391 "^ESO DET SEQ1 DIT$|"
392 "^ESO DET READ CURNAME$|"
393 "^ESO DET DIT$|"
394 "^ESO DET NCORRS NAME$");
395 cpl_propertylist_delete(plist);
396 }
397 enu_check(cpl_error_get_code()==CPL_ERROR_NONE, cpl_error_get_code(),
398 "error checking frame conformance");
399 cpl_image * image = cpl_image_load(filename, HDRL_TYPE_DATA,
400 0, 0);
401 hdrl_image * himage = hdrl_image_create(image, NULL);
402 hdrl_imagelist_set(dark_himlist, himage, idark);
403
404 cpl_image_delete(image);
405 }
406 enu_check(cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
407 "Could not construct DARK imagelist");
408 int isize = hdrl_imagelist_get_size(dark_himlist);
409 cpl_msg_debug(cpl_func, "Size of hdrl imagelist: %d", isize);
410 enu_check(isize > 1, CPL_ERROR_ILLEGAL_INPUT, "need at least 2 DARKs");
411
412 const char * instrume = cpl_propertylist_get_string(plist0, "INSTRUME");
413 if (!strcmp(instrume, "ERIS")) {
414 cpl_msg_info(cpl_func, "removing read_offsets");
415
416 for (cpl_size i = 0; i < hdrl_imagelist_get_size(dark_himlist); i++) {
418 plist0,
419 NULL,
420 CPL_FALSE);
421 }
422 }
423
424 /* Read the detector gain */
425
426 const char * gainfile = cpl_frame_get_filename(gainframe);
427 gain_propertylist = cpl_propertylist_load(gainfile, 0);
428 double gain = cpl_propertylist_get_double(gain_propertylist,
429 "ESO QC GAIN");
430 enu_check_error_code("Error reading QC.GAIN from %s", gainfile);
431 cpl_msg_info(cpl_func, "detector gain %5.2f", gain);
432
433 /* Now calculate the readout-noise using the standard CPL routine
434 - though shouldn't the result be divided by sqrt(2) as it is
435 - being derived from a difference image */
436
437 const hdrl_image * dark_0 = hdrl_imagelist_get_const(dark_himlist, 0);
438 const hdrl_image * dark_1 = hdrl_imagelist_get_const(dark_himlist, 1);
439 diff = hdrl_image_sub_image_create(dark_0, dark_1);
440 double read_noise = -1.0;
441 double read_noise_std = -1.0;
442 cpl_flux_get_noise_window(hdrl_image_get_image_const(diff), NULL,
443 -1, -1, &read_noise, &read_noise_std);
444 read_noise /= sqrt(2.0);
445 read_noise_std /= sqrt(2.0);
446 enu_check_error_code("Failed to calculate read-out noise");
447
448 /* Convert ron from ADU to electrons */
449
450 double read_noise_adu = read_noise;
451 double read_noise_std_adu = read_noise_std;
452 read_noise *= gain;
453 read_noise_std *= gain;
454 cpl_msg_info(cpl_func, "read-out noise = %5.2e +- %5.2e", read_noise,
455 read_noise_std);
456
457 /* Estimate the error plane of each dark */
458
459 const char * det_mode = enu_get_det_mode(plist0);
460 enu_check_error_code("Failed to read required detector mode");
461
462 /* Calculate the error, assuming no photons, read-noise contribution
463 only */
464
465 double variance = 0.0;
466 if (!strcmp(det_mode, "Double_RdRstRd")) {
467
468 /* CDS. Correlated Double Sampling.
469 In this mode the intensity is calculated from the difference
470 between sets of measurements at the start and end of the
471 integration. Variance from Vacca eqn 44. with I = 0 */
472
473 const double dit = enu_get_dit(plist0);
474 const double ndit = (double) cpl_propertylist_get_int(plist0,
475 "ESO DET NDIT");
476 const int nr = 2; /* is this right? */
477
478 variance = 2.0 * read_noise * read_noise /
479 (gain * gain * nr * ndit * dit * dit);
480
481 cpl_msg_info(cpl_func,
482 "variance=%6.2e read-noise=%6.2f gain=%6.2f ndit=%d "
483 "dit=%6.2f",
484 variance, read_noise, gain, (int) ndit, dit);
485
486 } else if (!strcmp(det_mode, "SLOW_GR_UTR")) {
487
488 /* Continuous sampling technique - line fitting - 'up the ramp'.
489 Variance from Vacca eqn 55 with I = 0. */
490
491 double dit = enu_get_dit(plist0);
492 const double ndit = (double) cpl_propertylist_get_int(plist0,
493 "ESO DET NDIT");
494 const int nr = cpl_propertylist_get_int(plist0, "ESO DET NDSAMPLES");
495
496 variance = 12.0 * read_noise * read_noise * (nr - 1.0) /
497 (gain * gain * nr * ndit * dit * dit * (nr + 1.0));
498 cpl_msg_info(cpl_func,
499 "variance=%6.2e read-noise=%6.2f gain=%6.2f ndit=%d "
500 "dit=%6.2f",
501 variance, read_noise, gain, (int) ndit, dit);
502
503 } else if (!strcmp(det_mode, "FAST_UNCORR")) {
504
505 /* FAST_UNCORR is not covered in Vacca et al. We could come up
506 with a similar formula but a real uncertainty is the
507 repeatability of the array state after reset at the start of the
508 integration.
509
510 Most robust to calculate the MAD directly from the data sequence */
511
512 cpl_imagelist * mad_working = cpl_imagelist_new();
513
514 for (cpl_size i=0; i < hdrl_imagelist_get_size(dark_himlist); i++) {
515 cpl_imagelist_set(mad_working,
516 cpl_image_duplicate(
518 hdrl_imagelist_get(dark_himlist, i))), i);
519 }
520
521 /* get median of dark frames */
522
523 cpl_image * dark_med =
524 cpl_imagelist_collapse_median_create(mad_working);
525 cpl_msg_info(cpl_func, "%e", cpl_image_get_median(dark_med));
526
527 /* fill mad_working with abs of diffs between frames and median */
528
529 for (cpl_size i=0; i < hdrl_imagelist_get_size(dark_himlist); i++) {
530 cpl_image * diff2 = cpl_image_subtract_create(dark_med,
532 hdrl_imagelist_get(dark_himlist, i)));
533 cpl_image_abs(diff2);
534 cpl_msg_info(cpl_func, "%d %e", (int)i,
535 cpl_image_get_median(diff2));
536 cpl_imagelist_set(mad_working, diff2, i);
537 }
538 cpl_image_delete(dark_med);
539 /* get the median of the diffs and get the median of that */
540
541 cpl_image * mad = cpl_imagelist_collapse_median_create(mad_working);
542 double median_mad = cpl_image_get_median(mad);
543 cpl_image_delete(mad);
544 cpl_msg_info(cpl_func, "median mad %e", median_mad);
545 variance = pow(1.4826 * median_mad, 2);
546
547 cpl_msg_info(cpl_func, "variance=%6.2e", variance);
548
549 cpl_imagelist_delete(mad_working);
550
551 } else {
552 cpl_error_set_message(cpl_func, CPL_ERROR_UNSUPPORTED_MODE,
553 "unsupported detector mode: %s", det_mode);
554 }
555 enu_check_error_code("failed to calculate master_dark error plane");
556
557 for (int idark = 0; idark < isize; idark++) {
558 cpl_image * error = hdrl_image_get_error(hdrl_imagelist_get(
559 dark_himlist, idark));
560 cpl_size nx = cpl_image_get_size_x(error);
561 cpl_size ny = cpl_image_get_size_y(error);
562 cpl_image_fill_window(error, 1, 1, nx, ny, sqrt(variance));
563 }
564
565 /* Use hdrl to calculate the MASTER_DARK data */
566
567 hdrl_imagelist_collapse(dark_himlist, collapse_params, &mdark,
568 &contribution);
569 enu_check_error_code("Failed to collapse imagelist");
570
571 /* Now compute the 'hot-pixel' BPM, the output will not include
572 pixels already set bad in the input image. */
573
574 hot_bpm = hdrl_bpm_2d_compute(mdark, bpm_params);
575 double kappa_high = hdrl_bpm_2d_parameter_get_kappa_high(bpm_params);
576 cpl_msg_info(cpl_func, "kappa-high %6.2e", kappa_high);
577 enu_check_error_code("failed to calculate hot-pixel BPM");
578
579 /* Set 'hot' pixels in the mask of the dark */
580
581 cpl_mask * old_mask = cpl_image_set_bpm(hdrl_image_get_image(mdark),
582 hot_bpm);
583 if (old_mask) {
584 cpl_mask_or(old_mask, hot_bpm);
585 cpl_image_reject_from_mask(hdrl_image_get_image(mdark),
586 old_mask);
587 cpl_mask_delete(old_mask);
588 }
589
590 /* Need to calculate CR rate. Could assume each pixel value that
591 was sigma-clipped was a CR, but no direct way to get the number of
592 pixels clipped from HDRL */
593 /* Could reconstruct the clipping using the hi-lo limits that can
594 be returned by HDRL. Or could apply the hot-pixel bpm and
595 use hdrl_lacosmic - concern there is that the dark images might
596 possess valid sharp edges */
597 /* Not very important, so leave for now */
598
599 cpl_msg_warning(cpl_func, "TBD: calculate CR rate");
600
601 /* construct the propertylist to be saved with the MASTER_DARK */
602
603 applist = cpl_propertylist_new();
604
605 /* Add the product category */
606
607 cpl_propertylist_append_string(applist, CPL_DFS_PRO_CATG,
608 ERIS_NIX_MASTER_DARK_IMG_PRO_CATG);
609 cpl_propertylist_update_string(applist, "PRODCATG", "ANCILLARY.IMAGE");
610
611 /* Info on the mode used */
612
613 cpl_propertylist_copy_property_regexp(applist, plist0,
614 "^ESO DET DIT$|"
615 "^ESO DET SEQ1 DIT$|"
616 "^ESO DET READ CURNAME$|"
617 "^ESO DET NCORRS NAME$", 0);
618
619 /* Add QC parameters */
620
621 cpl_propertylist_append_double(applist, "ESO QC READ NOISE", read_noise);
622 cpl_propertylist_set_comment(applist,"ESO QC READ NOISE",
623 "[e-] Read Out Noise");
624 cpl_propertylist_append_double(applist, "ESO QC READ NOISE VAR",
625 pow(read_noise_std, 2.0));
626 cpl_propertylist_set_comment(applist,"ESO QC READ NOISE VAR",
627 "[e-] Read Out Noise Variance");
628
629 cpl_propertylist_append_double(applist, "ESO QC READ NOISE ADU", read_noise_adu);
630 cpl_propertylist_set_comment(applist,"ESO QC READ NOISE ADU",
631 "[ADU] Read Out Noise");
632 cpl_propertylist_append_double(applist, "ESO QC READ NOISE VAR ADU",
633 pow(read_noise_std_adu, 2.0));
634 cpl_propertylist_set_comment(applist,"ESO QC READ NOISE VAR ADU",
635 "[ADU] Read Out Noise Variance");
636
637
638 hdrl_value dark_median = hdrl_image_get_median(mdark);
639 cpl_propertylist_append_double(applist, "ESO QC DARK MED",
640 (double) dark_median.data);
641 cpl_propertylist_set_comment(applist,"ESO QC DARK MED",
642 "[ADU] Median Master Dark");
643 hdrl_value dark_mean = hdrl_image_get_mean(mdark);
644 cpl_propertylist_append_double(applist, "ESO QC DARK MEAN",
645 (double) dark_mean.data);
646 cpl_propertylist_set_comment(applist,"ESO QC DARK MEAN",
647 "[ADU] Mean Master Dark");
648 double dark_rms = hdrl_image_get_stdev(mdark);
649 cpl_propertylist_append_double(applist, "ESO QC DARK RMS", dark_rms);
650 cpl_propertylist_set_comment(applist,"ESO QC DARK RMS",
651 "[ADU] RMS Master Dark");
652 cpl_size nhot = cpl_mask_count(hot_bpm);
653 cpl_size sx = cpl_mask_get_size_x(hot_bpm);
654 cpl_size sy = cpl_mask_get_size_y(hot_bpm);
655 double fraction = (double) nhot / (sx * sy);
656 cpl_propertylist_append_int(applist, "ESO QC NUMBER HOT PIXEL", (int)nhot);
657 cpl_propertylist_set_comment(applist,"ESO QC NUMBER HOT PIXEL",
658 "Number of hot pixels");
659 cpl_propertylist_append_double(applist, "ESO QC HOT PIXEL FRACTION", fraction);
660 cpl_propertylist_set_comment(applist,"ESO QC HOT PIXEL FRACTION",
661 "Fraction of hot pixels to total");
662 double particle_rate = -1.0;
663 cpl_propertylist_append_double(applist, "ESO QC PARTICLE_RATE",
664 particle_rate);
665
666 /* copied from gain info file */
667
668 cpl_propertylist_append_double(applist, "ESO QC GAIN", gain);
669 cpl_propertylist_set_comment(applist,"ESO QC GAIN",
670 "[e-/ADU] Detector Gain");
671
672 /* FPN computation */
673
674 double qc_fpn_val = 0, qc_fpn_err = 0;
675 cpl_size zone_def[4];
676 cpl_size hsize, nsamp;
677
678 zone_def[0] = cpl_parameter_get_int(cpl_parameterlist_find_const(parlist,
679 "eris.eris_nix_dark.qc_fpn_xmin"));
680
681 zone_def[1] = cpl_parameter_get_int(cpl_parameterlist_find_const(parlist,
682 "eris.eris_nix_dark.qc_fpn_xmax"));
683 zone_def[2] = cpl_parameter_get_int(cpl_parameterlist_find_const(parlist,
684 "eris.eris_nix_dark.qc_fpn_ymin"));
685 zone_def[3] = cpl_parameter_get_int(cpl_parameterlist_find_const(parlist,
686 "eris.eris_nix_dark.qc_fpn_ymax"));
687 hsize = cpl_parameter_get_int(cpl_parameterlist_find_const(parlist,
688 "eris.eris_nix_dark.qc_fpn_hsize"));
689 nsamp = cpl_parameter_get_int(cpl_parameterlist_find_const(parlist,
690 "eris.eris_nix_dark.qc_fpn_nsamp"));
691
692 /* window information */
693
694 cpl_size nx = 0;
695 cpl_size ny = 0;
696 int rot = 0;
697 cpl_size strx = 0;
698 cpl_size stry = 0;
699 cpl_size nx_chip = 0;
700 cpl_size ny_chip = 0;
701 cpl_boolean windowed = 0;
703 &ny,
704 &rot,
705 &strx,
706 &stry,
707 &nx_chip,
708 &ny_chip,
709 &windowed,
710 plist0);
711 /*
712 cpl_msg_info(cpl_func,
713 "nx=:%lld ny: %lld strx: %lld stry: %lld nx_chip: %lld ny_chip: %lld",
714 nx, ny, strx, stry, nx_chip, ny_chip);
715*/
716
717 zone_def[1] = (zone_def[1] > nx) ? nx: zone_def[1];
718 zone_def[3] = (zone_def[3] > ny) ? ny: zone_def[3];
719
720 cpl_msg_info(cpl_func,"Zone: [%lld,%lld,%lld,%lld]",
721 zone_def[0],zone_def[2],zone_def[1],zone_def[3]);
722 cpl_image* master_dark_ima = hdrl_image_get_image(mdark);
723 if(CPL_ERROR_NONE != cpl_flux_get_noise_window(master_dark_ima, zone_def, hsize,
724 nsamp, &qc_fpn_val, &qc_fpn_err)) {
725 /* rarely this may fail. If this occurs we set dummy values (to prevent seg
726 * fault later) and go on */
727 cpl_msg_error(cpl_func,"FPN computation failed, set dummy values");
728 qc_fpn_val=9999;
729 qc_fpn_err=99;
730 cpl_error_reset();
731 }
732
733 cpl_propertylist_append_double(applist,"ESO QC DARKFPN", qc_fpn_val);
734 cpl_propertylist_set_comment(applist,"ESO QC DARKFPN",
735 "Fixed Pattern Noise of combined frames");
736
738 mefs->mef[0] = enu_mef_new_mask(ERIS_NIX_HOT_BPM_EXTENSION, hot_bpm, NULL);
739
740 /* Save the master dark to a DFS-compliant MEF file */
741
742 enu_dfs_save_himage(frameset,
743 parlist,
744 frameset,
745 CPL_TRUE,
746 mdark,
747 NULL,
748 mefs,
749 "eris_nix_dark",
750 inherit,
751 applist,
752 NULL,
753 PACKAGE "/" PACKAGE_VERSION,
754 "master_dark.fits");
755 enu_check_error_code("Failed to save MASTER_DARK");
756
757cleanup:
758 cpl_frameset_delete(dark_frameset);
759 cpl_propertylist_delete(plist0);
760 hdrl_imagelist_delete(dark_himlist);
761 if(bpm_params != NULL) hdrl_parameter_delete(bpm_params);
762 if(contribution != NULL) cpl_image_delete(contribution);
763 if(mdark != NULL) hdrl_image_delete(mdark);
764
765 cpl_propertylist_delete(applist);
766 hdrl_image_delete(diff);
767 cpl_frameset_iterator_delete(frame_iter);
768 cpl_propertylist_delete(gain_propertylist);
769 cpl_frame_delete(inherit);
771
772 return (int) cpl_error_get_code();
773}
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_himage(cpl_frameset *allframes, const cpl_parameterlist *parlist, const cpl_frameset *provenance, const cpl_boolean prov_raw, const hdrl_image *image, const hdrl_imagelist *imagelist, const mef_extension_list *mefs, const char *recipe, const cpl_frame *inherit_frame, const cpl_propertylist *applist, const cpl_propertylist *wcs_plist, const char *pipe_id, const char *filename)
Save an hdrl_image/imagelist as a DFS-compliant MEF pipeline product.
Definition: eris_nix_dfs.c:423
mef_extension * enu_mef_new_mask(const char *name, const cpl_mask *data, const cpl_propertylist *plist)
Create a mef_extension struct holding a cpl_mask.
int enu_check_conformance(const cpl_propertylist *plist1, const cpl_propertylist *plist2, const char *regexp)
Check that the specified subset of two propertylists match.
cpl_error_code enu_get_window_info(cpl_size *nx, cpl_size *ny, int *rot, cpl_size *strx, cpl_size *stry, cpl_size *nx_chip, cpl_size *ny_chip, cpl_boolean *windowed, const cpl_propertylist *plist)
Get the detector 'window' information.
mef_extension_list * enu_mef_extension_list_new(cpl_size size)
Construct a new mef_extension_list.
cpl_error_code enu_remove_read_offsets(hdrl_image *himage, const cpl_propertylist *plist, cpl_image *confidence, const int set_confidence)
Function to remove read offsets from an himage and set blank pixels
void enu_mef_extension_list_delete(mef_extension_list *list)
Delete a mef_extension_list and its contents.
const char * enu_get_det_mode(const cpl_propertylist *plist)
Get the detector mode of an integration.
double enu_get_dit(const cpl_propertylist *plist)
Get the DIT of an integration.
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
double hdrl_bpm_2d_parameter_get_kappa_high(const hdrl_parameter *p)
Access the kappa_high in the BPM_2D parameter.
Definition: hdrl_bpm_2d.c:355
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
hdrl_value hdrl_image_get_median(const hdrl_image *self)
computes the median and associated error of an image.
hdrl_image * hdrl_image_sub_image_create(const hdrl_image *self, const hdrl_image *other)
Subtract two images.
double hdrl_image_get_stdev(const hdrl_image *self)
computes the standard deviation of the data of an image
cpl_image * hdrl_image_get_error(hdrl_image *himg)
get error as cpl image
Definition: hdrl_image.c:131
hdrl_value hdrl_image_get_mean(const hdrl_image *self)
computes mean pixel value and associated error of an image.
hdrl_image * hdrl_image_create(const cpl_image *image, const cpl_image *error)
create a new hdrl_image from to existing images by copying them
Definition: hdrl_image.c:295
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.
const hdrl_image * hdrl_imagelist_get_const(const hdrl_imagelist *himlist, cpl_size inum)
Get an image from a list of images.
cpl_size hdrl_imagelist_get_size(const hdrl_imagelist *himlist)
Get the number of images in the imagelist.
cpl_error_code hdrl_imagelist_collapse(const hdrl_imagelist *himlist, const hdrl_parameter *param, hdrl_image **out, cpl_image **contrib)
collapsing of image list
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.