MUSE Pipeline Reference Manual  2.1.1
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-2015 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 /*----------------------------------------------------------------------------*/
528 /*----------------------------------------------------------------------------*/
529 cpl_matrix *
530 muse_cplmatrix_multiply_create(const cpl_matrix *aMatrix1,
531  const cpl_matrix *aMatrix2)
532 {
533  cpl_ensure(aMatrix1 && aMatrix2, CPL_ERROR_NULL_INPUT, NULL);
534 
535  cpl_matrix *result = cpl_matrix_duplicate(aMatrix1);
536 
537  if (cpl_matrix_multiply(result, aMatrix2) != CPL_ERROR_NONE) {
538  cpl_error_set_where(__func__);
539  cpl_matrix_delete(result);
540  return NULL;
541  }
542  return result;
543 }
544 
545 /*----------------------------------------------------------------------------*/
561 /*----------------------------------------------------------------------------*/
562 cpl_array *
563 muse_cplmatrix_where(const cpl_matrix *aMatrix, double aValue,
565 {
566 
567  cpl_ensure(aMatrix, CPL_ERROR_NULL_INPUT, NULL);
568  cpl_ensure(aCondition, CPL_ERROR_NULL_INPUT, NULL);
569 
570  cpl_size i;
571  cpl_size count = 0;
572  cpl_size size = cpl_matrix_get_nrow(aMatrix) * cpl_matrix_get_ncol(aMatrix);
573 
574  const double *mdata = cpl_matrix_get_data_const(aMatrix);
575 
576  cpl_size *selection = cpl_malloc(size * sizeof *selection);
577  cpl_size *_selection = selection;
578 
579  for (i = 0; i < size; ++i) {
580  if (aCondition(mdata[i], aValue)) {
581  *_selection++ = i;
582  ++count;
583  }
584  }
585  cpl_array *where = cpl_array_new(count, CPL_TYPE_SIZE);
586  cpl_array_copy_data_cplsize(where, selection);
587  cpl_free(selection);
588 
589  return where;
590 
591 }
592 
593 /*----------------------------------------------------------------------------*/
613 /*----------------------------------------------------------------------------*/
614 cpl_matrix *
615 muse_cplmatrix_extract_selected(const cpl_matrix *aMatrix,
616  const cpl_array *aIndices)
617 {
618  cpl_ensure(aMatrix, CPL_ERROR_NULL_INPUT, NULL);
619  cpl_ensure(aIndices, CPL_ERROR_NULL_INPUT, NULL);
620  cpl_ensure(cpl_array_get_type(aIndices) == CPL_TYPE_SIZE,
621  CPL_ERROR_INVALID_TYPE, NULL);
622 
623  cpl_size maxpos = cpl_matrix_get_nrow(aMatrix) * cpl_matrix_get_ncol(aMatrix);
624  cpl_size sz = cpl_array_get_size(aIndices);
625  cpl_matrix *subset = cpl_matrix_new(1, sz);
626 
627  double *sdata = cpl_matrix_get_data(subset);
628  const double *mdata = cpl_matrix_get_data_const(aMatrix);
629  const cpl_size *idata = cpl_array_get_data_cplsize_const(aIndices);
630 
631  cpl_size i;
632  for (i = 0; i < sz; ++i) {
633  if ((idata[i] >= 0) && (idata[i] < maxpos)) {
634  *sdata++ = mdata[idata[i]];
635  }
636  }
637  return subset;
638 }
639 
640 /*----------------------------------------------------------------------------*/
649 /*----------------------------------------------------------------------------*/
650 double
651 muse_cplvector_get_adev_const(const cpl_vector *aVector, double aCenter)
652 {
653  cpl_ensure(aVector, CPL_ERROR_NULL_INPUT, 0.);
654  double mdev = 0;
655  cpl_size i, n = cpl_vector_get_size(aVector);
656  for (i = 0; i < n; i++) {
657  mdev += fabs(cpl_vector_get(aVector, i) - aCenter);
658  }
659  return mdev / (double)n; /* return normalized value */
660 } /* muse_cplvector_get_adev_const() */
661 
662 /*----------------------------------------------------------------------------*/
675 /*----------------------------------------------------------------------------*/
676 double
677 muse_cplvector_get_median_dev(cpl_vector *aVector, double *aMedian)
678 {
679  cpl_ensure(aVector, CPL_ERROR_NULL_INPUT, 0.);
680  double median = cpl_vector_get_median(aVector),
681  mdev = 0.;
682  cpl_size i, n = cpl_vector_get_size(aVector);
683  for (i = 0; i < n; i++) {
684  mdev += fabs(cpl_vector_get(aVector, i) - median);
685  }
686  if (aMedian) {
687  *aMedian = median;
688  }
689  return mdev / (double)n; /* return normalized value */
690 } /* muse_cplvector_get_median_dev() */
691 
692 /*----------------------------------------------------------------------------*/
706 /*----------------------------------------------------------------------------*/
707 double
709 {
710  double sqr = 0;
711  double median = cpl_vector_get_median_const(aVector);
712  cpl_vector *v = cpl_vector_duplicate(aVector), *v2;
713  int i, splitindex = 0;
714 
715  cpl_vector_sort(v, +1);
716 #if DEBUG_SQR
717  cpl_vector_dump(v, stdout);
718  fflush(stdout);
719  printf("median=%f%d\n", median);
720  fflush(stdout);
721 #endif
722  /* search for point to split the sorted vector, better just do it linearly */
723  splitindex = cpl_vector_find(v, median);
724 
725  /* copy upper half into new vector */
726  v2 = cpl_vector_new(cpl_vector_get_size(v) - splitindex - 1);
727 #if DEBUG_SQR
728  printf("Copying elements %d to %d\n", splitindex+1, cpl_vector_get_size(v)-1);
729 #endif
730  for (i = splitindex; i < cpl_vector_get_size(v); i++){
731 #if DEBUG_SQR
732  printf(" %d %f\n", i+1, cpl_vector_get(v, i));
733 #endif
734  cpl_vector_set(v2, i-splitindex, cpl_vector_get(v, i));
735  }
736 #if DEBUG_SQR
737  printf("\n");
738  fflush(stdout);
739 #endif
740  sqr = cpl_vector_get_median(v2); /* the upper median, non const OK */
741  cpl_vector_delete(v2);
742 
743  /* copy lower half into new vector */
744  v2 = cpl_vector_new(splitindex - 1);
745 #if DEBUG_SQR
746  printf("Copying elements %d to %d\n", 1, splitindex+1);
747 #endif
748  for (i = 0; i <= splitindex; i++) {
749 #if DEBUG_SQR
750  printf(" %d %f\n", i+1, cpl_vector_get(v, i));
751 #endif
752  cpl_vector_set(v2, i, cpl_vector_get(v, i));
753  }
754 #if DEBUG_SQR
755  printf("\n");
756  fflush(stdout);
757 #endif
758  sqr -= cpl_vector_get_median(v2); /* subtract the lower median, non const OK */
759  cpl_vector_delete(v2);
760 
761  return sqr/2.0; /* divide by two to get semiquartile range */
762 } /* muse_cplvector_get_semiquartile() */
763 
764 /*----------------------------------------------------------------------------*/
784 /*----------------------------------------------------------------------------*/
785 cpl_error_code
786 muse_cplvector_threshold(cpl_vector *aVec, double aLoCut, double aHiCut,
787  double aLoVal, double aHiVal)
788 {
789  cpl_ensure_code(aVec, CPL_ERROR_NULL_INPUT);
790  cpl_ensure_code(aLoCut <= aHiCut, CPL_ERROR_ILLEGAL_INPUT);
791 
792  double *data = cpl_vector_get_data(aVec);
793  int i, n = cpl_vector_get_size(aVec);
794  for (i = 0; i < n; i++) {
795  if (data[i] > aHiCut) {
796  data[i] = aHiVal;
797  } else if (data[i] < aLoCut) {
798  data[i] = aLoVal;
799  }
800  } /* for i (vector elements) */
801 
802  return CPL_ERROR_NONE;
803 }
804 
805 /*----------------------------------------------------------------------------*/
817 /*----------------------------------------------------------------------------*/
818 cpl_error_code
819 muse_cplvector_erase_element(cpl_vector *aVector, int aElement)
820 {
821  cpl_ensure_code(aVector, CPL_ERROR_NULL_INPUT);
822  int size = cpl_vector_get_size(aVector);
823  cpl_ensure_code(aElement >= 0 && aElement < size, CPL_ERROR_ILLEGAL_INPUT);
824 
825  if (aElement < size - 1) {
826  /* if it's not the last element, we need to move the remaining *
827  * elements so that they overwrite the one to be removed */
828  double *data = cpl_vector_get_data(aVector);
829  memmove(&data[aElement], &data[aElement+1],
830  (size-1 - aElement) * sizeof(double));
831  }
832 
833  /* resize the vector to account for the removed element */
834  return cpl_vector_set_size(aVector, size - 1);
835 } /* muse_cplvector_erase_element() */
836 
837 /*----------------------------------------------------------------------------*/
845 /*----------------------------------------------------------------------------*/
846 cpl_size
847 muse_cplvector_count_unique(const cpl_vector *aVector)
848 {
849  cpl_ensure(aVector, CPL_ERROR_NULL_INPUT, -1);
850  cpl_vector *sorted = cpl_vector_duplicate(aVector);
851  cpl_vector_sort(sorted, CPL_SORT_ASCENDING);
852  double *data = cpl_vector_get_data(sorted);
853  cpl_size i, n = cpl_vector_get_size(sorted),
854  nunique = 1; /* first element is always unique */
855  for (i = 1; i < n; i++) { /* start at 2nd element */
856  if (data[i] != data[i - 1]) {
857  nunique++;
858  }
859  } /* for i (all elements in sorted vector) */
860  cpl_vector_delete(sorted);
861  return nunique;
862 } /* muse_cplvector_count_unique() */
863 
864 /*----------------------------------------------------------------------------*/
872 /*----------------------------------------------------------------------------*/
873 cpl_vector *
874 muse_cplvector_get_unique(const cpl_vector *aVector)
875 {
876  cpl_ensure(aVector, CPL_ERROR_NULL_INPUT, NULL);
877  cpl_vector *sorted = cpl_vector_duplicate(aVector);
878  cpl_vector_sort(sorted, CPL_SORT_ASCENDING);
879  double *data = cpl_vector_get_data(sorted);
880  cpl_size i, n = cpl_vector_get_size(sorted),
881  iunique = 0;
882  cpl_vector *vunique = cpl_vector_new(n);
883  cpl_vector_set(vunique, iunique++, data[0]); /* set unique first element */
884  for (i = 1; i < n; i++) { /* start at 2nd element */
885  if (data[i] != data[i - 1]) {
886  cpl_vector_set(vunique, iunique++, data[i]);
887  }
888  } /* for i (all elements in sorted vector) */
889  cpl_vector_delete(sorted);
890  cpl_vector_set_size(vunique, iunique);
891  return vunique;
892 } /* muse_cplvector_get_unique() */
893 
894 /*----------------------------------------------------------------------------*/
904 /*----------------------------------------------------------------------------*/
905 cpl_table *
906 muse_cpltable_new(const muse_cpltable_def *aDef, cpl_size aLength)
907 {
908  cpl_ensure(aDef, CPL_ERROR_NULL_INPUT, NULL);
909  cpl_table *res = cpl_table_new(aLength);
910  for (; aDef->name != NULL; aDef++) {
911  cpl_error_code rc = CPL_ERROR_NONE;
912  if (aDef->type & CPL_TYPE_POINTER) {
913  rc = cpl_table_new_column_array(res, aDef->name, aDef->type, 2);
914  } else {
915  rc = cpl_table_new_column(res, aDef->name, aDef->type);
916  }
917  if (rc != CPL_ERROR_NONE) {
918  cpl_table_delete(res);
919  return NULL;
920  }
921  if (aDef->unit != NULL) {
922  if (cpl_table_set_column_unit(res, aDef->name,
923  aDef->unit) != CPL_ERROR_NONE) {
924  return NULL;
925  }
926  }
927  if (aDef->format != NULL) {
928  if (cpl_table_set_column_format(res, aDef->name,
929  aDef->format) != CPL_ERROR_NONE) {
930  return NULL;
931  }
932  }
933  }
934  return res;
935 }
936 
937 /*----------------------------------------------------------------------------*/
949 /*----------------------------------------------------------------------------*/
950 cpl_table *
951 muse_cpltable_load(const char *aFile, const char *aExtension,
952  const muse_cpltable_def aDefinition[])
953 {
954  int extension = cpl_fits_find_extension(aFile, aExtension);
955  if (extension <= 0) {
956  cpl_error_set_message(__func__, cpl_error_get_code(), "%s['%s']: "
957  "extension not found by EXTNAME", aFile, aExtension);
958  return NULL;
959  }
960  cpl_msg_debug(__func__, "Loading %s['%s'] from extension %d", aFile,
961  aExtension, extension);
962  cpl_table *tbl = cpl_table_load(aFile, extension, 1);
963  if (muse_cpltable_check(tbl, aDefinition) != CPL_ERROR_NONE) {
964  cpl_table_delete(tbl);
965  return NULL;
966  }
967  return tbl;
968 } /* muse_cpltable_load() */
969 
970 /*----------------------------------------------------------------------------*/
987 /*----------------------------------------------------------------------------*/
988 cpl_error_code
989 muse_cpltable_append_file(const cpl_table *aTable, const char *aFile,
990  const char *aExtension,
991  const muse_cpltable_def aDefinition[]) {
992  cpl_ensure_code(aTable != NULL, CPL_ERROR_NULL_INPUT);
993  cpl_ensure_code(aFile != NULL, CPL_ERROR_NULL_INPUT);
994  cpl_ensure_code(aExtension != NULL, CPL_ERROR_NULL_INPUT);
995  cpl_error_code r = muse_cpltable_check(aTable, aDefinition);
996  if (r != CPL_ERROR_NONE) {
997  cpl_msg_error(__func__, " %s['%s'] Table format error", aFile, aExtension);
998  cpl_error_set(__func__, r);
999  return r;
1000  }
1001  cpl_propertylist *props = cpl_propertylist_new();
1002  cpl_propertylist_update_string(props, "EXTNAME", aExtension);
1003  r = cpl_table_save(aTable, NULL, props, aFile, CPL_IO_EXTEND);
1004  cpl_propertylist_delete(props);
1005  if (r != CPL_ERROR_NONE) {
1006  cpl_msg_error(__func__, "%s[%s]: %s", aFile, aExtension,
1007  cpl_error_get_message());
1008  }
1009  return r;
1010 }
1011 
1012 
1013 /*----------------------------------------------------------------------------*/
1019 /*----------------------------------------------------------------------------*/
1020 cpl_error_code
1021 muse_cpltable_check(const cpl_table *aTable, const muse_cpltable_def *aDef)
1022 {
1023  if (aTable == NULL) {
1024  cpl_msg_error(__func__, "NULL table");
1025  cpl_error_set(__func__, CPL_ERROR_NULL_INPUT);
1026  return CPL_ERROR_NULL_INPUT;
1027  }
1028  if (aDef == NULL) {
1029  return CPL_ERROR_NONE;
1030  }
1031  cpl_error_code rc = CPL_ERROR_NONE;
1032  for (; aDef->name != NULL; aDef++) {
1033  if (!cpl_table_has_column(aTable, aDef->name)) {
1034  if (aDef->required) {
1035  rc = CPL_ERROR_ILLEGAL_INPUT;
1036  cpl_error_set_message(__func__, rc, "table column '%s' not found",
1037  aDef->name);
1038  }
1039  continue;
1040  }
1041  cpl_type coltype = cpl_table_get_column_type(aTable, aDef->name);
1042  if (((coltype | CPL_TYPE_POINTER) != (aDef->type | CPL_TYPE_POINTER)) ||
1043  ((coltype & CPL_TYPE_POINTER) && !(aDef->type & CPL_TYPE_POINTER))) {
1044  rc = CPL_ERROR_ILLEGAL_INPUT;
1045  cpl_error_set_message(__func__, rc,
1046  "table column '%s' format '%s' is not '%s'",
1047  aDef->name, cpl_type_get_name(coltype),
1048  cpl_type_get_name(aDef->type));
1049  }
1050  }
1051  return rc;
1052 } /* muse_cpltable_check() */
1053 
1054 /*----------------------------------------------------------------------------*/
1071 /*----------------------------------------------------------------------------*/
1072 cpl_array *
1073 muse_cpltable_extract_column(cpl_table *aTable, const char *aColumn)
1074 {
1075  cpl_ensure(aTable && aColumn, CPL_ERROR_NULL_INPUT, NULL);
1076  cpl_size nRows = cpl_table_get_nrow(aTable);
1077 
1078  cpl_type type = cpl_table_get_column_type(aTable, aColumn);
1079  if (nRows == 0) {
1080  return cpl_array_new(0, type);
1081  }
1082  if (type == CPL_TYPE_DOUBLE) {
1083  double *src = cpl_table_get_data_double(aTable, aColumn);
1084  return cpl_array_wrap_double(src, nRows);
1085  } else if (type == CPL_TYPE_FLOAT) {
1086  float *src = cpl_table_get_data_float(aTable, aColumn);
1087  return cpl_array_wrap_float(src, nRows);
1088  } else if (type == CPL_TYPE_INT) {
1089  int *src = cpl_table_get_data_int(aTable, aColumn);
1090  return cpl_array_wrap_int(src, nRows);
1091  } else {
1092  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
1093  cpl_msg_error(__func__, "%s: %i - %s", cpl_error_get_message(), type,
1094  cpl_type_get_name(type));
1095  return NULL;
1096  }
1097 }
1098 
1099 /*----------------------------------------------------------------------------*/
1109 /*----------------------------------------------------------------------------*/
1110 cpl_error_code
1111 muse_cpltable_copy_array(cpl_table *aTable, const char *aColumn,
1112  const cpl_array *aArray)
1113 {
1114  cpl_ensure_code(aTable && aColumn && aArray, CPL_ERROR_NULL_INPUT);
1115  cpl_size n_rows = cpl_table_get_nrow(aTable);
1116  cpl_size i;
1117  for (i = 0; i < n_rows; i++) {
1118  int flag;
1119  double d = cpl_array_get(aArray, i, &flag);
1120  if (flag == 0) {
1121  cpl_table_set(aTable, aColumn, i, d);
1122  } else {
1123  cpl_table_set_invalid(aTable, aColumn, i);
1124  }
1125  }
1126  return CPL_ERROR_NONE;
1127 }
1128 
1129 /*----------------------------------------------------------------------------*/
1139 /*----------------------------------------------------------------------------*/
1140 cpl_array *
1141 muse_cpltable_get_array_copy(cpl_table *aTable, const char *aColumn,
1142  cpl_size aRow)
1143 {
1144  cpl_ensure(aTable && aColumn, CPL_ERROR_NULL_INPUT, NULL);
1145  if (cpl_table_get_column_type(aTable, aColumn) & CPL_TYPE_POINTER) {
1146  return cpl_array_duplicate(cpl_table_get_array(aTable, aColumn, aRow));
1147  } else {
1148  cpl_array *res
1149  = cpl_array_new(1, cpl_table_get_column_type(aTable, aColumn));
1150  int flag;
1151  cpl_array_set(res, 0, cpl_table_get(aTable, aColumn, aRow, &flag));
1152  if (flag) {
1153  cpl_array_delete(res);
1154  return NULL;
1155  } else {
1156  return res;
1157  }
1158  }
1159 }
1160 /*----------------------------------------------------------------------------*/
1174 /*----------------------------------------------------------------------------*/
1175 
1176 cpl_size
1177 muse_cpltable_find_sorted(const cpl_table *aTable, const char *aColumn,
1178  double aValue) {
1179  cpl_ensure(aTable && aColumn, CPL_ERROR_NULL_INPUT, 0);
1180  cpl_array *array = muse_cpltable_extract_column((cpl_table *)aTable, aColumn);
1181  cpl_size res = muse_cplarray_find_sorted(array, aValue);
1182  cpl_array_unwrap(array);
1183  return res;
1184 }
1185 
1186 /*----------------------------------------------------------------------------*/
1194 /*----------------------------------------------------------------------------*/
1195 cpl_array *
1196 muse_cplarray_new_from_image(const cpl_image *aImage) {
1197  cpl_size nx = cpl_image_get_size_x(aImage);
1198  cpl_size ny = cpl_image_get_size_y(aImage);
1199  cpl_array *array = cpl_array_new(nx*ny, cpl_image_get_type(aImage));
1200  cpl_size i = 0;
1201  cpl_size iy;
1202  for (iy = 1; iy <= ny; iy++) {
1203  int ix;
1204  for (ix = 1; ix <= nx; ix++, i++) {
1205  int rej;
1206  double d = cpl_image_get(aImage, ix, iy, &rej);
1207  cpl_array_set(array, i, d);
1208  if (rej) {
1209  cpl_array_set_invalid(array, i);
1210  }
1211  }
1212  }
1213  return array;
1214 }
1215 
1216 /*----------------------------------------------------------------------------*/
1229 /*----------------------------------------------------------------------------*/
1230 cpl_error_code
1231 muse_cplarray_poly1d(cpl_array *aArray, const cpl_array *aCoeff)
1232 {
1233  cpl_ensure_code(aArray && aCoeff, CPL_ERROR_NULL_INPUT);
1234  const cpl_size nrows = cpl_array_get_size(aArray);
1235  cpl_size order = cpl_array_get_size(aCoeff);
1236  if (order == 0) {
1237  cpl_array_fill_window(aArray, 0, nrows, 0.0);
1238  return CPL_ERROR_NONE;
1239  }
1240  order--;
1241  cpl_array *x = cpl_array_duplicate(aArray);
1242  cpl_array_fill_window(aArray, 0, nrows, cpl_array_get(aCoeff, order, NULL));
1243 
1244  int k;
1245  for (k = order-1; k >= 0; k--) {
1246  cpl_array_multiply(aArray, x);
1247  cpl_array_add_scalar(aArray, cpl_array_get(aCoeff, k, NULL));
1248  }
1249 
1250  cpl_array_delete(x);
1251 
1252  return CPL_ERROR_NONE;
1253 }
1254 
1255 /*----------------------------------------------------------------------------*/
1267 /*----------------------------------------------------------------------------*/
1268 double
1269 muse_cplarray_poly1d_double(double aDouble, const cpl_array *aCoeff)
1270 {
1271  cpl_ensure(aCoeff, CPL_ERROR_NULL_INPUT, NAN);
1272  cpl_size order = cpl_array_get_size(aCoeff);
1273  if (order == 0) {
1274  return 0.0;
1275  }
1276  order--;
1277  double res = cpl_array_get(aCoeff, order, NULL);
1278  int k;
1279  for (k = order-1; k >= 0; k--) {
1280  res = res * aDouble + cpl_array_get(aCoeff, k, NULL);
1281  }
1282  return res;
1283 }
1284 
1285 /*----------------------------------------------------------------------------*/
1294 /*----------------------------------------------------------------------------*/
1295 cpl_error_code
1296 muse_cplarray_dump_name(const cpl_array *aArray, const char *aName)
1297 {
1298  cpl_ensure_code(aArray && aName, CPL_ERROR_NULL_INPUT);
1299  cpl_size i, size = cpl_array_get_size(aArray);
1300  for (i = 0; i < size; i++) {
1301  printf("%s[%"CPL_SIZE_FORMAT"] = %g\n", aName, i,
1302  cpl_array_get(aArray, i, NULL));
1303  }
1304  return CPL_ERROR_NONE;
1305 }
1306 
1307 /*----------------------------------------------------------------------------*/
1313 /*----------------------------------------------------------------------------*/
1314 cpl_error_code
1316 {
1317  cpl_ensure_code(aArray != NULL, CPL_ERROR_NULL_INPUT);
1318  cpl_size n = cpl_array_get_size(aArray);
1319  cpl_size n_val = n - cpl_array_count_invalid(aArray);
1320 #if 0 /* DEBUG */
1321  cpl_msg_debug(__func__, "size = %li, %li valid", (long)n, (long)n_val);
1322 #endif
1323  if (n_val == n) {
1324  return CPL_ERROR_NONE;
1325  }
1326  cpl_size i;
1327  cpl_size idx = 0;
1328  for (i = 0; (i < n) && (idx < n_val); i++) {
1329  int rej;
1330  double d = cpl_array_get(aArray, i, &rej);
1331  if (!rej) {
1332  if (idx < i) {
1333  cpl_array_set(aArray, idx, d);
1334  }
1335  idx++;
1336  }
1337  }
1338  cpl_array_set_size(aArray, n_val);
1339  return CPL_ERROR_NONE;
1340 }
1341 
1342 /*---------------------------------------------------------------------------*/
1357 /*---------------------------------------------------------------------------*/
1358 cpl_size
1359 muse_cplarray_erase_outliers(cpl_array *aArray, const cpl_bivector *aHistogram,
1360  cpl_size aGap, double aLimit)
1361 {
1362  cpl_ensure(aArray && aHistogram, CPL_ERROR_NULL_INPUT, -1);
1363  /* test for numerical array */
1364  int err;
1365  double value = cpl_array_get(aArray, 0, &err);
1366  cpl_ensure(err >= 0, CPL_ERROR_ILLEGAL_INPUT, -2);
1367 
1368  /* start at the peak of the histogram */
1369  const double *hpos = cpl_bivector_get_x_data_const(aHistogram),
1370  *hval = cpl_bivector_get_y_data_const(aHistogram);
1371  cpl_size nhist = cpl_bivector_get_size(aHistogram);
1372  cpl_array *ahist = cpl_array_wrap_double((double *)hval, nhist);
1373  cpl_size imax;
1374  cpl_array_get_maxpos(ahist, &imax);
1375  cpl_array_unwrap(ahist);
1376 
1377  /* go to lower values in the histogram, search for the first gap */
1378  double loval = hpos[0],
1379  hival = hpos[nhist - 1];
1380  cpl_size i, nlow = 0;
1381  for (i = imax; i >= 0; i--) {
1382  if (hval[i] <= aLimit) {
1383  if (nlow == 0) { /* keep this as the initial low value */
1384  loval = hpos[i];
1385  }
1386  nlow++;
1387  if (nlow == aGap) { /* gap already wide enough */
1388  break;
1389  }
1390  } else if (nlow > 0) {
1391  nlow = 0; /* gap not wide enough after all */
1392  loval = hpos[0];
1393  }
1394  } /* for i */
1395  /* same search now to higher histogram values */
1396  for (i = imax; i < nhist; i++) {
1397  if (hval[i] <= aLimit) {
1398  if (nlow == 0) { /* keep this as the initial low value */
1399  hival = hpos[i];
1400  }
1401  nlow++;
1402  if (nlow == aGap) { /* gap already wide enough */
1403  break;
1404  }
1405  } else if (nlow > 0) {
1406  nlow = 0; /* gap not wide enough after all */
1407  hival = hpos[nhist - 1];
1408  }
1409  } /* for i */
1410  cpl_msg_debug(__func__, "Histogram gaps (%"CPL_SIZE_FORMAT" consecutive "
1411  "entries <= %f) at %f and %f", aGap, aLimit, loval, hival);
1412 
1413  /* now go through the array, and set values larger *
1414  * or smaller than these extremes to invalid */
1415  cpl_size idx, narray = cpl_array_get_size(aArray);
1416  for (idx = 0; idx < narray; idx++) {
1417  value = cpl_array_get(aArray, idx, NULL);
1418  if (value > hival || value < loval) {
1419  cpl_array_set_invalid(aArray, idx);
1420  }
1421  } /* for idx */
1422 
1423  /* finally count them and then remove all invalid ones */
1424  cpl_size nbad = cpl_array_count_invalid(aArray);
1426  return nbad;
1427 } /* muse_cplarray_erase_outliers() */
1428 
1429 
1430 /*----------------------------------------------------------------------------*/
1431 /* Helper functions for quicksort */
1432 /*----------------------------------------------------------------------------*/
1434 static int cmp_double_asc(const void *p1, const void *p2) {
1435  double d = (*(const double *)p1 - *(const double *)p2);
1436  return (d < 0)?-1:(d>0)?1:0;
1437 }
1439 static int cmp_double_desc(const void *p1, const void *p2) {
1440  double d = (*(const double *)p1 - *(const double *)p2);
1441  return (d < 0)?1:(d>0)?-1:0;
1442 }
1444 static int cmp_float_asc(const void *p1, const void *p2) {
1445  float d = (*(const float *)p1 - *(const float *)p2);
1446  return (d < 0)?-1:(d>0)?1:0;
1447 }
1449 static int cmp_float_desc(const void *p1, const void *p2) {
1450  float d = (*(const float *)p1 - *(const float *)p2);
1451  return (d < 0)?1:(d>0)?-1:0;
1452 }
1454 static int cmp_int_asc(const void *p1, const void *p2) {
1455  return (*(const int *)p1 - *(const int *)p2);
1456 }
1458 static int cmp_int_desc(const void *p1, const void *p2) {
1459  return (*(const int *)p2 - *(const int *)p1);
1460 }
1461 
1463 static int cmp_long_asc(const void *p1, const void *p2) {
1464  return (*(const long *)p1 - *(const long *)p2);
1465 }
1467 static int cmp_long_desc(const void *p1, const void *p2) {
1468  return (*(const long *)p2 - *(const long *)p1);
1469 }
1470 
1472 static int cmp_string_asc(const void *p1, const void *p2) {
1473  return strcmp(*(const char **)p1, *(const char **)p2);
1474 }
1476 static int cmp_string_desc(const void *p1, const void *p2) {
1477  return strcmp(*(const char **)p2, *(const char **)p1);
1478 }
1479 
1480 /*----------------------------------------------------------------------------*/
1490 /*----------------------------------------------------------------------------*/
1491 cpl_error_code
1492 muse_cplarray_sort(cpl_array *aArray, cpl_boolean aOrder)
1493 {
1494  cpl_ensure_code(aArray != NULL, CPL_ERROR_NULL_INPUT);
1495  cpl_ensure_code(!cpl_array_has_invalid(aArray), CPL_ERROR_NULL_INPUT);
1496 
1497  cpl_size n = cpl_array_get_size(aArray);
1498  if (cpl_array_get_type(aArray) == CPL_TYPE_DOUBLE) {
1499  double *d = cpl_array_get_data_double(aArray);
1500  qsort(d, n, sizeof(double), (aOrder)?cmp_double_asc:cmp_double_desc);
1501  return CPL_ERROR_NONE;
1502  } else if (cpl_array_get_type(aArray) == CPL_TYPE_FLOAT) {
1503  float *d = cpl_array_get_data_float(aArray);
1504  qsort(d, n, sizeof(float), (aOrder)?cmp_float_asc:cmp_float_desc);
1505  return CPL_ERROR_NONE;
1506  } else if (cpl_array_get_type(aArray) == CPL_TYPE_INT) {
1507  int *d = cpl_array_get_data_int(aArray);
1508  qsort(d, n, sizeof(int), (aOrder)?cmp_int_asc:cmp_int_desc);
1509  return CPL_ERROR_NONE;
1510  } else if (cpl_array_get_type(aArray) == CPL_TYPE_LONG) {
1511  long *d = cpl_array_get_data_long(aArray);
1512  qsort(d, n, sizeof(long), (aOrder)?cmp_long_asc:cmp_long_desc);
1513  return CPL_ERROR_NONE;
1514  } else if (cpl_array_get_type(aArray) == CPL_TYPE_STRING) {
1515  char **d = cpl_array_get_data_string(aArray);
1516  qsort(d, n, sizeof(char *), (aOrder)?cmp_string_asc:cmp_string_desc);
1517  return CPL_ERROR_NONE;
1518  } else {
1519  return CPL_ERROR_ILLEGAL_INPUT;
1520  }
1521 }
1522 
1523 /*---------------------------------------------------------------------------*/
1542 /*---------------------------------------------------------------------------*/
1543 cpl_bivector *
1544 muse_cplarray_histogram(const cpl_array *aArray, double aWidth,
1545  double aMin, double aMax)
1546 {
1547  cpl_ensure(aArray, CPL_ERROR_NULL_INPUT, NULL);
1548  /* test for numerical array */
1549  int err;
1550  double value = cpl_array_get(aArray, 0, &err);
1551  cpl_ensure(err >= 0, CPL_ERROR_INVALID_TYPE, NULL);
1552  if (!isnan(aMin) && !isnan(aMax) && aMin >= aMax) { /* inverse extremes */
1553  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
1554  return NULL;
1555  }
1556  if (isnan(aMin)) {
1557  aMin = cpl_array_get_min(aArray);
1558  }
1559  if (isnan(aMax)) {
1560  aMax = cpl_array_get_max(aArray);
1561  }
1562  cpl_size hlen = lround((aMax - aMin) / aWidth) + 1;
1563  cpl_bivector *histogram = cpl_bivector_new(hlen);
1564 
1565  /* fill histogram positions */
1566  double *hpos = cpl_bivector_get_x_data(histogram);
1567  cpl_size i;
1568  for (i = 0; i < hlen; i++) {
1569  hpos[i] = i * aWidth + aMin;
1570  } /* for i */
1571 
1572  /* fill histogram values */
1573  double *hval = cpl_bivector_get_y_data(histogram);
1574  /* histogram has at least zero everywhere */
1575  cpl_vector_fill(cpl_bivector_get_y(histogram), 0.);
1576  cpl_size n = cpl_array_get_size(aArray);
1577  for (i = 0; i < n; i++) {
1578  value = cpl_array_get(aArray, i, &err);
1579  if (err) {
1580  continue;
1581  }
1582  /* find histogram index */
1583  cpl_size idx = lround((value - aMin) / aWidth);
1584  if (idx >= hlen || idx < 0) {
1585  continue;
1586  }
1587  /* add one to the histogram at the respective index */
1588  hval[idx] += 1;
1589  } /* for i */
1590 #if 0
1591  printf("histogram %f...%f / %f\n", aMin, aMax, aWidth);
1592  cpl_bivector_dump(histogram, stdout);
1593  fflush(stdout);
1594 #endif
1595  return histogram;
1596 } /* muse_cplarray_histogram() */
1597 
1598 /*----------------------------------------------------------------------------*/
1611 /*----------------------------------------------------------------------------*/
1612 cpl_size
1613 muse_cplarray_find_sorted(const cpl_array *aArray, double aValue)
1614 {
1615  cpl_ensure(aArray, CPL_ERROR_NULL_INPUT, 0);
1616  cpl_size min = 0;
1617  cpl_size max = cpl_array_get_size(aArray);
1618  cpl_type type = cpl_array_get_type(aArray);
1619  if (type == CPL_TYPE_DOUBLE) {
1620  const double *data = cpl_array_get_data_double_const(aArray);
1621  while (max - min > 1) {
1622  int i = (max + min)/2;
1623  if (data[i] > aValue) {
1624  max = i;
1625  } else {
1626  min = i;
1627  }
1628  }
1629  } else if (type == CPL_TYPE_FLOAT) {
1630  const float *data = cpl_array_get_data_float_const(aArray);
1631  while (max - min > 1) {
1632  int i = (max + min)/2;
1633  if (data[i] > aValue) {
1634  max = i;
1635  } else {
1636  min = i;
1637  }
1638  }
1639  } else if (type == CPL_TYPE_INT) {
1640  const int *data = cpl_array_get_data_int_const(aArray);
1641  while (max - min > 1) {
1642  int i = (max + min)/2;
1643  if (data[i] > aValue) {
1644  max = i;
1645  } else {
1646  min = i;
1647  }
1648  }
1649  } else {
1650  cpl_msg_error(__func__, "illegal type %i", type);
1651  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
1652  return 0;
1653  }
1654  return min;
1655 }
1656 
1657 /*----------------------------------------------------------------------------*/
1672 /*----------------------------------------------------------------------------*/
1673 cpl_boolean
1674 muse_cplarray_has_duplicate(const cpl_array *aArray)
1675 {
1676  cpl_ensure(aArray, CPL_ERROR_NULL_INPUT, CPL_FALSE);
1677  cpl_type type = cpl_array_get_type(aArray);
1678  switch (type) {
1679  case CPL_TYPE_INT:
1680  case CPL_TYPE_LONG:
1681  case CPL_TYPE_LONG_LONG:
1682  case CPL_TYPE_SIZE:
1683  break;
1684  default:
1685  cpl_error_set(__func__, CPL_ERROR_UNSUPPORTED_MODE);
1686  return CPL_FALSE;
1687  }
1688 
1689  cpl_size idx, n = cpl_array_get_size(aArray);
1690  for (idx = 0; idx < n - 1; idx++) {
1691  int err;
1692  cpl_size v1 = cpl_array_get(aArray, idx, &err);
1693  if (err) { /* invalid somehow, skip this one */
1694  continue;
1695  }
1696  cpl_size idx2;
1697  for (idx2 = idx + 1; idx2 < n; idx2++) {
1698  cpl_size v2 = cpl_array_get(aArray, idx2, &err);
1699  if (err) { /* invalid somehow, skip this one */
1700  continue;
1701  }
1702  if (v2 == v1) {
1703 #if 0
1704  cpl_msg_debug(__func__, "entry[%"CPL_SIZE_FORMAT"] == entry[%"
1705  CPL_SIZE_FORMAT"] == %"CPL_SIZE_FORMAT, idx, idx2, v1);
1706 #endif
1707  return CPL_TRUE;
1708  }
1709  } /* for idx2 (array indices starting after idx) */
1710  } /* for idx (all array indices but the last) */
1711  return CPL_FALSE;
1712 } /* muse_cplarray_has_duplicate() */
1713 
1714 /*----------------------------------------------------------------------------*/
1727 /*----------------------------------------------------------------------------*/
1728 cpl_array *
1729 muse_cplarray_extract(cpl_array *aArray, cpl_size aStart, cpl_size aCount)
1730 {
1731  cpl_size nrows = cpl_array_get_size(aArray);
1732  if (aCount > nrows - aStart) {
1733  aCount = nrows - aStart;
1734  }
1735  cpl_type type = cpl_array_get_type(aArray);
1736  if (type == CPL_TYPE_DOUBLE) {
1737  return cpl_array_wrap_double(cpl_array_get_data_double(aArray) + aStart,
1738  aCount);
1739  } else if (type == CPL_TYPE_FLOAT) {
1740  return cpl_array_wrap_float(cpl_array_get_data_float(aArray) + aStart,
1741  aCount);
1742  } else if (type == CPL_TYPE_INT) {
1743  return cpl_array_wrap_int(cpl_array_get_data_int(aArray) + aStart,
1744  aCount);
1745  } else {
1746  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
1747  return NULL;
1748  }
1749 }
1750 /*----------------------------------------------------------------------------*/
1764 /*----------------------------------------------------------------------------*/
1765 cpl_error_code
1766 muse_cplarray_add_window(cpl_array *aDest, cpl_size aStart,
1767  const cpl_array *aArray)
1768 {
1769  cpl_ensure_code(aDest && aArray, CPL_ERROR_NULL_INPUT);
1770  cpl_size count = cpl_array_get_size(aArray);
1771  cpl_array *destArray = muse_cplarray_extract(aDest, aStart, count);
1772  if (destArray == NULL) {
1773  return CPL_ERROR_ILLEGAL_INPUT;
1774  }
1775  cpl_array_add(destArray, aArray);
1776  cpl_array_unwrap(destArray);
1777 
1778  return CPL_ERROR_NONE;
1779 }
1780 
1781 /*----------------------------------------------------------------------------*/
1791 /*----------------------------------------------------------------------------*/
1792 cpl_array *
1793 muse_cplarray_diff(const cpl_array *aArray, int aOffset)
1794 {
1795  cpl_ensure(aArray, CPL_ERROR_NULL_INPUT, NULL);
1796  cpl_ensure(aOffset > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1797  cpl_size nrows = cpl_array_get_size(aArray);
1798 
1799  cpl_array *a1 = cpl_array_extract(aArray, 0, nrows - aOffset);
1800  cpl_array *a2 = cpl_array_extract(aArray, aOffset, nrows - aOffset);
1801  if (a1 == NULL || a2 == NULL) {
1802  cpl_array_delete(a1);
1803  cpl_array_delete(a2);
1804  return NULL;
1805  }
1806  cpl_array_subtract(a2, a1);
1807  cpl_array_delete(a1);
1808  return a2;
1809 }
1810 
1811 /*----------------------------------------------------------------------------*/
1824 /*----------------------------------------------------------------------------*/
1825 cpl_error_code
1826 muse_cplarray_erf(cpl_array *aArray)
1827 {
1828  cpl_ensure_code(aArray, CPL_ERROR_NULL_INPUT);
1829  cpl_type type = cpl_array_get_type(aArray);
1830  cpl_size n = cpl_array_get_size(aArray);
1831  if (type == CPL_TYPE_DOUBLE) {
1832  double *d = cpl_array_get_data_double(aArray);
1833  cpl_size i;
1834  for (i = 0; i < n; i++, d++) {
1835  *d = erf(*d);
1836  }
1837  } else if (type == CPL_TYPE_FLOAT) {
1838  float *d = cpl_array_get_data_float(aArray);
1839  cpl_size i;
1840  for (i = 0; i < n; i++, d++) {
1841  *d = erf(*d);
1842  }
1843  } else {
1844  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
1845  return CPL_ERROR_ILLEGAL_INPUT;
1846  }
1847  return CPL_ERROR_NONE;
1848 }
1849 
1850 /*----------------------------------------------------------------------------*/
1863 /*----------------------------------------------------------------------------*/
1864 cpl_error_code
1865 muse_cplarray_exp(cpl_array *aArray)
1866 {
1867  cpl_ensure_code(aArray, CPL_ERROR_NULL_INPUT);
1868  cpl_type type = cpl_array_get_type(aArray);
1869  cpl_size n = cpl_array_get_size(aArray);
1870  if (type == CPL_TYPE_DOUBLE) {
1871  double *d = cpl_array_get_data_double(aArray);
1872  cpl_size i;
1873  for (i = 0; i < n; i++, d++) {
1874  *d = exp(*d);
1875  }
1876  } else if (type == CPL_TYPE_FLOAT) {
1877  float *d = cpl_array_get_data_float(aArray);
1878  cpl_size i;
1879  for (i = 0; i < n; i++, d++) {
1880  *d = expf(*d);
1881  }
1882  } else {
1883  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
1884  return CPL_ERROR_ILLEGAL_INPUT;
1885  }
1886  return CPL_ERROR_NONE;
1887 }
1888 
1889 /*----------------------------------------------------------------------------*/
1912 /*----------------------------------------------------------------------------*/
1913 cpl_array *
1914 muse_cplarray_interpolate_linear(const cpl_array *aTargetAbscissa,
1915  const cpl_array *aSourceAbscissa,
1916  const cpl_array *aSourceOrdinate)
1917 {
1918  cpl_ensure(aTargetAbscissa && aSourceAbscissa && aSourceOrdinate,
1919  CPL_ERROR_NULL_INPUT, NULL);
1920 
1921  double *targetX = cpl_array_get_data_double((cpl_array *)aTargetAbscissa);
1922  double *srcX = cpl_array_get_data_double((cpl_array *)aSourceAbscissa);
1923  double *srcY = cpl_array_get_data_double((cpl_array *)aSourceOrdinate);
1924  cpl_ensure(targetX && srcX && srcY, CPL_ERROR_ILLEGAL_INPUT, NULL);
1925 
1926  cpl_array *targetOrdinate = cpl_array_duplicate(aTargetAbscissa);
1927  double *targetY = cpl_array_get_data_double(targetOrdinate);
1928 
1929  cpl_size n_src = cpl_array_get_size(aSourceAbscissa);
1930  cpl_vector *srcX_vec = cpl_vector_wrap(n_src, srcX);
1931  cpl_vector *srcY_vec = cpl_vector_wrap(n_src, srcY);
1932  cpl_bivector *src_vec = cpl_bivector_wrap_vectors(srcX_vec, srcY_vec);
1933 
1934  cpl_size offset = (srcX[0] <= targetX[0])?0:
1935  muse_cplarray_find_sorted(aTargetAbscissa, srcX[0]) + 1;
1936  cpl_size n_target =
1937  muse_cplarray_find_sorted(aTargetAbscissa, srcX[n_src-1]) - offset + 1;
1938 
1939  cpl_vector *targetX_vec = cpl_vector_wrap(n_target, targetX + offset);
1940  cpl_vector *targetY_vec = cpl_vector_wrap(n_target, targetY + offset);
1941  cpl_bivector *target_vec = cpl_bivector_wrap_vectors(targetX_vec,
1942  targetY_vec);
1943  if (offset > 0) {
1944  cpl_array_fill_window_invalid(targetOrdinate, 0, offset);
1945  }
1946  if (offset + n_target < (unsigned)cpl_array_get_size(targetOrdinate)) {
1947  cpl_array_fill_window_invalid(targetOrdinate, offset + n_target,
1948  cpl_array_get_size(targetOrdinate)
1949  - (offset + n_target));
1950  }
1951  cpl_bivector_interpolate_linear(target_vec, src_vec);
1952  cpl_bivector_unwrap_vectors(target_vec);
1953  cpl_vector_unwrap(targetX_vec);
1954  cpl_vector_unwrap(targetY_vec);
1955  cpl_bivector_unwrap_vectors(src_vec);
1956  cpl_vector_unwrap(srcX_vec);
1957  cpl_vector_unwrap(srcY_vec);
1958 
1959  return targetOrdinate;
1960 }
1961 
1962 /*----------------------------------------------------------------------------*/
1981 /*----------------------------------------------------------------------------*/
1982 cpl_array *
1983 muse_cplarray_interpolate_table_linear(const cpl_array *aTargetAbscissa,
1984  const cpl_table *aSrcTable,
1985  const char *aSrcAbscissa,
1986  const char *aSrcOrdinate)
1987 {
1988  cpl_array *sabs = muse_cpltable_extract_column((cpl_table *)aSrcTable,
1989  aSrcAbscissa);
1990  cpl_array *sord = muse_cpltable_extract_column((cpl_table *)aSrcTable,
1991  aSrcOrdinate);
1992  cpl_array *ord = muse_cplarray_interpolate_linear(aTargetAbscissa, sabs, sord);
1993  cpl_array_unwrap(sabs);
1994  cpl_array_unwrap(sord);
1995  return ord;
1996 }
1997 
1998 /*---------------------------------------------------------------------------*/
2012 /*---------------------------------------------------------------------------*/
2013 cpl_array *
2014 muse_cplarray_new_from_delimited_string(const char *aString, const char *aDelim)
2015 {
2016  cpl_ensure(aString && aDelim, CPL_ERROR_NULL_INPUT, NULL);
2017  /* duplicate the string to be able to work on it */
2018  char *string = cpl_strdup(aString);
2019 
2020  /* loop to find delimiters and save sub-strings in array */
2021  char *prev = string, *next;
2022  cpl_array *out = cpl_array_new(0, CPL_TYPE_STRING);
2023  int ntok = 0;
2024  do {
2025  next = strstr(prev, aDelim);
2026  if (next) {
2027  *next = '\0'; /* terminate this token starting at |prev| */
2028  }
2029  if (strlen(prev)) { /* don't want to add non-empty strings */
2030  cpl_array_set_size(out, ++ntok);
2031  cpl_array_set_string(out, ntok - 1, prev);
2032  }
2033  prev = next + strlen(aDelim);
2034  } while (next);
2035  cpl_free(string);
2036 
2037 #if 0
2038  printf("Input string %s and delimiter %s resulted in output\n",
2039  aString, aDelim);
2040  cpl_array_dump(out, 0, cpl_array_get_size(out), stdout);
2041  fflush(stdout);
2042 #endif
2043  return out;
2044 } /* muse_cplarray_new_from_delimited_string() */
2045 
2046 /*---------------------------------------------------------------------------*/
2061 /*---------------------------------------------------------------------------*/
2062 cpl_array *
2063 muse_cplarray_string_to_double(const cpl_array *aArray)
2064 {
2065  cpl_ensure(aArray, CPL_ERROR_NULL_INPUT, NULL);
2066  cpl_ensure(cpl_array_get_type(aArray) == CPL_TYPE_STRING,
2067  CPL_ERROR_ILLEGAL_INPUT, NULL);
2068 
2069  cpl_size i, n = cpl_array_get_size(aArray);
2070  cpl_array *darray = cpl_array_new(n, CPL_TYPE_DOUBLE);
2071  for (i = 0; i < n; i++) {
2072  const char *string = cpl_array_get_string(aArray, i);
2073  if (!string) {
2074  continue;
2075  }
2076  cpl_array_set_double(darray, i, atof(string));
2077  } /* for i (array elements) */
2078  return darray;
2079 } /* muse_cplarray_string_to_double() */
2080 
2081 /*---------------------------------------------------------------------------*/
2095 /*---------------------------------------------------------------------------*/
2096 cpl_parameter *
2097 muse_cplparamerterlist_find_prefix(cpl_parameterlist *aParameters,
2098  const char *aPrefix, const char *aName)
2099 {
2100  char *fullname = cpl_sprintf("%s.%s", aPrefix, aName);
2101  cpl_parameter *p = cpl_parameterlist_find(aParameters, fullname);
2102  cpl_free(fullname);
2103  return p;
2104 }
2105 
2106 /*---------------------------------------------------------------------------*/
2131 /*---------------------------------------------------------------------------*/
2132 cpl_parameterlist *
2133 muse_cplparameterlist_from_propertylist(const cpl_propertylist *aHeader,
2134  int aRecNum)
2135 {
2136  cpl_ensure(aHeader, CPL_ERROR_NULL_INPUT, NULL);
2137  cpl_ensure(aRecNum > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
2138 
2139  /* check that the input header has a recipe name */
2140  char *kw = cpl_sprintf("ESO PRO REC%d ID", aRecNum);
2141  const char *recipe = cpl_propertylist_get_string(aHeader, kw);
2142  cpl_free(kw);
2143  cpl_ensure(recipe, CPL_ERROR_ILLEGAL_INPUT, NULL);
2144  /* check that the input header was written by the MUSE pipeline */
2145  kw = cpl_sprintf("ESO PRO REC%d PIPE ID", aRecNum);
2146  const char *pipeid = cpl_propertylist_get_string(aHeader, kw);
2147  cpl_free(kw);
2148  cpl_ensure(strstr(recipe, "muse_") && strstr(pipeid, "muse"),
2149  CPL_ERROR_INCOMPATIBLE_INPUT, NULL);
2150  char *context = cpl_sprintf("muse.%s", recipe);
2151 
2152  /* create the new parameter list to be filled from the header */
2153  cpl_parameterlist *parlist = cpl_parameterlist_new();
2154  int npar;
2155  for (npar = 1; npar < cpl_propertylist_get_size(aHeader); npar++) {
2156  char *kwname = cpl_sprintf("ESO PRO REC%d PARAM%d NAME", aRecNum, npar),
2157  *kwvalue = cpl_sprintf("ESO PRO REC%d PARAM%d VALUE", aRecNum, npar);
2158  if (!cpl_propertylist_has(aHeader, kwname) ||
2159  !cpl_propertylist_has(aHeader, kwvalue)) {
2160  cpl_free(kwname);
2161  cpl_free(kwvalue);
2162  break;
2163  }
2164  const cpl_property *prop = cpl_propertylist_get_property_const(aHeader,
2165  kwvalue);
2166  /* since they are all saved as strings, convert them to other types *
2167  * based on the first character and the presence of a dot */
2168  const char *value = cpl_property_get_string(prop);
2169  cpl_type type = CPL_TYPE_STRING;
2170  if (!strncmp(value, "true", 5) || !strncmp(value, "false", 6)) {
2171  type = CPL_TYPE_BOOL;
2172  } else if (!strchr(value, ',') && /* no comma-separator of multiple numbers */
2173  ((value[0] >= '0' && value[0] <= '9') || /* numerical type */
2174  value[0] == '-' || value[0] == '+')) {
2175  /* this might mis-identify a few doubles saved without dot as ints! */
2176  if (strchr(value, '.') || strchr(value, 'E')) {
2177  type = CPL_TYPE_DOUBLE;
2178  } else {
2179  type = CPL_TYPE_INT;
2180  } /* else */
2181  } /* else */
2182  char *parname = cpl_sprintf("muse.%s.%s", recipe,
2183  cpl_propertylist_get_string(aHeader, kwname));
2184  const char *comment = cpl_property_get_comment(prop),
2185  *comname = cpl_propertylist_get_comment(aHeader, kwname);
2186  char defstr[41] = "true"; /* string with the default value */
2187  if (comment) {
2188  sscanf(comment, "Default: %40s", defstr);
2189  }
2190  cpl_parameter *par = NULL;
2191  switch (type) {
2192  case CPL_TYPE_BOOL:
2193  par = cpl_parameter_new_value(parname, type, comname, context,
2194  !strncmp(defstr, "true", 5) ? CPL_TRUE : CPL_FALSE);
2195  if (!strncmp(value, "true", 5)) {
2196  cpl_parameter_set_bool(par, CPL_TRUE);
2197  } else {
2198  cpl_parameter_set_bool(par, CPL_FALSE);
2199  }
2200  break;
2201  case CPL_TYPE_INT:
2202  par = cpl_parameter_new_value(parname, type, comname, context, atoi(defstr));
2203  cpl_parameter_set_int(par, atoi(value));
2204  break;
2205  case CPL_TYPE_DOUBLE:
2206  par = cpl_parameter_new_value(parname, type, comname, context, atof(defstr));
2207  cpl_parameter_set_double(par, atof(value));
2208  break;
2209  case CPL_TYPE_STRING:
2210  par = cpl_parameter_new_value(parname, type, comname, context, defstr);
2211  cpl_parameter_set_string(par, value);
2212  break;
2213  default:
2214  /* cannot do anything */
2215  par = cpl_parameter_new_value(parname, type, comname, context, 0);
2216  cpl_msg_warning(__func__, "property of type %s (%d) found!",
2217  cpl_type_get_name(type), type);
2218  } /* switch */
2219  cpl_parameterlist_append(parlist, par);
2220  cpl_free(parname);
2221  cpl_free(kwname);
2222  cpl_free(kwvalue);
2223  } /* for npar */
2224  cpl_free(context);
2225  return parlist;
2226 } /* muse_cplparameterlist_from_propertylist() */
2227 
2228 /*---------------------------------------------------------------------------*/
2240 /*---------------------------------------------------------------------------*/
2241 cpl_parameterlist *
2242 muse_cplparameterlist_duplicate(const cpl_parameterlist *aPList)
2243 {
2244  cpl_ensure(aPList, CPL_ERROR_NULL_INPUT, NULL);
2245 
2246  cpl_parameterlist *list = cpl_parameterlist_new();
2247  const cpl_parameter *par = cpl_parameterlist_get_first_const(aPList);
2248  while (par) {
2249  cpl_parameterlist_append(list, cpl_parameter_duplicate(par));
2250  par = cpl_parameterlist_get_next_const(aPList);
2251  } /* while */
2252  return list;
2253 } /* muse_cplparameterlist_duplicate() */
2254 
2255 /*----------------------------------------------------------------------------*/
2273 /*----------------------------------------------------------------------------*/
2274 cpl_error_code
2275 muse_cplpropertylist_update_long_long(cpl_propertylist *aHeader,
2276  const char *aKeyword, cpl_size aValue)
2277 {
2278  cpl_ensure_code(aHeader && aKeyword, CPL_ERROR_NULL_INPUT);
2279  cpl_property *p = cpl_propertylist_get_property(aHeader, aKeyword);
2280  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
2281  cpl_error_code rc = CPL_ERROR_NONE;
2282  switch (cpl_property_get_type(p)) {
2283  case CPL_TYPE_LONG_LONG:
2284  rc = cpl_property_set_long_long(p, aValue);
2285  break;
2286  case CPL_TYPE_LONG:
2287  rc = cpl_property_set_long(p, aValue);
2288  break;
2289  default:
2290  rc = cpl_property_set_int(p, aValue);
2291  } /* switch */
2292  return rc;
2293 } /* muse_cplpropertylist_update_long_long() */
2294 
2295 /*----------------------------------------------------------------------------*/
2306 /*----------------------------------------------------------------------------*/
2307 cpl_error_code
2308 muse_cplframeset_erase_all(cpl_frameset *aFrames)
2309 {
2310  cpl_ensure_code(aFrames, CPL_ERROR_NULL_INPUT);
2311  cpl_error_code rc = CPL_ERROR_NONE;
2312  /* always get and erase the first frame until we are done */
2313  while (cpl_frameset_get_size(aFrames) > 0 && rc == CPL_ERROR_NONE) {
2314  cpl_frame *frame = cpl_frameset_get_position(aFrames, 0);
2315  rc = cpl_frameset_erase_frame(aFrames, frame);
2316  } /* while */
2317  return rc;
2318 } /* muse_cplframeset_erase_all() */
2319 
2320 /*----------------------------------------------------------------------------*/
2337 /*----------------------------------------------------------------------------*/
2338 cpl_error_code
2339 muse_cplframeset_erase_duplicate(cpl_frameset *aFrames)
2340 {
2341  cpl_ensure_code(aFrames, CPL_ERROR_NULL_INPUT);
2342 #if 0
2343  printf("\n\n\n%s input frameset (with duplicates):\n", __func__);
2344  cpl_frameset_dump(aFrames, stdout);
2345  printf("---------------------------------------------------------------------------\n");
2346  fflush(stdout);
2347 #endif
2348  cpl_error_code rc = CPL_ERROR_NONE;
2349  /* Loop through all frames but the last, and compare all frame properties *
2350  * to all following frames. Delete the frame if they are all the same. */
2351  cpl_size i;
2352  for (i = 0; i < cpl_frameset_get_size(aFrames) - 1; i++) {
2353  cpl_frame *fref = cpl_frameset_get_position(aFrames, i);
2354  cpl_size j;
2355  for (j = i + 1; j < cpl_frameset_get_size(aFrames); j++) {
2356  cpl_frame *fother = cpl_frameset_get_position(aFrames, j);
2357  cpl_boolean areequal = CPL_FALSE;
2358  cpl_errorstate state = cpl_errorstate_get();
2359  const char *fn1 = cpl_frame_get_filename(fref),
2360  *fn2 = cpl_frame_get_filename(fother);
2361  if (!cpl_errorstate_is_equal(state)) {
2362  cpl_errorstate_set(state);
2363  }
2364  if ((!fn1 && fn2) || (fn1 && !fn2)) {
2365  areequal = CPL_FALSE;
2366  } else if (!fn1 && !fn2) {
2367  areequal = CPL_TRUE;
2368  } else {
2369  areequal = !strcmp(fn1, fn2);
2370  }
2371  areequal = areequal
2372  && !strcmp(cpl_frame_get_tag(fref), cpl_frame_get_tag(fother));
2373  areequal = areequal
2374  && (cpl_frame_get_group(fref) == cpl_frame_get_group(fother));
2375  areequal = areequal
2376  && (cpl_frame_get_level(fref) == cpl_frame_get_level(fother));
2377  areequal = areequal
2378  && (cpl_frame_get_type(fref) == cpl_frame_get_type(fother));
2379  if (areequal) {
2380 #if 0
2381  printf("%ld/%ld are equal: %s/%s, %s/%s, %d/%d, %d/%d, %d/%d\n", i, j,
2382  fn1, fn2, tag1, tag2,
2383  cpl_frame_get_group(fref), cpl_frame_get_group(fother),
2384  cpl_frame_get_level(fref), cpl_frame_get_level(fother),
2385  cpl_frame_get_type(fref), cpl_frame_get_type(fother));
2386  fflush(stdout);
2387 #endif
2388  /* would really like to erase the other frame, *
2389  * but it's not possible to delete by position! */
2390  rc = cpl_frameset_erase_frame(aFrames, fref);
2391  i--; /* stay at the same reference position in the frameset */
2392  break;
2393  } /* if equal */
2394  } /* for j (all following frames) */
2395  } /* for i (all frames but the last) */
2396 #if 0
2397  printf("---------------------------------------------------------------------------\n");
2398  printf("%s input frameset (without duplicates):\n", __func__);
2399  cpl_frameset_dump(aFrames, stdout);
2400  printf("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n\n");
2401  fflush(stdout);
2402 #endif
2403  return rc;
2404 } /* muse_cplframeset_erase_duplicate() */
2405 
2406 /*----------------------------------------------------------------------------*/
2418 /*----------------------------------------------------------------------------*/
2419 void
2420 muse_cplerrorstate_dump_some(unsigned aCurrent, unsigned aFirst, unsigned aLast)
2421 {
2422  const cpl_boolean is_reverse = aFirst > aLast ? CPL_TRUE : CPL_FALSE;
2423  const char *revmsg = is_reverse ? " in reverse order" : "";
2424  const unsigned newest = is_reverse ? aFirst : aLast,
2425  nmax = labs((long int)aLast - (long int)aFirst) + 1;
2426  unsigned ndump = 20;
2427  if (getenv("MUSE_CPL_ERRORSTATE_NDUMP") &&
2428  atoi(getenv("MUSE_CPL_ERRORSTATE_NDUMP")) > 0) {
2429  ndump = atoi(getenv("MUSE_CPL_ERRORSTATE_NDUMP"));
2430  }
2431  ndump = nmax < ndump ? nmax : ndump;
2432 
2433  if (newest) { /* there are errors to dump */
2434  if (aCurrent == aLast - (ndump-1)) {
2435  cpl_msg_error(__func__, "Dumping the %u most recent error(s) out of a "
2436  "total of %u errors%s:", ndump, newest, revmsg);
2437  cpl_msg_indent_more();
2438  }
2439  if (aCurrent >= aLast - (ndump-1)) {
2440  cpl_msg_error(__func__, "[%u/%u] '%s' (%u) at %s", aCurrent, newest,
2441  cpl_error_get_message(), cpl_error_get_code(),
2442  cpl_error_get_where());
2443  }
2444  if (aCurrent == aLast) {
2445  cpl_msg_indent_less();
2446  }
2447  } else {
2448  cpl_msg_info(__func__, "No error(s) to dump");
2449  }
2450 } /* muse_cplerrorstate_dump_some() */
2451 
2452 
2453 /*----------------------------------------------------------------------------*/
2466 /*----------------------------------------------------------------------------*/
2468 #ifdef HAVE_READLINK
2469  char buffer[FILENAME_MAX] = "\0";
2470  int length = readlink("/proc/self/exe", buffer, sizeof(buffer) - 1);
2471  if (length != -1) {
2472  buffer[length] = '\0';
2473  }
2474  if (strstr(buffer, "esorex")) {
2475  return MUSE_CPLFRAMEWORK_ESOREX;
2476  } else if (strstr(buffer, "python")) {
2478  } else if (strstr(buffer, "jre")) {
2480  } else {
2482  }
2483 #else
2485 #endif
2486 }
2487 
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).
int(* muse_cplmatrix_element_compare_func)(double aValue1, double aValue2)
Matrix element comparison function type definition.
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_matrix * muse_cplmatrix_extract_selected(const cpl_matrix *aMatrix, const cpl_array *aIndices)
Extract the elements given by the index array.
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 &#39;OR&#39; 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.
cpl_matrix * muse_cplmatrix_multiply_create(const cpl_matrix *aMatrix1, const cpl_matrix *aMatrix2)
Compute the element-wise product of two matrices.
cpl_array * muse_cplmatrix_where(const cpl_matrix *aMatrix, double aValue, muse_cplmatrix_element_compare_func aCondition)
Select matrix elements according to a condition.
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)