38#include "eris_nix_utils.h"
39#include "eris_nix_lss_utils.h"
40#include "eris_nix_dfs.h"
41#include "eris_utils.h"
49static const char eris_nix_lss_skysub_description[] =
50"This recipe estimates and subtracts the sky background from a set of \n"
51ERIS_NIX_CAL_DET_OBJECT_LSS_JITTER_PRO_CATG
" or "
52ERIS_NIX_CAL_DET_STD_LSS_JITTER_PRO_CATG
" frames.\n"
56" The recipe has 2 modes of operation.\n"
57" If --sky-source='target' then the sky background will be estimated \n"
58" from the target frames themselves.\n"
60" DO CATG Explanation Req. #Frames\n"
61" ------- ----------- --- -------\n"
62" "ERIS_NIX_CAL_DET_OBJECT_LSS_JITTER_PRO_CATG
63 " target frames with the Y 1-n\n"
64" or detector signature\n"
65" "ERIS_NIX_CAL_DET_STD_LSS_JITTER_PRO_CATG
68" If --sky-source='offset' and for "
69ERIS_NIX_CAL_DET_OBJECT_LSS_JITTER_PRO_CATG
"\n"
70" data only, the sky background will be estimated from a set of \n"
71" frames offset from the target region.\n"
73" DO CATG Explanation Req. #Frames\n"
74" ------- ----------- --- -------\n"
75" "ERIS_NIX_CAL_DET_OBJECT_LSS_JITTER_PRO_CATG
76 " target frames with the Y 1-n\n"
77" detector signature\n"
79" "ERIS_NIX_CAL_DET_SKY_LSS_JITTER_PRO_CATG
80 " sky frames with the Y 1-m\n"
81" detector signature\n"
86" DO CATG Explanation \n"
87" ------- ----------- \n"
88" "ERIS_NIX_SKYSUB_OBJECT_LSS_JITTER_PRO_CATG
89 " target frames with the sky removed.\n"
91" "ERIS_NIX_SKYSUB_STD_LSS_JITTER_PRO_CATG
"\n"
93" The output will be FITS files named 'skysub.<input filename>',\n"
94" containing extensions:\n"
95" - DATA, with the target data.\n"
96" - ERR, with the target error plane.\n"
97" - DQ, with the target data quality plane.\n"
98" - CONFIDENCE, with the target confidence plane.\n"
99" - BKG_DATA, with the estimated sky background.\n"
100" - BKG_ERR, with the error on the sky background.\n"
101" - BKG_CONF, with the confidence of the sky background.\n"
103"Notes on the method.\n"
104" Sky frames are taken from the pool of target or offset\n"
105" according to param --sky-source.\n"
107" The background for each frame is estimated from sky frames\n"
108" taken within sky-bracket-time/2 seconds of it.\n"
110" A first estimate of the background is made.\n"
111" If param --sky-method='collapse-median':\n"
112" - The estimate is a median collapse of the sky frames\n"
113" selected. This is prone to problems if the field is\n"
115" If --sky-method='median-median':\n"
116" - The median of each sky frame is obtained, and the\n"
117" background frame set at the median of those values.\n"
118" The background is forced to be flat, which is more\n"
119" robust in crowded fields, or where there is\n"
122" The estimated backgrounds are subtracted from the sky\n"
123" frames, and a search made for objects in each image.\n"
124" Object masks are constructed which blank out astronomical\n"
125" flux the sky frames. The --catalogue.xxx params listed\n"
126" below are used in this search for objects.\n"
128" The masked sky frames are then used to re-estimate the\n"
129" sky backgrounds following the same sky-method.\n";
132#define RECIPE_NAME "eris.eris_nix_lss_skysub"
138cpl_recipe_define(eris_nix_lss_skysub, ERIS_BINARY_VERSION,
140 PACKAGE_BUGREPORT,
"2017",
141 "Subtract sky background from LSS frames",
142 eris_nix_lss_skysub_description);
158static cpl_error_code eris_nix_lss_skysub_fill_parameterlist(
159 cpl_parameterlist * self) {
161 if (cpl_error_get_code() != CPL_ERROR_NONE)
return cpl_error_get_code();
163 cpl_parameter * p = NULL;
167 p = cpl_parameter_new_enum(RECIPE_NAME
".sky-source", CPL_TYPE_STRING,
168 "data to be used for calculation of sky "
169 "background", RECIPE_NAME,
170 "auto", 3,
"auto",
"target",
"offset");
171 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sky-source");
172 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
173 cpl_parameterlist_append(self, p);
175 p = cpl_parameter_new_enum(RECIPE_NAME
".sky-selector", CPL_TYPE_STRING,
176 "method for selecting sky frames",
177 RECIPE_NAME,
"bracket", 1,
"bracket");
178 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sky-selector");
179 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
180 cpl_parameterlist_append(self, p);
182 p = cpl_parameter_new_range(RECIPE_NAME
".sky-bracket-time", CPL_TYPE_DOUBLE,
183 "2 * max.time between target and sky measurement",
184 RECIPE_NAME, 1800.0, 60.0, 18000.0);
185 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sky-bracket-time");
186 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
187 cpl_parameterlist_append(self, p);
189 p = cpl_parameter_new_value(RECIPE_NAME
".premask_objects",
191 "create object masks before background estimation",
192 RECIPE_NAME, CPL_TRUE);
193 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"premask-objects");
194 cpl_parameterlist_append(self, p);
196 p = cpl_parameter_new_value(RECIPE_NAME
".premask_nsigma",
198 "sigma cutoff for premask object detection",
200 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"premask-nsigma");
201 cpl_parameterlist_append(self, p);
203 p = cpl_parameter_new_value(RECIPE_NAME
".debug-data",
204 CPL_TYPE_BOOL,
"true to save interim results",
205 RECIPE_NAME, CPL_FALSE);
206 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"debug-data");
207 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
208 cpl_parameterlist_append(self, p);
212 p = cpl_parameter_new_value(RECIPE_NAME
".x_probe", CPL_TYPE_INT,
213 "x coord of diagnostic pixel",
215 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"x-probe");
216 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
217 cpl_parameterlist_append(self, p);
219 p = cpl_parameter_new_value(RECIPE_NAME
".y_probe", CPL_TYPE_INT,
220 "y coord of diagnostic pixel",
222 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"y-probe");
223 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
224 cpl_parameterlist_append(self, p);
239static int eris_nix_lss_skysub(cpl_frameset * frameset,
240 const cpl_parameterlist * parlist) {
242 located_imagelist * object_jitters = NULL;
243 const char * out_tag = NULL;
244 const cpl_parameter * p = NULL;
245 located_imagelist * sky_jitters = NULL;
246 located_imagelist * std_jitters = NULL;
247 located_imagelist * target_jitters = NULL;
248 cpl_frameset * used_frameset = NULL;
250 enu_check_error_code(
"%s():%d: An error is already set: %s",
251 cpl_func, __LINE__, cpl_error_get_where());
255 cpl_ensure_code(frameset, CPL_ERROR_NULL_INPUT);
256 cpl_ensure_code(parlist, CPL_ERROR_NULL_INPUT);
260 cpl_msg_set_level_from_env();
261 cpl_msg_severity severity = cpl_msg_get_level();
262 cpl_msg_info(cpl_func,
"level %d", (
int) severity);
266 return CPL_ERROR_BAD_FILE_FORMAT;
270 p = cpl_parameterlist_find_const(parlist, RECIPE_NAME
".sky-source");
271 const char * sky_source = cpl_parameter_get_string(p);
272 p = cpl_parameterlist_find_const(parlist, RECIPE_NAME
".sky-selector");
273 const char * sky_selector = cpl_parameter_get_string(p);
274 p = cpl_parameterlist_find_const(parlist, RECIPE_NAME
".sky-bracket-time");
275 const double sky_time_range = cpl_parameter_get_double(p);
276 p = cpl_parameterlist_find_const(parlist, RECIPE_NAME
".premask_objects");
277 int premask_objects = cpl_parameter_get_bool(p);
278 p = cpl_parameterlist_find_const(parlist, RECIPE_NAME
".premask_nsigma");
279 double premask_nsigma = cpl_parameter_get_double(p);
284 p = cpl_parameterlist_find_const(parlist, RECIPE_NAME
".x_probe");
285 cpl_size x_probe = (cpl_size) cpl_parameter_get_int(p);
286 p = cpl_parameterlist_find_const(parlist, RECIPE_NAME
".y_probe");
287 cpl_size y_probe = (cpl_size) cpl_parameter_get_int(p);
289 enu_check_error_code(
"Could not retrieve input parameters");
294 enu_check_error_code(
"Could not identify RAW and CALIB frames");
296 used_frameset = cpl_frameset_new();
302 ERIS_NIX_CAL_DET_OBJECT_LSS_JITTER_PRO_CATG,
305 ERIS_NIX_CAL_DET_SKY_LSS_JITTER_PRO_CATG, used_frameset);
307 ERIS_NIX_CAL_DET_STD_LSS_JITTER_PRO_CATG, used_frameset);
308 enu_check_error_code(
"Could not load input frames");
310 cpl_msg_info(cpl_func,
"%d "
311 ERIS_NIX_CAL_DET_OBJECT_LSS_JITTER_PRO_CATG
" frames read",
312 (
int) object_jitters->size);
313 cpl_msg_info(cpl_func,
"%d "
314 ERIS_NIX_CAL_DET_SKY_LSS_JITTER_PRO_CATG
" frames read",
315 (
int) sky_jitters->size);
316 cpl_msg_info(cpl_func,
"%d "
317 ERIS_NIX_CAL_DET_STD_LSS_JITTER_PRO_CATG
" frames read",
318 (
int) std_jitters->size);
322 enu_check(!(object_jitters->size == 0 && std_jitters->size == 0),
323 CPL_ERROR_DATA_NOT_FOUND,
"SoF contains no "
324 ERIS_NIX_CAL_DET_OBJECT_LSS_JITTER_PRO_CATG
" or "
325 ERIS_NIX_CAL_DET_STD_LSS_JITTER_PRO_CATG
" frames");
326 enu_check(!(object_jitters->size > 0 && std_jitters->size > 0),
327 CPL_ERROR_ILLEGAL_INPUT,
"SoF contains both "
328 ERIS_NIX_CAL_DET_OBJECT_LSS_JITTER_PRO_CATG
" and "
329 ERIS_NIX_CAL_DET_STD_LSS_JITTER_PRO_CATG
" frames");
330 enu_check(!(!strcmp(sky_source,
"offset") && sky_jitters->size==0),
331 CPL_ERROR_INCOMPATIBLE_INPUT,
332 "offset sky position requested but no"
333 ERIS_NIX_CAL_DET_SKY_LSS_JITTER_PRO_CATG
" in sof");
337 if (object_jitters->size > 0) {
338 target_jitters = object_jitters;
339 out_tag = ERIS_NIX_SKYSUB_OBJECT_LSS_JITTER_PRO_CATG;
340 }
else if (std_jitters->size > 0) {
341 target_jitters = std_jitters;
342 out_tag = ERIS_NIX_SKYSUB_STD_LSS_JITTER_PRO_CATG;
348 if (!strcmp(sky_source,
"auto")) {
349 if (sky_jitters->size > 0) {
350 sky_source =
"offset";
352 sky_source =
"target";
354 cpl_msg_info(cpl_func,
"sky-source=='auto', resetting to '%s'",
358 if (!strcmp(sky_source,
"offset")) {
360 if (premask_objects) {
371 cpl_msg_info(cpl_func,
"Estimating sky background with source blanking ...");
373 sky_jitters, x_probe, y_probe,
375 enu_check_error_code(
"error in sky background subtraction");
377 }
else if (!strcmp(sky_source,
"target")) {
386 cpl_msg_info(cpl_func,
"Estimating sky background:");
387 if (premask_objects) {
395 sky_time_range, target_jitters,
396 x_probe, y_probe, target_jitters);
397 enu_check_error_code(
"error in sky background: sky-subtract");
400 enu_check_error_code(
"failed to remove sky background");
408 for (cpl_size i = 0; i < target_jitters->size; i++) {
409 cpl_propertylist * applist = cpl_propertylist_new();
410 cpl_propertylist_update_string(applist, CPL_DFS_PRO_CATG, out_tag);
411 cpl_propertylist_update_string(applist,
"PRODCATG",
"ANCILLARY.IMAGE");
416 target_jitters->limages[i]->frame),
422 target_jitters->limages[i],
424 target_jitters->limages[i]->frame,
426 PACKAGE
"/" PACKAGE_VERSION,
430 cpl_propertylist_delete(applist);
437 cpl_frameset_delete(used_frameset);
439 return (
int) cpl_error_get_code();
cpl_error_code enu_dfs_save_limage(cpl_frameset *allframes, const cpl_parameterlist *parlist, const cpl_frameset *provenance, const cpl_boolean prov_raw, const located_image *limage, const char *recipe, const cpl_frame *inherit, cpl_propertylist *applist, const char *pipe_id, const char *filename)
Save a located image structure to a MEF.
cpl_error_code eris_nix_dfs_set_groups(cpl_frameset *set)
Set the group as RAW or CALIB in a frameset.
cpl_error_code enlu_divide_slit_response(located_imagelist *jitters)
Divide LSS 2d-spectra by the slit response.
void enu_located_imagelist_delete(located_imagelist *limlist)
Delete a located_imagelist and its contents.
cpl_error_code enu_opm_lss_limlist(located_imagelist *limlist, const int nsigma_cut)
Calculate object masks for LSS images in a located_imagelist.
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.
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.
char * enu_repreface(const char *filename, const char *preface)
Preface a raw filename with a string.
cpl_error_code eris_files_dont_exist(cpl_frameset *frameset)
Check if all SOF files exist.