MUSE Pipeline Reference Manual  1.0.2
muse_cplwrappers.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-2014 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 #ifdef HAVE_READLINK
30 #define _BSD_SOURCE /* get readlink() from unistd.h */
31 #include <unistd.h> /* readlink(), has to be included before cpl.h */
32 #endif
33 #include <cpl.h>
34 #include <string.h>
35 #include <math.h>
36 
37 #include "muse_cplwrappers.h"
38 
39 /*----------------------------------------------------------------------------*
40  * Debugging Macros *
41  * Set these to 1 or higher for (lots of) debugging output *
42  *----------------------------------------------------------------------------*/
43 #define DEBUG_SQR 0 /* debugging in muse_cplvector_get_semiquartile() */
44 
45 /*----------------------------------------------------------------------------*/
55 /*----------------------------------------------------------------------------*/
56 
59 /*----------------------------------------------------------------------------*/
75 /*----------------------------------------------------------------------------*/
76 cpl_error_code
77 muse_cplimage_or(cpl_image *aTarget, const cpl_image *aImage, unsigned int mask)
78 {
79  cpl_ensure_code(aTarget && aImage, CPL_ERROR_NULL_INPUT);
80  cpl_ensure_code(cpl_image_get_type(aTarget) == CPL_TYPE_INT,
81  CPL_ERROR_INVALID_TYPE);
82  cpl_ensure_code(cpl_image_get_type(aImage) == CPL_TYPE_INT,
83  CPL_ERROR_INVALID_TYPE);
84  cpl_ensure_code(cpl_image_get_size_x(aTarget) == cpl_image_get_size_x(aImage),
85  CPL_ERROR_ILLEGAL_INPUT);
86  cpl_ensure_code(cpl_image_get_size_y(aTarget) == cpl_image_get_size_y(aImage),
87  CPL_ERROR_ILLEGAL_INPUT);
88 
89  int *target = cpl_image_get_data_int(aTarget);
90  const int *data = cpl_image_get_data_int_const(aImage);
91  cpl_size nData = cpl_image_get_size_x(aImage) * cpl_image_get_size_y(aImage);
92  cpl_size i;
93  for (i = 0; i < nData; i++, data++, target++) {
94  *target |= *data & mask;
95  }
96  return CPL_ERROR_NONE;
97 } /* muse_cplimage_or() */
98 
99 /*----------------------------------------------------------------------------*/
113 /*----------------------------------------------------------------------------*/
114 cpl_image *
115 muse_cplimage_concat_y(const cpl_image *aImage1, const cpl_image *aImage2)
116 {
117  cpl_ensure(aImage1 || aImage2, CPL_ERROR_NULL_INPUT, NULL);
118  if (aImage1 == NULL) {
119  return cpl_image_duplicate(aImage2);
120  }
121  if (aImage2 == NULL) {
122  return cpl_image_duplicate(aImage1);
123  }
124  cpl_type type = cpl_image_get_type(aImage1);
125  cpl_ensure(type == cpl_image_get_type(aImage2), CPL_ERROR_ILLEGAL_INPUT, NULL);
126  cpl_size xsize = cpl_image_get_size_x(aImage1);
127  cpl_ensure(xsize == cpl_image_get_size_x(aImage2), CPL_ERROR_ILLEGAL_INPUT, NULL);
128 
129  cpl_size ysize1 = cpl_image_get_size_y(aImage1);
130  cpl_size ysize2 = cpl_image_get_size_y(aImage2);
131  cpl_image *res = cpl_image_new(xsize, ysize1 + ysize2, type);
132  void *resdata = cpl_image_get_data(res);
133  const void *data1 = cpl_image_get_data_const(aImage1);
134  cpl_size size1 = xsize * ysize1 * cpl_type_get_sizeof(type);
135  const void *data2 = cpl_image_get_data_const(aImage2);
136  cpl_size size2 = xsize * ysize2 * cpl_type_get_sizeof(type);
137  memcpy(resdata, data1, size1);
138  memcpy((char *)resdata+size1, data2, size2);
139 
140  return res;
141 }
142 
143 /*----------------------------------------------------------------------------*/
157 /*----------------------------------------------------------------------------*/
158 cpl_image *
159 muse_cplimage_concat_x(const cpl_image *aImage1, const cpl_image *aImage2)
160 {
161  cpl_ensure(aImage1 || aImage2, CPL_ERROR_NULL_INPUT, NULL);
162  if (aImage1 == NULL) {
163  return cpl_image_duplicate(aImage2);
164  }
165  if (aImage2 == NULL) {
166  return cpl_image_duplicate(aImage1);
167  }
168  cpl_type type = cpl_image_get_type(aImage1);
169  cpl_ensure(type == cpl_image_get_type(aImage2), CPL_ERROR_ILLEGAL_INPUT, NULL);
170  cpl_size ysize = cpl_image_get_size_y(aImage1);
171  cpl_ensure(ysize == cpl_image_get_size_y(aImage2), CPL_ERROR_ILLEGAL_INPUT, NULL);
172 
173  cpl_size xsize1 = cpl_image_get_size_x(aImage1);
174  cpl_size xsize2 = cpl_image_get_size_x(aImage2);
175  cpl_image *res = cpl_image_new(xsize1 + xsize2, ysize, type);
176  void *resdata = cpl_image_get_data(res);
177  const void *data1 = cpl_image_get_data_const(aImage1);
178  cpl_size size1 = xsize1 * cpl_type_get_sizeof(type);
179  const void *data2 = cpl_image_get_data_const(aImage2);
180  cpl_size size2 = xsize2 * cpl_type_get_sizeof(type);
181  cpl_size size = (size1 + size2) * ysize;
182  cpl_size y, y3, y4; /* instead of y1 and y2 to circumvent warning */
183  for (y = 0, y3 = 0, y4 = 0; y < size; y+=size1+size2, y3+=size1, y4+=size2) {
184  memcpy((char *)resdata + y, (char *)data1 + y3, size1);
185  memcpy((char *)resdata + y + size1, (char *)data2 + y4, size2);
186  }
187  return res;
188 }
189 
190 /*----------------------------------------------------------------------------*/
201 /*----------------------------------------------------------------------------*/
202 cpl_image *
204  unsigned int aNX, unsigned int aNY)
205 {
206  cpl_ensure(aImage, CPL_ERROR_NULL_INPUT, NULL);
207  /* make sure here already that none is an even number */
208  cpl_ensure((aNX & 1) && (aNY & 1), CPL_ERROR_ILLEGAL_INPUT, NULL);
209 
210  /* create filtered image of the same size as input image */
211  cpl_image *filtered = cpl_image_new(cpl_image_get_size_x(aImage),
212  cpl_image_get_size_y(aImage),
213  CPL_TYPE_FLOAT);
214  /* create mask of the necessary size */
215  cpl_mask *mask = cpl_mask_new(aNX, aNY);
216  cpl_mask_not(mask);
217  cpl_errorstate prestate = cpl_errorstate_get();
218  cpl_image_filter_mask(filtered, aImage, mask, CPL_FILTER_MEDIAN,
219  CPL_BORDER_FILTER);
220  if (!cpl_errorstate_is_equal(prestate)) {
221  cpl_msg_error(__func__, "filtering failed: %s", cpl_error_get_message());
222  cpl_mask_delete(mask);
223  cpl_image_delete(filtered);
224  return NULL;
225  }
226  cpl_mask_delete(mask);
227 
228  /* now subtract the filtered image from the input image */
229  cpl_image *subtracted = cpl_image_subtract_create(aImage, filtered);
230  cpl_image_delete(filtered);
231 
232  return subtracted;
233 } /* muse_cplimage_filter_median_subtract() */
234 
235 /*----------------------------------------------------------------------------*/
256 /*----------------------------------------------------------------------------*/
257 cpl_vector *
258 muse_cplimage_slope_window(const cpl_image *aImage, const cpl_size *aWindow)
259 {
260  cpl_ensure(aImage && aWindow, CPL_ERROR_NULL_INPUT, NULL);
261  /* duplicate the input image to remove the bad pixel mask, if one exists */
262  cpl_image *image = cpl_image_duplicate(aImage);
263  cpl_image_accept_all(image);
264 
265  cpl_vector *slopes = cpl_vector_new(2); /* two elements: x- and y-slope */
266  unsigned char k; /* vector index, collapsing direction */
267  for (k = 0; k <= 1; k++) {
268  /* collapse by row (direction 0) or column (1) */
269  cpl_image *coll = cpl_image_collapse_window_create(image,
270  aWindow[0], aWindow[2],
271  aWindow[1], aWindow[3],
272  k);
273  if (!coll) {
274  cpl_image_delete(image);
275  cpl_vector_delete(slopes);
276  return NULL;
277  }
278  /* we need the average, not the sum! */
279  if (k == 0) {
280  cpl_image_divide_scalar(coll, aWindow[3] - aWindow[2] + 1);
281  } else {
282  cpl_image_divide_scalar(coll, aWindow[1] - aWindow[0] + 1);
283  }
284  int npx = k == 0 ? cpl_image_get_size_x(coll) : cpl_image_get_size_y(coll);
285  /* convert coordinates into matrices */
286  cpl_matrix *coords = cpl_matrix_new(1, npx);
287  cpl_vector *values = cpl_vector_new(npx);
288  float *data = cpl_image_get_data_float(coll);
289  int i;
290  for (i = 0; i < npx; i++) {
291  cpl_matrix_set(coords, 0, i, i + 1);
292  /* do it manually one-by-one, to use cpl_vector_wrap() *
293  * one would first need to cast the data to double */
294  cpl_vector_set(values, i, data[i]);
295  } /* for i (all pixels) */
296 
297  cpl_polynomial *fit = cpl_polynomial_new(1);
298  const cpl_boolean sym = CPL_FALSE;
299  const cpl_size mindeg = 0, maxdeg = 1;
300  cpl_error_code err = cpl_polynomial_fit(fit, coords, &sym, values, NULL,
301  CPL_FALSE, &mindeg, &maxdeg);
302  cpl_matrix_delete(coords);
303  cpl_vector_delete(values);
304  cpl_image_delete(coll);
305 
306  if (err != CPL_ERROR_NONE) {
307  cpl_msg_warning(__func__, "Could not fit %s slope: %s",
308  k == 0 ? "horizontal" : "vertical",
309  cpl_error_get_message());
310  cpl_polynomial_delete(fit);
311  cpl_vector_delete(slopes);
312  cpl_image_delete(image);
313  return NULL;
314  }
315 #if 0
316  printf("%s: fit (%s)\n", __func__, k == 0 ? "rows" : "cols");
317  cpl_polynomial_dump(fit, stdout);
318  fflush(stdout);
319 #endif
320  const cpl_size pows = { 1 };
321  cpl_vector_set(slopes, k, cpl_polynomial_get_coeff(fit, &pows));
322  cpl_polynomial_delete(fit);
323  } /* for k (collapsing direction) */
324  cpl_image_delete(image);
325 #if 0
326  printf("slopes vector:\n");
327  cpl_vector_dump(slopes, stdout);
328  fflush(stdout);
329 #endif
330 
331  return slopes;
332 } /* muse_cplimage_slope_window() */
333 
334 /*----------------------------------------------------------------------------*/
345 /*----------------------------------------------------------------------------*/
346 double
347 muse_cplimage_get_percentile(const cpl_image *aImage, double aFraction) {
348  cpl_ensure(aImage != NULL, CPL_ERROR_NULL_INPUT, 0.0);
349 
350  cpl_array *a = muse_cplarray_new_from_image(aImage);
352  cpl_size n = cpl_array_get_size(a);
353  muse_cplarray_sort(a, TRUE);
354  if (aFraction < 0) aFraction = 0;
355  if (aFraction > 1) aFraction = 1;
356  n = lround(n * aFraction);
357  double res = cpl_array_get(a, n-1, NULL);
358  cpl_array_delete(a);
359  return res;
360 
361 }
362 
363 /*----------------------------------------------------------------------------*/
377 /*----------------------------------------------------------------------------*/
378 cpl_image *
379 muse_cplimagelist_collapse_or_create(const cpl_imagelist *imlist)
380 {
381  cpl_ensure(imlist, CPL_ERROR_NULL_INPUT, NULL);
382  int count = cpl_imagelist_get_size(imlist);
383  cpl_ensure(count > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
384  cpl_image *res = cpl_image_duplicate(cpl_imagelist_get_const(imlist, 0));
385  int i;
386  unsigned int mask = 0xffffffff;
387  for (i = 1; i < count; i++) {
388  int r = muse_cplimage_or(res, cpl_imagelist_get_const(imlist, i), mask);
389  if (r != CPL_ERROR_NONE) {
390  cpl_image_delete(res);
391  return NULL;
392  }
393  }
394  return res;
395 }
396 
397 /*----------------------------------------------------------------------------*/
414 /*----------------------------------------------------------------------------*/
415 cpl_mask *
416 muse_cplmask_adapt_to_image(const cpl_mask *aMask, const cpl_image *aImage)
417 {
418  cpl_ensure(aMask && aImage, CPL_ERROR_NULL_INPUT, NULL);
419 
420  /* find masked region */
421  enum corner { NONE = 0,
422  BOTTOMLEFT = 1, BOTTOMRIGHT = 2,
423  TOPRIGHT = 3, TOPLEFT = 4 };
424  const char *cnames[] = { "none",
425  "bottom left", "bottom right",
426  "top right", "top left" };
427  int nx = cpl_mask_get_size_x(aMask),
428  ny = cpl_mask_get_size_y(aMask),
429  nximage = cpl_image_get_size_x(aImage),
430  nyimage = cpl_image_get_size_y(aImage),
431  nmax = 0;
432  enum corner nmaxcorner = NONE;
433  int ncount = cpl_mask_count_window(aMask, 1, 1, nx/2, ny/2);
434  if (ncount > nmax) {
435  nmaxcorner = BOTTOMLEFT;
436  nmax = ncount;
437  }
438  ncount = cpl_mask_count_window(aMask, nx/2, 1, nx, ny/2);
439  if (ncount > nmax) {
440  nmaxcorner = BOTTOMRIGHT;
441  nmax = ncount;
442  }
443  ncount = cpl_mask_count_window(aMask, nx/2, ny/2, nx, ny);
444  if (ncount > nmax) {
445  nmaxcorner = TOPRIGHT;
446  nmax = ncount;
447  }
448  ncount = cpl_mask_count_window(aMask, 1, ny/2, nx/2, ny);
449  if (ncount > nmax) {
450  nmaxcorner = TOPLEFT;
451  nmax = ncount;
452  }
453  if (nmaxcorner == NONE) {
454  cpl_error_set_message(__func__, CPL_ERROR_DATA_NOT_FOUND, "No masked "
455  "quadrant found, cannot adapt %dx%d mask to %dx%d "
456  "image size!", nx, ny, nximage, nyimage);
457  return NULL;
458  }
459  cpl_msg_debug(__func__, "Adapting %dx%d mask in %s quadrant (%d masked pixels)"
460  " to %dx%d image", nx, ny, cnames[nmaxcorner], nmax,
461  nximage, nyimage);
462  /* extract masked quadrant */
463  cpl_mask *xmask;
464  switch (nmaxcorner) {
465  case BOTTOMLEFT:
466  xmask = cpl_mask_extract(aMask, 1, 1, nx/2, ny/2);
467  break;
468  case BOTTOMRIGHT:
469  xmask = cpl_mask_extract(aMask, nx/2, 1, nx, ny/2);
470  break;
471  case TOPRIGHT:
472  xmask = cpl_mask_extract(aMask, nx/2, ny/2, nx, ny);
473  break;
474  default: /* TOPLEFT */
475  xmask = cpl_mask_extract(aMask, 1, ny/2, nx/2, ny);
476  } /* switch */
477  /* track the extracted size */
478  nx = cpl_mask_get_size_x(xmask);
479  ny = cpl_mask_get_size_y(xmask);
480 
481  /* create new mask of the right size */
482  cpl_mask *outmask = cpl_mask_new(nximage, nyimage);
483  /* copy the extracted region into it, so that it aligns with the right corner */
484  cpl_error_code rc = CPL_ERROR_NONE;
485  switch (nmaxcorner) {
486  case BOTTOMLEFT:
487  rc = cpl_mask_copy(outmask, xmask, 1, 1);
488  break;
489  case BOTTOMRIGHT:
490  rc = cpl_mask_copy(outmask, xmask, nximage - nx + 1, 1);
491  break;
492  case TOPRIGHT:
493  rc = cpl_mask_copy(outmask, xmask, nximage - nx + 1, nyimage - ny + 1);
494  break;
495  default: /* TOPLEFT */
496  rc = cpl_mask_copy(outmask, xmask, 1, nyimage - ny + 1);
497  } /* switch */
498  cpl_mask_delete(xmask);
499  if (rc != CPL_ERROR_NONE) {
500  cpl_mask_delete(outmask);
501  cpl_error_set_message(__func__, rc, "Could not copy %dx%d quadrant with "
502  "masked region into new %dx%d mask", nx, ny,
503  nximage, nyimage);
504  return NULL;
505  }
506 
507  return outmask;
508 } /* muse_cplmask_adapt_to_image() */
509 
510 /*----------------------------------------------------------------------------*/
519 /*----------------------------------------------------------------------------*/
520 double
521 muse_cplvector_get_adev_const(const cpl_vector *aVector, double aCenter)
522 {
523  cpl_ensure(aVector, CPL_ERROR_NULL_INPUT, 0.);
524  double mdev = 0;
525  cpl_size i, n = cpl_vector_get_size(aVector);
526  for (i = 0; i < n; i++) {
527  mdev += fabs(cpl_vector_get(aVector, i) - aCenter);
528  }
529  return mdev / (double)n; /* return normalized value */
530 } /* muse_cplvector_get_adev_const() */
531 
532 /*----------------------------------------------------------------------------*/
545 /*----------------------------------------------------------------------------*/
546 double
547 muse_cplvector_get_median_dev(cpl_vector *aVector, double *aMedian)
548 {
549  cpl_ensure(aVector, CPL_ERROR_NULL_INPUT, 0.);
550  double median = cpl_vector_get_median(aVector),
551  mdev = 0.;
552  cpl_size i, n = cpl_vector_get_size(aVector);
553  for (i = 0; i < n; i++) {
554  mdev += fabs(cpl_vector_get(aVector, i) - median);
555  }
556  if (aMedian) {
557  *aMedian = median;
558  }
559  return mdev / (double)n; /* return normalized value */
560 } /* muse_cplvector_get_median_dev() */
561 
562 /*----------------------------------------------------------------------------*/
576 /*----------------------------------------------------------------------------*/
577 double
579 {
580  double sqr = 0;
581  double median = cpl_vector_get_median_const(aVector);
582  cpl_vector *v = cpl_vector_duplicate(aVector), *v2;
583  int i, splitindex = 0;
584 
585  cpl_vector_sort(v, +1);
586 #if DEBUG_SQR
587  cpl_vector_dump(v, stdout);
588  fflush(stdout);
589  printf("median=%f%d\n", median);
590  fflush(stdout);
591 #endif
592  /* search for point to split the sorted vector, better just do it linearly */
593  splitindex = cpl_vector_find(v, median);
594 
595  /* copy upper half into new vector */
596  v2 = cpl_vector_new(cpl_vector_get_size(v) - splitindex - 1);
597 #if DEBUG_SQR
598  printf("Copying elements %d to %d\n", splitindex+1, cpl_vector_get_size(v)-1);
599 #endif
600  for (i = splitindex; i < cpl_vector_get_size(v); i++){
601 #if DEBUG_SQR
602  printf(" %d %f\n", i+1, cpl_vector_get(v, i));
603 #endif
604  cpl_vector_set(v2, i-splitindex, cpl_vector_get(v, i));
605  }
606 #if DEBUG_SQR
607  printf("\n");
608  fflush(stdout);
609 #endif
610  sqr = cpl_vector_get_median(v2); /* the upper median, non const OK */
611  cpl_vector_delete(v2);
612 
613  /* copy lower half into new vector */
614  v2 = cpl_vector_new(splitindex - 1);
615 #if DEBUG_SQR
616  printf("Copying elements %d to %d\n", 1, splitindex+1);
617 #endif
618  for (i = 0; i <= splitindex; i++) {
619 #if DEBUG_SQR
620  printf(" %d %f\n", i+1, cpl_vector_get(v, i));
621 #endif
622  cpl_vector_set(v2, i, cpl_vector_get(v, i));
623  }
624 #if DEBUG_SQR
625  printf("\n");
626  fflush(stdout);
627 #endif
628  sqr -= cpl_vector_get_median(v2); /* subtract the lower median, non const OK */
629  cpl_vector_delete(v2);
630 
631  return sqr/2.0; /* divide by two to get semiquartile range */
632 } /* muse_cplvector_get_semiquartile() */
633 
634 /*----------------------------------------------------------------------------*/
654 /*----------------------------------------------------------------------------*/
655 cpl_error_code
656 muse_cplvector_threshold(cpl_vector *aVec, double aLoCut, double aHiCut,
657  double aLoVal, double aHiVal)
658 {
659  cpl_ensure_code(aVec, CPL_ERROR_NULL_INPUT);
660  cpl_ensure_code(aLoCut <= aHiCut, CPL_ERROR_ILLEGAL_INPUT);
661 
662  double *data = cpl_vector_get_data(aVec);
663  int i, n = cpl_vector_get_size(aVec);
664  for (i = 0; i < n; i++) {
665  if (data[i] > aHiCut) {
666  data[i] = aHiVal;
667  } else if (data[i] < aLoCut) {
668  data[i] = aLoVal;
669  }
670  } /* for i (vector elements) */
671 
672  return CPL_ERROR_NONE;
673 }
674 
675 /*----------------------------------------------------------------------------*/
687 /*----------------------------------------------------------------------------*/
688 cpl_error_code
689 muse_cplvector_erase_element(cpl_vector *aVector, int aElement)
690 {
691  cpl_ensure_code(aVector, CPL_ERROR_NULL_INPUT);
692  int size = cpl_vector_get_size(aVector);
693  cpl_ensure_code(aElement >= 0 && aElement < size, CPL_ERROR_ILLEGAL_INPUT);
694 
695  if (aElement < size - 1) {
696  /* if it's not the last element, we need to move the remaining *
697  * elements so that they overwrite the one to be removed */
698  double *data = cpl_vector_get_data(aVector);
699  memmove(&data[aElement], &data[aElement+1],
700  (size-1 - aElement) * sizeof(double));
701  }
702 
703  /* resize the vector to account for the removed element */
704  return cpl_vector_set_size(aVector, size - 1);
705 } /* muse_cplvector_erase_element() */
706 
707 /*----------------------------------------------------------------------------*/
715 /*----------------------------------------------------------------------------*/
716 cpl_size
717 muse_cplvector_count_unique(const cpl_vector *aVector)
718 {
719  cpl_ensure(aVector, CPL_ERROR_NULL_INPUT, -1);
720  cpl_vector *sorted = cpl_vector_duplicate(aVector);
721  cpl_vector_sort(sorted, CPL_SORT_ASCENDING);
722  double *data = cpl_vector_get_data(sorted);
723  cpl_size i, n = cpl_vector_get_size(sorted),
724  nunique = 1; /* first element is always unique */
725  for (i = 1; i < n; i++) { /* start at 2nd element */
726  if (data[i] != data[i - 1]) {
727  nunique++;
728  }
729  } /* for i (all elements in sorted vector) */
730  cpl_vector_delete(sorted);
731  return nunique;
732 } /* muse_cplvector_count_unique() */
733 
734 /*----------------------------------------------------------------------------*/
742 /*----------------------------------------------------------------------------*/
743 cpl_vector *
744 muse_cplvector_get_unique(const cpl_vector *aVector)
745 {
746  cpl_ensure(aVector, CPL_ERROR_NULL_INPUT, NULL);
747  cpl_vector *sorted = cpl_vector_duplicate(aVector);
748  cpl_vector_sort(sorted, CPL_SORT_ASCENDING);
749  double *data = cpl_vector_get_data(sorted);
750  cpl_size i, n = cpl_vector_get_size(sorted),
751  iunique = 0;
752  cpl_vector *vunique = cpl_vector_new(n);
753  cpl_vector_set(vunique, iunique++, data[0]); /* set unique first element */
754  for (i = 1; i < n; i++) { /* start at 2nd element */
755  if (data[i] != data[i - 1]) {
756  cpl_vector_set(vunique, iunique++, data[i]);
757  }
758  } /* for i (all elements in sorted vector) */
759  cpl_vector_delete(sorted);
760  cpl_vector_set_size(vunique, iunique);
761  return vunique;
762 } /* muse_cplvector_get_unique() */
763 
764 /*----------------------------------------------------------------------------*/
774 /*----------------------------------------------------------------------------*/
775 cpl_table *
776 muse_cpltable_new(const muse_cpltable_def *aDef, cpl_size aLength)
777 {
778  cpl_ensure(aDef, CPL_ERROR_NULL_INPUT, NULL);
779  cpl_table *res = cpl_table_new(aLength);
780  for (; aDef->name != NULL; aDef++) {
781  cpl_error_code rc = CPL_ERROR_NONE;
782  if (aDef->type & CPL_TYPE_POINTER) {
783  rc = cpl_table_new_column_array(res, aDef->name, aDef->type, 2);
784  } else {
785  rc = cpl_table_new_column(res, aDef->name, aDef->type);
786  }
787  if (rc != CPL_ERROR_NONE) {
788  cpl_table_delete(res);
789  return NULL;
790  }
791  if (aDef->unit != NULL) {
792  if (cpl_table_set_column_unit(res, aDef->name,
793  aDef->unit) != CPL_ERROR_NONE) {
794  return NULL;
795  }
796  }
797  if (aDef->format != NULL) {
798  if (cpl_table_set_column_format(res, aDef->name,
799  aDef->format) != CPL_ERROR_NONE) {
800  return NULL;
801  }
802  }
803  }
804  return res;
805 }
806 
807 /*----------------------------------------------------------------------------*/
819 /*----------------------------------------------------------------------------*/
820 cpl_table *
821 muse_cpltable_load(const char *aFile, const char *aExtension,
822  const muse_cpltable_def aDefinition[])
823 {
824  int extension = cpl_fits_find_extension(aFile, aExtension);
825  if (extension <= 0) {
826  cpl_error_set_message(__func__, cpl_error_get_code(), "%s['%s']: "
827  "extension not found by EXTNAME", aFile, aExtension);
828  return NULL;
829  }
830  cpl_msg_debug(__func__, "Loading %s['%s'] from extension %d", aFile,
831  aExtension, extension);
832  cpl_table *tbl = cpl_table_load(aFile, extension, 2);
833  if (muse_cpltable_check(tbl, aDefinition) != CPL_ERROR_NONE) {
834  cpl_table_delete(tbl);
835  return NULL;
836  }
837  return tbl;
838 } /* muse_cpltable_load() */
839 
840 /*----------------------------------------------------------------------------*/
857 /*----------------------------------------------------------------------------*/
858 cpl_error_code
859 muse_cpltable_append_file(const cpl_table *aTable, const char *aFile,
860  const char *aExtension,
861  const muse_cpltable_def aDefinition[]) {
862  cpl_ensure_code(aTable != NULL, CPL_ERROR_NULL_INPUT);
863  cpl_ensure_code(aFile != NULL, CPL_ERROR_NULL_INPUT);
864  cpl_ensure_code(aExtension != NULL, CPL_ERROR_NULL_INPUT);
865  cpl_error_code r = muse_cpltable_check(aTable, aDefinition);
866  if (r != CPL_ERROR_NONE) {
867  cpl_msg_error(__func__, " %s['%s'] Table format error", aFile, aExtension);
868  cpl_error_set(__func__, r);
869  return r;
870  }
871  cpl_propertylist *props = cpl_propertylist_new();
872  cpl_propertylist_update_string(props, "EXTNAME", aExtension);
873  r = cpl_table_save(aTable, NULL, props, aFile, CPL_IO_EXTEND);
874  cpl_propertylist_delete(props);
875  if (r != CPL_ERROR_NONE) {
876  cpl_msg_error(__func__, "%s[%s]: %s", aFile, aExtension,
877  cpl_error_get_message());
878  }
879  return r;
880 }
881 
882 
883 /*----------------------------------------------------------------------------*/
889 /*----------------------------------------------------------------------------*/
890 cpl_error_code
891 muse_cpltable_check(const cpl_table *aTable, const muse_cpltable_def *aDef)
892 {
893  if (aTable == NULL) {
894  cpl_msg_error(__func__, "NULL table");
895  cpl_error_set(__func__, CPL_ERROR_NULL_INPUT);
896  return CPL_ERROR_NULL_INPUT;
897  }
898  if (aDef == NULL) {
899  return CPL_ERROR_NONE;
900  }
901  cpl_error_code rc = CPL_ERROR_NONE;
902  for (; aDef->name != NULL; aDef++) {
903  if (!cpl_table_has_column(aTable, aDef->name)) {
904  if (aDef->required) {
905  rc = CPL_ERROR_ILLEGAL_INPUT;
906  cpl_error_set_message(__func__, rc, "table column '%s' not found",
907  aDef->name);
908  }
909  continue;
910  }
911  cpl_type coltype = cpl_table_get_column_type(aTable, aDef->name);
912  if (((coltype | CPL_TYPE_POINTER) != (aDef->type | CPL_TYPE_POINTER)) ||
913  ((coltype & CPL_TYPE_POINTER) && !(aDef->type & CPL_TYPE_POINTER))) {
914  rc = CPL_ERROR_ILLEGAL_INPUT;
915  cpl_error_set_message(__func__, rc,
916  "table column '%s' format '%s' is not '%s'",
917  aDef->name, cpl_type_get_name(coltype),
918  cpl_type_get_name(aDef->type));
919  }
920  }
921  return rc;
922 } /* muse_cpltable_check() */
923 
924 /*----------------------------------------------------------------------------*/
941 /*----------------------------------------------------------------------------*/
942 cpl_array *
943 muse_cpltable_extract_column(cpl_table *aTable, const char *aColumn)
944 {
945  cpl_ensure(aTable && aColumn, CPL_ERROR_NULL_INPUT, NULL);
946  cpl_size nRows = cpl_table_get_nrow(aTable);
947 
948  cpl_type type = cpl_table_get_column_type(aTable, aColumn);
949  if (nRows == 0) {
950  return cpl_array_new(0, type);
951  }
952  if (type == CPL_TYPE_DOUBLE) {
953  double *src = cpl_table_get_data_double(aTable, aColumn);
954  return cpl_array_wrap_double(src, nRows);
955  } else if (type == CPL_TYPE_FLOAT) {
956  float *src = cpl_table_get_data_float(aTable, aColumn);
957  return cpl_array_wrap_float(src, nRows);
958  } else if (type == CPL_TYPE_INT) {
959  int *src = cpl_table_get_data_int(aTable, aColumn);
960  return cpl_array_wrap_int(src, nRows);
961  } else {
962  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
963  cpl_msg_error(__func__, "%s: %i - %s", cpl_error_get_message(), type,
964  cpl_type_get_name(type));
965  return NULL;
966  }
967 }
968 
969 /*----------------------------------------------------------------------------*/
979 /*----------------------------------------------------------------------------*/
980 cpl_error_code
981 muse_cpltable_copy_array(cpl_table *aTable, const char *aColumn,
982  const cpl_array *aArray)
983 {
984  cpl_ensure_code(aTable && aColumn && aArray, CPL_ERROR_NULL_INPUT);
985  cpl_size n_rows = cpl_table_get_nrow(aTable);
986  cpl_size i;
987  for (i = 0; i < n_rows; i++) {
988  int flag;
989  double d = cpl_array_get(aArray, i, &flag);
990  if (flag == 0) {
991  cpl_table_set(aTable, aColumn, i, d);
992  } else {
993  cpl_table_set_invalid(aTable, aColumn, i);
994  }
995  }
996  return CPL_ERROR_NONE;
997 }
998 
999 /*----------------------------------------------------------------------------*/
1009 /*----------------------------------------------------------------------------*/
1010 cpl_array *
1011 muse_cpltable_get_array_copy(cpl_table *aTable, const char *aColumn,
1012  cpl_size aRow)
1013 {
1014  cpl_ensure(aTable && aColumn, CPL_ERROR_NULL_INPUT, NULL);
1015  if (cpl_table_get_column_type(aTable, aColumn) & CPL_TYPE_POINTER) {
1016  return cpl_array_duplicate(cpl_table_get_array(aTable, aColumn, aRow));
1017  } else {
1018  cpl_array *res
1019  = cpl_array_new(1, cpl_table_get_column_type(aTable, aColumn));
1020  int flag;
1021  cpl_array_set(res, 0, cpl_table_get(aTable, aColumn, aRow, &flag));
1022  if (flag) {
1023  cpl_array_delete(res);
1024  return NULL;
1025  } else {
1026  return res;
1027  }
1028  }
1029 }
1030 /*----------------------------------------------------------------------------*/
1044 /*----------------------------------------------------------------------------*/
1045 
1046 cpl_size
1047 muse_cpltable_find_sorted(const cpl_table *aTable, const char *aColumn,
1048  double aValue) {
1049  cpl_ensure(aTable && aColumn, CPL_ERROR_NULL_INPUT, 0);
1050  cpl_array *array = muse_cpltable_extract_column((cpl_table *)aTable, aColumn);
1051  cpl_size res = muse_cplarray_find_sorted(array, aValue);
1052  cpl_array_unwrap(array);
1053  return res;
1054 }
1055 
1056 /*----------------------------------------------------------------------------*/
1064 /*----------------------------------------------------------------------------*/
1065 cpl_array *
1066 muse_cplarray_new_from_image(const cpl_image *aImage) {
1067  cpl_size nx = cpl_image_get_size_x(aImage);
1068  cpl_size ny = cpl_image_get_size_y(aImage);
1069  cpl_array *array = cpl_array_new(nx*ny, cpl_image_get_type(aImage));
1070  cpl_size i = 0;
1071  cpl_size iy;
1072  for (iy = 1; iy <= ny; iy++) {
1073  int ix;
1074  for (ix = 1; ix <= nx; ix++, i++) {
1075  int rej;
1076  double d = cpl_image_get(aImage, ix, iy, &rej);
1077  cpl_array_set(array, i, d);
1078  if (rej) {
1079  cpl_array_set_invalid(array, i);
1080  }
1081  }
1082  }
1083  return array;
1084 }
1085 
1086 /*----------------------------------------------------------------------------*/
1099 /*----------------------------------------------------------------------------*/
1100 cpl_error_code
1101 muse_cplarray_poly1d(cpl_array *aArray, const cpl_array *aCoeff)
1102 {
1103  cpl_ensure_code(aArray && aCoeff, CPL_ERROR_NULL_INPUT);
1104  const cpl_size nrows = cpl_array_get_size(aArray);
1105  cpl_size order = cpl_array_get_size(aCoeff);
1106  if (order == 0) {
1107  cpl_array_fill_window(aArray, 0, nrows, 0.0);
1108  return CPL_ERROR_NONE;
1109  }
1110  order--;
1111  cpl_array *x = cpl_array_duplicate(aArray);
1112  cpl_array_fill_window(aArray, 0, nrows, cpl_array_get(aCoeff, order, NULL));
1113 
1114  int k;
1115  for (k = order-1; k >= 0; k--) {
1116  cpl_array_multiply(aArray, x);
1117  cpl_array_add_scalar(aArray, cpl_array_get(aCoeff, k, NULL));
1118  }
1119 
1120  cpl_array_delete(x);
1121 
1122  return CPL_ERROR_NONE;
1123 }
1124 
1125 /*----------------------------------------------------------------------------*/
1137 /*----------------------------------------------------------------------------*/
1138 double
1139 muse_cplarray_poly1d_double(double aDouble, const cpl_array *aCoeff)
1140 {
1141  cpl_ensure(aCoeff, CPL_ERROR_NULL_INPUT, NAN);
1142  cpl_size order = cpl_array_get_size(aCoeff);
1143  if (order == 0) {
1144  return 0.0;
1145  }
1146  order--;
1147  double res = cpl_array_get(aCoeff, order, NULL);
1148  int k;
1149  for (k = order-1; k >= 0; k--) {
1150  res = res * aDouble + cpl_array_get(aCoeff, k, NULL);
1151  }
1152  return res;
1153 }
1154 
1155 /*----------------------------------------------------------------------------*/
1164 /*----------------------------------------------------------------------------*/
1165 cpl_error_code
1166 muse_cplarray_dump_name(const cpl_array *aArray, const char *aName)
1167 {
1168  cpl_ensure_code(aArray && aName, CPL_ERROR_NULL_INPUT);
1169  cpl_size i, size = cpl_array_get_size(aArray);
1170  for (i = 0; i < size; i++) {
1171  printf("%s[%"CPL_SIZE_FORMAT"] = %g\n", aName, i,
1172  cpl_array_get(aArray, i, NULL));
1173  }
1174  return CPL_ERROR_NONE;
1175 }
1176 
1177 /*----------------------------------------------------------------------------*/
1183 /*----------------------------------------------------------------------------*/
1184 cpl_error_code
1186 {
1187  cpl_ensure_code(aArray != NULL, CPL_ERROR_NULL_INPUT);
1188  cpl_size n = cpl_array_get_size(aArray);
1189  cpl_size n_val = n - cpl_array_count_invalid(aArray);
1190  cpl_msg_debug(__func__, "size = %li, %li valid", (long)n, (long)n_val);
1191  if (n_val == n) {
1192  return CPL_ERROR_NONE;
1193  }
1194  cpl_size i;
1195  cpl_size idx = 0;
1196  for (i = 0; (i < n) && (idx < n_val); i++) {
1197  int rej;
1198  double d = cpl_array_get(aArray, i, &rej);
1199  if (!rej) {
1200  if (idx < i) {
1201  cpl_array_set(aArray, idx, d);
1202  }
1203  idx++;
1204  }
1205  }
1206  cpl_array_set_size(aArray, n_val);
1207  return CPL_ERROR_NONE;
1208 }
1209 
1210 /*---------------------------------------------------------------------------*/
1225 /*---------------------------------------------------------------------------*/
1226 cpl_size
1227 muse_cplarray_erase_outliers(cpl_array *aArray, const cpl_bivector *aHistogram,
1228  cpl_size aGap, double aLimit)
1229 {
1230  cpl_ensure(aArray && aHistogram, CPL_ERROR_NULL_INPUT, -1);
1231  /* test for numerical array */
1232  int err;
1233  double value = cpl_array_get(aArray, 0, &err);
1234  cpl_ensure(err >= 0, CPL_ERROR_ILLEGAL_INPUT, -2);
1235 
1236  /* start at the peak of the histogram */
1237  const double *hpos = cpl_bivector_get_x_data_const(aHistogram),
1238  *hval = cpl_bivector_get_y_data_const(aHistogram);
1239  cpl_size nhist = cpl_bivector_get_size(aHistogram);
1240  cpl_array *ahist = cpl_array_wrap_double((double *)hval, nhist);
1241  cpl_size imax;
1242  cpl_array_get_maxpos(ahist, &imax);
1243  cpl_array_unwrap(ahist);
1244 
1245  /* go to lower values in the histogram, search for the first gap */
1246  double loval = hpos[0],
1247  hival = hpos[nhist - 1];
1248  cpl_size i, nlow = 0;
1249  for (i = imax; i >= 0; i--) {
1250  if (hval[i] <= aLimit) {
1251  if (nlow == 0) { /* keep this as the initial low value */
1252  loval = hpos[i];
1253  }
1254  nlow++;
1255  if (nlow == aGap) { /* gap already wide enough */
1256  break;
1257  }
1258  } else if (nlow > 0) {
1259  nlow = 0; /* gap not wide enough after all */
1260  loval = hpos[0];
1261  }
1262  } /* for i */
1263  /* same search now to higher histogram values */
1264  for (i = imax; i < nhist; i++) {
1265  if (hval[i] <= aLimit) {
1266  if (nlow == 0) { /* keep this as the initial low value */
1267  hival = hpos[i];
1268  }
1269  nlow++;
1270  if (nlow == aGap) { /* gap already wide enough */
1271  break;
1272  }
1273  } else if (nlow > 0) {
1274  nlow = 0; /* gap not wide enough after all */
1275  hival = hpos[nhist - 1];
1276  }
1277  } /* for i */
1278  cpl_msg_debug(__func__, "Histogram gaps (%"CPL_SIZE_FORMAT" consecutive "
1279  "entries <= %f) at %f and %f", aGap, aLimit, loval, hival);
1280 
1281  /* now go through the array, and set values larger *
1282  * or smaller than these extremes to invalid */
1283  cpl_size idx, narray = cpl_array_get_size(aArray);
1284  for (idx = 0; idx < narray; idx++) {
1285  value = cpl_array_get(aArray, idx, NULL);
1286  if (value > hival || value < loval) {
1287  cpl_array_set_invalid(aArray, idx);
1288  }
1289  } /* for idx */
1290 
1291  /* finally count them and then remove all invalid ones */
1292  cpl_size nbad = cpl_array_count_invalid(aArray);
1294  return nbad;
1295 } /* muse_cplarray_erase_outliers() */
1296 
1297 
1298 /*----------------------------------------------------------------------------*/
1299 /* Helper functions for quicksort */
1300 /*----------------------------------------------------------------------------*/
1302 static int cmp_double_asc(const void *p1, const void *p2) {
1303  double d = (*(const double *)p1 - *(const double *)p2);
1304  return (d < 0)?-1:(d>0)?1:0;
1305 }
1307 static int cmp_double_desc(const void *p1, const void *p2) {
1308  double d = (*(const double *)p1 - *(const double *)p2);
1309  return (d < 0)?1:(d>0)?-1:0;
1310 }
1312 static int cmp_float_asc(const void *p1, const void *p2) {
1313  float d = (*(const float *)p1 - *(const float *)p2);
1314  return (d < 0)?-1:(d>0)?1:0;
1315 }
1317 static int cmp_float_desc(const void *p1, const void *p2) {
1318  float d = (*(const float *)p1 - *(const float *)p2);
1319  return (d < 0)?1:(d>0)?-1:0;
1320 }
1322 static int cmp_int_asc(const void *p1, const void *p2) {
1323  return (*(const int *)p1 - *(const int *)p2);
1324 }
1326 static int cmp_int_desc(const void *p1, const void *p2) {
1327  return (*(const int *)p2 - *(const int *)p1);
1328 }
1329 
1330 /*----------------------------------------------------------------------------*/
1340 /*----------------------------------------------------------------------------*/
1341 cpl_error_code
1342 muse_cplarray_sort(cpl_array *aArray, cpl_boolean aOrder)
1343 {
1344  cpl_ensure_code(aArray != NULL, CPL_ERROR_NULL_INPUT);
1345  cpl_ensure_code(!cpl_array_has_invalid(aArray), CPL_ERROR_NULL_INPUT);
1346 
1347  cpl_size n = cpl_array_get_size(aArray);
1348  if (cpl_array_get_type(aArray) == CPL_TYPE_DOUBLE) {
1349  double *d = cpl_array_get_data_double(aArray);
1350  qsort(d, n, sizeof(double), (aOrder)?cmp_double_asc:cmp_double_desc);
1351  return CPL_ERROR_NONE;
1352  } else if (cpl_array_get_type(aArray) == CPL_TYPE_FLOAT) {
1353  float *d = cpl_array_get_data_float(aArray);
1354  qsort(d, n, sizeof(float), (aOrder)?cmp_float_asc:cmp_float_desc);
1355  return CPL_ERROR_NONE;
1356  } else if (cpl_array_get_type(aArray) == CPL_TYPE_INT) {
1357  int *d = cpl_array_get_data_int(aArray);
1358  qsort(d, n, sizeof(int), (aOrder)?cmp_int_asc:cmp_int_desc);
1359  return CPL_ERROR_NONE;
1360  } else {
1361  return CPL_ERROR_ILLEGAL_INPUT;
1362  }
1363 }
1364 
1365 /*---------------------------------------------------------------------------*/
1384 /*---------------------------------------------------------------------------*/
1385 cpl_bivector *
1386 muse_cplarray_histogram(const cpl_array *aArray, double aWidth,
1387  double aMin, double aMax)
1388 {
1389  cpl_ensure(aArray, CPL_ERROR_NULL_INPUT, NULL);
1390  /* test for numerical array */
1391  int err;
1392  double value = cpl_array_get(aArray, 0, &err);
1393  cpl_ensure(err >= 0, CPL_ERROR_INVALID_TYPE, NULL);
1394  if (!isnan(aMin) && !isnan(aMax) && aMin >= aMax) { /* inverse extremes */
1395  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
1396  return NULL;
1397  }
1398  if (isnan(aMin)) {
1399  aMin = cpl_array_get_min(aArray);
1400  }
1401  if (isnan(aMax)) {
1402  aMax = cpl_array_get_max(aArray);
1403  }
1404  cpl_size hlen = lround((aMax - aMin) / aWidth) + 1;
1405  cpl_bivector *histogram = cpl_bivector_new(hlen);
1406 
1407  /* fill histogram positions */
1408  double *hpos = cpl_bivector_get_x_data(histogram);
1409  cpl_size i;
1410  for (i = 0; i < hlen; i++) {
1411  hpos[i] = i * aWidth + aMin;
1412  } /* for i */
1413 
1414  /* fill histogram values */
1415  double *hval = cpl_bivector_get_y_data(histogram);
1416  /* histogram has at least zero everywhere */
1417  cpl_vector_fill(cpl_bivector_get_y(histogram), 0.);
1418  cpl_size n = cpl_array_get_size(aArray);
1419  for (i = 0; i < n; i++) {
1420  value = cpl_array_get(aArray, i, &err);
1421  if (err) {
1422  continue;
1423  }
1424  /* find histogram index */
1425  cpl_size idx = lround((value - aMin) / aWidth);
1426  if (idx >= hlen || idx < 0) {
1427  continue;
1428  }
1429  /* add one to the histogram at the respective index */
1430  hval[idx] += 1;
1431  } /* for i */
1432 #if 0
1433  printf("histogram %f...%f / %f\n", aMin, aMax, aWidth);
1434  cpl_bivector_dump(histogram, stdout);
1435  fflush(stdout);
1436 #endif
1437  return histogram;
1438 } /* muse_cplarray_histogram() */
1439 
1440 /*----------------------------------------------------------------------------*/
1453 /*----------------------------------------------------------------------------*/
1454 cpl_size
1455 muse_cplarray_find_sorted(const cpl_array *aArray, double aValue)
1456 {
1457  cpl_ensure(aArray, CPL_ERROR_NULL_INPUT, 0);
1458  cpl_size min = 0;
1459  cpl_size max = cpl_array_get_size(aArray);
1460  cpl_type type = cpl_array_get_type(aArray);
1461  if (type == CPL_TYPE_DOUBLE) {
1462  const double *data = cpl_array_get_data_double_const(aArray);
1463  while (max - min > 1) {
1464  int i = (max + min)/2;
1465  if (data[i] > aValue) {
1466  max = i;
1467  } else {
1468  min = i;
1469  }
1470  }
1471  } else if (type == CPL_TYPE_FLOAT) {
1472  const float *data = cpl_array_get_data_float_const(aArray);
1473  while (max - min > 1) {
1474  int i = (max + min)/2;
1475  if (data[i] > aValue) {
1476  max = i;
1477  } else {
1478  min = i;
1479  }
1480  }
1481  } else if (type == CPL_TYPE_INT) {
1482  const int *data = cpl_array_get_data_int_const(aArray);
1483  while (max - min > 1) {
1484  int i = (max + min)/2;
1485  if (data[i] > aValue) {
1486  max = i;
1487  } else {
1488  min = i;
1489  }
1490  }
1491  } else {
1492  cpl_msg_error(__func__, "illegal type %i", type);
1493  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
1494  return 0;
1495  }
1496  return min;
1497 }
1498 
1499 /*----------------------------------------------------------------------------*/
1514 /*----------------------------------------------------------------------------*/
1515 cpl_boolean
1516 muse_cplarray_has_duplicate(const cpl_array *aArray)
1517 {
1518  cpl_ensure(aArray, CPL_ERROR_NULL_INPUT, CPL_FALSE);
1519  cpl_type type = cpl_array_get_type(aArray);
1520  switch (type) {
1521  case CPL_TYPE_INT:
1522  case CPL_TYPE_LONG:
1523  case CPL_TYPE_LONG_LONG:
1524  case CPL_TYPE_SIZE:
1525  break;
1526  default:
1527  cpl_error_set(__func__, CPL_ERROR_UNSUPPORTED_MODE);
1528  return CPL_FALSE;
1529  }
1530 
1531  cpl_size idx, n = cpl_array_get_size(aArray);
1532  for (idx = 0; idx < n - 1; idx++) {
1533  int err;
1534  cpl_size v1 = cpl_array_get(aArray, idx, &err);
1535  if (err) { /* invalid somehow, skip this one */
1536  continue;
1537  }
1538  cpl_size idx2;
1539  for (idx2 = idx + 1; idx2 < n; idx2++) {
1540  cpl_size v2 = cpl_array_get(aArray, idx2, &err);
1541  if (err) { /* invalid somehow, skip this one */
1542  continue;
1543  }
1544  if (v2 == v1) {
1545 #if 0
1546  cpl_msg_debug(__func__, "entry[%"CPL_SIZE_FORMAT"] == entry[%"
1547  CPL_SIZE_FORMAT"] == %"CPL_SIZE_FORMAT, idx, idx2, v1);
1548 #endif
1549  return CPL_TRUE;
1550  }
1551  } /* for idx2 (array indices starting after idx) */
1552  } /* for idx (all array indices but the last) */
1553  return CPL_FALSE;
1554 } /* muse_cplarray_has_duplicate() */
1555 
1556 /*----------------------------------------------------------------------------*/
1569 /*----------------------------------------------------------------------------*/
1570 cpl_array *
1571 muse_cplarray_extract(cpl_array *aArray, cpl_size aStart, cpl_size aCount)
1572 {
1573  cpl_size nrows = cpl_array_get_size(aArray);
1574  if (aCount > nrows - aStart) {
1575  aCount = nrows - aStart;
1576  }
1577  cpl_type type = cpl_array_get_type(aArray);
1578  if (type == CPL_TYPE_DOUBLE) {
1579  return cpl_array_wrap_double(cpl_array_get_data_double(aArray) + aStart,
1580  aCount);
1581  } else if (type == CPL_TYPE_FLOAT) {
1582  return cpl_array_wrap_float(cpl_array_get_data_float(aArray) + aStart,
1583  aCount);
1584  } else if (type == CPL_TYPE_INT) {
1585  return cpl_array_wrap_int(cpl_array_get_data_int(aArray) + aStart,
1586  aCount);
1587  } else {
1588  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
1589  return NULL;
1590  }
1591 }
1592 /*----------------------------------------------------------------------------*/
1606 /*----------------------------------------------------------------------------*/
1607 cpl_error_code
1608 muse_cplarray_add_window(cpl_array *aDest, cpl_size aStart,
1609  const cpl_array *aArray)
1610 {
1611  cpl_ensure_code(aDest && aArray, CPL_ERROR_NULL_INPUT);
1612  cpl_size count = cpl_array_get_size(aArray);
1613  cpl_array *destArray = muse_cplarray_extract(aDest, aStart, count);
1614  if (destArray == NULL) {
1615  return CPL_ERROR_ILLEGAL_INPUT;
1616  }
1617  cpl_array_add(destArray, aArray);
1618  cpl_array_unwrap(destArray);
1619 
1620  return CPL_ERROR_NONE;
1621 }
1622 
1623 /*----------------------------------------------------------------------------*/
1633 /*----------------------------------------------------------------------------*/
1634 cpl_array *
1635 muse_cplarray_diff(const cpl_array *aArray, int aOffset)
1636 {
1637  cpl_ensure(aArray, CPL_ERROR_NULL_INPUT, NULL);
1638  cpl_ensure(aOffset > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1639  cpl_size nrows = cpl_array_get_size(aArray);
1640 
1641  cpl_array *a1 = cpl_array_extract(aArray, 0, nrows - aOffset);
1642  cpl_array *a2 = cpl_array_extract(aArray, aOffset, nrows - aOffset);
1643  if (a1 == NULL || a2 == NULL) {
1644  cpl_array_delete(a1);
1645  cpl_array_delete(a2);
1646  return NULL;
1647  }
1648  cpl_array_subtract(a2, a1);
1649  cpl_array_delete(a1);
1650  return a2;
1651 }
1652 
1653 /*----------------------------------------------------------------------------*/
1666 /*----------------------------------------------------------------------------*/
1667 cpl_error_code
1668 muse_cplarray_erf(cpl_array *aArray)
1669 {
1670  cpl_ensure_code(aArray, CPL_ERROR_NULL_INPUT);
1671  cpl_type type = cpl_array_get_type(aArray);
1672  cpl_size n = cpl_array_get_size(aArray);
1673  if (type == CPL_TYPE_DOUBLE) {
1674  double *d = cpl_array_get_data_double(aArray);
1675  cpl_size i;
1676  for (i = 0; i < n; i++, d++) {
1677  *d = erf(*d);
1678  }
1679  } else if (type == CPL_TYPE_FLOAT) {
1680  float *d = cpl_array_get_data_float(aArray);
1681  cpl_size i;
1682  for (i = 0; i < n; i++, d++) {
1683  *d = erf(*d);
1684  }
1685  } else {
1686  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
1687  return CPL_ERROR_ILLEGAL_INPUT;
1688  }
1689  return CPL_ERROR_NONE;
1690 }
1691 
1692 /*----------------------------------------------------------------------------*/
1705 /*----------------------------------------------------------------------------*/
1706 cpl_error_code
1707 muse_cplarray_exp(cpl_array *aArray)
1708 {
1709  cpl_ensure_code(aArray, CPL_ERROR_NULL_INPUT);
1710  cpl_type type = cpl_array_get_type(aArray);
1711  cpl_size n = cpl_array_get_size(aArray);
1712  if (type == CPL_TYPE_DOUBLE) {
1713  double *d = cpl_array_get_data_double(aArray);
1714  cpl_size i;
1715  for (i = 0; i < n; i++, d++) {
1716  *d = exp(*d);
1717  }
1718  } else if (type == CPL_TYPE_FLOAT) {
1719  float *d = cpl_array_get_data_float(aArray);
1720  cpl_size i;
1721  for (i = 0; i < n; i++, d++) {
1722  *d = expf(*d);
1723  }
1724  } else {
1725  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
1726  return CPL_ERROR_ILLEGAL_INPUT;
1727  }
1728  return CPL_ERROR_NONE;
1729 }
1730 
1731 /*----------------------------------------------------------------------------*/
1755 /*----------------------------------------------------------------------------*/
1756 cpl_array *
1757 muse_cplarray_interpolate_linear(const cpl_array *aTargetAbscissa,
1758  const cpl_array *aSourceAbscissa,
1759  const cpl_array *aSourceOrdinate)
1760 {
1761  cpl_ensure(aTargetAbscissa && aSourceAbscissa && aSourceOrdinate,
1762  CPL_ERROR_NULL_INPUT, NULL);
1763 
1764  double *targetX = cpl_array_get_data_double((cpl_array *)aTargetAbscissa);
1765  double *srcX = cpl_array_get_data_double((cpl_array *)aSourceAbscissa);
1766  double *srcY = cpl_array_get_data_double((cpl_array *)aSourceOrdinate);
1767  cpl_ensure(targetX && srcX && srcY, CPL_ERROR_ILLEGAL_INPUT, NULL);
1768 
1769  cpl_array *targetOrdinate = cpl_array_duplicate(aTargetAbscissa);
1770  double *targetY = cpl_array_get_data_double(targetOrdinate);
1771 
1772  cpl_size n_src = cpl_array_get_size(aSourceAbscissa);
1773  cpl_vector *srcX_vec = cpl_vector_wrap(n_src, srcX);
1774  cpl_vector *srcY_vec = cpl_vector_wrap(n_src, srcY);
1775  cpl_bivector *src_vec = cpl_bivector_wrap_vectors(srcX_vec, srcY_vec);
1776 
1777  cpl_size offset = (srcX[0] <= targetX[0])?0:
1778  muse_cplarray_find_sorted(aTargetAbscissa, srcX[0]) + 1;
1779  cpl_size n_target =
1780  muse_cplarray_find_sorted(aTargetAbscissa, srcX[n_src-1]) - offset + 1;
1781 
1782  cpl_vector *targetX_vec = cpl_vector_wrap(n_target, targetX + offset);
1783  cpl_vector *targetY_vec = cpl_vector_wrap(n_target, targetY + offset);
1784  cpl_bivector *target_vec = cpl_bivector_wrap_vectors(targetX_vec,
1785  targetY_vec);
1786  if (offset > 0) {
1787  cpl_array_fill_window_invalid(targetOrdinate, 0, offset);
1788  }
1789  if (offset + n_target < (unsigned)cpl_array_get_size(targetOrdinate)) {
1790  cpl_array_fill_window_invalid(targetOrdinate, offset + n_target,
1791  cpl_array_get_size(targetOrdinate)
1792  - (offset + n_target));
1793  }
1794  cpl_bivector_interpolate_linear(target_vec, src_vec);
1795  cpl_bivector_unwrap_vectors(target_vec);
1796  cpl_vector_unwrap(targetX_vec);
1797  cpl_vector_unwrap(targetY_vec);
1798  cpl_bivector_unwrap_vectors(src_vec);
1799  cpl_vector_unwrap(srcX_vec);
1800  cpl_vector_unwrap(srcY_vec);
1801 
1802  return targetOrdinate;
1803 }
1804 
1805 /*----------------------------------------------------------------------------*/
1824 /*----------------------------------------------------------------------------*/
1825 cpl_array *
1826 muse_cplarray_interpolate_table_linear(const cpl_array *aTargetAbscissa,
1827  const cpl_table *aSrcTable,
1828  const char *aSrcAbscissa,
1829  const char *aSrcOrdinate)
1830 {
1831  cpl_array *sabs = muse_cpltable_extract_column((cpl_table *)aSrcTable,
1832  aSrcAbscissa);
1833  cpl_array *sord = muse_cpltable_extract_column((cpl_table *)aSrcTable,
1834  aSrcOrdinate);
1835  cpl_array *ord = muse_cplarray_interpolate_linear(aTargetAbscissa, sabs, sord);
1836  cpl_array_unwrap(sabs);
1837  cpl_array_unwrap(sord);
1838  return ord;
1839 }
1840 
1841 /*---------------------------------------------------------------------------*/
1855 /*---------------------------------------------------------------------------*/
1856 cpl_array *
1857 muse_cplarray_new_from_delimited_string(const char *aString, const char *aDelim)
1858 {
1859  cpl_ensure(aString && aDelim, CPL_ERROR_NULL_INPUT, NULL);
1860  /* duplicate the string to be able to work on it */
1861  char *string = cpl_strdup(aString);
1862 
1863  /* loop to find delimiters and save sub-strings in array */
1864  char *prev = string, *next;
1865  cpl_array *out = cpl_array_new(0, CPL_TYPE_STRING);
1866  int ntok = 0;
1867  do {
1868  next = strstr(prev, aDelim);
1869  if (next) {
1870  *next = '\0'; /* terminate this token starting at |prev| */
1871  }
1872  if (strlen(prev)) { /* don't want to add non-empty strings */
1873  cpl_array_set_size(out, ++ntok);
1874  cpl_array_set_string(out, ntok - 1, prev);
1875  }
1876  prev = next + strlen(aDelim);
1877  } while (next);
1878  cpl_free(string);
1879 
1880 #if 0
1881  printf("Input string %s and delimiter %s resulted in output\n",
1882  aString, aDelim);
1883  cpl_array_dump(out, 0, cpl_array_get_size(out), stdout);
1884  fflush(stdout);
1885 #endif
1886  return out;
1887 } /* muse_cplarray_new_from_delimited_string() */
1888 
1889 /*---------------------------------------------------------------------------*/
1904 /*---------------------------------------------------------------------------*/
1905 cpl_array *
1906 muse_cplarray_string_to_double(const cpl_array *aArray)
1907 {
1908  cpl_ensure(aArray, CPL_ERROR_NULL_INPUT, NULL);
1909  cpl_ensure(cpl_array_get_type(aArray) == CPL_TYPE_STRING,
1910  CPL_ERROR_ILLEGAL_INPUT, NULL);
1911 
1912  cpl_size i, n = cpl_array_get_size(aArray);
1913  cpl_array *darray = cpl_array_new(n, CPL_TYPE_DOUBLE);
1914  for (i = 0; i < n; i++) {
1915  const char *string = cpl_array_get_string(aArray, i);
1916  if (!string) {
1917  continue;
1918  }
1919  cpl_array_set_double(darray, i, atof(string));
1920  } /* for i (array elements) */
1921  return darray;
1922 } /* muse_cplarray_string_to_double() */
1923 
1924 /*---------------------------------------------------------------------------*/
1938 /*---------------------------------------------------------------------------*/
1939 cpl_parameter *
1940 muse_cplparamerterlist_find_prefix(cpl_parameterlist *aParameters,
1941  const char *aPrefix, const char *aName)
1942 {
1943  char *fullname = cpl_sprintf("%s.%s", aPrefix, aName);
1944  cpl_parameter *p = cpl_parameterlist_find(aParameters, fullname);
1945  cpl_free(fullname);
1946  return p;
1947 }
1948 
1949 /*---------------------------------------------------------------------------*/
1974 /*---------------------------------------------------------------------------*/
1975 cpl_parameterlist *
1976 muse_cplparameterlist_from_propertylist(const cpl_propertylist *aHeader,
1977  int aRecNum)
1978 {
1979  cpl_ensure(aHeader, CPL_ERROR_NULL_INPUT, NULL);
1980  cpl_ensure(aRecNum > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1981 
1982  /* check that the input header has a recipe name */
1983  char *kw = cpl_sprintf("ESO PRO REC%d ID", aRecNum);
1984  const char *recipe = cpl_propertylist_get_string(aHeader, kw);
1985  cpl_free(kw);
1986  cpl_ensure(recipe, CPL_ERROR_ILLEGAL_INPUT, NULL);
1987  /* check that the input header was written by the MUSE pipeline */
1988  kw = cpl_sprintf("ESO PRO REC%d PIPE ID", aRecNum);
1989  const char *pipeid = cpl_propertylist_get_string(aHeader, kw);
1990  cpl_free(kw);
1991  cpl_ensure(strstr(recipe, "muse_") && strstr(pipeid, "muse"),
1992  CPL_ERROR_INCOMPATIBLE_INPUT, NULL);
1993  char *context = cpl_sprintf("muse.%s", recipe);
1994 
1995  /* create the new parameter list to be filled from the header */
1996  cpl_parameterlist *parlist = cpl_parameterlist_new();
1997  int npar;
1998  for (npar = 1; npar < cpl_propertylist_get_size(aHeader); npar++) {
1999  char *kwname = cpl_sprintf("ESO PRO REC%d PARAM%d NAME", aRecNum, npar),
2000  *kwvalue = cpl_sprintf("ESO PRO REC%d PARAM%d VALUE", aRecNum, npar);
2001  if (!cpl_propertylist_has(aHeader, kwname) ||
2002  !cpl_propertylist_has(aHeader, kwvalue)) {
2003  cpl_free(kwname);
2004  cpl_free(kwvalue);
2005  break;
2006  }
2007  const cpl_property *prop = cpl_propertylist_get_property_const(aHeader,
2008  kwvalue);
2009  /* since they are all saved as strings, convert them to other types *
2010  * based on the first character and the presence of a dot */
2011  const char *value = cpl_property_get_string(prop);
2012  cpl_type type = CPL_TYPE_STRING;
2013  if (!strncmp(value, "true", 5) || !strncmp(value, "false", 6)) {
2014  type = CPL_TYPE_BOOL;
2015  } else if (!strchr(value, ',') && /* no comma-separator of multiple numbers */
2016  ((value[0] >= '0' && value[0] <= '9') || /* numerical type */
2017  value[0] == '-' || value[0] == '+')) {
2018  /* this might mis-identify a few doubles saved without dot as ints! */
2019  if (strchr(value, '.') || strchr(value, 'E')) {
2020  type = CPL_TYPE_DOUBLE;
2021  } else {
2022  type = CPL_TYPE_INT;
2023  } /* else */
2024  } /* else */
2025  char *parname = cpl_sprintf("muse.%s.%s", recipe,
2026  cpl_propertylist_get_string(aHeader, kwname));
2027  cpl_parameter *par = cpl_parameter_new_value(parname, type,
2028  cpl_propertylist_get_comment(aHeader, kwname),
2029  context);
2030  cpl_free(parname);
2031  switch (type) {
2032  case CPL_TYPE_BOOL:
2033  if (!strncmp(value, "true", 5)) {
2034  cpl_parameter_set_bool(par, CPL_TRUE);
2035  } else {
2036  cpl_parameter_set_bool(par, CPL_FALSE);
2037  }
2038  break;
2039  case CPL_TYPE_INT:
2040  cpl_parameter_set_int(par, atoi(value));
2041  break;
2042  case CPL_TYPE_DOUBLE:
2043  cpl_parameter_set_double(par, atof(value));
2044  break;
2045  case CPL_TYPE_STRING:
2046  cpl_parameter_set_string(par, value);
2047  break;
2048  default:
2049  cpl_msg_warning(__func__, "property of type %s (%d) found!",
2050  cpl_type_get_name(type), type);
2051  } /* switch */
2052  cpl_parameterlist_append(parlist, par);
2053  cpl_free(kwname);
2054  cpl_free(kwvalue);
2055  } /* for npar */
2056  cpl_free(context);
2057  return parlist;
2058 } /* muse_cplparameterlist_from_propertylist() */
2059 
2060 /*---------------------------------------------------------------------------*/
2072 /*---------------------------------------------------------------------------*/
2073 cpl_parameterlist *
2074 muse_cplparameterlist_duplicate(const cpl_parameterlist *aPList)
2075 {
2076  cpl_ensure(aPList, CPL_ERROR_NULL_INPUT, NULL);
2077 
2078  cpl_parameterlist *list = cpl_parameterlist_new();
2079  const cpl_parameter *par = cpl_parameterlist_get_first_const(aPList);
2080  while (par) {
2081  cpl_parameterlist_append(list, cpl_parameter_duplicate(par));
2082  par = cpl_parameterlist_get_next_const(aPList);
2083  } /* while */
2084  return list;
2085 } /* muse_cplparameterlist_duplicate() */
2086 
2087 /*----------------------------------------------------------------------------*/
2105 /*----------------------------------------------------------------------------*/
2106 cpl_error_code
2107 muse_cplpropertylist_update_long_long(cpl_propertylist *aHeader,
2108  const char *aKeyword, cpl_size aValue)
2109 {
2110  cpl_ensure_code(aHeader && aKeyword, CPL_ERROR_NULL_INPUT);
2111  cpl_property *p = cpl_propertylist_get_property(aHeader, aKeyword);
2112  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
2113  cpl_error_code rc = CPL_ERROR_NONE;
2114  switch (cpl_property_get_type(p)) {
2115  case CPL_TYPE_LONG_LONG:
2116  rc = cpl_property_set_long_long(p, aValue);
2117  break;
2118  case CPL_TYPE_LONG:
2119  rc = cpl_property_set_long(p, aValue);
2120  break;
2121  default:
2122  rc = cpl_property_set_int(p, aValue);
2123  } /* switch */
2124  return rc;
2125 } /* muse_cplpropertylist_update_long_long() */
2126 
2127 /*----------------------------------------------------------------------------*/
2138 /*----------------------------------------------------------------------------*/
2139 cpl_error_code
2140 muse_cplframeset_erase_all(cpl_frameset *aFrames)
2141 {
2142  cpl_ensure_code(aFrames, CPL_ERROR_NULL_INPUT);
2143  cpl_error_code rc = CPL_ERROR_NONE;
2144  /* always get and erase the first frame until we are done */
2145  while (cpl_frameset_get_size(aFrames) > 0 && rc == CPL_ERROR_NONE) {
2146  cpl_frame *frame = cpl_frameset_get_position(aFrames, 0);
2147  rc = cpl_frameset_erase_frame(aFrames, frame);
2148  } /* while */
2149  return rc;
2150 } /* muse_cplframeset_erase_all() */
2151 
2152 /*----------------------------------------------------------------------------*/
2169 /*----------------------------------------------------------------------------*/
2170 cpl_error_code
2171 muse_cplframeset_erase_duplicate(cpl_frameset *aFrames)
2172 {
2173  cpl_ensure_code(aFrames, CPL_ERROR_NULL_INPUT);
2174 #if 0
2175  printf("\n\n\n%s input frameset (with duplicates):\n", __func__);
2176  cpl_frameset_dump(aFrames, stdout);
2177  printf("---------------------------------------------------------------------------\n");
2178  fflush(stdout);
2179 #endif
2180  cpl_error_code rc = CPL_ERROR_NONE;
2181  /* Loop through all frames but the last, and compare all frame properties *
2182  * to all following frames. Delete the frame if they are all the same. */
2183  cpl_size i;
2184  for (i = 0; i < cpl_frameset_get_size(aFrames) - 1; i++) {
2185  cpl_frame *fref = cpl_frameset_get_position(aFrames, i);
2186  cpl_size j;
2187  for (j = i + 1; j < cpl_frameset_get_size(aFrames); j++) {
2188  cpl_frame *fother = cpl_frameset_get_position(aFrames, j);
2189  cpl_boolean areequal = CPL_FALSE;
2190  cpl_errorstate state = cpl_errorstate_get();
2191  const char *fn1 = cpl_frame_get_filename(fref),
2192  *fn2 = cpl_frame_get_filename(fother);
2193  if (!cpl_errorstate_is_equal(state)) {
2194  cpl_errorstate_set(state);
2195  }
2196  if ((!fn1 && fn2) || (fn1 && !fn2)) {
2197  areequal = CPL_FALSE;
2198  } else if (!fn1 && !fn2) {
2199  areequal = CPL_TRUE;
2200  } else {
2201  areequal = !strcmp(fn1, fn2);
2202  }
2203  areequal = areequal
2204  && !strcmp(cpl_frame_get_tag(fref), cpl_frame_get_tag(fother));
2205  areequal = areequal
2206  && (cpl_frame_get_group(fref) == cpl_frame_get_group(fother));
2207  areequal = areequal
2208  && (cpl_frame_get_level(fref) == cpl_frame_get_level(fother));
2209  areequal = areequal
2210  && (cpl_frame_get_type(fref) == cpl_frame_get_type(fother));
2211  if (areequal) {
2212 #if 0
2213  printf("%ld/%ld are equal: %s/%s, %s/%s, %d/%d, %d/%d, %d/%d\n", i, j,
2214  fn1, fn2, tag1, tag2,
2215  cpl_frame_get_group(fref), cpl_frame_get_group(fother),
2216  cpl_frame_get_level(fref), cpl_frame_get_level(fother),
2217  cpl_frame_get_type(fref), cpl_frame_get_type(fother));
2218  fflush(stdout);
2219 #endif
2220  /* would really like to erase the other frame, *
2221  * but it's not possible to delete by position! */
2222  rc = cpl_frameset_erase_frame(aFrames, fref);
2223  i--; /* stay at the same reference position in the frameset */
2224  break;
2225  } /* if equal */
2226  } /* for j (all following frames) */
2227  } /* for i (all frames but the last) */
2228 #if 0
2229  printf("---------------------------------------------------------------------------\n");
2230  printf("%s input frameset (without duplicates):\n", __func__);
2231  cpl_frameset_dump(aFrames, stdout);
2232  printf("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n\n");
2233  fflush(stdout);
2234 #endif
2235  return rc;
2236 } /* muse_cplframeset_erase_duplicate() */
2237 
2238 /*----------------------------------------------------------------------------*/
2250 /*----------------------------------------------------------------------------*/
2251 void
2252 muse_cplerrorstate_dump_some(unsigned aCurrent, unsigned aFirst, unsigned aLast)
2253 {
2254  const cpl_boolean is_reverse = aFirst > aLast ? CPL_TRUE : CPL_FALSE;
2255  const char *revmsg = is_reverse ? " in reverse order" : "";
2256  const unsigned newest = is_reverse ? aFirst : aLast,
2257  nmax = labs(aLast - aFirst) + 1;
2258  unsigned ndump = 20;
2259  if (getenv("MUSE_CPL_ERRORSTATE_NDUMP") &&
2260  atoi(getenv("MUSE_CPL_ERRORSTATE_NDUMP")) > 0) {
2261  ndump = atoi(getenv("MUSE_CPL_ERRORSTATE_NDUMP"));
2262  }
2263  ndump = nmax < ndump ? nmax : ndump;
2264 
2265  if (newest) { /* there are errors to dump */
2266  if (aCurrent == aLast - (ndump-1)) {
2267  cpl_msg_error(__func__, "Dumping the %u most recent error(s) out of a "
2268  "total of %u errors%s:", ndump, newest, revmsg);
2269  cpl_msg_indent_more();
2270  }
2271  if (aCurrent >= aLast - (ndump-1)) {
2272  cpl_msg_error(__func__, "[%u/%u] '%s' (%u) at %s", aCurrent, newest,
2273  cpl_error_get_message(), cpl_error_get_code(),
2274  cpl_error_get_where());
2275  }
2276  if (aCurrent == aLast) {
2277  cpl_msg_indent_less();
2278  }
2279  } else {
2280  cpl_msg_info(__func__, "No error(s) to dump");
2281  }
2282 } /* muse_cplerrorstate_dump_some() */
2283 
2284 
2285 /*----------------------------------------------------------------------------*/
2298 /*----------------------------------------------------------------------------*/
2300 #ifdef HAVE_READLINK
2301  char buffer[FILENAME_MAX] = "\0";
2302  int length = readlink("/proc/self/exe", buffer, sizeof(buffer) - 1);
2303  if (length != -1) {
2304  buffer[length] = '\0';
2305  }
2306  if (strstr(buffer, "esorex")) {
2307  return MUSE_CPLFRAMEWORK_ESOREX;
2308  } else if (strstr(buffer, "python")) {
2310  } else if (strstr(buffer, "jre")) {
2312  } else {
2314  }
2315 #else
2317 #endif
2318 }
2319 
cpl_error_code muse_cplarray_erase_invalid(cpl_array *aArray)
Erase all invalid values from an array.
cpl_type type
Column type (use CPL_TYPE_POINTER for array columns).
cpl_array * muse_cplarray_interpolate_table_linear(const cpl_array *aTargetAbscissa, const cpl_table *aSrcTable, const char *aSrcAbscissa, const char *aSrcOrdinate)
Linear interpolation of a 1d column.
const int required
Is column required?
cpl_error_code muse_cplarray_dump_name(const cpl_array *aArray, const char *aName)
Dump a numerical array to stdout with a name prefixed to each line.
cpl_image * muse_cplimage_filter_median_subtract(cpl_image *aImage, unsigned int aNX, unsigned int aNY)
Subtract a median-filtered version of the input image from itself.
cpl_array * muse_cplarray_extract(cpl_array *aArray, cpl_size aStart, cpl_size aCount)
Create an array from a section of another array.
muse_cplframework_type muse_cplframework(void)
Return the CPL framework the recipe is run under.
cpl_array * muse_cplarray_string_to_double(const cpl_array *aArray)
Convert a string array into an array of type double.
cpl_error_code muse_cplarray_sort(cpl_array *aArray, cpl_boolean aOrder)
Sort float, int or double array by quicksort.
const char * unit
Column unit, or NULL.
cpl_error_code muse_cplarray_poly1d(cpl_array *aArray, const cpl_array *aCoeff)
Apply a polynomial to an array.
double muse_cplvector_get_median_dev(cpl_vector *aVector, double *aMedian)
Compute the median and average absolute deviation against the median of a vector. ...
cpl_vector * muse_cplvector_get_unique(const cpl_vector *aVector)
Separate out all unique entries in a given vector into a new one.
double muse_cplvector_get_semiquartile(cpl_vector *aVector)
compute the semi-quartile range of a vector of elements
cpl_boolean muse_cplarray_has_duplicate(const cpl_array *aArray)
Check, if an array contains duplicate values.
cpl_image * muse_cplimage_concat_y(const cpl_image *aImage1, const cpl_image *aImage2)
Concatenate two images in y direction.
cpl_error_code muse_cpltable_check(const cpl_table *aTable, const muse_cpltable_def *aDef)
Check whether the table contains the fields of the definition.
cpl_table * muse_cpltable_load(const char *aFile, const char *aExtension, const muse_cpltable_def aDefinition[])
Load a table from disk (and check against definition).
cpl_table * muse_cpltable_new(const muse_cpltable_def *aDef, cpl_size aLength)
Create an empty table according to the specified definition.
cpl_error_code muse_cplarray_exp(cpl_array *aArray)
Compute the exponential function of array elements.
cpl_error_code muse_cplimage_or(cpl_image *aTarget, const cpl_image *aImage, unsigned int mask)
Provide an 'OR' operation of two integer images.
cpl_array * muse_cplarray_new_from_delimited_string(const char *aString, const char *aDelim)
Convert a delimited string into an array of strings.
cpl_array * muse_cpltable_get_array_copy(cpl_table *aTable, const char *aColumn, cpl_size aRow)
Return the copy of an array of a table cell.
cpl_array * muse_cpltable_extract_column(cpl_table *aTable, const char *aColumn)
Create an array from a section of a column.
cpl_error_code muse_cplvector_erase_element(cpl_vector *aVector, int aElement)
delete the given element from the input vector
const char * name
Column name.
const char * format
Default print format, or NULL.
cpl_array * muse_cplarray_new_from_image(const cpl_image *aImage)
Copy the image data into an array.
cpl_bivector * muse_cplarray_histogram(const cpl_array *aArray, double aWidth, double aMin, double aMax)
Create a histogram for a numerical array.
cpl_array * muse_cplarray_interpolate_linear(const cpl_array *aTargetAbscissa, const cpl_array *aSourceAbscissa, const cpl_array *aSourceOrdinate)
Linear interpolation of a 1d array.
double muse_cplimage_get_percentile(const cpl_image *aImage, double aFraction)
Get the percentile of an image.
void muse_cplerrorstate_dump_some(unsigned aCurrent, unsigned aFirst, unsigned aLast)
Dump some CPL errors.
cpl_vector * muse_cplimage_slope_window(const cpl_image *aImage, const cpl_size *aWindow)
Compute slopes of an image, both horizontally and vertically.
cpl_error_code muse_cplarray_erf(cpl_array *aArray)
Compute the error function of array elements.
cpl_error_code muse_cplarray_add_window(cpl_array *aDest, cpl_size aStart, const cpl_array *aArray)
Add the value of an array to a window of a table column.
cpl_error_code muse_cplpropertylist_update_long_long(cpl_propertylist *aHeader, const char *aKeyword, cpl_size aValue)
Update an integer-like property irrespective of the real type.
cpl_size muse_cpltable_find_sorted(const cpl_table *aTable, const char *aColumn, double aValue)
Find a row in a table.
cpl_image * muse_cplimage_concat_x(const cpl_image *aImage1, const cpl_image *aImage2)
Concatenate two images in x direction.
cpl_error_code muse_cpltable_copy_array(cpl_table *aTable, const char *aColumn, const cpl_array *aArray)
Copy an array into a table.
cpl_array * muse_cplarray_diff(const cpl_array *aArray, int aOffset)
Build the difference of any element and one of the next elements.
cpl_parameterlist * muse_cplparameterlist_duplicate(const cpl_parameterlist *aPList)
Duplicate a CPL parameter list.
cpl_error_code muse_cplframeset_erase_duplicate(cpl_frameset *aFrames)
Erase all duplicate frames from a frameset.
cpl_error_code muse_cplframeset_erase_all(cpl_frameset *aFrames)
Erase all frames in a frameset.
cpl_size muse_cplarray_erase_outliers(cpl_array *aArray, const cpl_bivector *aHistogram, cpl_size aGap, double aLimit)
Erase outliers from an array using histogram information.
muse_cplframework_type
Type for the framework that called the recipe.
cpl_size muse_cplvector_count_unique(const cpl_vector *aVector)
Count the number of unique entries in a given vector.
Definition of a cpl table structure.
double muse_cplvector_get_adev_const(const cpl_vector *aVector, double aCenter)
Compute the average absolute deviation of a (constant) vector.
cpl_parameter * muse_cplparamerterlist_find_prefix(cpl_parameterlist *aParameters, const char *aPrefix, const char *aName)
Return the full recipe parameter belonging to prefix and shortname.
double muse_cplarray_poly1d_double(double aDouble, const cpl_array *aCoeff)
Apply a polynomial to a double value.
cpl_size muse_cplarray_find_sorted(const cpl_array *aArray, double aValue)
Find a row in an array.
cpl_error_code muse_cplvector_threshold(cpl_vector *aVec, double aLoCut, double aHiCut, double aLoVal, double aHiVal)
Threshold a vector to a given interval.
cpl_mask * muse_cplmask_adapt_to_image(const cpl_mask *aMask, const cpl_image *aImage)
Adapt mask with masked region in one quadrant to size of an image.
cpl_parameterlist * muse_cplparameterlist_from_propertylist(const cpl_propertylist *aHeader, int aRecNum)
Recreate a cpl_parameterlist from the RECi headers of an output MUSE product.
cpl_image * muse_cplimagelist_collapse_or_create(const cpl_imagelist *imlist)
Compute the OR of an image list to a single image.
cpl_error_code muse_cpltable_append_file(const cpl_table *aTable, const char *aFile, const char *aExtension, const muse_cpltable_def aDefinition[])
Save a table to disk (into a FITS extension)