File: muse_processinginfo.c

package info (click to toggle)
cpl-plugin-muse 2.6%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 13,352 kB
  • sloc: ansic: 78,724; sh: 4,276; python: 1,943; makefile: 706
file content (489 lines) | stat: -rw-r--r-- 19,520 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set sw=2 sts=2 et cin: */
/*
 * This file is part of the MUSE Instrument Pipeline
 * Copyright (C) 2005-2013 European Southern Observatory
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/*----------------------------------------------------------------------------*
 *                              Includes                                      *
 *----------------------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <cpl.h>

#include "muse_processing.h"

#include "muse_utils.h"

/*---------------------------------------------------------------------------*/
/**
 * @addtogroup muse_processing
 */
/*---------------------------------------------------------------------------*/

/**@{*/

/*----------------------------------------------------------------------------*
 *                          Static variables                                  *
 *----------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/**
  Structure to hold the extended processing information.
 */
/*---------------------------------------------------------------------------*/
typedef struct muse_processinginfo_s {
  struct muse_processinginfo_s *prev;
  struct muse_processinginfo_s *next;
  cpl_recipe *plugin;
  cpl_recipeconfig *recipeconfig;
  /** @brief Function to check the FITS header and insert the comments */
  muse_processing_prepare_header_func *prepare_header;
  /** @brief Function to get the processing level of a frame */
  muse_processing_get_frame_level_func *get_frame_level;
  /** @brief Function to get the processing level of a frame */
  muse_processing_get_frame_mode_func *get_frame_mode;
} muse_processinginfo_t;

/*---------------------------------------------------------------------------*/
/**
  NULL-terminated array of all registered processing information
 */
/*---------------------------------------------------------------------------*/
static muse_processinginfo_t *muse_processinginfo = NULL;

/*---------------------------------------------------------------------------*/
/**
  @brief Get processinginfo for a certain recipe
 */
/*---------------------------------------------------------------------------*/

static muse_processinginfo_t *
muse_processinginfo_get(const cpl_recipe *aRecipe) {
  if (muse_processinginfo != NULL) {
    muse_processinginfo_t *m;
    for (m = muse_processinginfo; m != NULL; m = m->next) {
      if (m->plugin == aRecipe) {
        return m;
      }
    }
  }
  return NULL;
}

/*---------------------------------------------------------------------------*/
/**
  @brief Register extended functionalities for MUSE recipes
  @param plugin            the CPL recipe
  @param recipeconfig      the recipe configuration
  @param prepare_header    function to declare the properties of a frame
  @param get_frame_level   function that returns the processing level of
  @param get_frame_mode    function that returns the output mode of a frame

  This functions registers all extensions that are used to use our
  framework.
 */
/*---------------------------------------------------------------------------*/
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) {

  muse_processinginfo_t *m = muse_processinginfo;
  if (muse_processinginfo == NULL) {
    muse_processinginfo = cpl_calloc(1, sizeof(muse_processinginfo_t));
    m = muse_processinginfo;
  } else {
    while (m->next != NULL) {
      m = m->next;
    }
    m->next = cpl_calloc(1, sizeof(muse_processinginfo_t));
    m->next->prev = m;
    m = m->next;
  }
  m->plugin = plugin;
  m->recipeconfig = recipeconfig;
  m->prepare_header = prepare_header;
  m->get_frame_level = get_frame_level;
  m->get_frame_mode = get_frame_mode;
}

/*---------------------------------------------------------------------------*/
/**
  @brief Clear all information from the processing info and from the recipe
         config.
  @param aRecipe     the CPL recipe

  To be called before closing the program.
 */
/*---------------------------------------------------------------------------*/
void
muse_processinginfo_delete(cpl_recipe *aRecipe) {
  muse_processinginfo_t *m = muse_processinginfo_get(aRecipe);
  if (m == NULL) {
    return;
  }
  if (m == muse_processinginfo) {
    muse_processinginfo = m->next;
    if (muse_processinginfo != NULL) {
      muse_processinginfo->prev = NULL;
    }
  } else {
    m->prev->next = m->next;
    if (m->next != NULL) {
      m->next->prev = m->prev;
    }
  }
  cpl_recipeconfig_delete(m->recipeconfig);
  cpl_free(m);
}

/*---------------------------------------------------------------------------*/
/**
  @brief Prepare and check a FITS header for a certain frame tag.
  @param aRecipe     the CPL recipe
  @param aFrametag   the tag of the output frame
  @param aHeader     the FITS header of the output frame
  @return CPL_ERROR_NONE if the header was OK
 */
/*---------------------------------------------------------------------------*/
cpl_error_code muse_processing_prepare_header(const cpl_recipe *aRecipe,
                                              const char *aFrametag,
                                              cpl_propertylist *aHeader) {
  muse_processinginfo_t *m = muse_processinginfo_get(aRecipe);
  return (m != NULL)? (* m->prepare_header)(aFrametag, aHeader): CPL_ERROR_NONE;
}

/*---------------------------------------------------------------------------*/
/**
  @brief Get the level for a product frame with a certain tag
  @param aRecipe     the CPL recipe
  @param aFrametag   the tag of the output frame
  @return its frame level, CPL_FRAME_LEVEL_NONE if the tag was not registered.
 */
/*---------------------------------------------------------------------------*/
cpl_frame_level
muse_processing_get_frame_level(const cpl_recipe *aRecipe,
                                const char *aFrametag) {
  muse_processinginfo_t *m = muse_processinginfo_get(aRecipe);
  return (m != NULL)? (* m->get_frame_level)(aFrametag): CPL_FRAME_LEVEL_NONE;
}

/*---------------------------------------------------------------------------*/
/**
  @brief Get the mode for a product frame with a certain tag
  @param aRecipe     the CPL recipe
  @param aFrametag   the tag of the output frame
  @return its frame level, MUSE_FRAME_MODE_ALL if the tag was not registered.
 */
/*---------------------------------------------------------------------------*/
int
muse_processing_get_frame_mode(const cpl_recipe *aRecipe,
                               const char *aFrametag) {
  muse_processinginfo_t *m = muse_processinginfo_get(aRecipe);
  return (m != NULL)?(* m->get_frame_mode)(aFrametag): MUSE_FRAME_MODE_ALL;
}

/*---------------------------------------------------------------------------*/
/**
  @brief Get the recipe (frame) configuration.
  @param aRecipe Pointer to the recipe
  @return the recipe config, or NULL if not found.
 */
/*---------------------------------------------------------------------------*/
cpl_recipeconfig *
muse_processing_get_recipeconfig(cpl_recipe *aRecipe) {
  muse_processinginfo_t *m = muse_processinginfo_get(aRecipe);
  return (m != NULL)?m->recipeconfig: NULL;
}

/*---------------------------------------------------------------------------*/
/**
  @brief Prepare and check the specified property
  @param aHeader the header to be prepared
  @param aName the property name
  @param aType the property type
  @param aDescription the description (comment) of this property
  @return CPL error code

  Check the specified property for its existence and correct type and
  append the comment to it.

  @error{return CPL_ERROR_DATA_NOT_FOUND, the property was not found}
  @error{return CPL_ERROR_TYPE_MISMATCH, the property has different type}
  @error{return CPL_ERROR_NULL_INPUT, the header or the name was NULL}
 */
/*---------------------------------------------------------------------------*/
cpl_error_code
muse_processing_prepare_property(cpl_propertylist *aHeader, const char *aName,
                                 cpl_type aType, const char *aDescription)
{
  cpl_ensure_code(aHeader, CPL_ERROR_NULL_INPUT);
  cpl_ensure_code(aName, CPL_ERROR_NULL_INPUT);

  cpl_error_code rc = CPL_ERROR_NONE;

  cpl_propertylist *list = cpl_propertylist_new();
  cpl_propertylist_copy_property_regexp(list, aHeader, aName, 0);
  if (cpl_propertylist_is_empty(list)) {
    cpl_propertylist_delete(list);

    // The tag MUSE PRIVATE DOCUMENTATION is set in xmldoc.c and checked
    // here:
    // If it is not set (the normal case in a recipe), just an error
    // message is generated in case of a missing header.
    // If the description contains the string "(optional)", the property may not
    // be present, but this failure should be ignored.
    if (!cpl_propertylist_has(aHeader, "MUSE PRIVATE DOCUMENTATION") &&
        (aDescription && !strstr(aDescription, "(optional)"))) {
      cpl_msg_warning(__func__, "Property %s (%s) not used", aName,
                      aDescription);
      return CPL_ERROR_DATA_NOT_FOUND;
    }
    // If this property is set (if the function is used from
    // muse_xmldoc), then we add missing headers with some default
    // values.
    // (For floating-point keywords, use "curious" values, since the better
    // choice of NAN cannot be written to FITS headers and causes an error.)
    switch(aType) {
    case CPL_TYPE_FLOAT:
        cpl_propertylist_append_float(aHeader, aName, -99.);
        break;
      case CPL_TYPE_DOUBLE:
        cpl_propertylist_append_double(aHeader, aName, -999.);
        break;
      case CPL_TYPE_STRING:
        cpl_propertylist_append_string(aHeader, aName, "");
        break;
      case CPL_TYPE_INT:
        cpl_propertylist_append_int(aHeader, aName, INT_MAX);
        break;
      case CPL_TYPE_LONG:
        cpl_propertylist_append_long(aHeader, aName, LONG_MAX);
        break;
      case CPL_TYPE_BOOL:
        cpl_propertylist_append_bool(aHeader, aName, FALSE);
        break;
      default:
        return CPL_ERROR_INVALID_TYPE;
    }

    /* XXX ugly: copied code from below for the moment to keep the case *
     *     of the documentation working                                 */
    cpl_property *property = cpl_propertylist_get_property(aHeader, aName);
    if (aDescription != NULL && strlen(aDescription)>0) {
      rc = cpl_property_set_comment(property, aDescription);
    }
    cpl_type type = cpl_property_get_type(property);
    if (type != aType) {
      cpl_msg_warning(__func__, "Type of property %s is %s but should be %s",
                      aName, cpl_type_get_name(type), cpl_type_get_name(aType));
      return CPL_ERROR_TYPE_MISMATCH;
    }
    return CPL_ERROR_NONE;
  } /* empty list of properties of regexp search */

  /* loop through the properties that matched the regular expressions */
  int i;
  for (i = 0; i < cpl_propertylist_get_size(list); i++) {
    cpl_property *prop = cpl_propertylist_get(list, i);
    cpl_property *property =
      cpl_propertylist_get_property(aHeader, cpl_property_get_name(prop));
    if (aDescription != NULL && strlen(aDescription)>0) {
      rc = cpl_property_set_comment(property, aDescription);
    }
    cpl_type type = cpl_property_get_type(property);
    if (type != aType) {
      cpl_msg_warning(__func__, "Type of property %s is %s but should be %s",
                      aName, cpl_type_get_name(type), cpl_type_get_name(aType));
      cpl_propertylist_delete(list);
      return CPL_ERROR_TYPE_MISMATCH;
    }
  } /* for i (all regexp-found properties) */
  cpl_propertylist_delete(list);
  return rc;
}

/*---------------------------------------------------------------------------*/
/**
  @brief  Output main pipeline configuration, inputs, and parameters.
  @param  aPlugin   the CPL plugin of the recipe in question

  Output pipeline name (PACKAGE_NAME) and version (PACKAGE_VERSION) and if
  aPlugin is non-NULL, give all input frames (filenames and tags), non-default
  parameters, and relevant (MUSE and OpenMP) environment variables.
  @note Only known environment variables are tested.

  This function is meant to be called at the beginning of a MUSE recipe.
 */
/*---------------------------------------------------------------------------*/
void
muse_processing_recipeinfo(cpl_plugin *aPlugin)
{
  cpl_msg_set_threadid_off();
  cpl_msg_info(__func__, "%s v%s", PACKAGE_NAME, PACKAGE_VERSION);
  if (!aPlugin) {
    return;
  }
  cpl_recipe *recipe = (cpl_recipe *)aPlugin;
  cpl_errorstate state = cpl_errorstate_get();
  cpl_size nframes = cpl_frameset_get_size(recipe->frames);
  if (!cpl_errorstate_is_equal(state)) {
    cpl_errorstate_set(state); /* swallow error about missing frames */
  }
  cpl_msg_debug(__func__, "%"CPL_SIZE_FORMAT" input frames:", nframes);

  cpl_msg_indent_more();
  cpl_size iframe;
  for (iframe = 0; iframe < nframes; iframe++) {
    cpl_frame *frame = cpl_frameset_get_position(recipe->frames, iframe);
    cpl_msg_debug(__func__, "%s\t%s", cpl_frame_get_filename(frame),
                  cpl_frame_get_tag(frame));
  } /* for iframe (all frames) */
  cpl_msg_indent_less();

  // print non-default parameters
  cpl_msg_debug(__func__, "non-default parameters:");
  cpl_msg_indent_more();
  int n = 0; /* count non-default parameters */
  const cpl_parameter *p = cpl_parameterlist_get_first(recipe->parameters);
  for ( ; p; p = cpl_parameterlist_get_next(recipe->parameters)) {
    /* the alias is the short name, and we always set the *
     * same one for both command line and configuration   */
    const char *name = cpl_parameter_get_alias(p, CPL_PARAMETER_MODE_CLI);
    cpl_type type = cpl_parameter_get_type(p);

     switch (type) {
     case CPL_TYPE_BOOL: {
       cpl_boolean value = cpl_parameter_get_bool(p),
                   dval = cpl_parameter_get_default_bool(p);
       if (value != dval) {
         cpl_msg_debug(__func__, "--%s=%s [%s]", name,
                       value ? "true" : "false", dval ? "true" : "false");
         n++;
       }
       break;
     }
     case CPL_TYPE_INT: {
       int value = cpl_parameter_get_int(p),
           dval = cpl_parameter_get_default_int(p);
       if (value != dval) {
         cpl_msg_debug(__func__, "--%s=%d [%d]", name, value, dval);
         n++;
       }
       break;
     }
     case CPL_TYPE_DOUBLE: {
       double value = cpl_parameter_get_double(p),
              dval = cpl_parameter_get_default_double(p);
       if (value != dval) {
         cpl_msg_debug(__func__, "--%s=%g [%g]", name, value, dval);
         n++;
       }
       break;
     }
     case CPL_TYPE_STRING: {
       const char *value = cpl_parameter_get_string(p),
                  *dval = cpl_parameter_get_default_string(p);
       if (value && dval && strncmp(value, dval, strlen(dval) + 1)) {
         cpl_msg_debug(__func__, "--%s=\"%s\" [\"%s\"]", name, value, dval);
         n++;
       }
       break;
     }
     default:
       cpl_msg_debug(__func__, "--%s: parameter of unknown type!", name);
       break;
     } /* switch */
  } /* for ipar (all parameters) */
  if (!n) { /* if no non-default parameters were found */
    cpl_msg_debug(__func__, "none");
  }
  cpl_msg_indent_less();

  /* print known MUSE* environment variables, keep this in sync with README */
  cpl_msg_debug(__func__, "relevant MUSE environment variables:");
  cpl_msg_indent_more();
  const char *env[] = { "MUSE_AIT_HACK_SLICE_NUMBER",
                        "MUSE_BASICPROC_SKIP_GAIN_OVERRIDE",
                        "MUSE_BASICPROC_SKIP_NONLIN_CORR",
                        "MUSE_TWILIGHT_SCALES", "MUSE_TWILIGHT_SKIP",
                        "MUSE_GEOMETRY_SKIP", "MUSE_GEOMETRY_NO_INVERSION",
                        "MUSE_GEOMETRY_MASK_ROTATION",
                        "MUSE_GEOMETRY_PINHOLE_DY", "MUSE_GEOMETRY_STD_GAP",
                        "MUSE_GEOMETRY_HORI_OFFSETS", "MUSE_DAR_CORRECT_METHOD",
                        "MUSE_PIXTABLE_SAVE_AS_TABLE", "MUSE_COLLAPSE_PIXTABLE",
                        "MUSE_COLLAPSE_USE_VARIANCE",
                        "MUSE_CPL_ERRORSTATE_NDUMP", "MUSE_EXPERT_USER",
                        "MUSE_DEBUG_QUADRANTS",
                        "MUSE_DEBUG_TRACE", "MUSE_DEBUG_WAVECAL",
                        "MUSE_DEBUG_IGNORE_READOUT", "MUSE_DEBUG_IGNORE_INSMODE",
                        "MUSE_DEBUG_LSF_FIT", "MUSE_DEBUG_SKY",
                        "MUSE_PLOT_TRACE", "MUSE_DEBUG_DCR", "MUSE_DEBUG_FLUX",
                        "MUSE_DEBUG_PIXTABLE_LIMITS",
                        "MUSE_DEBUG_GEO_VERIFY_DY", "MUSE_DEBUG_GEO_VERTICAL",
                        "MUSE_DEBUG_MEMORY_PROGRAM", "MUSE_DEBUG_WCS",
                        "MUSE_DEBUG_GRID_CONVERSION", "MUSE_DEBUG_NEAREST",
                        "MUSE_DEBUG_WEIGHTED", "MUSE_DEBUG_WEIGHTED_X",
                        "MUSE_DEBUG_WEIGHTED_Y", "MUSE_DEBUG_WEIGHTED_Z",
                        "MUSE_DEBUG_WEIGHTED_GRID", "MUSE_DEBUG_WEIGHT_CUBE",
                        "MUSE_DEBUG_CRREJECT", "MUSE_DEBUG_CRREJECT_X",
                        "MUSE_DEBUG_CRREJECT_Y", "MUSE_DEBUG_CRREJECT_Z",
                        "MUSE_DEBUG_AUTOCALIB", "MUSE_SUPERFLAT_POS",
                        NULL };
  int ienv = 0;
  while (env[ienv]) {
    char *value = getenv(env[ienv]);
    if (value) {
      cpl_msg_debug(__func__, "%s=%s", env[ienv], value);
    } /* if */
    ienv++;
  } /* while */
  cpl_msg_indent_less();

  /* print OpenMP-related variables */
  cpl_msg_debug(__func__, "relevant OpenMP environment variables:");
  cpl_msg_indent_more();
  /* list all variables from OpenMP spec v3.1, section 4, add    *
   * those that are also part of OpenMP v4.0 and v4.5 at the end */
  const char *envomp[] = { "OMP_SCHEDULE", "OMP_NUM_THREADS", "OMP_DYNAMIC",
                           "OMP_PROC_BIND", "OMP_NESTED", "OMP_STACKSIZE",
                           "OMP_WAIT_POLICY", "OMP_MAX_ACTIVE_LEVELS",
                           "OMP_THREAD_LIMIT", /* v3.1 */
                           "OMP_PLACES", "OMP_CANCELLATION", "OMP_DISPLAY_ENV",
                           "OMP_DEFAULT_DEVICE", /* v4.0 */
                           "OMP_MAX_TASK_PRIORITY", /* v4.5 */ NULL };
  ienv = 0;
  while (envomp[ienv]) {
    char *value = getenv(envomp[ienv]);
    if (value) {
      cpl_msg_debug(__func__, "%s=%s", envomp[ienv], value);
    } /* if */
    ienv++;
  } /* while */
  cpl_msg_indent_less();
} /* muse_processing_recipeinfo() */

/**@}*/