IIINSTRUMENT Pipeline Reference Manual  0.1.6
rrrecipe.c
1 /* $Id: rrrecipe.c,v 1.33 2013-03-26 17:00:45 jtaylor Exp $
2  *
3  * This file is part of the IIINSTRUMENT 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /*
22  * $Author: jtaylor $
23  * $Date: 2013-03-26 17:00:45 $
24  * $Revision: 1.33 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 /*-----------------------------------------------------------------------------
33  Includes
34  -----------------------------------------------------------------------------*/
35 
36 #include "iiinstrument_utils.h"
37 #include "iiinstrument_pfits.h"
38 #include "iiinstrument_dfs.h"
39 
40 #include <cpl.h>
41 
42 /*-----------------------------------------------------------------------------
43  Plugin registration
44  -----------------------------------------------------------------------------*/
45 
46 int cpl_plugin_get_info(cpl_pluginlist * list);
47 
48 /*-----------------------------------------------------------------------------
49  Private function prototypes
50  -----------------------------------------------------------------------------*/
51 
52 static int rrrecipe_create(cpl_plugin *);
53 static int rrrecipe_exec(cpl_plugin *);
54 static int rrrecipe_destroy(cpl_plugin *);
55 static int rrrecipe(cpl_frameset *, const cpl_parameterlist *);
56 
57 /*-----------------------------------------------------------------------------
58  Static variables
59  -----------------------------------------------------------------------------*/
60 
61 static char rrrecipe_description[] =
62 "This example text is used to describe the recipe.\n"
63 "The description should include the required FITS-files and\n"
64 "their associated tags, e.g.\n"
65 "IIINSTRUMENT-RRRECIPE-raw-file.fits " RRRECIPE_RAW "\n"
66 "and any optional files, e.g.\n"
67 "IIINSTRUMENT-RRRECIPE-flat-file.fits " IIINSTRUMENT_CALIB_FLAT "\n"
68 "\n"
69 "Additionally, it should describe functionality of the expected output."
70 "\n";
71 
72 /*-----------------------------------------------------------------------------
73  Function code
74  -----------------------------------------------------------------------------*/
75 
76 /*----------------------------------------------------------------------------*/
86 /*----------------------------------------------------------------------------*/
87 int cpl_plugin_get_info(cpl_pluginlist * list)
88 {
89  cpl_recipe * recipe = cpl_calloc(1, sizeof *recipe );
90  cpl_plugin * plugin = &recipe->interface;
91 
92  if (cpl_plugin_init(plugin,
93  CPL_PLUGIN_API,
94  IIINSTRUMENT_BINARY_VERSION,
95  CPL_PLUGIN_TYPE_RECIPE,
96  "rrrecipe",
97  "Short description of rrrecipe",
98  rrrecipe_description,
99  "Firstname Lastname",
100  PACKAGE_BUGREPORT,
101  iiinstrument_get_license(),
102  rrrecipe_create,
103  rrrecipe_exec,
104  rrrecipe_destroy)) {
105  cpl_msg_error(cpl_func, "Plugin initialization failed");
106  (void)cpl_error_set_where(cpl_func);
107  return 1;
108  }
109 
110  if (cpl_pluginlist_append(list, plugin)) {
111  cpl_msg_error(cpl_func, "Error adding plugin to list");
112  (void)cpl_error_set_where(cpl_func);
113  return 1;
114  }
115 
116  return 0;
117 }
118 
119 /*----------------------------------------------------------------------------*/
127 /*----------------------------------------------------------------------------*/
128 static int rrrecipe_create(cpl_plugin * plugin)
129 {
130  cpl_recipe * recipe;
131  cpl_parameter * p;
132 
133  /* Do not create the recipe if an error code is already set */
134  if (cpl_error_get_code() != CPL_ERROR_NONE) {
135  cpl_msg_error(cpl_func, "%s():%d: An error is already set: %s",
136  cpl_func, __LINE__, cpl_error_get_where());
137  return (int)cpl_error_get_code();
138  }
139 
140  if (plugin == NULL) {
141  cpl_msg_error(cpl_func, "Null plugin");
142  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
143  }
144 
145  /* Verify plugin type */
146  if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
147  cpl_msg_error(cpl_func, "Plugin is not a recipe");
148  cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
149  }
150 
151  /* Get the recipe */
152  recipe = (cpl_recipe *)plugin;
153 
154  /* Create the parameters list in the cpl_recipe object */
155  recipe->parameters = cpl_parameterlist_new();
156  if (recipe->parameters == NULL) {
157  cpl_msg_error(cpl_func, "Parameter list allocation failed");
158  cpl_ensure_code(0, (int)CPL_ERROR_ILLEGAL_OUTPUT);
159  }
160 
161  /* Fill the parameters list */
162  /* --stropt */
163  p = cpl_parameter_new_value("iiinstrument.rrrecipe.str_option",
164  CPL_TYPE_STRING, "the string option",
165  "iiinstrument.rrrecipe", "NONE");
166  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stropt");
167  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
168  cpl_parameterlist_append(recipe->parameters, p);
169 
170  p = cpl_parameter_new_value("iiinstrument.rrrecipe.file_option",
171  CPL_TYPE_STRING, "the string option",
172  "iiinstrument.rrrecipe", "NONE");
173  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fileopt");
174  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
175  cpl_parameterlist_append(recipe->parameters, p);
176 
177  /* --boolopt */
178  p = cpl_parameter_new_value("iiinstrument.rrrecipe.bool_option",
179  CPL_TYPE_BOOL, "a flag",
180  "iiinstrument.rrrecipe", TRUE);
181  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "boolopt");
182  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
183  cpl_parameterlist_append(recipe->parameters, p);
184 
185  p = cpl_parameter_new_value("iiinstrument.rrrecipe.int_option",
186  CPL_TYPE_INT, "a flag",
187  "iiinstrument.rrrecipe", 3);
188  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "intopt");
189  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
190  cpl_parameterlist_append(recipe->parameters, p);
191 
192  p = cpl_parameter_new_value("iiinstrument.rrrecipe.float_option", CPL_TYPE_DOUBLE,
193  "A float",
194  "Example", 0.5);
195  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "floatopt");
196  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
197  cpl_parameterlist_append(recipe->parameters, p);
198 
199  p = cpl_parameter_new_range("iiinstrument.rrrecipe.range_option", CPL_TYPE_INT,
200  "This is a value range of type int",
201  "Example", 3, 0, 10);
202  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rangeopt");
203  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
204  cpl_parameterlist_append(recipe->parameters, p);
205 
206  p = cpl_parameter_new_enum("iiinstrument.rrrecipe.enum_option", CPL_TYPE_STRING,
207  "This is an enumeration of type " "string",
208  "Example", "first", 3, "first", "second", "third");
209  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "enumopt");
210  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
211  cpl_parameterlist_append(recipe->parameters, p);
212 
213  p = cpl_parameter_new_range("iiinstrument.rrrecipe.float_range_option", CPL_TYPE_DOUBLE,
214  "This is a value range of type float."
215  " Valid ragne is [-5.5, 5.5]",
216  "Example", 3.5, -5.5, 5.5);
217  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "floatrangeopt");
218  cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
219  cpl_parameterlist_append(recipe->parameters, p);
220 
221  return 0;
222 }
223 
224 /*----------------------------------------------------------------------------*/
230 /*----------------------------------------------------------------------------*/
231 static int rrrecipe_exec(cpl_plugin * plugin)
232 {
233 
234  cpl_recipe * recipe;
235  int recipe_status;
236  cpl_errorstate initial_errorstate = cpl_errorstate_get();
237 
238  /* Return immediately if an error code is already set */
239  if (cpl_error_get_code() != CPL_ERROR_NONE) {
240  cpl_msg_error(cpl_func, "%s():%d: An error is already set: %s",
241  cpl_func, __LINE__, cpl_error_get_where());
242  return (int)cpl_error_get_code();
243  }
244 
245  if (plugin == NULL) {
246  cpl_msg_error(cpl_func, "Null plugin");
247  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
248  }
249 
250  /* Verify plugin type */
251  if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
252  cpl_msg_error(cpl_func, "Plugin is not a recipe");
253  cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
254  }
255 
256  /* Get the recipe */
257  recipe = (cpl_recipe *)plugin;
258 
259  /* Verify parameter and frame lists */
260  if (recipe->parameters == NULL) {
261  cpl_msg_error(cpl_func, "Recipe invoked with NULL parameter list");
262  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
263  }
264  if (recipe->frames == NULL) {
265  cpl_msg_error(cpl_func, "Recipe invoked with NULL frame set");
266  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
267  }
268 
269  /* Invoke the recipe */
270  recipe_status = rrrecipe(recipe->frames, recipe->parameters);
271 
272  /* Ensure DFS-compliance of the products */
273  if (cpl_dfs_update_product_header(recipe->frames)) {
274  if (!recipe_status) recipe_status = (int)cpl_error_get_code();
275  }
276 
277  if (!cpl_errorstate_is_equal(initial_errorstate)) {
278  /* Dump the error history since recipe execution start.
279  At this point the recipe cannot recover from the error */
280  cpl_errorstate_dump(initial_errorstate, CPL_FALSE, NULL);
281  }
282 
283  return recipe_status;
284 }
285 
286 /*----------------------------------------------------------------------------*/
292 /*----------------------------------------------------------------------------*/
293 static int rrrecipe_destroy(cpl_plugin * plugin)
294 {
295  cpl_recipe * recipe;
296 
297  if (plugin == NULL) {
298  cpl_msg_error(cpl_func, "Null plugin");
299  cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
300  }
301 
302  /* Verify plugin type */
303  if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
304  cpl_msg_error(cpl_func, "Plugin is not a recipe");
305  cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
306  }
307 
308  /* Get the recipe */
309  recipe = (cpl_recipe *)plugin;
310 
311  cpl_parameterlist_delete(recipe->parameters);
312 
313  return 0;
314 }
315 
316 /*----------------------------------------------------------------------------*/
323 /*----------------------------------------------------------------------------*/
324 static int rrrecipe(cpl_frameset * frameset,
325  const cpl_parameterlist * parlist)
326 {
327  const cpl_parameter * param;
328  const char * str_option;
329  int bool_option;
330  const cpl_frame * rawframe;
331  const cpl_frame * flat;
332  double qc_param;
333  cpl_propertylist * plist;
334  cpl_propertylist * applist;
335  cpl_image * image;
336 
337  /* Use the errorstate to detect an error in a function that does not
338  return an error code. */
339  cpl_errorstate prestate = cpl_errorstate_get();
340 
341  /* HOW TO RETRIEVE INPUT PARAMETERS */
342  /* --stropt */
343  param = cpl_parameterlist_find_const(parlist,
344  "iiinstrument.rrrecipe.str_option");
345  str_option = cpl_parameter_get_string(param);
346 
347  /* --boolopt */
348  param = cpl_parameterlist_find_const(parlist,
349  "iiinstrument.rrrecipe.bool_option");
350  bool_option = cpl_parameter_get_bool(param);
351 
352  if (!cpl_errorstate_is_equal(prestate)) {
353  return (int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
354  "Could not retrieve the input "
355  "parameters");
356  }
357 
358  /* Identify the RAW and CALIB frames in the input frameset */
359  cpl_ensure_code(iiinstrument_dfs_set_groups(frameset) == CPL_ERROR_NONE,
360  cpl_error_get_code());
361 
362  /* HOW TO ACCESS INPUT DATA */
363  /* - A required file */
364  rawframe = cpl_frameset_find_const(frameset, RRRECIPE_RAW);
365  if (rawframe == NULL) {
366  /* cpl_frameset_find_const() does not set an error code, when a frame
367  is not found, so we will set one here. */
368  return (int)cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
369  "SOF does not have any file tagged "
370  "with %s", RRRECIPE_RAW);
371  }
372  /* - A recommended file */
373  flat = cpl_frameset_find(frameset, IIINSTRUMENT_CALIB_FLAT);
374  if (flat == NULL) {
375  cpl_msg_warning(cpl_func, "SOF does not have any file tagged with %s",
376  IIINSTRUMENT_CALIB_FLAT);
377  }
378 
379  /* HOW TO GET THE VALUE OF A FITS KEYWORD */
380  /* - Load only DETector related keys */
381  plist = cpl_propertylist_load_regexp(cpl_frame_get_filename(rawframe),
382  0, "ESO DET ", 0);
383  if (plist == NULL) {
384  /* In this case an error message is added to the error propagation */
385  return (int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
386  "Could not read the FITS header");
387  }
388 
389  qc_param = iiinstrument_pfits_get_dit(plist);
390  cpl_propertylist_delete(plist);
391 
392  /* Check for a change in the CPL error state */
393  /* - if it did change then propagate the error and return */
394  cpl_ensure_code(cpl_errorstate_is_equal(prestate), cpl_error_get_code());
395 
396  /* NOW PERFORMING THE DATA REDUCTION */
397  /* Let's just load an image for the example */
398  image = cpl_image_load(cpl_frame_get_filename(rawframe), CPL_TYPE_FLOAT, 0,
399  0);
400  if (image == NULL) {
401  return (int)cpl_error_set_message(cpl_func, cpl_error_get_code(),
402  "Could not load the image");
403  }
404 
405  applist = cpl_propertylist_new();
406 
407  /* Add the product category */
408  cpl_propertylist_append_string(applist, CPL_DFS_PRO_CATG,
409  RRRECIPE_OUT_PROCATG);
410 
411  /* Add a QC parameter */
412  cpl_propertylist_append_double(applist, "ESO QC QCPARAM", qc_param);
413 
414  /* HOW TO SAVE A DFS-COMPLIANT PRODUCT TO DISK */
415  if (cpl_dfs_save_image(frameset, NULL, parlist, frameset, NULL, image,
416  CPL_BPP_IEEE_FLOAT, "rrrecipe", applist,
417  NULL, PACKAGE "/" PACKAGE_VERSION,
418  "rrrecipe.fits")) {
419  /* Propagate the error */
420  (void)cpl_error_set_where(cpl_func);
421  }
422 
423  cpl_image_delete(image);
424  cpl_propertylist_delete(applist);
425 
426  return (int)cpl_error_get_code();
427 }