UVES Pipeline Reference Manual  5.4.6
uves_cd_align_impl.c
1 /* *
2  * This file is part of the ESO UVES Pipeline *
3  * Copyright (C) 2004,2005 European Southern Observatory *
4  * *
5  * This library 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, 51 Franklin St, Fifth Floor, Boston MA 02110-1301 USA *
18  */
19 
20 /*
21  * $Author: amodigli $
22  * $Date: 2013-08-08 13:36:46 $
23  * $Revision: 1.19 $
24  * $Name: not supported by cvs2svn $
25  * $Log: not supported by cvs2svn $
26  * Revision 1.18 2013/07/01 15:36:08 amodigli
27  * Rename DEBUG to debug_mode to remove compiler error on some platforms (that name is reserved to special compiler options)
28  *
29  * Revision 1.17 2012/03/02 16:23:45 amodigli
30  * fixed compiler warnings related to CPL6 upgrade
31  *
32  * Revision 1.16 2011/12/08 13:59:05 amodigli
33  * Fox warnings with CPL6
34  *
35  * Revision 1.15 2010/09/24 09:32:02 amodigli
36  * put back QFITS dependency to fix problem spot by NRI on FIBER mode (with MIDAS calibs) data
37  *
38  * Revision 1.13 2008/02/15 12:43:49 amodigli
39  * allow lower/upper chip for parameter process_chip
40  *
41  * Revision 1.12 2007/10/05 16:01:44 amodigli
42  * using proces_chip parameter to process or not a given RED chip
43  *
44  * Revision 1.11 2007/06/22 09:28:24 jmlarsen
45  * Changed interface of uves_save_image
46  *
47  * Revision 1.10 2007/06/11 13:28:26 jmlarsen
48  * Changed recipe contact address to cpl at eso.org
49  *
50  * Revision 1.9 2007/06/08 13:06:16 jmlarsen
51  * Send bug reports to Andrea
52  *
53  * Revision 1.8 2007/06/06 08:17:33 amodigli
54  * replace tab with 4 spaces
55  *
56  * Revision 1.7 2007/05/22 11:29:53 jmlarsen
57  * Changed text
58  *
59  * Revision 1.6 2007/05/14 08:09:48 amodigli
60  * updated input frames and tag description in recipe man page
61  *
62  * Revision 1.5 2007/04/24 12:50:29 jmlarsen
63  * Replaced cpl_propertylist -> uves_propertylist which is much faster
64  *
65  * Revision 1.4 2007/03/05 10:14:56 jmlarsen
66  * Support slope parameter in 1d fitting
67  *
68  * Revision 1.3 2007/02/16 10:36:15 jmlarsen
69  * Renamed variable y0->y_0
70  *
71  * Revision 1.2 2007/02/09 13:36:32 jmlarsen
72  * Use defines for recipe id
73  *
74  * Revision 1.1 2007/02/08 11:38:37 jmlarsen
75  * Added cd_align recipe
76  *
77  * Revision 1.31 2007/01/10 12:37:39 jmlarsen
78  * Removed obsolete comments
79  *
80  */
81 
82 #ifdef HAVE_CONFIG_H
83 # include <config.h>
84 #endif
85 
86 /*----------------------------------------------------------------------------*/
93 /*----------------------------------------------------------------------------*/
94 
95 /*-----------------------------------------------------------------------------
96  Includes
97  -----------------------------------------------------------------------------*/
98 #include <uves_cd_align_impl.h>
99 
100 #include <uves.h>
101 #include <uves_plot.h>
102 #include <uves_parameters.h>
103 #include <uves_dfs.h>
104 #include <uves_pfits.h>
105 #include <uves_qclog.h>
106 #include <uves_recipe.h>
107 #include <uves_utils_cpl.h>
108 #include <uves_utils_wrappers.h>
109 #include <uves_error.h>
110 #include <uves_msg.h>
111 
112 #include <cpl.h>
113 
114 /*-----------------------------------------------------------------------------
115  Functions prototypes
116  -----------------------------------------------------------------------------*/
117 
118 static int
119 uves_cal_cd_align_define_parameters(cpl_parameterlist *parameters);
120 
121 /*-----------------------------------------------------------------------------
122  Recipe standard code
123  -----------------------------------------------------------------------------*/
124 #define cpl_plugin_get_info uves_cal_cd_align_get_info
125 UVES_RECIPE_DEFINE(
126  UVES_CD_ALIGN_ID, UVES_CD_ALIGN_DOM, uves_cal_cd_align_define_parameters,
127  "Jonas M. Larsen", "cpl@eso.org",
128  "Measures the reproducability of the cross disperser positioning",
129  "Given two input frames (CD_ALIGN_xxx where xxx = BLUE or RED) which contain only\n"
130  "one echelle order, this recipe measures the shift in the cross-dispersion \n"
131  "direction of that order. For RED input frames, only the lower chip is processed.\n"
132  "\n"
133  "The recipe produces a CD_ALIGN_TABLE_xxxx (with xxxx = BLUE or REDL) with columns\n"
134  "X: Column number\n"
135  "YCENi: Centroid from Gaussian fit (for i = 1,2)\n"
136  "SIGMAi: Stdev from Gaussian fit\n"
137  "BACKi: Constant background from Gaussian fit\n"
138  "NORMi: Normalization constant from Gaussian fit\n"
139  "YDIFF: Difference YCEN2 - YCEN1 of centroid positions\n"
140  "\n"
141  "and the QC-parameters ESO.QC.YDIFF(AVG|MED|RMS), which are the average,\n"
142  "median and root-mean-square of the y-shift, respectively.\n");
143 
144 /*-----------------------------------------------------------------------------
145  Functions code
146  -----------------------------------------------------------------------------*/
148 static int
149 uves_cal_cd_align_define_parameters(cpl_parameterlist *parameters)
150 {
151  const char *subcontext = NULL;
152  const char *recipe_id = make_str(UVES_CD_ALIGN_ID);
153 
154  /*****************
155  * General *
156  *****************/
157  if (uves_define_global_parameters(parameters) != CPL_ERROR_NONE)
158  {
159  return -1;
160  }
161 
162  /* stepsize */
163  uves_par_new_range("steps",
164  CPL_TYPE_INT,
165  "Step size in pixels",
166  100, 1, INT_MAX);
167 
168  /* xborder */
169  uves_par_new_range("xborder",
170  CPL_TYPE_INT,
171  "Exclude a border region of this size (pixels)",
172  200, 0, INT_MAX);
173 
174  /* window */
175  uves_par_new_range("window",
176  CPL_TYPE_INT,
177  "The half window height used for Gaussian fitting",
178  50, 1, INT_MAX);
179 
180  return (cpl_error_get_code() != CPL_ERROR_NONE);
181 }
182 
183 /*----------------------------------------------------------------------------*/
200 /*----------------------------------------------------------------------------*/
201 cpl_table *
202 uves_cd_align_process(const cpl_image *im1,
203  const cpl_image *im2,
204  const uves_propertylist *rotated_header1,
205  const uves_propertylist *rotated_header2,
206  int steps,
207  int xborder,
208  int window,
209  bool debug_mode,
210  enum uves_chip chip)
211 {
212  cpl_table *result = NULL;
213  int row = 0; /* number of table rows used */
214  const cpl_image *images[2];
215  cpl_image *rows = NULL;
216  cpl_size max_row[2]; /* image row with max flux */
217  int nx, ny, x;
218  cpl_size num_fits, fit_succeeded;
219 
220  images[0] = im1;
221  images[1] = im2;
222  nx = cpl_image_get_size_x(images[0]);
223  ny = cpl_image_get_size_y(images[0]);
224 
225  if (debug_mode) check( uves_save_image_local("CD alignment frame", "cd_align1",
226  images[0], chip, -1, -1,
227  rotated_header1, true),
228  "Error saving 1st CD aligment frame");
229 
230  if (debug_mode) check( uves_save_image_local("CD alignment frame", "cd_align2",
231  images[1], chip, -1, -1,
232  rotated_header2, true),
233  "Error saving 2nd CD aligment frame");
234 
235  assure( cpl_image_get_size_x(images[0]) == cpl_image_get_size_x(images[1]) &&
236  cpl_image_get_size_y(images[0]) == cpl_image_get_size_y(images[1]),
237  CPL_ERROR_INCOMPATIBLE_INPUT,
238  "Images sizes: %" CPL_SIZE_FORMAT "x%" CPL_SIZE_FORMAT " and %" CPL_SIZE_FORMAT "x%" CPL_SIZE_FORMAT "",
239  cpl_image_get_size_x(images[0]),
240  cpl_image_get_size_y(images[0]),
241  cpl_image_get_size_x(images[1]),
242  cpl_image_get_size_y(images[1]) );
243 
244 
245  result = cpl_table_new(nx); row = 0;
246  cpl_table_new_column(result, "X" , CPL_TYPE_INT);
247  cpl_table_new_column(result, "YCEN1", CPL_TYPE_DOUBLE);
248  cpl_table_new_column(result, "YCEN2", CPL_TYPE_DOUBLE);
249  cpl_table_new_column(result, "SIGMA1", CPL_TYPE_DOUBLE);
250  cpl_table_new_column(result, "SIGMA2", CPL_TYPE_DOUBLE);
251  cpl_table_new_column(result, "BACK1", CPL_TYPE_DOUBLE);
252  cpl_table_new_column(result, "BACK2", CPL_TYPE_DOUBLE);
253  cpl_table_new_column(result, "NORM1", CPL_TYPE_DOUBLE);
254  cpl_table_new_column(result, "NORM2", CPL_TYPE_DOUBLE);
255 
256  cpl_table_set_column_unit(result,"X","pix");
257  cpl_table_set_column_unit(result,"YCEN1","pix");
258  cpl_table_set_column_unit(result,"YCEN2","pix");
259  cpl_table_set_column_unit(result,"SIGMA1","pix");
260  cpl_table_set_column_unit(result,"SIGMA2","pix");
261  cpl_table_set_column_unit(result,"BACK1","ADU");
262  cpl_table_set_column_unit(result,"BACK2","ADU");
263  cpl_table_set_column_unit(result,"NORM1","ADU");
264  cpl_table_set_column_unit(result,"NORM2","ADU");
265 
266  assure_mem( result );
267 
268  /* Find row of max accumulated flux (i.e. position of the order) */
269  {
270  int im;
271  for (im = 0; im < 2; im++)
272  {
273  int direction = 1; /* To get image of single column */
274  cpl_size max_col;
275 
276  uves_free_image(&rows);
277  rows = cpl_image_collapse_create(images[im], direction);
278 
279  cpl_image_get_maxpos(rows, &max_col, &(max_row[im]));
280  uves_msg("Row of max flux (%" CPL_SIZE_FORMAT ". image) = %" CPL_SIZE_FORMAT "", (cpl_size)im+1, max_row[im]);
281 
282  assure( max_col == 1, CPL_ERROR_ILLEGAL_OUTPUT,
283  "Something went wrong, max_col in collapsed image is = %" CPL_SIZE_FORMAT "", max_col);
284  }
285  }
286 
287 
288  num_fits = 0; /* Number of measure points */
289  fit_succeeded = 0; /* Number of successful Gauss fits */
290  for (x = 1 + xborder; x <= nx - xborder; x += steps)
291  {
292  int im;
293  for (im = 0; im < 2; im++)
294  {
295  bool horizontal = false;
296  bool fix_background = false;
297  bool fit_background = false;
298  int number_of_parameters = 4;
299  double y_0, sigma, norm, background;
300  int ylow = uves_max_int(1, uves_min_int(ny, max_row[im] - window));
301  int yhigh = uves_max_int(1, uves_min_int(ny, max_row[im] + window));
302 
303  uves_fit_1d_image(images[im],
304  NULL, NULL, /* errors, bpm */
305  horizontal, fix_background, fit_background,
306  ylow, yhigh, x,
307  &y_0, &sigma, &norm, &background, NULL, /* slope */
308  NULL, NULL, /* mse, red_chisq */
309  NULL, /* Covariance */
311  number_of_parameters);
312 
313  num_fits += 1;
314  if (cpl_error_get_code() == CPL_ERROR_CONTINUE)
315  {
317 
318  uves_msg_warning("Fitting window (%" CPL_SIZE_FORMAT ", %" CPL_SIZE_FORMAT ") - (%" CPL_SIZE_FORMAT ", %" CPL_SIZE_FORMAT ") failed",
319  (cpl_size)x, (cpl_size)ylow,
320  (cpl_size)x, (cpl_size)yhigh);
321  }
322  else
323  {
324  fit_succeeded += 1;
325 
326  assure( cpl_error_get_code() == CPL_ERROR_NONE,
327  cpl_error_get_code(),
328  "Gaussian fitting failed");
329 
330  cpl_table_set_int (result, "X" , row, x);
331  cpl_table_set_double(result, (im == 0) ? "YCEN1" : "YCEN2", row, y_0);
332  cpl_table_set_double(result, (im == 0) ? "SIGMA1": "SIGMA2", row, sigma);
333  cpl_table_set_double(result, (im == 0) ? "BACK1" : "BACK2", row, norm);
334  cpl_table_set_double(result, (im == 0) ? "NORM1" : "NORM2", row, background);
335  }
336  }
337  row++;
338  }
339 
340  cpl_table_set_size(result, row);
341 
342  uves_msg_low("Was able to fit %" CPL_SIZE_FORMAT " of %" CPL_SIZE_FORMAT " columns", fit_succeeded, num_fits);
343 
344  check(( cpl_table_duplicate_column(result, "YDIFF", result, "YCEN2"),
345  cpl_table_subtract_columns(result, "YDIFF", "YCEN1")),
346  "Error calculating residuals of fit");
347  cpl_table_set_column_unit(result,"YDIFF","pix");
348  {
349  cpl_size num_valid = cpl_table_get_nrow(result) - cpl_table_count_invalid(result, "YDIFF");
350 
351  assure( num_valid >= 1, CPL_ERROR_ILLEGAL_OUTPUT,
352  "Only %" CPL_SIZE_FORMAT " valid YDIFF value(s), 1 or more needed",
353  num_valid);
354  }
355 
356 
357  cleanup:
358  uves_free_image(&rows);
359  return result;
360 }
361 
362 /*----------------------------------------------------------------------------*/
371 /*----------------------------------------------------------------------------*/
372 
373 static cpl_table*
374 cd_align_qclog(const cpl_table *cdalign,
375  const uves_propertylist *raw_header,
376  enum uves_chip chip)
377 {
378  cpl_table *qclog = NULL;
379  double mean, sigma, median;
380 
381  check( qclog = uves_qclog_init(raw_header, chip),
382  "Error during QC initialization");
383 
384  mean = cpl_table_get_column_mean (cdalign, "YDIFF");
385  sigma = cpl_table_get_column_stdev (cdalign, "YDIFF");
386  median = cpl_table_get_column_median(cdalign, "YDIFF");
387 
388  uves_qclog_add_string(qclog,
389  "QC TEST1 ID",
390  "Test-of-CD-Alignment",
391  "Name of QC test",
392  "%s");
393 
394  uves_qclog_add_double(qclog,
395  "QC YDIFFAVG",
396  mean,
397  "Average Y difference",
398  "%8.4f");
399 
400  uves_qclog_add_double(qclog,
401  "QC YDIFFMED",
402  median,
403  "Median Y difference",
404  "%8.4f");
405 
406  uves_qclog_add_double(qclog,
407  "QC YDIFFRMS",
408  sigma,
409  "RMS Y difference",
410  "%8.4f");
411 
412 
413  uves_msg("Average shift = %.4f +- %.4f pixels",
414  mean, sigma);
415 
416 
417  cleanup:
418  return qclog;
419 }
420 
421 /*----------------------------------------------------------------------------*/
429 /*----------------------------------------------------------------------------*/
430 static double
431 avg_flux(const cpl_image *im)
432 {
433  double result = 0;
434  cpl_image *median_filt = NULL;
435  bool extrapolate_border = true;
436 
437  /* Report total flux after bias subtraction.
438  Bias is estimated as the median value
439 
440  Note that: total flux - nx*ny*median =
441  nx*ny(mean - median)
442 
443  so just report (mean - median)
444  */
445 
446  /* First apply a small window (3x3) median filter to
447  get a bit robust avg, but without destroying the echelle order signal
448  */
449 
450  median_filt = cpl_image_duplicate(im);
451  assure_mem( median_filt );
452 
453  uves_filter_image_median(&median_filt, 1, 1,
454  extrapolate_border);
455 
456  result =
457  cpl_image_get_mean (median_filt) -
458  cpl_image_get_median(median_filt);
459 
460  cleanup:
461  uves_free_image(&median_filt);
462  return result;
463 }
464 
465 /*----------------------------------------------------------------------------*/
473 /*----------------------------------------------------------------------------*/
474 static void
475 uves_cal_cd_align_exe(cpl_frameset *frames, const cpl_parameterlist *parameters,
476  const char *starttime)
477 {
478  /* Input */
479  cpl_image *raw_images[2][2] = {{NULL, NULL}, {NULL, NULL}};
480 
481  /* This 2x2 array of images contain:
482 
483  raw_images[0][0]: First frame, REDL or BLUE chip
484  raw_images[0][1]: First frame, REDU or NULL
485  raw_images[1][0]: Second frame, REDL or BLUE chip
486  raw_images[1][1]: Second frame, REDU or NULL
487 
488  etc. for the following arrays
489  */
490 
491  uves_propertylist *raw_headers[2][2] = {{NULL, NULL}, {NULL, NULL}};
492  uves_propertylist *rotated_headers[2][2] = {{NULL, NULL}, {NULL, NULL}};
493 
494  cpl_table* qclog[2] = {NULL, NULL};
495 
496  /* Output */
497  uves_propertylist *product_header = NULL;
498  uves_propertylist *table_header = NULL;
499  cpl_table *cd_align = NULL;
500 
501  /* Parameters */
502  int steps, xborder, window;
503  bool debug_mode;
504 
505  /* Local variables */
506  const char *product_filename = NULL;
507  bool blue;
508  enum uves_chip chip;
509  const char *raw_filename[2];
510  int raw_index;
511 
512  const char* PROCESS_CHIP=NULL;
513 
514  check( uves_get_parameter(parameters, NULL, "uves", "debug",
515  CPL_TYPE_BOOL, &debug_mode), "Could not read parameter");
516 
517  check( uves_get_parameter(parameters, NULL, "uves", "process_chip", CPL_TYPE_STRING, &PROCESS_CHIP),
518  "Could not read parameter");
519  uves_string_toupper((char*)PROCESS_CHIP);
520 
521  check( uves_get_parameter(parameters, NULL, make_str(UVES_CD_ALIGN_ID), "steps",
522  CPL_TYPE_INT , &steps), "Could not read parameter");
523  check( uves_get_parameter(parameters, NULL, make_str(UVES_CD_ALIGN_ID), "xborder",
524  CPL_TYPE_INT , &xborder), "Could not read parameter");
525  check( uves_get_parameter(parameters, NULL, make_str(UVES_CD_ALIGN_ID), "window",
526  CPL_TYPE_INT , &window), "Could not read parameter");
527 
528 
529  check( uves_load_cd_align(frames,
530  &raw_filename[0],
531  &raw_filename[1],
532  raw_images[0],
533  raw_images[1],
534  raw_headers[0],
535  raw_headers[1],
536  rotated_headers[0],
537  rotated_headers[1],
538  &blue),
539  "Error loading raw frame");
540 
541  uves_msg("Using %s", raw_filename[0]);
542  uves_msg("Using %s", raw_filename[1]);
543 
544 
545  if (blue)
546  {
547  chip = UVES_CHIP_BLUE;
548  }
549  else
550  {
551  if (debug_mode)
552  {
553  int raw_index_l = uves_chip_get_index(UVES_CHIP_REDL);
554  int raw_index_u = uves_chip_get_index(UVES_CHIP_REDU);
555 
556  uves_msg("1. REDL average flux per pixel = %f ADU", avg_flux(raw_images[0][raw_index_l]));
557  uves_msg("2. REDL average flux per pixel = %f ADU", avg_flux(raw_images[1][raw_index_l]));
558 
559  uves_msg("1. REDU average flux per pixel = %f ADU", avg_flux(raw_images[0][raw_index_u]));
560  uves_msg("2. REDU average flux per pixel = %f ADU", avg_flux(raw_images[1][raw_index_u]));
561  }
562 
563  chip = UVES_CHIP_REDL; /* Process only lower red chip */
564  }
565 
566  raw_index = uves_chip_get_index(chip);
567 
568  uves_msg("Processing %s chip",
570 
571  check( cd_align = uves_cd_align_process(raw_images[0][raw_index],
572  raw_images[1][raw_index],
573  rotated_headers[0][raw_index],
574  rotated_headers[1][raw_index],
575  steps,
576  xborder,
577  window,
578  debug_mode,
579  chip),
580  "Error during processing");
581 
582  check( qclog[0] = cd_align_qclog(cd_align,
583  raw_headers[0][raw_index], /* of first frame */
584  chip),
585  "Could not compute QC");
586 
587  product_header = uves_propertylist_new();
588 
589  product_filename = uves_cd_align_filename(chip);
590  check( uves_frameset_insert(frames,
591  cd_align,
592  CPL_FRAME_GROUP_PRODUCT,
593  CPL_FRAME_TYPE_TABLE,
594  CPL_FRAME_LEVEL_FINAL,
595  product_filename,
596  UVES_CD_ALIGN_TABLE(blue),
597  raw_headers[0][raw_index],
598  product_header,
599  NULL, /* table header */
600  parameters,
601  make_str(UVES_CD_ALIGN_ID),
602  PACKAGE "/" PACKAGE_VERSION,
603  qclog, /* No QC */
604  starttime, true,
605  0),
606  "Could not add CD align table %s to frameset", product_filename);
607 
608  uves_msg("CD align table %s (%s) added to frameset",
609  product_filename, UVES_CD_ALIGN_TABLE(blue));
610 
611  cleanup:
612  uves_free_image(&raw_images[0][0]);
613  uves_free_image(&raw_images[0][1]);
614  uves_free_image(&raw_images[1][0]);
615  uves_free_image(&raw_images[1][1]);
616  uves_free_propertylist(&raw_headers[0][0]);
617  uves_free_propertylist(&raw_headers[0][1]);
618  uves_free_propertylist(&raw_headers[1][0]);
619  uves_free_propertylist(&raw_headers[1][1]);
620  uves_free_propertylist(&rotated_headers[0][0]);
621  uves_free_propertylist(&rotated_headers[0][1]);
622  uves_free_propertylist(&rotated_headers[1][0]);
623  uves_free_propertylist(&rotated_headers[1][1]);
624 
625  uves_free_table(&qclog[0]);
626  uves_free_string_const(&product_filename);
627  uves_free_table(&cd_align);
628  uves_free_propertylist(&product_header);
629 
630  return;
631 }
632 
633 
cpl_error_code uves_filter_image_median(cpl_image **image, int xwindow, int ywindow, bool extrapolate_border)
Median filter.
#define uves_msg_warning(...)
Print an warning message.
Definition: uves_msg.h:87
int uves_qclog_add_string(cpl_table *table, const char *key_name, const char *value, const char *key_help, const char *format)
Add string key to QC-LOG table.
Definition: uves_qclog.c:683
int uves_gauss_derivative(const double x[], const double a[], double result[])
Evaluate the derivatives of a gaussian.
Definition: uves_utils.c:4346
int uves_qclog_add_double(cpl_table *table, const char *key_name, const double value, const char *key_help, const char *format)
Add double key to QC-LOG table.
Definition: uves_qclog.c:641
uves_propertylist * uves_propertylist_new(void)
Create an empty property list.
#define uves_msg(...)
Print a message on 'info' or 'debug' level.
Definition: uves_msg.h:119
int uves_gauss(const double x[], const double a[], double *result)
Evaluate a gaussian.
Definition: uves_utils.c:4291
#define assure_mem(PTR)
Definition: uves_error.h:181
int uves_chip_get_index(enum uves_chip chip)
Convert to integer.
Definition: uves_chip.c:124
#define uves_error_reset()
Definition: uves_error.h:215
#define uves_msg_low(...)
Print a message on a lower message level.
Definition: uves_msg.h:105
const char * uves_chip_tostring_upper(enum uves_chip chip)
Convert to string.
Definition: uves_chip.c:156
const char * uves_string_toupper(char *s)
Convert all lowercase characters in a string into uppercase characters.
Definition: uves_utils.c:1493
#define check(CMD,...)
Definition: uves_error.h:198
cpl_table * uves_qclog_init(const uves_propertylist *raw_header, enum uves_chip chip)
Init QC-LOG table.
Definition: uves_qclog.c:410