MUSE Pipeline Reference Manual  2.1.1
muse_processinginfo.c
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set sw=2 sts=2 et cin: */
3 /*
4  * This file is part of the MUSE Instrument Pipeline
5  * Copyright (C) 2005-2013 European Southern Observatory
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 /*----------------------------------------------------------------------------*
27  * Includes *
28  *----------------------------------------------------------------------------*/
29 #include <stdio.h>
30 #include <string.h>
31 #include <math.h>
32 #include <cpl.h>
33 
34 #include "muse_processing.h"
35 
36 #include "muse_utils.h"
37 
38 /*---------------------------------------------------------------------------*/
42 /*---------------------------------------------------------------------------*/
43 
46 /*----------------------------------------------------------------------------*
47  * Static variables *
48  *----------------------------------------------------------------------------*/
49 /*---------------------------------------------------------------------------*/
53 /*---------------------------------------------------------------------------*/
54 typedef struct muse_processinginfo_s {
55  struct muse_processinginfo_s *prev;
56  struct muse_processinginfo_s *next;
57  cpl_recipe *plugin;
58  cpl_recipeconfig *recipeconfig;
60  muse_processing_prepare_header_func *prepare_header;
62  muse_processing_get_frame_level_func *get_frame_level;
64  muse_processing_get_frame_mode_func *get_frame_mode;
66 
67 /*---------------------------------------------------------------------------*/
71 /*---------------------------------------------------------------------------*/
73 
74 /*---------------------------------------------------------------------------*/
78 /*---------------------------------------------------------------------------*/
79 
80 static muse_processinginfo_t *
81 muse_processinginfo_get(const cpl_recipe *aRecipe) {
82  if (muse_processinginfo != NULL) {
84  for (m = muse_processinginfo; m != NULL; m = m->next) {
85  if (m->plugin == aRecipe) {
86  return m;
87  }
88  }
89  }
90  return NULL;
91 }
92 
93 /*---------------------------------------------------------------------------*/
105 /*---------------------------------------------------------------------------*/
106 void
108 ( cpl_recipe *plugin,
109  cpl_recipeconfig *recipeconfig,
110  muse_processing_prepare_header_func *prepare_header,
111  muse_processing_get_frame_level_func *get_frame_level,
112  muse_processing_get_frame_mode_func *get_frame_mode) {
113 
115  if (muse_processinginfo == NULL) {
116  muse_processinginfo = cpl_calloc(1, sizeof(muse_processinginfo_t));
118  } else {
119  while (m->next != NULL) {
120  m = m->next;
121  }
122  m->next = cpl_calloc(1, sizeof(muse_processinginfo_t));
123  m->next->prev = m;
124  m = m->next;
125  }
126  m->plugin = plugin;
127  m->recipeconfig = recipeconfig;
128  m->prepare_header = prepare_header;
129  m->get_frame_level = get_frame_level;
130  m->get_frame_mode = get_frame_mode;
131 }
132 
133 /*---------------------------------------------------------------------------*/
141 /*---------------------------------------------------------------------------*/
142 void
143 muse_processinginfo_delete(cpl_recipe *aRecipe) {
145  if (m == NULL) {
146  return;
147  }
148  if (m == muse_processinginfo) {
149  muse_processinginfo = m->next;
150  if (muse_processinginfo != NULL) {
151  muse_processinginfo->prev = NULL;
152  }
153  } else {
154  m->prev->next = m->next;
155  if (m->next != NULL) {
156  m->next->prev = m->prev;
157  }
158  }
159  cpl_recipeconfig_delete(m->recipeconfig);
160  cpl_free(m);
161 }
162 
163 /*---------------------------------------------------------------------------*/
171 /*---------------------------------------------------------------------------*/
172 cpl_error_code muse_processing_prepare_header(const cpl_recipe *aRecipe,
173  const char *aFrametag,
174  cpl_propertylist *aHeader) {
176  return (m != NULL)? (* m->prepare_header)(aFrametag, aHeader): CPL_ERROR_NONE;
177 }
178 
179 /*---------------------------------------------------------------------------*/
186 /*---------------------------------------------------------------------------*/
187 cpl_frame_level
188 muse_processing_get_frame_level(const cpl_recipe *aRecipe,
189  const char *aFrametag) {
191  return (m != NULL)? (* m->get_frame_level)(aFrametag): CPL_FRAME_LEVEL_NONE;
192 }
193 
194 /*---------------------------------------------------------------------------*/
201 /*---------------------------------------------------------------------------*/
202 int
203 muse_processing_get_frame_mode(const cpl_recipe *aRecipe,
204  const char *aFrametag) {
206  return (m != NULL)?(* m->get_frame_mode)(aFrametag): MUSE_FRAME_MODE_ALL;
207 }
208 
209 /*---------------------------------------------------------------------------*/
215 /*---------------------------------------------------------------------------*/
216 cpl_recipeconfig *
217 muse_processing_get_recipeconfig(cpl_recipe *aRecipe) {
219  return (m != NULL)?m->recipeconfig: NULL;
220 }
221 
222 /*---------------------------------------------------------------------------*/
238 /*---------------------------------------------------------------------------*/
239 cpl_error_code
240 muse_processing_prepare_property(cpl_propertylist *aHeader, const char *aName,
241  cpl_type aType, const char *aDescription)
242 {
243  cpl_ensure_code(aHeader, CPL_ERROR_NULL_INPUT);
244  cpl_ensure_code(aName, CPL_ERROR_NULL_INPUT);
245 
246  cpl_error_code rc = CPL_ERROR_NONE;
247 
248  cpl_propertylist *list = cpl_propertylist_new();
249  cpl_propertylist_copy_property_regexp(list, aHeader, aName, 0);
250  if (cpl_propertylist_is_empty(list)) {
251  cpl_propertylist_delete(list);
252 
253  // The tag MUSE PRIVATE DOCUMENTATION is set in xmldoc.c and checked
254  // here:
255  // If it is not set (the normal case in a recipe), just an error
256  // message is generated in case of a missing header.
257  // If the description contains the string "(optional)", the property may not
258  // be present, but this failure should be ignored.
259  if (!cpl_propertylist_has(aHeader, "MUSE PRIVATE DOCUMENTATION") &&
260  (aDescription && !strstr(aDescription, "(optional)"))) {
261  cpl_msg_warning(__func__, "Property %s (%s) not used", aName,
262  aDescription);
263  return CPL_ERROR_DATA_NOT_FOUND;
264  }
265  // If this property is set (if the function is used from
266  // muse_xmldoc), then we add missing headers with some default
267  // values.
268  // (For floating-point keywords, use "curious" values, since the better
269  // choice of NAN cannot be written to FITS headers and causes an error.)
270  switch(aType) {
271  case CPL_TYPE_FLOAT:
272  cpl_propertylist_append_float(aHeader, aName, -99.);
273  break;
274  case CPL_TYPE_DOUBLE:
275  cpl_propertylist_append_double(aHeader, aName, -999.);
276  break;
277  case CPL_TYPE_STRING:
278  cpl_propertylist_append_string(aHeader, aName, "");
279  break;
280  case CPL_TYPE_INT:
281  cpl_propertylist_append_int(aHeader, aName, INT_MAX);
282  break;
283  case CPL_TYPE_LONG:
284  cpl_propertylist_append_long(aHeader, aName, LONG_MAX);
285  break;
286  case CPL_TYPE_BOOL:
287  cpl_propertylist_append_bool(aHeader, aName, FALSE);
288  break;
289  default:
290  return CPL_ERROR_INVALID_TYPE;
291  }
292 
293  /* XXX ugly: copied code from below for the moment to keep the case *
294  * of the documentation working */
295  cpl_property *property = cpl_propertylist_get_property(aHeader, aName);
296  if (aDescription != NULL && strlen(aDescription)>0) {
297  rc = cpl_property_set_comment(property, aDescription);
298  }
299  cpl_type type = cpl_property_get_type(property);
300  if (type != aType) {
301  cpl_msg_warning(__func__, "Type of property %s is %s but should be %s",
302  aName, cpl_type_get_name(type), cpl_type_get_name(aType));
303  return CPL_ERROR_TYPE_MISMATCH;
304  }
305  return CPL_ERROR_NONE;
306  } /* empty list of properties of regexp search */
307 
308  /* loop through the properties that matched the regular expressions */
309  int i;
310  for (i = 0; i < cpl_propertylist_get_size(list); i++) {
311  cpl_property *prop = cpl_propertylist_get(list, i);
312  cpl_property *property =
313  cpl_propertylist_get_property(aHeader, cpl_property_get_name(prop));
314  if (aDescription != NULL && strlen(aDescription)>0) {
315  rc = cpl_property_set_comment(property, aDescription);
316  }
317  cpl_type type = cpl_property_get_type(property);
318  if (type != aType) {
319  cpl_msg_warning(__func__, "Type of property %s is %s but should be %s",
320  aName, cpl_type_get_name(type), cpl_type_get_name(aType));
321  cpl_propertylist_delete(list);
322  return CPL_ERROR_TYPE_MISMATCH;
323  }
324  } /* for i (all regexp-found properties) */
325  cpl_propertylist_delete(list);
326  return rc;
327 }
328 
329 /*---------------------------------------------------------------------------*/
341 /*---------------------------------------------------------------------------*/
342 void
343 muse_processing_recipeinfo(cpl_plugin *aPlugin)
344 {
345  cpl_msg_set_threadid_off();
346  cpl_msg_info(__func__, "%s v%s", PACKAGE_NAME, PACKAGE_VERSION);
347  if (!aPlugin) {
348  return;
349  }
350  cpl_recipe *recipe = (cpl_recipe *)aPlugin;
351  cpl_errorstate state = cpl_errorstate_get();
352  cpl_size nframes = cpl_frameset_get_size(recipe->frames);
353  if (!cpl_errorstate_is_equal(state)) {
354  cpl_errorstate_set(state); /* swallow error about missing frames */
355  }
356  cpl_msg_debug(__func__, "%"CPL_SIZE_FORMAT" input frames:", nframes);
357 
358  cpl_msg_indent_more();
359  cpl_size iframe;
360  for (iframe = 0; iframe < nframes; iframe++) {
361  cpl_frame *frame = cpl_frameset_get_position(recipe->frames, iframe);
362  cpl_msg_debug(__func__, "%s\t%s", cpl_frame_get_filename(frame),
363  cpl_frame_get_tag(frame));
364  } /* for iframe (all frames) */
365  cpl_msg_indent_less();
366 
367  // print non-default parameters
368  cpl_msg_debug(__func__, "non-default parameters:");
369  cpl_msg_indent_more();
370  int n = 0; /* count non-default parameters */
371  const cpl_parameter *p = cpl_parameterlist_get_first(recipe->parameters);
372  for ( ; p; p = cpl_parameterlist_get_next(recipe->parameters)) {
373  /* the alias is the short name, and we always set the *
374  * same one for both command line and configuration */
375  const char *name = cpl_parameter_get_alias(p, CPL_PARAMETER_MODE_CLI);
376  cpl_type type = cpl_parameter_get_type(p);
377 
378  switch (type) {
379  case CPL_TYPE_BOOL: {
380  cpl_boolean value = cpl_parameter_get_bool(p),
381  dval = cpl_parameter_get_default_bool(p);
382  if (value != dval) {
383  cpl_msg_debug(__func__, "--%s=%s [%s]", name,
384  value ? "true" : "false", dval ? "true" : "false");
385  n++;
386  }
387  break;
388  }
389  case CPL_TYPE_INT: {
390  int value = cpl_parameter_get_int(p),
391  dval = cpl_parameter_get_default_int(p);
392  if (value != dval) {
393  cpl_msg_debug(__func__, "--%s=%d [%d]", name, value, dval);
394  n++;
395  }
396  break;
397  }
398  case CPL_TYPE_DOUBLE: {
399  double value = cpl_parameter_get_double(p),
400  dval = cpl_parameter_get_default_double(p);
401  if (value != dval) {
402  cpl_msg_debug(__func__, "--%s=%g [%g]", name, value, dval);
403  n++;
404  }
405  break;
406  }
407  case CPL_TYPE_STRING: {
408  const char *value = cpl_parameter_get_string(p),
409  *dval = cpl_parameter_get_default_string(p);
410  if (value && dval && strncmp(value, dval, strlen(dval) + 1)) {
411  cpl_msg_debug(__func__, "--%s=\"%s\" [\"%s\"]", name, value, dval);
412  n++;
413  }
414  break;
415  }
416  default:
417  cpl_msg_debug(__func__, "--%s: parameter of unknown type!", name);
418  break;
419  } /* switch */
420  } /* for ipar (all parameters) */
421  if (!n) { /* if no non-default parameters were found */
422  cpl_msg_debug(__func__, "none");
423  }
424  cpl_msg_indent_less();
425 
426  /* print known MUSE* environment variables, keep this in sync with README */
427  cpl_msg_debug(__func__, "relevant MUSE environment variables:");
428  cpl_msg_indent_more();
429  const char *env[] = { "MUSE_AIT_HACK_SLICE_NUMBER",
430  "MUSE_BASICPROC_SKIP_GAIN_OVERRIDE",
431  "MUSE_BASICPROC_SKIP_NONLIN_CORR",
432  "MUSE_TWILIGHT_SCALES", "MUSE_TWILIGHT_SKIP",
433  "MUSE_GEOMETRY_SKIP", "MUSE_GEOMETRY_NO_INVERSION",
434  "MUSE_GEOMETRY_MASK_ROTATION",
435  "MUSE_GEOMETRY_PINHOLE_DY", "MUSE_GEOMETRY_STD_GAP",
436  "MUSE_GEOMETRY_HORI_OFFSETS", "MUSE_DAR_CORRECT_METHOD",
437  "MUSE_PIXTABLE_SAVE_AS_TABLE", "MUSE_COLLAPSE_PIXTABLE",
438  "MUSE_COLLAPSE_USE_VARIANCE",
439  "MUSE_CPL_ERRORSTATE_NDUMP", "MUSE_EXPERT_USER",
440  "MUSE_BADPIX_FROM_MASKCUBE", "MUSE_DEBUG_QUADRANTS",
441  "MUSE_DEBUG_TRACE", "MUSE_DEBUG_WAVECAL",
442  "MUSE_DEBUG_LSF_FIT", "MUSE_DEBUG_SKY",
443  "MUSE_PLOT_TRACE", "MUSE_DEBUG_DCR", "MUSE_DEBUG_FLUX",
444  "MUSE_DEBUG_PIXTABLE_LIMITS",
445  "MUSE_DEBUG_GEO_VERIFY_DY", "MUSE_DEBUG_GEO_VERTICAL",
446  "MUSE_DEBUG_MEMORY_PROGRAM", "MUSE_DEBUG_WCS",
447  "MUSE_DEBUG_GRID_CONVERSION", "MUSE_DEBUG_NEAREST",
448  "MUSE_DEBUG_WEIGHTED", "MUSE_DEBUG_WEIGHTED_X",
449  "MUSE_DEBUG_WEIGHTED_Y", "MUSE_DEBUG_WEIGHTED_Z",
450  "MUSE_DEBUG_WEIGHTED_GRID", "MUSE_DEBUG_WEIGHT_CUBE",
451  "MUSE_DEBUG_CRREJECT", "MUSE_DEBUG_CRREJECT_X",
452  "MUSE_DEBUG_CRREJECT_Y", "MUSE_DEBUG_CRREJECT_Z",
453  NULL };
454  int ienv = 0;
455  while (env[ienv]) {
456  char *value = getenv(env[ienv]);
457  if (value) {
458  cpl_msg_debug(__func__, "%s=%s", env[ienv], value);
459  } /* if */
460  ienv++;
461  } /* while */
462  cpl_msg_indent_less();
463 
464  /* print OpenMP-related variables */
465  cpl_msg_debug(__func__, "relevant OpenMP environment variables:");
466  cpl_msg_indent_more();
467  /* list all variables from OpenMP spec v3.1, section 4, add *
468  * those that are also part of OpenMP v4.0 and v4.5 at the end */
469  const char *envomp[] = { "OMP_SCHEDULE", "OMP_NUM_THREADS", "OMP_DYNAMIC",
470  "OMP_PROC_BIND", "OMP_NESTED", "OMP_STACKSIZE",
471  "OMP_WAIT_POLICY", "OMP_MAX_ACTIVE_LEVELS",
472  "OMP_THREAD_LIMIT", /* v3.1 */
473  "OMP_PLACES", "OMP_CANCELLATION", "OMP_DISPLAY_ENV",
474  "OMP_DEFAULT_DEVICE", /* v4.0 */
475  "OMP_MAX_TASK_PRIORITY", /* v4.5 */ NULL };
476  ienv = 0;
477  while (envomp[ienv]) {
478  char *value = getenv(envomp[ienv]);
479  if (value) {
480  cpl_msg_debug(__func__, "%s=%s", envomp[ienv], value);
481  } /* if */
482  ienv++;
483  } /* while */
484  cpl_msg_indent_less();
485 } /* muse_processing_recipeinfo() */
486 
int muse_processing_get_frame_mode(const cpl_recipe *aRecipe, const char *aFrametag)
Get the mode for a product frame with a certain tag.
cpl_error_code muse_processing_prepare_header(const cpl_recipe *aRecipe, const char *aFrametag, cpl_propertylist *aHeader)
Prepare and check a FITS header for a certain frame tag.
struct muse_processinginfo_s muse_processinginfo_t
cpl_frame_level muse_processing_get_frame_level(const cpl_recipe *aRecipe, const char *aFrametag)
Get the level for a product frame with a certain tag.
void muse_processinginfo_delete(cpl_recipe *aRecipe)
Clear all information from the processing info and from the recipe config.
cpl_recipeconfig * muse_processing_get_recipeconfig(cpl_recipe *aRecipe)
Get the recipe (frame) configuration.
void muse_processinginfo_register(cpl_recipe *plugin, cpl_recipeconfig *recipeconfig, muse_processing_prepare_header_func *prepare_header, muse_processing_get_frame_level_func *get_frame_level, muse_processing_get_frame_mode_func *get_frame_mode)
Register extended functionalities for MUSE recipes.
static muse_processinginfo_t * muse_processinginfo_get(const cpl_recipe *aRecipe)
Get processinginfo for a certain recipe.
void muse_processing_recipeinfo(cpl_plugin *aPlugin)
Output main pipeline configuration, inputs, and parameters.
static muse_processinginfo_t * muse_processinginfo
cpl_error_code muse_processing_prepare_property(cpl_propertylist *aHeader, const char *aName, cpl_type aType, const char *aDescription)
Prepare and check the specified property.