ERIS Pipeline Reference Manual 1.9.3
eris_nix_img_supersky.c
1/* $Id$
2 *
3 * This file is part of the ERIS/NIX Pipeline
4 * Copyright (C) 2025 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
17#ifdef HAVE_CONFIG_H
18#include <config.h>
19#endif
20
21/*-----------------------------------------------------------------------------
22 Includes
23 -----------------------------------------------------------------------------*/
24
25#include "eris_utils.h"
26#include "eris_pfits.h"
27#include "eris_dfs.h"
28#include "eris_nix_dfs.h"
29#include "eris_nix_utils.h"
30#include "eris_nix_img_supersky.h"
31
32#include <cpl.h>
33#include <hdrl.h>
34#include <math.h>
35
36/*-----------------------------------------------------------------------------
37 Static variables
38 -----------------------------------------------------------------------------*/
39#define RECIPE_NAME "eris.eris_nix_img_supersky"
40
41static const char eris_nix_img_supersky_description[] =
42"Creates and applies super-sky flat for mid-infrared (M-IR) imaging data\n"
43"to correct for highly variable sky emission in Short-Lp, Lp, and Mp filters.\n"
44"\n"
45"Input files:\n"
46" NIX_SCIENCE_REDUCED: Detector-corrected science exposures (REQUIRED, multiple)\n"
47" MASTER_BPM: Master bad pixel map (REQUIRED, single)\n"
48"\n"
49"Output files:\n"
50" MASTER_SKYFLAT: Final super-sky flat\n"
51" SKYSUB_OBJECT_JITTER: Sky-subtracted science frames (if save-skysub=TRUE)\n"
52"\n"
53"Algorithm:\n"
54"1. Create first-pass super-sky by sigma-clipped combination of all frames\n"
55"2. Subtract scaled super-sky from each frame\n"
56"3. Detect and mask sources in corrected frames using local background\n"
57"4. Create final super-sky with source masks applied\n"
58"5. Subtract scaled final super-sky from original frames\n"
59"\n"
60"The recipe handles both point-source (default) and extended-source observations.\n"
61"For extended sources, use OFF-SOURCE frames as input.\n";
62
63/*-----------------------------------------------------------------------------
64 Private function prototypes
65 -----------------------------------------------------------------------------*/
66
67cpl_recipe_define(eris_nix_img_supersky, ERIS_BINARY_VERSION, "ESO Pipeline Team",
68 PACKAGE_BUGREPORT, "2025",
69 "Create and apply super-sky flat for M-IR imaging",
70 eris_nix_img_supersky_description);
71
72/*-----------------------------------------------------------------------------
73 Functions
74 -----------------------------------------------------------------------------*/
75
76/*----------------------------------------------------------------------------*/
82/*----------------------------------------------------------------------------*/
83static cpl_error_code eris_nix_img_supersky_fill_parameterlist(
84 cpl_parameterlist *self)
85{
86 cpl_errorstate prestate = cpl_errorstate_get();
87 cpl_parameter* p;
88
89 /* Combination method */
90 p = cpl_parameter_new_enum("eris.eris_nix_img_supersky.combine_method",
91 CPL_TYPE_STRING,
92 "Method to combine frames",
93 "eris.eris_nix_img_supersky",
94 "sigmaclip", 2,
95 "median", "sigmaclip");
96 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "combine-method");
97 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
98 cpl_parameterlist_append(self, p);
99
100 /* Sigma clipping threshold */
101 p = cpl_parameter_new_value("eris.eris_nix_img_supersky.sigma_clip",
102 CPL_TYPE_DOUBLE,
103 "Sigma threshold for clipping",
104 "eris.eris_nix_img_supersky", 2.0); //2.5
105 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sigma-clip");
106 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
107 cpl_parameterlist_append(self, p);
108
109 /* Maximum iterations for sigma clipping */
110 p = cpl_parameter_new_value("eris.eris_nix_img_supersky.max_iter",
111 CPL_TYPE_INT,
112 "Maximum iterations for sigma clipping",
113 "eris.eris_nix_img_supersky", 5);
114 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "max-iter");
115 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
116 cpl_parameterlist_append(self, p);
117
118 /* Source detection threshold */
119 p = cpl_parameter_new_value("eris.eris_nix_img_supersky.detect_threshold",
120 CPL_TYPE_DOUBLE,
121 "Detection threshold in sigma above background",
122 "eris.eris_nix_img_supersky", 3.0);//5.0
123 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "detect-threshold");
124 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
125 cpl_parameterlist_append(self, p);
126
127 /* Source FWHM */
128 p = cpl_parameter_new_value("eris.eris_nix_img_supersky.source_fwhm",
129 CPL_TYPE_DOUBLE,
130 "Stellar FWHM in pixels",
131 "eris.eris_nix_img_supersky", 5.0);
132 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "source-fwhm");
133 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
134 cpl_parameterlist_append(self, p);
135
136 /* Minimum source area */
137 p = cpl_parameter_new_value("eris.eris_nix_img_supersky.min_area",
138 CPL_TYPE_INT,
139 "Minimum connected pixels for source detection",
140 "eris.eris_nix_img_supersky", 500); //20
141 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "min-area");
142 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
143 cpl_parameterlist_append(self, p);
144
145 /* Mask dilation */
146 p = cpl_parameter_new_value("eris.eris_nix_img_supersky.mask_dilate",
147 CPL_TYPE_INT,
148 "Source mask dilation radius in pixels",
149 "eris.eris_nix_img_supersky", 10);
150 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "mask-dilate");
151 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
152 cpl_parameterlist_append(self, p);
153
154 /* Save sky-subtracted frames */
155 p = cpl_parameter_new_value("eris.eris_nix_img_supersky.save_skysub",
156 CPL_TYPE_BOOL,
157 "Save individual sky-subtracted frames",
158 "eris.eris_nix_img_supersky", TRUE);
159 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "save-skysub");
160 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
161 cpl_parameterlist_append(self, p);
162
163 /* Save sky-subtracted frames */
164 p = cpl_parameter_new_value("eris.eris_nix_img_supersky.debug_data",
165 CPL_TYPE_BOOL,
166 "Save individual sky-subtracted frames",
167 "eris.eris_nix_img_supersky", TRUE);
168 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "debug-data");
169 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
170 cpl_parameterlist_append(self, p);
171
172
173
174
175 /* parameters to mask objects */
176
177
178
179 /* Get default parameters in the recipe */
180 /* Default values of the hdrl_parameter in the hdrl_catalogue */
181 int obj_min_pixels = 300; //4
182 double obj_threshold = 3.0; //2.5
183 cpl_boolean obj_deblending = CPL_TRUE;
184 double obj_core_radius = 30.;//5.
185 cpl_boolean bkg_estimate = CPL_TRUE;
186 int bkg_mesh_size = 64;
187 double bkg_smooth_fwhm = 2.;
188 double det_eff_gain = 3.;
189 double det_saturation = HDRL_SATURATION_INIT;
190 hdrl_catalogue_options resulttype = HDRL_CATALOGUE_BKG;
191
192
193
194 /* Create a parameter list */
195 hdrl_parameter *c_def = hdrl_catalogue_parameter_create(
196 obj_min_pixels, obj_threshold, obj_deblending, obj_core_radius,
197 bkg_estimate, bkg_mesh_size, bkg_smooth_fwhm,
198 det_eff_gain, det_saturation, resulttype);
199
200
201 cpl_parameterlist *s_param = hdrl_catalogue_parameter_create_parlist(RECIPE_NAME, "catalogue", c_def);
202 hdrl_parameter_delete(c_def) ;
203
204
205 /* Duplicate in the input/output parameterlist the parameters in the catalogue */
206 for (p = cpl_parameterlist_get_first(s_param); p != NULL;
207 p = cpl_parameterlist_get_next(s_param) ) {
208 cpl_parameterlist_append(self, cpl_parameter_duplicate(p));
209 }
210 cpl_parameterlist_delete(s_param);
211
212 cpl_parameter *par;
213
214 /* --hdrldemo_bpm_2d.post-filter-x */
215 par = cpl_parameter_new_value(RECIPE_NAME".post-filter-x", CPL_TYPE_INT,
216 "X Size of the post filtering kernel.", RECIPE_NAME, 21);//3
217 cpl_parameter_set_alias(par, CPL_PARAMETER_MODE_CLI, "pfx");
218 cpl_parameter_disable(par, CPL_PARAMETER_MODE_ENV);
219 cpl_parameterlist_append(self, par);
220
221 /* --hdrldemo_bpm_2d.post-filter-y */
222 par = cpl_parameter_new_value(RECIPE_NAME".post-filter-y", CPL_TYPE_INT,
223 "Y Size of the post filtering kernel.", RECIPE_NAME, 21);//3
224 cpl_parameter_set_alias(par, CPL_PARAMETER_MODE_CLI, "pfy");
225 cpl_parameter_disable(par, CPL_PARAMETER_MODE_ENV);
226 cpl_parameterlist_append(self, par);
227
228 /* --hdrldemo_bpm_2d.post-filter-mode */
229 par = cpl_parameter_new_enum(RECIPE_NAME".post-filter-mode",
230 CPL_TYPE_STRING, "Post filtering mode.", RECIPE_NAME,
231 "dilation", 2, "closing", "dilation");//closing
232 cpl_parameter_set_alias(par, CPL_PARAMETER_MODE_CLI, "pfm");
233 cpl_parameter_disable(par, CPL_PARAMETER_MODE_ENV);
234 cpl_parameterlist_append(self, par);
235
236
237
238
239 return cpl_errorstate_is_equal(prestate) ? CPL_ERROR_NONE
240 : cpl_error_set_where(cpl_func);
241}
242
243/*----------------------------------------------------------------------------*/
250/*----------------------------------------------------------------------------*/
251static int eris_nix_img_supersky(cpl_frameset * frameset,
252 const cpl_parameterlist * parlist)
253{
254 const cpl_parameter * param;
255 const char * combine_method;
256 double sigma_clip;
257 int max_iter;
258 double detect_threshold;
259 double source_fwhm;
260 int min_area;
261 int mask_dilate;
262 cpl_boolean save_skysub;
263 cpl_frameset * product_frames = NULL;
264 cpl_error_code error;
265
266 /* Retrieve input parameters */
267 param = cpl_parameterlist_find_const(parlist,
268 "eris.eris_nix_img_supersky.combine_method");
269 combine_method = cpl_parameter_get_string(param);
270
271 param = cpl_parameterlist_find_const(parlist,
272 "eris.eris_nix_img_supersky.sigma_clip");
273 sigma_clip = cpl_parameter_get_double(param);
274
275 param = cpl_parameterlist_find_const(parlist,
276 "eris.eris_nix_img_supersky.max_iter");
277 max_iter = cpl_parameter_get_int(param);
278
279
280 param = cpl_parameterlist_find_const(parlist,
281 "eris.eris_nix_img_supersky.source_fwhm");
282 source_fwhm = cpl_parameter_get_double(param);
283
284 param = cpl_parameterlist_find_const(parlist,
285 "eris.eris_nix_img_supersky.catalogue.obj.min-pixels");
286 min_area = cpl_parameter_get_int(param);
287
288 param = cpl_parameterlist_find_const(parlist,
289 "eris.eris_nix_img_supersky.catalogue.obj.threshold");
290 detect_threshold = cpl_parameter_get_double(param);
291
292 param = cpl_parameterlist_find_const(parlist,
293 "eris.eris_nix_img_supersky.mask_dilate");
294 mask_dilate = cpl_parameter_get_int(param);
295
296 param = cpl_parameterlist_find_const(parlist,
297 "eris.eris_nix_img_supersky.save_skysub");
298 save_skysub = cpl_parameter_get_bool(param);
299
300 cpl_msg_info(cpl_func, "Recipe parameters:");
301 cpl_msg_info(cpl_func, " combine_method = %s", combine_method);
302 cpl_msg_info(cpl_func, " sigma_clip = %.2f", sigma_clip);
303 cpl_msg_info(cpl_func, " max_iter = %d", max_iter);
304 cpl_msg_info(cpl_func, " detect_threshold = %.2f", detect_threshold);
305 cpl_msg_info(cpl_func, " source_fwhm = %.2f", source_fwhm);
306 cpl_msg_info(cpl_func, " min_area = %d", min_area);
307 cpl_msg_info(cpl_func, " mask_dilate = %d", mask_dilate);
308 cpl_msg_info(cpl_func, " save_skysub = %s", save_skysub ? "TRUE" : "FALSE");
309
310 /* Identify the RAW and CALIB frames in the input frameset */
311 cpl_ensure_code(eris_nix_dfs_set_groups(frameset) == CPL_ERROR_NONE,
312 cpl_error_get_code());
313
314 /* Call the main processing function */
315 error = eris_nix_img_supersky_run(frameset, parlist, RECIPE_NAME, &product_frames);
316
317 if (error != CPL_ERROR_NONE) {
318 cpl_msg_error(cpl_func, "Super-sky creation failed");
319 if (product_frames) cpl_frameset_delete(product_frames);
320 return (int)cpl_error_set_where(cpl_func);
321 }
322
323 cpl_msg_info(cpl_func, "Recipe completed successfully. Generated %lld products",
324 product_frames ? cpl_frameset_get_size(product_frames) : 0);
325
326 if (product_frames) cpl_frameset_delete(product_frames);
327
328 return (int)cpl_error_get_code();
329}
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
hdrl_parameter * hdrl_catalogue_parameter_create(int obj_min_pixels, double obj_threshold, cpl_boolean obj_deblending, double obj_core_radius, cpl_boolean bkg_estimate, int bkg_mesh_size, double bkg_smooth_fwhm, double det_eff_gain, double det_saturation, hdrl_catalogue_options resulttype)
Creates catalogue Parameters object.
cpl_parameterlist * hdrl_catalogue_parameter_create_parlist(const char *base_context, const char *prefix, hdrl_parameter *defaults)
Create parameter list for the catalogue computation.
void hdrl_parameter_delete(hdrl_parameter *obj)
shallow delete of a parameter