UVES Pipeline Reference Manual  5.4.6
uves_wavecal_firstsolution.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 02111-1307 USA *
18  * */
19 
20 /*
21  * $Author: amodigli $
22  * $Date: 2010-09-24 09:32:09 $
23  * $Revision: 1.23 $
24  * $Name: not supported by cvs2svn $
25  * $Log: not supported by cvs2svn $
26  * Revision 1.21 2007/08/21 13:08:26 jmlarsen
27  * Removed irplib_access module, largely deprecated by CPL-4
28  *
29  * Revision 1.20 2007/06/06 08:17:33 amodigli
30  * replace tab with 4 spaces
31  *
32  * Revision 1.19 2007/05/25 07:05:21 jmlarsen
33  * Decreased warning verbosity
34  *
35  * Revision 1.18 2007/04/26 13:21:04 jmlarsen
36  * Made more robust against inaccurate abs_order polynomial
37  *
38  * Revision 1.17 2007/04/10 07:11:56 jmlarsen
39  * Changed interface of polynomial_regression_2d()
40  *
41  * Revision 1.16 2007/03/05 10:22:24 jmlarsen
42  * Fixed bug in computation of max/min physical order number
43  *
44  * Revision 1.15 2007/01/15 08:58:20 jmlarsen
45  * More robust polynomial fitting
46  *
47  * Revision 1.14 2007/01/10 12:40:12 jmlarsen
48  * Removed unused parameter
49  *
50  * Revision 1.13 2006/12/07 08:29:58 jmlarsen
51  * Compute correct Ynew column for FLAMES
52  *
53  * Revision 1.12 2006/11/24 16:24:32 jmlarsen
54  * Added check of abs order polynomial
55  *
56  * Revision 1.11 2006/11/15 15:02:15 jmlarsen
57  * Implemented const safe workarounds for CPL functions
58  *
59  * Revision 1.9 2006/11/15 14:04:08 jmlarsen
60  * Removed non-const version of parameterlist_get_first/last/next which is
61  * already in CPL, added const-safe wrapper, unwrapper and deallocator functions
62  *
63  * Revision 1.8 2006/11/06 15:19:42 jmlarsen
64  * Removed unused include directives
65  *
66  * Revision 1.7 2006/08/18 07:07:43 jmlarsen
67  * Switched order of cpl_calloc arguments
68  *
69  * Revision 1.6 2006/07/14 12:43:47 jmlarsen
70  * Documentation update
71  *
72  * Revision 1.5 2006/07/03 13:29:45 jmlarsen
73  * Reduced max line length
74  *
75  * Revision 1.4 2006/03/03 13:54:11 jmlarsen
76  * Changed syntax of check macro
77  *
78  * Revision 1.3 2006/02/15 13:19:15 jmlarsen
79  * Reduced source code max. line length
80  *
81  * Revision 1.2 2006/02/08 09:25:05 jmlarsen
82  * Fixed bug caused by == comparison of doubles
83  *
84  * Revision 1.1 2006/02/03 07:46:30 jmlarsen
85  * Moved recipe implementations to ./uves directory
86  *
87  * Revision 1.27 2005/12/20 08:11:44 jmlarsen
88  * Added CVS entry
89  *
90  */
91 /*----------------------------------------------------------------------------*/
92 /*
93  * @addtogroup uves_wavecal
94  */
95 /*----------------------------------------------------------------------------*/
98 #ifdef HAVE_CONFIG_H
99 # include <config.h>
100 #endif
101 
102 #include <uves_wavecal_firstsolution.h>
103 
104 #include <uves_utils.h>
105 #include <uves_utils_wrappers.h>
106 #include <uves_dump.h>
107 #include <uves_error.h>
108 #include <uves_msg.h>
109 
110 #include <cpl.h>
111 
112 #include <math.h>
113 
114 static int *
115 write_physical_order(cpl_table *linetable,
116  const polynomial *absolute_order,
117  const cpl_table *ordertable,
118  const polynomial *order_locations,
119  int *first_abs_order, int *last_abs_order);
120 
121 static double
122 calculate_shift(const cpl_table *linetable, const cpl_table *previous,
123  const char *column, const char *reference_column,
124  double range, double step, double tolerance);
125 
126 static double
127 cross_correlation(double shift,
128  const cpl_table *t1, const cpl_table *t2,
129  const char *column, const char* reference_column,
130  int minref, int maxref, double tolerance);
131 
132 static polynomial *apply_shift(const cpl_table *previous,
133  const double shift, const int degree, double *mse);
134 
135 /*----------------------------------------------------------------------------*/
182 /*----------------------------------------------------------------------------*/
183 polynomial *
184 uves_wavecal_firstsolution(cpl_table *linetable,
185  const cpl_table *guess,
186  polynomial **absolute_order,
187  const cpl_table *ordertable,
188  const polynomial *order_locations,
189  bool flames,
190  double offset,
191  int **relative_order,
192  int DEGREE, double CORREL_RANGE, double CORREL_STEP,
193  double CORREL_TOLERANCE, double MAXERROR,
194  int *first_abs_order, int *last_abs_order)
195 {
196  polynomial *initial_dispersion = NULL;
197  polynomial *new_absorder = NULL;
198  const char *er_msg = NULL;
199  double shift;
200  double mse;
201 
202  /* Get physical order numbering */
203  check( *relative_order = write_physical_order(linetable, *absolute_order,
204  ordertable,
205  order_locations,
206  first_abs_order,
207  last_abs_order),
208  "Could not calculate absolute order numbers");
209 
210  /* Update the 'absolute_order' map */
211  {
212  int row;
213 
214  /* Create column for Y-location (in pixels) of order */
215  cpl_table_new_column(linetable, "Ynew", CPL_TYPE_DOUBLE);
216  for (row = 0; row < cpl_table_get_nrow(linetable); row++)
217  {
218  /* For historical reasons, the column 'Y' contains the
219  (relative) order number while 'Ynew' contains
220  the y-coordinate (in pixels) of the emission line. */
221  int order = cpl_table_get_int (linetable, "Y", row, NULL);
222  double x = cpl_table_get_double(linetable, "X", row, NULL);
223 
224  cpl_table_set_double(
225  linetable, "Ynew", row,
226  uves_polynomial_evaluate_2d(order_locations, x, order));
227  }
228 
229  assure_nomsg( cpl_error_get_code() == CPL_ERROR_NONE,
230  cpl_error_get_code() );
231 
232  new_absorder =
233  uves_polynomial_regression_2d(linetable, "X", "Ynew", "Order",
234  NULL, /* uncertainty of order number */
235  DEGREE, DEGREE,
236  NULL, NULL, NULL, /* New columns */
237  NULL, NULL, /* mse, chi^2 */
238  NULL, /* variance pol. */
239  -1, -1); /* kappa */
240  cpl_table_set_column_unit(linetable,"X","pix");
241  cpl_table_set_column_unit(linetable,"Ynew","pix");
242  cpl_table_set_column_unit(linetable,"Order"," ");
243 
244  if (cpl_error_get_code() != CPL_ERROR_NONE) /* Singular matrix, or too few points */
245  {
246  er_msg = uves_sprintf("%s", cpl_error_get_message());
247 
249  uves_msg_warning("Could not make global fit of absolute order number (%s). "
250  "Polynomial is not updated",
251  er_msg);
252  }
253  else
254  {
255  uves_polynomial_delete(absolute_order);
256  *absolute_order = uves_polynomial_duplicate(new_absorder);
257  }
258 
259  /* Calculate absolute_order wrt center of orders, but add offset to Ynew column */
260  if (flames)
261  {
262  cpl_table_add_scalar(linetable, "Ynew", + offset);
263  }
264  }
265 
266  /* Sort linetable by 'Order' (ascending), then 'X' (ascending) */
267  uves_sort_table_2(linetable, "Order", "X", false, false);
268 
269  /* Cross correlation of guess (linetable) and linetable */
270  /* Step size should not be less than 2*tolerance */
271  check( shift = calculate_shift(guess, linetable, "X", "Order",
272  CORREL_RANGE, CORREL_STEP, CORREL_TOLERANCE),
273  "Could not calculate shift of position w.r.t. guess solution");
274 
275  /* Apply shift to guess solution
276  * Note that it doesn't help to simply call uves_polynomial_shift()
277  * on the guess solution
278  * because the requested 'DEGREE' might be different from
279  * the degree used in the guess solution
280  */
281 
282  check( initial_dispersion = apply_shift(guess, shift, DEGREE, &mse),
283  "Could not calculate initial dispersion relation");
284  /* This fit may fail if the input guess table has too few or badly
285  distributed points, but there is not much to do about that */
286 
287  /* Check quality of initial solution */
288  if(mse > MAXERROR*MAXERROR)
289  {
290  uves_msg_warning("RMS of initial fit (%f pixels) is greater "
291  "than tolerance (%f pixels)", sqrt(mse), MAXERROR);
292  }
293 
294  cleanup:
295  uves_free_string_const(&er_msg);
296  uves_polynomial_delete(&new_absorder);
297  if (cpl_error_get_code() != CPL_ERROR_NONE)
298  {
299  uves_polynomial_delete(&initial_dispersion);
300  }
301 
302  return initial_dispersion;
303 }
304 
305 /*----------------------------------------------------------------------------*/
320 /*----------------------------------------------------------------------------*/
321 static polynomial *
322 apply_shift(const cpl_table *guess, double shift, int degree, double *mse)
323 {
324  polynomial *result = NULL;
325  cpl_table *t = NULL;
326 
327  /* Copy guess table */
328  check( t = cpl_table_duplicate(guess),
329  "Error duplicating table");
330 
331  /* Create auxillary column Ident*Order */
332  check(( cpl_table_duplicate_column(t, "ident_order", t, "Ident"),
333  cpl_table_multiply_columns(t, "ident_order", "Order")),
334  /* ident_order = Ident * Order */
335  "Error creating auxillary column");
336 
337  /* Shift x values */
338  check( cpl_table_add_scalar(t, "X", shift), "Error shifting column 'X'");
339 
340  /* Fit lambda*m = f(x, m) */
341  /* Don't use uncertainties because they might not exist in guess solution */
342  result = uves_polynomial_regression_2d(t, "X", "Order", "ident_order", NULL,
343  degree, degree,
344  NULL, NULL, NULL,
345  mse, NULL,
346  NULL, -1, -1);
347 
348  /* If failed, set error to SINGULAR_MATRIX */
349  if (cpl_error_get_code() != CPL_ERROR_NONE) /* Singular matrix or too few points */
350  {
352 
353  assure( false, CPL_ERROR_SINGULAR_MATRIX,
354  "Polynomial fitting failed");
355  }
356 
357  cleanup:
358  uves_free_table(&t);
359  return result;
360 }
361 
362 /*----------------------------------------------------------------------------*/
385 /*----------------------------------------------------------------------------*/
386 
387 static double
388 calculate_shift(const cpl_table *linetable, const cpl_table *guess, const char *column,
389  const char *reference_column, double range, double step, double tolerance)
390 {
391  cpl_type t;
392  int minorder, maxorder;
393  int N, i;
394  double shift, max_corr, median_corr, maxpos = 0;
395  cpl_table *temp = NULL;
396 
397  assure( cpl_table_has_column(linetable, column),
398  CPL_ERROR_ILLEGAL_INPUT, "Table has no '%s' column", column);
399  assure( cpl_table_has_column(guess , column),
400  CPL_ERROR_ILLEGAL_INPUT, "Table has no '%s' column", column);
401  assure( cpl_table_has_column(linetable, reference_column),
402  CPL_ERROR_ILLEGAL_INPUT, "Table has no '%s' column", reference_column);
403  assure( cpl_table_has_column(guess , reference_column),
404  CPL_ERROR_ILLEGAL_INPUT, "Table has no '%s' column", reference_column);
405  assure( range > 0, CPL_ERROR_ILLEGAL_INPUT, "Range = %f", range);
406 
407  t = cpl_table_get_column_type(linetable, column);
408  assure( t == CPL_TYPE_DOUBLE, CPL_ERROR_TYPE_MISMATCH,
409  "Column '%s' has type '%s'. Double expected", column, uves_tostring_cpl_type(t));
410 
411  t = cpl_table_get_column_type(guess, column);
412  assure( t == CPL_TYPE_DOUBLE, CPL_ERROR_TYPE_MISMATCH,
413  "Column '%s' has type '%s'. Double expected", column, uves_tostring_cpl_type(t));
414 
415  t = cpl_table_get_column_type(linetable, reference_column);
416  assure( t == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
417  "Ref. column '%s' has type '%s'. Integer expected",
418  reference_column, uves_tostring_cpl_type(t));
419 
420  t = cpl_table_get_column_type(guess, reference_column);
421  assure( t == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
422  "Ref. column '%s' has type '%s'. Integer expected",
423  reference_column, uves_tostring_cpl_type(t));
424 
425  /* Identify common orders */
426  check(( minorder =
427  uves_max_int(cpl_table_get_column_min(guess, reference_column),
428  cpl_table_get_column_min(linetable, reference_column)),
429  maxorder =
430  uves_min_int(cpl_table_get_column_max(guess, reference_column),
431  cpl_table_get_column_max(linetable, reference_column))),
432  "Error reading column '%s'", reference_column);
433 
434  assure(maxorder >= minorder, CPL_ERROR_ILLEGAL_INPUT, "No common orders found");
435 
436  uves_msg("Min/max common absolute orders = %d - %d", minorder, maxorder);
437 
438  /* Find maximum of cross correlation function
439  for shifts in [-range ; range]
440  */
441 
442  /* Count number of candidates,
443  so we can create a table of the correct size
444  which is used to get the median of
445  all cross-correlation values */
446  N = 0;
447  for (shift = -range; shift <= range; shift += step)
448  {
449  N += 1;
450  }
451 
452  temp = cpl_table_new(N);
453  cpl_table_new_column(temp, "Corr", CPL_TYPE_DOUBLE);
454 
455  max_corr = -1;
456  maxpos = 0;
457  for (shift = -range, i = 0;
458  i < N;
459  shift += step , i++)
460  {
461  double corr;
462  check( corr = cross_correlation(shift, linetable, guess, column,
463  reference_column, minorder, maxorder, tolerance),
464  "Error calculating spectrum cross correlation for shift = %f pixel(s)",
465  shift);
466 
467  /* Update table */
468  check( cpl_table_set_double(temp, "Corr", i, corr),
469  "Error updating table");
470 
471  uves_msg_debug("Correlation(shift=%f) = %f", shift, corr);
472 
473  if (corr > max_corr)
474  {
475  max_corr = corr;
476  maxpos = shift;
477  }
478  }
479 
480  /* To estimate significance,
481  compare the detected max cross-correlation
482  value to "no correlation" estimated as the
483  median of all cross-corr. values */
484 
485  median_corr = cpl_table_get_column_median(temp, "Corr");
486 
487  /* Correlation value is integer ; don't divide by zero */
488  if (median_corr < 0.5)
489  {
490  median_corr = 1;
491  }
492 
493  uves_msg("Estimated shift compared to guess solution is %f pixels (%.2f sigma detection)",
494  maxpos, max_corr / median_corr);
495 
496  /* The correlation peak is usually
497  ~30 or more times the background,
498  so warn if peak value is less than, say,
499  10 times background. */
500  if (max_corr / median_corr < 10)
501  {
502  uves_msg_warning("Cross-correlation with guess solution is "
503  "only %f times no correlation (usually >30). "
504  "Make sure that the guess solution is within ~10 pixels "
505  "of the real dispersion relation; otherwise the following "
506  "wavelength calibration is likely to fail or converge "
507  "to a wrong solution",
508  max_corr / median_corr);
509  }
510 
511  cleanup:
512  uves_free_table(&temp);
513  return maxpos;
514 }
515 
516 /*----------------------------------------------------------------------------*/
538 /*----------------------------------------------------------------------------*/
539 static double
540 cross_correlation(double shift,
541  const cpl_table *t1, const cpl_table *t2,
542  const char *column, const char* reference_column,
543  int minref, int maxref, double tolerance)
544 {
545  double result = 0; /* The result */
546  int i1 = 0; /* Pointers to table rows */
547  int i2 = 0;
548 
549  /* For efficiency reasons, retrieve the pointers to the columns */
550  const double *col1 = cpl_table_get_data_double_const(t1, column);
551  const double *col2 = cpl_table_get_data_double_const(t2, column);
552  const int *ref1 = cpl_table_get_data_int_const(t1, reference_column);
553  const int *ref2 = cpl_table_get_data_int_const(t2, reference_column);
554 
555  int N1 = cpl_table_get_nrow(t1);
556  int N2 = cpl_table_get_nrow(t2);
557 
558  assure( cpl_error_get_code() == CPL_ERROR_NONE, cpl_error_get_code(),
559  "Error reading input table");
560 
561  /* Search for matching rows */
562  while (i1 < N1 && ref1[i1] <= maxref &&
563  i2 < N2 && ref2[i2] <= maxref) {
564  if (i1 < minref || ref1[i1] < ref2[i2])
565  i1++;
566  else if (i2 < minref || ref1[i1] > ref2[i2])
567  i2++;
568  else {
569  /* Reference values match */
570  double difference = col2[i2] - (col1[i1] + shift);
571 
572  if (difference > tolerance)
573  {
574  i1++;
575  }
576  else if (difference < -tolerance)
577  {
578  i2++;
579  }
580  else {
581  /* Matching rows found: |col2-col1-shift| <= tolerance.
582  Update result and continue search */
583  result += 1.0;
584  i2++;
585  }
586  }
587  }
588 
589 
590  cleanup:
591  return result;
592 }
593 
594 
595 /*----------------------------------------------------------------------------*/
614 /*----------------------------------------------------------------------------*/
615 static int *
616 write_physical_order(cpl_table *linetable, const polynomial *absolute_order,
617  const cpl_table *ordertable,
618  const polynomial *order_locations,
619  int *first_abs_order, int *last_abs_order)
620 {
621  int *relative_order = NULL; /* Result */
622  int *physical_order = NULL;
623  int minorder, maxorder;
624  int maxphysical;
625  cpl_table *temp = NULL;
626  const polynomial *map = NULL;
627 
628  double *sum = NULL; /* Auxillary variables used to calculate the average */
629  int *N = NULL;
630 
631  int i;
632 
633  check( cpl_table_new_column(linetable, "Order", CPL_TYPE_INT),
634  "Error creating column");
635 
636  check( cpl_table_new_column(linetable, "AbsOrder", CPL_TYPE_DOUBLE),
637  "Error creating column");
638 
639  check(( minorder = cpl_table_get_column_min(ordertable, "Order"),
640  maxorder = cpl_table_get_column_max(ordertable, "Order")),
641  "Could not read min. and max. order numbers");
642 
643  assure( minorder > 0, CPL_ERROR_ILLEGAL_INPUT,
644  "Non-positive order number (%d) in linetable", minorder);
645 
646  physical_order = cpl_calloc(maxorder + 1, sizeof(int));
647  assure_mem( physical_order );
648 
649  /* First calculate the estimation of the
650  absolute order number at each line position */
651  for (i = 0; i < cpl_table_get_nrow(linetable); i++) {
652  double x, y;
653  double absorder;
654  int order;
655 
656  order = cpl_table_get_int (linetable, "Y", i, NULL);
657  /* The column 'Y' contains the (relative) order number */
658 
659  x = cpl_table_get_double(linetable, "X", i, NULL);
660 
661  y = uves_polynomial_evaluate_2d(order_locations, x, order);
662 
663  absorder = uves_polynomial_evaluate_2d(absolute_order, x, y);
664 
665  uves_msg_debug("Order #%d: Absolute order = %f at x = %f",
666  order, absorder, x);
667 
668  cpl_table_set_double(linetable, "AbsOrder", i, absorder);
669  }
670 
671  {
672  int degree = 1;
673  int coeff1, coeff2; /* absorder = coeff1 + coeff2 * relative_order */
674  int order;
675  int relorder_median;
676  int absorder_median;
677 
678  check_nomsg( map =
680  "Y", "AbsOrder", NULL,
681  degree,
682  NULL, NULL, NULL, -1));
683 
684  relorder_median = uves_round_double(cpl_table_get_column_median(linetable, "Y"));
685  absorder_median = uves_round_double(uves_polynomial_evaluate_1d(map, relorder_median));
686 
687  if (uves_polynomial_derivative_1d(map, relorder_median) > 0) {
688  coeff2 = 1;
689  }
690  else {
691  coeff2 = -1;
692  }
693 
694  coeff1 = absorder_median - coeff2 * relorder_median;
695 
696  uves_msg_debug("Assuming relation: abs.order = %d + (%d) * rel.order",
697  coeff1, coeff2);
698 
699  maxphysical = -1;
700  for (order = minorder; order <= maxorder; order++) {
701  physical_order[order] = coeff1 + coeff2 * order;
702 
703  assure(physical_order[order] > 0, CPL_ERROR_ILLEGAL_OUTPUT,
704  "Estimated physical order number is non-positive (%d)",
705  physical_order[order]);
706 
707  if (physical_order[order] > maxphysical)
708  {
709  maxphysical = physical_order[order];
710  }
711 
712  uves_msg_debug("Mapping relative order #%d to absolute order #%d",
713  order, physical_order[order]);
714  }
715 
716  /* Get first and last physical orders */
717  *first_abs_order = physical_order[minorder];
718  *last_abs_order = physical_order[maxorder];
719 
720  passure( *first_abs_order - *last_abs_order == coeff2*(minorder - maxorder),
721  "%d %d %d %d %d",
722  *first_abs_order, *last_abs_order, coeff2, minorder, maxorder);
723 
724  }
725 
726  /* Then write this rounded mean value to every row of the table */
727  for (i = 0; i < cpl_table_get_nrow(linetable); i++) {
728  int order;
729  order = cpl_table_get_int (linetable, "Y", i, NULL);
730  cpl_table_set_int(linetable, "Order", i, physical_order[order]);
731  }
732 
733  /* Calculate the inverse of 'physical_order' */
734  relative_order = cpl_calloc(maxphysical + 1, sizeof(int));
735  for (i = 0; i <= maxorder; i++)
736  {
737  relative_order[physical_order[i]] = i;
738  }
739 
740  cleanup:
741  uves_free_table(&temp);
743  cpl_free(sum);
744  cpl_free(physical_order);
745  cpl_free(N);
746 
747  return relative_order;
748 }
double uves_polynomial_derivative_1d(const polynomial *p, double x)
Evaluate the derivative of a 1d polynomial.
void uves_polynomial_delete(polynomial **p)
Delete a polynomial.
#define uves_msg_warning(...)
Print an warning message.
Definition: uves_msg.h:87
#define check_nomsg(CMD)
Definition: uves_error.h:204
#define passure(BOOL,...)
Definition: uves_error.h:207
#define uves_msg(...)
Print a message on 'info' or 'debug' level.
Definition: uves_msg.h:119
polynomial * uves_polynomial_duplicate(const polynomial *p)
Copy a polynomial.
polynomial * uves_polynomial_regression_2d(cpl_table *t, const char *X1, const char *X2, const char *Y, const char *sigmaY, int degree1, int degree2, const char *polynomial_fit, const char *residual_square, const char *variance_fit, double *mse, double *red_chisq, polynomial **variance, double kappa, double min_reject)
Fit a 2d polynomial to three table columns.
Definition: uves_utils.c:2869
void uves_polynomial_delete_const(const polynomial **p)
Delete a const polynomial.
#define assure_mem(PTR)
Definition: uves_error.h:181
double uves_polynomial_evaluate_2d(const polynomial *p, double x1, double x2)
Evaluate a 2d polynomial.
double uves_polynomial_evaluate_1d(const polynomial *p, double x)
Evaluate a 1d polynomial.
polynomial * uves_polynomial_regression_1d(cpl_table *t, const char *X, const char *Y, const char *sigmaY, int degree, const char *polynomial_fit, const char *residual_square, double *mean_squared_error, double kappa)
Fit a 1d polynomial to two table columns.
Definition: uves_utils.c:2590
const char * uves_tostring_cpl_type(cpl_type t)
Convert a CPL type to a string.
Definition: uves_dump.c:378
#define uves_error_reset()
Definition: uves_error.h:215
#define uves_msg_debug(...)
Print a debug message.
Definition: uves_msg.h:97
#define assure_nomsg(BOOL, CODE)
Definition: uves_error.h:177
#define check(CMD,...)
Definition: uves_error.h:198