GRAVI Pipeline Reference Manual  0.6.3
rrrecipe.c
1 /* $Id: rrrecipe.c,v 1.29 2009/02/10 09:16:12 llundin Exp $
2  *
3  * This file is part of the GRAVI Pipeline
4  * Copyright (C) 2002,2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: llundin $
23  * $Date: 2009/02/10 09:16:12 $
24  * $Revision: 1.29 $
25  * $Name: HEAD $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 /*-----------------------------------------------------------------------------
33  Includes
34  -----------------------------------------------------------------------------*/
35 
36 #include <cpl.h>
37 
38 #include "gravi_utils.h"
39 #include "gravi_pfits.h"
40 #include "gravi_dfs.h"
41 
42 /*-----------------------------------------------------------------------------
43  Private function prototypes
44  -----------------------------------------------------------------------------*/
45 
46 static int rrrecipe_create(cpl_plugin *);
47 static int rrrecipe_exec(cpl_plugin *);
48 static int rrrecipe_destroy(cpl_plugin *);
49 static int rrrecipe(cpl_frameset *, const cpl_parameterlist *);
50 
51 /*-----------------------------------------------------------------------------
52  Static variables
53  -----------------------------------------------------------------------------*/
54 
55 static char rrrecipe_description[] =
56 "This example text is used to describe the recipe.\n"
57 "The description should include the required FITS-files and\n"
58 "their associated tags, e.g.\n"
59 "GRAVI-RRRECIPE-raw-file.fits " RRRECIPE_RAW "\n"
60 "and any optional files, e.g.\n"
61 "GRAVI-RRRECIPE-flat-file.fits " GRAVI_CALIB_FLAT "\n"
62 "\n"
63 "Additionally, it should describe functionality of the expected output."
64 "\n";
65 
66 /*-----------------------------------------------------------------------------
67  Function code
68  -----------------------------------------------------------------------------*/
69 
70 /*----------------------------------------------------------------------------*/
80 /*----------------------------------------------------------------------------*/
81 int cpl_plugin_get_info(cpl_pluginlist * list)
82 {
83  cpl_recipe * recipe = cpl_calloc(1, sizeof *recipe );
84  cpl_plugin * plugin = &recipe->interface;
85 
86  if (cpl_plugin_init(plugin,
87  CPL_PLUGIN_API,
88  GRAVI_BINARY_VERSION,
89  CPL_PLUGIN_TYPE_RECIPE,
90  "rrrecipe",
91  "Short description of rrrecipe",
92  rrrecipe_description,
93  "Firstname Lastname",
94  PACKAGE_BUGREPORT,
95  gravi_get_license(),
96  rrrecipe_create,
97  rrrecipe_exec,
98  rrrecipe_destroy)) {
99  cpl_msg_error(cpl_func, "Plugin initialization failed");
100  (void)cpl_error_set_where(cpl_func);
101  return 1;
102  }
103 
104  if (cpl_pluginlist_append(list, plugin)) {
105  cpl_msg_error(cpl_func, "Error adding plugin to list");
106  (void)cpl_error_set_where(cpl_func);
107  return 1;
108  }
109 
110  return 0;
111 }
112 
113 /*----------------------------------------------------------------------------*/
121 /*----------------------------------------------------------------------------*/
122 static int rrrecipe_create(cpl_plugin * plugin)
123 {
124  cpl_recipe * recipe;
125  cpl_parameter * p;
126 
127  /* Do not create the recipe if an error code is already set */
128  if (cpl_error_get_code() != CPL_ERROR_NONE) {
129  cpl_msg_error(cpl_func, "%s():%d: An error is already set: %s",
130  cpl_func, __LINE__, cpl_error_get_where());
131  return (int)cpl_error_get_code();
132  }
133 
134  if (plugin == NULL) {
135  cpl_msg_error(cpl_func, "Null plugin");
136  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
137  }
138 
139  /* Verify plugin type */
140  if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
141  cpl_msg_error(cpl_func, "Plugin is not a recipe");
142  cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
143  }
144 
145  /* Get the recipe */
146  recipe = (cpl_recipe *)plugin;
147 
148  /* Create the parameters list in the cpl_recipe object */
149  recipe->parameters = cpl_parameterlist_new();
150  if (recipe->parameters == NULL) {
151  cpl_msg_error(cpl_func, "Parameter list allocation failed");
152  cpl_ensure_code(0, (int)CPL_ERROR_ILLEGAL_OUTPUT);
153  }
154 
155  /* Fill the parameters list */
156  /* --stropt */
157  p = cpl_parameter_new_value("gravi.rrrecipe.str_option",
158  CPL_TYPE_STRING, "the string option", "gravi.rrrecipe",NULL);
159  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stropt");
160  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
161  cpl_parameterlist_append(recipe->parameters, p);
162 
163  /* --boolopt */
164  p = cpl_parameter_new_value("gravi.rrrecipe.bool_option",
165  CPL_TYPE_BOOL, "a flag", "gravi.rrrecipe", TRUE);
166  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "boolopt");
167  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
168  cpl_parameterlist_append(recipe->parameters, p);
169 
170  return 0;
171 }
172 
173 /*----------------------------------------------------------------------------*/
179 /*----------------------------------------------------------------------------*/
180 static int rrrecipe_exec(cpl_plugin * plugin)
181 {
182 
183  cpl_recipe * recipe;
184  int recipe_status;
185  cpl_errorstate initial_errorstate = cpl_errorstate_get();
186 
187  /* Return immediately if an error code is already set */
188  if (cpl_error_get_code() != CPL_ERROR_NONE) {
189  cpl_msg_error(cpl_func, "%s():%d: An error is already set: %s",
190  cpl_func, __LINE__, cpl_error_get_where());
191  return (int)cpl_error_get_code();
192  }
193 
194  if (plugin == NULL) {
195  cpl_msg_error(cpl_func, "Null plugin");
196  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
197  }
198 
199  /* Verify plugin type */
200  if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
201  cpl_msg_error(cpl_func, "Plugin is not a recipe");
202  cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
203  }
204 
205  /* Get the recipe */
206  recipe = (cpl_recipe *)plugin;
207 
208  /* Verify parameter and frame lists */
209  if (recipe->parameters == NULL) {
210  cpl_msg_error(cpl_func, "Recipe invoked with NULL parameter list");
211  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
212  }
213  if (recipe->frames == NULL) {
214  cpl_msg_error(cpl_func, "Recipe invoked with NULL frame set");
215  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
216  }
217 
218  /* Invoke the recipe */
219  recipe_status = rrrecipe(recipe->frames, recipe->parameters);
220 
221  /* Ensure DFS-compliance of the products */
222  if (cpl_dfs_update_product_header(recipe->frames)) {
223  if (!recipe_status) recipe_status = (int)cpl_error_get_code();
224  }
225 
226  if (!cpl_errorstate_is_equal(initial_errorstate)) {
227  /* Dump the error history since recipe execution start.
228  At this point the recipe cannot recover from the error */
229  cpl_errorstate_dump(initial_errorstate, CPL_FALSE, NULL);
230  }
231 
232  return recipe_status;
233 }
234 
235 /*----------------------------------------------------------------------------*/
241 /*----------------------------------------------------------------------------*/
242 static int rrrecipe_destroy(cpl_plugin * plugin)
243 {
244  cpl_recipe * recipe;
245 
246  if (plugin == NULL) {
247  cpl_msg_error(cpl_func, "Null plugin");
248  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
249  }
250 
251  /* Verify plugin type */
252  if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
253  cpl_msg_error(cpl_func, "Plugin is not a recipe");
254  cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
255  }
256 
257  /* Get the recipe */
258  recipe = (cpl_recipe *)plugin;
259 
260  cpl_parameterlist_delete(recipe->parameters);
261 
262  return 0;
263 }
264 
265 /*----------------------------------------------------------------------------*/
272 /*----------------------------------------------------------------------------*/
273 static int rrrecipe(cpl_frameset * frameset,
274  const cpl_parameterlist * parlist)
275 {
276  const cpl_parameter * param;
277  const char * str_option;
278  int bool_option;
279  const cpl_frame * rawframe;
280  const cpl_frame * flat;
281  double qc_param;
282  cpl_propertylist * plist;
283  cpl_propertylist * applist;
284  cpl_image * image;
285 
286  /* Use the errorstate to detect an error in a function that does not
287  return an error code. */
288  cpl_errorstate prestate = cpl_errorstate_get();
289 
290  /* HOW TO RETRIEVE INPUT PARAMETERS */
291  /* --stropt */
292  param = cpl_parameterlist_find_const(parlist,
293  "gravi.rrrecipe.str_option");
294  str_option = cpl_parameter_get_string(param);
295 
296  /* --boolopt */
297  param = cpl_parameterlist_find_const(parlist,
298  "gravi.rrrecipe.bool_option");
299  bool_option = cpl_parameter_get_bool(param);
300 
301  if (!cpl_errorstate_is_equal(prestate)) {
302  return (int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
303  "Could not retrieve the input "
304  "parameters");
305  }
306 
307  /* Identify the RAW and CALIB frames in the input frameset */
308  cpl_ensure_code(gravi_dfs_set_groups(frameset) == CPL_ERROR_NONE,
309  cpl_error_get_code());
310 
311  /* HOW TO ACCESS INPUT DATA */
312  /* - A required file */
313  rawframe = cpl_frameset_find_const(frameset, RRRECIPE_RAW);
314  if (rawframe == NULL) {
315  /* cpl_frameset_find_const() does not set an error code, when a frame
316  is not found, so we will set one here. */
317  return (int)cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
318  "SOF does not have any file tagged "
319  "with %s", RRRECIPE_RAW);
320  }
321  /* - A recommended file */
322  flat = cpl_frameset_find(frameset, GRAVI_CALIB_FLAT);
323  if (flat == NULL) {
324  cpl_msg_warning(cpl_func, "SOF does not have any file tagged with %s",
325  GRAVI_CALIB_FLAT);
326  }
327 
328  /* HOW TO GET THE VALUE OF A FITS KEYWORD */
329  /* - Load only DETector related keys */
330  plist = cpl_propertylist_load_regexp(cpl_frame_get_filename(rawframe),
331  0, "ESO DET ", 0);
332  if (plist == NULL) {
333  /* In this case an error message is added to the error propagation */
334  return (int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
335  "Could not read the FITS header");
336  }
337 
338  qc_param = gravi_pfits_get_dit(plist);
339  cpl_propertylist_delete(plist);
340 
341  /* Check for a change in the CPL error state */
342  /* - if it did change then propagate the error and return */
343  cpl_ensure_code(cpl_errorstate_is_equal(prestate), cpl_error_get_code());
344 
345  /* NOW PERFORMING THE DATA REDUCTION */
346  /* Let's just load an image for the example */
347  image = cpl_image_load(cpl_frame_get_filename(rawframe), CPL_TYPE_FLOAT, 0,
348  0);
349  if (image == NULL) {
350  return (int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
351  "Could not load the image");
352  }
353 
354  applist = cpl_propertylist_new();
355 
356  /* Add the product category */
357  cpl_propertylist_append_string(applist, CPL_DFS_PRO_CATG,
358  RRRECIPE_XXX_PROCATG);
359 
360  /* Add a QC parameter */
361  cpl_propertylist_append_double(applist, "ESO QC QCPARAM", qc_param);
362 
363  /* HOW TO SAVE A DFS-COMPLIANT PRODUCT TO DISK */
364  if (cpl_dfs_save_image(frameset, NULL, parlist, frameset, NULL, image,
365  CPL_BPP_IEEE_FLOAT, "rrrecipe", applist,
366  NULL, PACKAGE "/" PACKAGE_VERSION,
367  "rrrecipe.fits")) {
368  /* Propagate the error */
369  (void)cpl_error_set_where(cpl_func);
370  }
371 
372  cpl_image_delete(image);
373  cpl_propertylist_delete(applist);
374 
375  return (int)cpl_error_get_code();
376 }