EXAM Pipeline Reference Manual  0.1.0
exam_lacosmic.c
1 /*
2  * This file is part of the EXAM Pipeline
3  * Copyright (C) 2002-2014 European Southern Observatory
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 
24 /*-----------------------------------------------------------------------------
25  Includes
26  -----------------------------------------------------------------------------*/
27 
28 #include "exam_dfs.h"
29 #include "exam_utils.h"
30 #include "exam_pfits.h"
31 
32 #include <cpl.h>
33 #include <hdrl.h>
34 
35 /*-----------------------------------------------------------------------------
36  Plugin registration
37  -----------------------------------------------------------------------------*/
38 
39 int cpl_plugin_get_info(cpl_pluginlist * list);
40 
41 /*-----------------------------------------------------------------------------
42  Private function prototypes
43  -----------------------------------------------------------------------------*/
44 
45 static int exam_lacosmic_create(cpl_plugin *);
46 static int exam_lacosmic_exec(cpl_plugin *);
47 static int exam_lacosmic_destroy(cpl_plugin *);
48 static int exam_lacosmic(cpl_frameset *, const cpl_parameterlist *);
49 
50 /*-----------------------------------------------------------------------------
51  Static variables
52  -----------------------------------------------------------------------------*/
53 
54 static char exam_lacosmic_description[] =
55 "This example text is used to describe the recipe.\n"
56 "The description should include the required FITS-files and\n"
57 "their associated tags, e.g.\n"
58 "raw-file.fits RAW\n"
59 "and any optional files, e.g.\n"
60 "flat-file.fits NORM_FLAT\n"
61 "master-bias.fits MASTER_BIAS\n"
62 "bad-pixel-map.fits BPM\n"
63 "\n"
64 "Additionally, it should describe functionality of the expected output."
65 "\n";
66 
67 /*-----------------------------------------------------------------------------
68  Function code
69  -----------------------------------------------------------------------------*/
70 
71 /*----------------------------------------------------------------------------*/
81 /*----------------------------------------------------------------------------*/
82 int cpl_plugin_get_info(cpl_pluginlist * list)
83 {
84  cpl_recipe * recipe = cpl_calloc(1, sizeof *recipe );
85  cpl_plugin * plugin = &recipe->interface;
86 
87  if (cpl_plugin_init(plugin,
88  CPL_PLUGIN_API,
89  EXAM_BINARY_VERSION,
90  CPL_PLUGIN_TYPE_RECIPE,
91  "exam_lacosmic",
92  "Short description of exam_lacosmic",
93  exam_lacosmic_description,
94  "Firstname Lastname",
95  PACKAGE_BUGREPORT,
96  exam_get_license(),
97  exam_lacosmic_create,
98  exam_lacosmic_exec,
99  exam_lacosmic_destroy)) {
100  cpl_msg_error(cpl_func, "Plugin initialization failed");
101  (void)cpl_error_set_where(cpl_func);
102  return 1;
103  }
104 
105  if (cpl_pluginlist_append(list, plugin)) {
106  cpl_msg_error(cpl_func, "Error adding plugin to list");
107  (void)cpl_error_set_where(cpl_func);
108  return 1;
109  }
110 
111  return 0;
112 }
113 
114 /*----------------------------------------------------------------------------*/
122 /*----------------------------------------------------------------------------*/
123 static int exam_lacosmic_create(cpl_plugin * plugin)
124 {
125  cpl_recipe * recipe;
126  cpl_parameter * p;
127 
128  /* Do not create the recipe if an error code is already set */
129  if (cpl_error_get_code() != CPL_ERROR_NONE) {
130  cpl_msg_error(cpl_func, "%s():%d: An error is already set: %s",
131  cpl_func, __LINE__, cpl_error_get_where());
132  return (int)cpl_error_get_code();
133  }
134 
135  if (plugin == NULL) {
136  cpl_msg_error(cpl_func, "Null plugin");
137  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
138  }
139 
140  /* Verify plugin type */
141  if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
142  cpl_msg_error(cpl_func, "Plugin is not a recipe");
143  cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
144  }
145 
146  /* Get the recipe */
147  recipe = (cpl_recipe *)plugin;
148 
149  /* Create the parameters list in the cpl_recipe object */
150  recipe->parameters = cpl_parameterlist_new();
151  if (recipe->parameters == NULL) {
152  cpl_msg_error(cpl_func, "Parameter list allocation failed");
153  cpl_ensure_code(0, (int)CPL_ERROR_ILLEGAL_OUTPUT);
154  }
155 
156  hdrl_parameter * plac = hdrl_lacosmic_parameter_create(5, 2, 5);
157  cpl_parameterlist * lac_plist =
158  hdrl_lacosmic_parameter_create_parlist("exam.exam_lacosmic", "", plac);
159  hdrl_parameter_delete(plac) ;
160  for (cpl_parameter * p = cpl_parameterlist_get_first(lac_plist);
161  p != NULL; p = cpl_parameterlist_get_next(lac_plist))
162  cpl_parameterlist_append(recipe->parameters, cpl_parameter_duplicate(p));
163  cpl_parameterlist_delete(lac_plist);
164 
165  return 0;
166 }
167 
168 /*----------------------------------------------------------------------------*/
174 /*----------------------------------------------------------------------------*/
175 static int exam_lacosmic_exec(cpl_plugin * plugin)
176 {
177 
178  cpl_recipe * recipe;
179  int recipe_status;
180  cpl_errorstate initial_errorstate = cpl_errorstate_get();
181 
182  /* Return immediately if an error code is already set */
183  if (cpl_error_get_code() != CPL_ERROR_NONE) {
184  cpl_msg_error(cpl_func, "%s():%d: An error is already set: %s",
185  cpl_func, __LINE__, cpl_error_get_where());
186  return (int)cpl_error_get_code();
187  }
188 
189  if (plugin == NULL) {
190  cpl_msg_error(cpl_func, "Null plugin");
191  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
192  }
193 
194  /* Verify plugin type */
195  if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
196  cpl_msg_error(cpl_func, "Plugin is not a recipe");
197  cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
198  }
199 
200  /* Get the recipe */
201  recipe = (cpl_recipe *)plugin;
202 
203  /* Verify parameter and frame lists */
204  if (recipe->parameters == NULL) {
205  cpl_msg_error(cpl_func, "Recipe invoked with NULL parameter list");
206  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
207  }
208  if (recipe->frames == NULL) {
209  cpl_msg_error(cpl_func, "Recipe invoked with NULL frame set");
210  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
211  }
212 
213  /* Invoke the recipe */
214  recipe_status = exam_lacosmic(recipe->frames, recipe->parameters);
215 
216  /* Ensure DFS-compliance of the products */
217  if (cpl_dfs_update_product_header(recipe->frames)) {
218  if (!recipe_status) recipe_status = (int)cpl_error_get_code();
219  }
220 
221  if (!cpl_errorstate_is_equal(initial_errorstate)) {
222  /* Dump the error history since recipe execution start.
223  At this point the recipe cannot recover from the error */
224  cpl_errorstate_dump(initial_errorstate, CPL_FALSE, NULL);
225  }
226 
227  return recipe_status;
228 }
229 
230 /*----------------------------------------------------------------------------*/
236 /*----------------------------------------------------------------------------*/
237 static int exam_lacosmic_destroy(cpl_plugin * plugin)
238 {
239  cpl_recipe * recipe;
240 
241  if (plugin == NULL) {
242  cpl_msg_error(cpl_func, "Null plugin");
243  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
244  }
245 
246  /* Verify plugin type */
247  if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
248  cpl_msg_error(cpl_func, "Plugin is not a recipe");
249  cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
250  }
251 
252  /* Get the recipe */
253  recipe = (cpl_recipe *)plugin;
254 
255  cpl_parameterlist_delete(recipe->parameters);
256 
257  return 0;
258 }
259 
260 /*----------------------------------------------------------------------------*/
267 /*----------------------------------------------------------------------------*/
268 static int exam_lacosmic(cpl_frameset * frameset,
269  const cpl_parameterlist * parlist)
270 {
271  const cpl_parameter * param;
272  const char * str_option;
273  int bool_option;
274  const cpl_frame * rawframe;
275  const cpl_frame * flat_fs;
276  const cpl_frame * bpm_fs;
277  const cpl_frame * bias_fs;
278  cpl_propertylist * plist;
279  cpl_propertylist * applist;
280  cpl_image * image;
281 
282  /* Use the errorstate to detect an error in a function that does not
283  return an error code. */
284  cpl_errorstate prestate = cpl_errorstate_get();
285 
286  /* create an initialized hdrl parameter from the commandline input of the
287  * esorex recipe call */
288  hdrl_parameter * plac =
289  hdrl_lacosmic_parameter_parse_parlist(parlist,
290  "exam.exam_lacosmic");
291 
292  if (!cpl_errorstate_is_equal(prestate)) {
293  return cpl_error_get_code();
294  }
295 
296  /* Identify the RAW and CALIB frames in the input frameset */
297  cpl_ensure_code(exam_dfs_set_groups(frameset) == CPL_ERROR_NONE,
298  cpl_error_get_code());
299 
300  /* HOW TO ACCESS INPUT DATA */
301  /* - A required file */
302  rawframe = cpl_frameset_find_const(frameset, "RAW");
303  if (rawframe == NULL) {
304  /* cpl_frameset_find_const() does not set an error code, when a frame
305  is not found, so we will set one here. */
306  return (int)cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
307  "SOF does not have any file tagged "
308  "with RAW");
309  }
310  /* - A recommended file */
311  flat_fs = cpl_frameset_find(frameset, "NORM_FLAT");
312  if (flat_fs == NULL) {
313  cpl_msg_warning(cpl_func,
314  "SOF does not have any file tagged with NORM_FLAT,"
315  "not performing flat correction");
316  }
317 
318  /* - A recommended file */
319  bpm_fs = cpl_frameset_find(frameset, "BPM");
320 
321  /* - A recommended file */
322  bias_fs = cpl_frameset_find(frameset, "MASTER_BIAS");
323  if (bias_fs == NULL) {
324  cpl_msg_warning(cpl_func,
325  "SOF does not have any file tagged with MASTER_BIAS,"
326  "not performing bias correction");
327  }
328 
329  /* Check for a change in the CPL error state */
330  /* - if it did change then propagate the error and return */
331  cpl_ensure_code(cpl_errorstate_is_equal(prestate), cpl_error_get_code());
332 
333  /* NOW PERFORMING THE DATA REDUCTION */
334  /* Let's just load an image for the example */
335  image =
336  cpl_image_load(cpl_frame_get_filename(rawframe), CPL_TYPE_FLOAT, 0, 0);
337  if (image == NULL) {
338  return (int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
339  "Could not load the image");
340  }
341 
342  /* load optional bad pixel map */
343  if (bpm_fs) {
344  cpl_mask * bpm = cpl_mask_load(cpl_frame_get_filename(bpm_fs), 0, 0);
345  if (bpm == NULL) {
346  return (int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
347  "Could not load the bpm");
348  }
349  cpl_image_reject_from_mask(image, bpm);
350  cpl_mask_delete(bpm);
351  }
352 
353  /* create hdrl image that also carries error information */
354  hdrl_image * science_himg_raw = hdrl_image_create(image, NULL);
355  /* delete cpl image, hdrl_image made copy */
356  cpl_image_delete(image);
357 
358  /* add a constant error to the image for illustration purposes */
359  hdrl_image_add_scalar(science_himg_raw, (hdrl_value){0., 10.});
360 
361  /* apply bias correction */
362  if (bias_fs) {
363  cpl_image * bias_img =
364  cpl_image_load(cpl_frame_get_filename(bias_fs),
365  CPL_TYPE_FLOAT, 0, 0);
366  if (bias_img == NULL) {
367  return (int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
368  "Could not load the bias");
369  }
370  hdrl_image * bias_himg = hdrl_image_create(bias_img, NULL);
371  /* use standard deviation as its error */
372  hdrl_image_add_scalar(bias_himg,
373  (hdrl_value){0, cpl_image_get_stdev(bias_img)});;
374  /* delete cpl image, hdrl_image made copy */
375  cpl_image_delete(bias_img);
376 
377  cpl_msg_info(cpl_func, "Applying bias to science image");
378  /* apply bias to science image with error propagation */
379  hdrl_image_sub_image(science_himg_raw, bias_himg);
380  hdrl_image_delete(bias_himg);
381  }
382 
383  /* apply flat correction */
384  if (flat_fs) {
385  cpl_image * flat_img =
386  cpl_image_load(cpl_frame_get_filename(flat_fs),
387  CPL_TYPE_FLOAT, 0, 0);
388  if (flat_img == NULL) {
389  return (int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
390  "Could not load the flat");
391  }
392  hdrl_image * flat_himg = hdrl_image_create(flat_img, NULL);
393  /* delete cpl image, hdrl_image made copy */
394  cpl_image_delete(flat_img);
395 
396  cpl_msg_info(cpl_func, "Applying flat to science image");
397  /* apply flat to science image with error propagation */
398  hdrl_image_div_image(science_himg_raw, flat_himg);
399  hdrl_image_delete(flat_himg);
400  }
401 
402  /* trim overscan regions */
403  hdrl_image * science_himg =
404  hdrl_image_extract(science_himg_raw, 1, 6, 0, -5);
405  hdrl_image_delete(science_himg_raw);
406 
407  cpl_msg_info(cpl_func, "Performing cosmic ray detection");
408  cpl_mask * cmap = hdrl_lacosmic_edgedetect(science_himg, plac);
409  cpl_msg_info(cpl_func, "%lld cosmic pixels found", cpl_mask_count(cmap));
410  hdrl_parameter_delete(plac);
411 
412  applist = cpl_propertylist_new();
413 
414  /* interpolate cosmics */
415  image = hdrl_image_get_image(science_himg);
416  cpl_image_reject_from_mask(image, cmap);
417  cpl_detector_interpolate_rejected(image);
418 
419  /* Add a QC parameter */
420  cpl_propertylist_append_int(applist, "ESO QC NCOSMICPIX",
421  cpl_mask_count(cmap));
422 
423  /* Add the product category */
424  cpl_propertylist_append_string(applist, CPL_DFS_PRO_CATG,
425  "COSMIC_REMOVED");
426 
427  /* HOW TO SAVE A DFS-COMPLIANT PRODUCT TO DISK */
428  if (cpl_dfs_save_image(frameset, NULL, parlist, frameset, NULL, image,
429  CPL_TYPE_FLOAT, "exam_lacosmic", applist,
430  NULL, PACKAGE "/" PACKAGE_VERSION,
431  "exam_lacosmic.fits")) {
432  /* Propagate the error */
433  (void)cpl_error_set_where(cpl_func);
434  }
435 
436  /* store the image error in an extension */
437  cpl_propertylist * eplist = cpl_propertylist_new();
438  cpl_propertylist_append_string(eplist, "EXTNAME", "ERROR");
439  cpl_image_save(hdrl_image_get_error(science_himg), "exam_lacosmic.fits",
440  CPL_TYPE_FLOAT, eplist, CPL_IO_EXTEND);
441  cpl_propertylist_delete(eplist);
442 
443  /* Add the product category */
444  cpl_propertylist_update_string(applist, CPL_DFS_PRO_CATG,
445  "COSMIC_MASK");
446  cpl_image * cmap_img = cpl_image_new_from_mask(cmap);
447  cpl_mask_delete(cmap);
448  if (cpl_dfs_save_image(frameset, NULL, parlist, frameset, NULL, cmap_img,
449  CPL_TYPE_UCHAR, "exam_lacosmic", applist,
450  NULL, PACKAGE "/" PACKAGE_VERSION,
451  "exam_lacosmic_cmap.fits")) {
452  /* Propagate the error */
453  (void)cpl_error_set_where(cpl_func);
454  }
455 
456  hdrl_image_delete(science_himg);
457  cpl_image_delete(cmap_img);
458  cpl_propertylist_delete(applist);
459 
460  return (int)cpl_error_get_code();
461 }
int cpl_plugin_get_info(cpl_pluginlist *list)
Build the list of available plugins, for this module.
Definition: exam_flat.c:103