MUSE Pipeline Reference Manual  0.18.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-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 /*----------------------------------------------------------------------------*/
406 /*----------------------------------------------------------------------------*/
407 double
408 muse_cplvector_get_adev_const(const cpl_vector *aVector, double aCenter)
409 {
410  cpl_ensure(aVector, CPL_ERROR_NULL_INPUT, 0.);
411  double mdev = 0;
412  cpl_size i, n = cpl_vector_get_size(aVector);
413  for (i = 0; i < n; i++) {
414  mdev += fabs(cpl_vector_get(aVector, i) - aCenter);
415  }
416  return mdev / (double)n; /* return normalized value */
417 } /* muse_cplvector_get_adev_const() */
418 
419 /*----------------------------------------------------------------------------*/
432 /*----------------------------------------------------------------------------*/
433 double
434 muse_cplvector_get_median_dev(cpl_vector *aVector, double *aMedian)
435 {
436  cpl_ensure(aVector, CPL_ERROR_NULL_INPUT, 0.);
437  double median = cpl_vector_get_median(aVector),
438  mdev = 0.;
439  cpl_size i, n = cpl_vector_get_size(aVector);
440  for (i = 0; i < n; i++) {
441  mdev += fabs(cpl_vector_get(aVector, i) - median);
442  }
443  if (aMedian) {
444  *aMedian = median;
445  }
446  return mdev / (double)n; /* return normalized value */
447 } /* muse_cplvector_get_median_dev() */
448 
449 /*----------------------------------------------------------------------------*/
463 /*----------------------------------------------------------------------------*/
464 double
466 {
467  double sqr = 0;
468  double median = cpl_vector_get_median_const(aVector);
469  cpl_vector *v = cpl_vector_duplicate(aVector), *v2;
470  int i, splitindex = 0;
471 
472  cpl_vector_sort(v, +1);
473 #if DEBUG_SQR
474  cpl_vector_dump(v, stdout);
475  fflush(stdout);
476  printf("median=%f%d\n", median);
477  fflush(stdout);
478 #endif
479  /* search for point to split the sorted vector, better just do it linearly */
480  splitindex = cpl_vector_find(v, median);
481 
482  /* copy upper half into new vector */
483  v2 = cpl_vector_new(cpl_vector_get_size(v) - splitindex - 1);
484 #if DEBUG_SQR
485  printf("Copying elements %d to %d\n", splitindex+1, cpl_vector_get_size(v)-1);
486 #endif
487  for (i = splitindex; i < cpl_vector_get_size(v); i++){
488 #if DEBUG_SQR
489  printf(" %d %f\n", i+1, cpl_vector_get(v, i));
490 #endif
491  cpl_vector_set(v2, i-splitindex, cpl_vector_get(v, i));
492  }
493 #if DEBUG_SQR
494  printf("\n");
495  fflush(stdout);
496 #endif
497  sqr = cpl_vector_get_median(v2); /* the upper median, non const OK */
498  cpl_vector_delete(v2);
499 
500  /* copy lower half into new vector */
501  v2 = cpl_vector_new(splitindex - 1);
502 #if DEBUG_SQR
503  printf("Copying elements %d to %d\n", 1, splitindex+1);
504 #endif
505  for (i = 0; i <= splitindex; i++) {
506 #if DEBUG_SQR
507  printf(" %d %f\n", i+1, cpl_vector_get(v, i));
508 #endif
509  cpl_vector_set(v2, i, cpl_vector_get(v, i));
510  }
511 #if DEBUG_SQR
512  printf("\n");
513  fflush(stdout);
514 #endif
515  sqr -= cpl_vector_get_median(v2); /* subtract the lower median, non const OK */
516  cpl_vector_delete(v2);
517 
518  return sqr/2.0; /* divide by two to get semiquartile range */
519 } /* muse_cplvector_get_semiquartile() */
520 
521 /*----------------------------------------------------------------------------*/
541 /*----------------------------------------------------------------------------*/
542 cpl_error_code
543 muse_cplvector_threshold(cpl_vector *aVec, double aLoCut, double aHiCut,
544  double aLoVal, double aHiVal)
545 {
546  cpl_ensure_code(aVec, CPL_ERROR_NULL_INPUT);
547  cpl_ensure_code(aLoCut <= aHiCut, CPL_ERROR_ILLEGAL_INPUT);
548 
549  double *data = cpl_vector_get_data(aVec);
550  int i, n = cpl_vector_get_size(aVec);
551  for (i = 0; i < n; i++) {
552  if (data[i] > aHiCut) {
553  data[i] = aHiVal;
554  } else if (data[i] < aLoCut) {
555  data[i] = aLoVal;
556  }
557  } /* for i (vector elements) */
558 
559  return CPL_ERROR_NONE;
560 }
561 
562 /*----------------------------------------------------------------------------*/
574 /*----------------------------------------------------------------------------*/
575 cpl_error_code
576 muse_cplvector_erase_element(cpl_vector *aVector, int aElement)
577 {
578  cpl_ensure_code(aVector, CPL_ERROR_NULL_INPUT);
579  int size = cpl_vector_get_size(aVector);
580  cpl_ensure_code(aElement >= 0 && aElement < size, CPL_ERROR_ILLEGAL_INPUT);
581 
582  if (aElement < size - 1) {
583  /* if it's not the last element, we need to move the remaining *
584  * elements so that they overwrite the one to be removed */
585  double *data = cpl_vector_get_data(aVector);
586  memmove(&data[aElement], &data[aElement+1],
587  (size-1 - aElement) * sizeof(double));
588  }
589 
590  /* resize the vector to account for the removed element */
591  return cpl_vector_set_size(aVector, size - 1);
592 } /* muse_cplvector_erase_element() */
593 
594 /*----------------------------------------------------------------------------*/
602 /*----------------------------------------------------------------------------*/
603 cpl_size
604 muse_cplvector_count_unique(const cpl_vector *aVector)
605 {
606  cpl_ensure(aVector, CPL_ERROR_NULL_INPUT, -1);
607  cpl_vector *sorted = cpl_vector_duplicate(aVector);
608  cpl_vector_sort(sorted, CPL_SORT_ASCENDING);
609  double *data = cpl_vector_get_data(sorted);
610  cpl_size i, n = cpl_vector_get_size(sorted),
611  nunique = 1; /* first element is always unique */
612  for (i = 1; i < n; i++) { /* start at 2nd element */
613  if (data[i] != data[i - 1]) {
614  nunique++;
615  }
616  } /* for i (all elements in sorted vector) */
617  cpl_vector_delete(sorted);
618  return nunique;
619 } /* muse_cplvector_count_unique() */
620 
621 /*----------------------------------------------------------------------------*/
629 /*----------------------------------------------------------------------------*/
630 cpl_vector *
631 muse_cplvector_get_unique(const cpl_vector *aVector)
632 {
633  cpl_ensure(aVector, CPL_ERROR_NULL_INPUT, NULL);
634  cpl_vector *sorted = cpl_vector_duplicate(aVector);
635  cpl_vector_sort(sorted, CPL_SORT_ASCENDING);
636  double *data = cpl_vector_get_data(sorted);
637  cpl_size i, n = cpl_vector_get_size(sorted),
638  iunique = 0;
639  cpl_vector *vunique = cpl_vector_new(n);
640  cpl_vector_set(vunique, iunique++, data[0]); /* set unique first element */
641  for (i = 1; i < n; i++) { /* start at 2nd element */
642  if (data[i] != data[i - 1]) {
643  cpl_vector_set(vunique, iunique++, data[i]);
644  }
645  } /* for i (all elements in sorted vector) */
646  cpl_vector_delete(sorted);
647  cpl_vector_set_size(vunique, iunique);
648  return vunique;
649 } /* muse_cplvector_get_unique() */
650 
651 /*----------------------------------------------------------------------------*/
661 /*----------------------------------------------------------------------------*/
662 cpl_table *
663 muse_cpltable_new(const muse_cpltable_def *aDef, cpl_size aLength)
664 {
665  cpl_ensure(aDef, CPL_ERROR_NULL_INPUT, NULL);
666  cpl_table *res = cpl_table_new(aLength);
667  for (; aDef->name != NULL; aDef++) {
668  cpl_error_code rc = CPL_ERROR_NONE;
669  if (aDef->type & CPL_TYPE_POINTER) {
670  rc = cpl_table_new_column_array(res, aDef->name, aDef->type, 2);
671  } else {
672  rc = cpl_table_new_column(res, aDef->name, aDef->type);
673  }
674  if (rc != CPL_ERROR_NONE) {
675  cpl_table_delete(res);
676  return NULL;
677  }
678  if (aDef->unit != NULL) {
679  if (cpl_table_set_column_unit(res, aDef->name,
680  aDef->unit) != CPL_ERROR_NONE) {
681  return NULL;
682  }
683  }
684  if (aDef->format != NULL) {
685  if (cpl_table_set_column_format(res, aDef->name,
686  aDef->format) != CPL_ERROR_NONE) {
687  return NULL;
688  }
689  }
690  }
691  return res;
692 }
693 
694 /*----------------------------------------------------------------------------*/
706 /*----------------------------------------------------------------------------*/
707 cpl_table *
708 muse_cpltable_load(const char *aFile, const char *aExtension,
709  const muse_cpltable_def aDefinition[])
710 {
711  int extension = cpl_fits_find_extension(aFile, aExtension);
712  if (extension <= 0) {
713  cpl_error_set_message(__func__, cpl_error_get_code(), "%s['%s']: "
714  "extension not found by EXTNAME", aFile, aExtension);
715  return NULL;
716  }
717  cpl_msg_debug(__func__, "Loading %s['%s'] from extension %d", aFile,
718  aExtension, extension);
719  cpl_table *tbl = cpl_table_load(aFile, extension, 2);
720  if (muse_cpltable_check(tbl, aDefinition) != CPL_ERROR_NONE) {
721  cpl_table_delete(tbl);
722  return NULL;
723  }
724  return tbl;
725 } /* muse_cpltable_load() */
726 
727 /*----------------------------------------------------------------------------*/
744 /*----------------------------------------------------------------------------*/
745 cpl_error_code
746 muse_cpltable_append_file(const cpl_table *aTable, const char *aFile,
747  const char *aExtension,
748  const muse_cpltable_def aDefinition[]) {
749  cpl_ensure_code(aTable != NULL, CPL_ERROR_NULL_INPUT);
750  cpl_ensure_code(aFile != NULL, CPL_ERROR_NULL_INPUT);
751  cpl_ensure_code(aExtension != NULL, CPL_ERROR_NULL_INPUT);
752  cpl_error_code r = muse_cpltable_check(aTable, aDefinition);
753  if (r != CPL_ERROR_NONE) {
754  cpl_msg_error(__func__, " %s['%s'] Table format error", aFile, aExtension);
755  cpl_error_set(__func__, r);
756  return r;
757  }
758  cpl_propertylist *props = cpl_propertylist_new();
759  cpl_propertylist_update_string(props, "EXTNAME", aExtension);
760  r = cpl_table_save(aTable, NULL, props, aFile, CPL_IO_EXTEND);
761  cpl_propertylist_delete(props);
762  if (r != CPL_ERROR_NONE) {
763  cpl_msg_error(__func__, "%s[%s]: %s", aFile, aExtension,
764  cpl_error_get_message());
765  }
766  return r;
767 }
768 
769 
770 /*----------------------------------------------------------------------------*/
776 /*----------------------------------------------------------------------------*/
777 cpl_error_code
778 muse_cpltable_check(const cpl_table *aTable, const muse_cpltable_def *aDef)
779 {
780  if (aTable == NULL) {
781  cpl_msg_error(__func__, "NULL table");
782  cpl_error_set(__func__, CPL_ERROR_NULL_INPUT);
783  return CPL_ERROR_NULL_INPUT;
784  }
785  if (aDef == NULL) {
786  return CPL_ERROR_NONE;
787  }
788  cpl_error_code rc = CPL_ERROR_NONE;
789  for (; aDef->name != NULL; aDef++) {
790  if (!cpl_table_has_column(aTable, aDef->name)) {
791  if (aDef->required) {
792  rc = CPL_ERROR_ILLEGAL_INPUT;
793  cpl_error_set_message(__func__, rc, "table column '%s' not found",
794  aDef->name);
795  }
796  continue;
797  }
798  cpl_type coltype = cpl_table_get_column_type(aTable, aDef->name);
799  if (((coltype | CPL_TYPE_POINTER) != (aDef->type | CPL_TYPE_POINTER)) ||
800  ((coltype & CPL_TYPE_POINTER) && !(aDef->type & CPL_TYPE_POINTER))) {
801  rc = CPL_ERROR_ILLEGAL_INPUT;
802  cpl_error_set_message(__func__, rc,
803  "table column '%s' format '%s' is not '%s'",
804  aDef->name, cpl_type_get_name(coltype),
805  cpl_type_get_name(aDef->type));
806  }
807  }
808  return rc;
809 } /* muse_cpltable_check() */
810 
811 /*----------------------------------------------------------------------------*/
828 /*----------------------------------------------------------------------------*/
829 cpl_array *
830 muse_cpltable_extract_column(cpl_table *aTable, const char *aColumn)
831 {
832  cpl_ensure(aTable && aColumn, CPL_ERROR_NULL_INPUT, NULL);
833  cpl_size nRows = cpl_table_get_nrow(aTable);
834 
835  cpl_type type = cpl_table_get_column_type(aTable, aColumn);
836  if (nRows == 0) {
837  return cpl_array_new(0, type);
838  }
839  if (type == CPL_TYPE_DOUBLE) {
840  double *src = cpl_table_get_data_double(aTable, aColumn);
841  return cpl_array_wrap_double(src, nRows);
842  } else if (type == CPL_TYPE_FLOAT) {
843  float *src = cpl_table_get_data_float(aTable, aColumn);
844  return cpl_array_wrap_float(src, nRows);
845  } else if (type == CPL_TYPE_INT) {
846  int *src = cpl_table_get_data_int(aTable, aColumn);
847  return cpl_array_wrap_int(src, nRows);
848  } else {
849  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
850  cpl_msg_error(__func__, "%s: %i - %s", cpl_error_get_message(), type,
851  cpl_type_get_name(type));
852  return NULL;
853  }
854 }
855 
856 /*----------------------------------------------------------------------------*/
866 /*----------------------------------------------------------------------------*/
867 cpl_error_code
868 muse_cpltable_copy_array(cpl_table *aTable, const char *aColumn,
869  const cpl_array *aArray)
870 {
871  cpl_ensure_code(aTable && aColumn && aArray, CPL_ERROR_NULL_INPUT);
872  cpl_size n_rows = cpl_table_get_nrow(aTable);
873  cpl_size i;
874  for (i = 0; i < n_rows; i++) {
875  int flag;
876  double d = cpl_array_get(aArray, i, &flag);
877  if (flag == 0) {
878  cpl_table_set(aTable, aColumn, i, d);
879  } else {
880  cpl_table_set_invalid(aTable, aColumn, i);
881  }
882  }
883  return CPL_ERROR_NONE;
884 }
885 
886 /*----------------------------------------------------------------------------*/
896 /*----------------------------------------------------------------------------*/
897 cpl_array *
898 muse_cpltable_get_array_copy(cpl_table *aTable, const char *aColumn,
899  cpl_size aRow)
900 {
901  cpl_ensure(aTable && aColumn, CPL_ERROR_NULL_INPUT, NULL);
902  if (cpl_table_get_column_type(aTable, aColumn) & CPL_TYPE_POINTER) {
903  return cpl_array_duplicate(cpl_table_get_array(aTable, aColumn, aRow));
904  } else {
905  cpl_array *res
906  = cpl_array_new(1, cpl_table_get_column_type(aTable, aColumn));
907  int flag;
908  cpl_array_set(res, 0, cpl_table_get(aTable, aColumn, aRow, &flag));
909  if (flag) {
910  cpl_array_delete(res);
911  return NULL;
912  } else {
913  return res;
914  }
915  }
916 }
917 /*----------------------------------------------------------------------------*/
931 /*----------------------------------------------------------------------------*/
932 
933 cpl_size
934 muse_cpltable_find_sorted(const cpl_table *aTable, const char *aColumn,
935  double aValue) {
936  cpl_ensure(aTable && aColumn, CPL_ERROR_NULL_INPUT, 0);
937  cpl_array *array = muse_cpltable_extract_column((cpl_table *)aTable, aColumn);
938  cpl_size res = muse_cplarray_find_sorted(array, aValue);
939  cpl_array_unwrap(array);
940  return res;
941 }
942 
943 /*----------------------------------------------------------------------------*/
951 /*----------------------------------------------------------------------------*/
952 cpl_array *
953 muse_cplarray_new_from_image(const cpl_image *aImage) {
954  cpl_size nx = cpl_image_get_size_x(aImage);
955  cpl_size ny = cpl_image_get_size_y(aImage);
956  cpl_array *array = cpl_array_new(nx*ny, cpl_image_get_type(aImage));
957  cpl_size i = 0;
958  cpl_size iy;
959  for (iy = 1; iy <= ny; iy++) {
960  int ix;
961  for (ix = 1; ix <= nx; ix++, i++) {
962  int rej;
963  double d = cpl_image_get(aImage, ix, iy, &rej);
964  cpl_array_set(array, i, d);
965  if (rej) {
966  cpl_array_set_invalid(array, i);
967  }
968  }
969  }
970  return array;
971 }
972 
973 /*----------------------------------------------------------------------------*/
986 /*----------------------------------------------------------------------------*/
987 cpl_error_code
988 muse_cplarray_poly1d(cpl_array *aArray, const cpl_array *aCoeff)
989 {
990  cpl_ensure_code(aArray && aCoeff, CPL_ERROR_NULL_INPUT);
991  const cpl_size nrows = cpl_array_get_size(aArray);
992  cpl_size order = cpl_array_get_size(aCoeff);
993  if (order == 0) {
994  cpl_array_fill_window(aArray, 0, nrows, 0.0);
995  return CPL_ERROR_NONE;
996  }
997  order--;
998  cpl_array *x = cpl_array_duplicate(aArray);
999  cpl_array_fill_window(aArray, 0, nrows, cpl_array_get(aCoeff, order, NULL));
1000 
1001  int k;
1002  for (k = order-1; k >= 0; k--) {
1003  cpl_array_multiply(aArray, x);
1004  cpl_array_add_scalar(aArray, cpl_array_get(aCoeff, k, NULL));
1005  }
1006 
1007  cpl_array_delete(x);
1008 
1009  return CPL_ERROR_NONE;
1010 }
1011 
1012 /*----------------------------------------------------------------------------*/
1024 /*----------------------------------------------------------------------------*/
1025 double
1026 muse_cplarray_poly1d_double(double aDouble, const cpl_array *aCoeff)
1027 {
1028  cpl_ensure(aCoeff, CPL_ERROR_NULL_INPUT, NAN);
1029  cpl_size order = cpl_array_get_size(aCoeff);
1030  if (order == 0) {
1031  return 0.0;
1032  }
1033  order--;
1034  double res = cpl_array_get(aCoeff, order, NULL);
1035  int k;
1036  for (k = order-1; k >= 0; k--) {
1037  res = res * aDouble + cpl_array_get(aCoeff, k, NULL);
1038  }
1039  return res;
1040 }
1041 
1042 /*----------------------------------------------------------------------------*/
1051 /*----------------------------------------------------------------------------*/
1052 cpl_error_code
1053 muse_cplarray_dump_name(const cpl_array *aArray, const char *aName)
1054 {
1055  cpl_ensure_code(aArray && aName, CPL_ERROR_NULL_INPUT);
1056  cpl_size i, size = cpl_array_get_size(aArray);
1057  for (i = 0; i < size; i++) {
1058  printf("%s[%"CPL_SIZE_FORMAT"] = %g\n", aName, i,
1059  cpl_array_get(aArray, i, NULL));
1060  }
1061  return CPL_ERROR_NONE;
1062 }
1063 
1064 /*----------------------------------------------------------------------------*/
1070 /*----------------------------------------------------------------------------*/
1071 cpl_error_code
1073 {
1074  cpl_ensure_code(aArray != NULL, CPL_ERROR_NULL_INPUT);
1075  cpl_size n = cpl_array_get_size(aArray);
1076  cpl_size n_val = n - cpl_array_count_invalid(aArray);
1077  cpl_msg_debug(__func__, "size = %li, %li valid", (long)n, (long)n_val);
1078  if (n_val == n) {
1079  return CPL_ERROR_NONE;
1080  }
1081  cpl_size i;
1082  cpl_size idx = 0;
1083  for (i = 0; (i < n) && (idx < n_val); i++) {
1084  int rej;
1085  double d = cpl_array_get(aArray, i, &rej);
1086  if (!rej) {
1087  if (idx < i) {
1088  cpl_array_set(aArray, idx, d);
1089  }
1090  idx++;
1091  }
1092  }
1093  cpl_array_set_size(aArray, n_val);
1094  return CPL_ERROR_NONE;
1095 }
1096 
1097 /*---------------------------------------------------------------------------*/
1112 /*---------------------------------------------------------------------------*/
1113 cpl_size
1114 muse_cplarray_erase_outliers(cpl_array *aArray, const cpl_bivector *aHistogram,
1115  cpl_size aGap, double aLimit)
1116 {
1117  cpl_ensure(aArray && aHistogram, CPL_ERROR_NULL_INPUT, -1);
1118  /* test for numerical array */
1119  int err;
1120  double value = cpl_array_get(aArray, 0, &err);
1121  cpl_ensure(err >= 0, CPL_ERROR_ILLEGAL_INPUT, -2);
1122 
1123  /* start at the peak of the histogram */
1124  const double *hpos = cpl_bivector_get_x_data_const(aHistogram),
1125  *hval = cpl_bivector_get_y_data_const(aHistogram);
1126  cpl_size nhist = cpl_bivector_get_size(aHistogram);
1127  cpl_array *ahist = cpl_array_wrap_double((double *)hval, nhist);
1128  cpl_size imax;
1129  cpl_array_get_maxpos(ahist, &imax);
1130  cpl_array_unwrap(ahist);
1131 
1132  /* go to lower values in the histogram, search for the first gap */
1133  double loval = hpos[0],
1134  hival = hpos[nhist - 1];
1135  cpl_size i, nlow = 0;
1136  for (i = imax; i >= 0; i--) {
1137  if (hval[i] <= aLimit) {
1138  if (nlow == 0) { /* keep this as the initial low value */
1139  loval = hpos[i];
1140  }
1141  nlow++;
1142  if (nlow == aGap) { /* gap already wide enough */
1143  break;
1144  }
1145  } else if (nlow > 0) {
1146  nlow = 0; /* gap not wide enough after all */
1147  loval = hpos[0];
1148  }
1149  } /* for i */
1150  /* same search now to higher histogram values */
1151  for (i = imax; i < nhist; i++) {
1152  if (hval[i] <= aLimit) {
1153  if (nlow == 0) { /* keep this as the initial low value */
1154  hival = hpos[i];
1155  }
1156  nlow++;
1157  if (nlow == aGap) { /* gap already wide enough */
1158  break;
1159  }
1160  } else if (nlow > 0) {
1161  nlow = 0; /* gap not wide enough after all */
1162  hival = hpos[nhist - 1];
1163  }
1164  } /* for i */
1165  cpl_msg_debug(__func__, "Histogram gaps (%"CPL_SIZE_FORMAT" consecutive "
1166  "entries <= %f) at %f and %f", aGap, aLimit, loval, hival);
1167 
1168  /* now go through the array, and set values larger *
1169  * or smaller than these extremes to invalid */
1170  cpl_size idx, narray = cpl_array_get_size(aArray);
1171  for (idx = 0; idx < narray; idx++) {
1172  value = cpl_array_get(aArray, idx, NULL);
1173  if (value > hival || value < loval) {
1174  cpl_array_set_invalid(aArray, idx);
1175  }
1176  } /* for idx */
1177 
1178  /* finally count them and then remove all invalid ones */
1179  cpl_size nbad = cpl_array_count_invalid(aArray);
1181  return nbad;
1182 } /* muse_cplarray_erase_outliers() */
1183 
1184 
1185 /*----------------------------------------------------------------------------*/
1186 /* Helper functions for quicksort */
1187 /*----------------------------------------------------------------------------*/
1189 static int cmp_double_asc(const void *p1, const void *p2) {
1190  double d = (*(const double *)p1 - *(const double *)p2);
1191  return (d < 0)?-1:(d>0)?1:0;
1192 }
1194 static int cmp_double_desc(const void *p1, const void *p2) {
1195  double d = (*(const double *)p1 - *(const double *)p2);
1196  return (d < 0)?1:(d>0)?-1:0;
1197 }
1199 static int cmp_float_asc(const void *p1, const void *p2) {
1200  float d = (*(const float *)p1 - *(const float *)p2);
1201  return (d < 0)?-1:(d>0)?1:0;
1202 }
1204 static int cmp_float_desc(const void *p1, const void *p2) {
1205  float d = (*(const float *)p1 - *(const float *)p2);
1206  return (d < 0)?1:(d>0)?-1:0;
1207 }
1209 static int cmp_int_asc(const void *p1, const void *p2) {
1210  return (*(const int *)p1 - *(const int *)p2);
1211 }
1213 static int cmp_int_desc(const void *p1, const void *p2) {
1214  return (*(const int *)p2 - *(const int *)p1);
1215 }
1216 
1217 /*----------------------------------------------------------------------------*/
1227 /*----------------------------------------------------------------------------*/
1228 cpl_error_code
1229 muse_cplarray_sort(cpl_array *aArray, cpl_boolean aOrder)
1230 {
1231  cpl_ensure_code(aArray != NULL, CPL_ERROR_NULL_INPUT);
1232  cpl_ensure_code(!cpl_array_has_invalid(aArray), CPL_ERROR_NULL_INPUT);
1233 
1234  cpl_size n = cpl_array_get_size(aArray);
1235  if (cpl_array_get_type(aArray) == CPL_TYPE_DOUBLE) {
1236  double *d = cpl_array_get_data_double(aArray);
1237  qsort(d, n, sizeof(double), (aOrder)?cmp_double_asc:cmp_double_desc);
1238  return CPL_ERROR_NONE;
1239  } else if (cpl_array_get_type(aArray) == CPL_TYPE_FLOAT) {
1240  float *d = cpl_array_get_data_float(aArray);
1241  qsort(d, n, sizeof(float), (aOrder)?cmp_float_asc:cmp_float_desc);
1242  return CPL_ERROR_NONE;
1243  } else if (cpl_array_get_type(aArray) == CPL_TYPE_INT) {
1244  int *d = cpl_array_get_data_int(aArray);
1245  qsort(d, n, sizeof(int), (aOrder)?cmp_int_asc:cmp_int_desc);
1246  return CPL_ERROR_NONE;
1247  } else {
1248  return CPL_ERROR_ILLEGAL_INPUT;
1249  }
1250 }
1251 
1252 /*---------------------------------------------------------------------------*/
1271 /*---------------------------------------------------------------------------*/
1272 cpl_bivector *
1273 muse_cplarray_histogram(const cpl_array *aArray, double aWidth,
1274  double aMin, double aMax)
1275 {
1276  cpl_ensure(aArray, CPL_ERROR_NULL_INPUT, NULL);
1277  /* test for numerical array */
1278  int err;
1279  double value = cpl_array_get(aArray, 0, &err);
1280  cpl_ensure(err >= 0, CPL_ERROR_INVALID_TYPE, NULL);
1281  if (!isnan(aMin) && !isnan(aMax) && aMin >= aMax) { /* inverse extremes */
1282  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
1283  return NULL;
1284  }
1285  if (isnan(aMin)) {
1286  aMin = cpl_array_get_min(aArray);
1287  }
1288  if (isnan(aMax)) {
1289  aMax = cpl_array_get_max(aArray);
1290  }
1291  cpl_size hlen = lround((aMax - aMin) / aWidth) + 1;
1292  cpl_bivector *histogram = cpl_bivector_new(hlen);
1293 
1294  /* fill histogram positions */
1295  double *hpos = cpl_bivector_get_x_data(histogram);
1296  cpl_size i;
1297  for (i = 0; i < hlen; i++) {
1298  hpos[i] = i * aWidth + aMin;
1299  } /* for i */
1300 
1301  /* fill histogram values */
1302  double *hval = cpl_bivector_get_y_data(histogram);
1303  /* histogram has at least zero everywhere */
1304  cpl_vector_fill(cpl_bivector_get_y(histogram), 0.);
1305  cpl_size n = cpl_array_get_size(aArray);
1306  for (i = 0; i < n; i++) {
1307  value = cpl_array_get(aArray, i, &err);
1308  if (err) {
1309  continue;
1310  }
1311  /* find histogram index */
1312  cpl_size idx = lround((value - aMin) / aWidth);
1313  if (idx >= hlen || idx < 0) {
1314  continue;
1315  }
1316  /* add one to the histogram at the respective index */
1317  hval[idx] += 1;
1318  } /* for i */
1319 #if 0
1320  printf("histogram %f...%f / %f\n", aMin, aMax, aWidth);
1321  cpl_bivector_dump(histogram, stdout);
1322  fflush(stdout);
1323 #endif
1324  return histogram;
1325 } /* muse_cplarray_histogram() */
1326 
1327 /*----------------------------------------------------------------------------*/
1340 /*----------------------------------------------------------------------------*/
1341 cpl_size
1342 muse_cplarray_find_sorted(const cpl_array *aArray, double aValue)
1343 {
1344  cpl_ensure(aArray, CPL_ERROR_NULL_INPUT, 0);
1345  cpl_size min = 0;
1346  cpl_size max = cpl_array_get_size(aArray);
1347  cpl_type type = cpl_array_get_type(aArray);
1348  if (type == CPL_TYPE_DOUBLE) {
1349  const double *data = cpl_array_get_data_double_const(aArray);
1350  while (max - min > 1) {
1351  int i = (max + min)/2;
1352  if (data[i] > aValue) {
1353  max = i;
1354  } else {
1355  min = i;
1356  }
1357  }
1358  } else if (type == CPL_TYPE_FLOAT) {
1359  const float *data = cpl_array_get_data_float_const(aArray);
1360  while (max - min > 1) {
1361  int i = (max + min)/2;
1362  if (data[i] > aValue) {
1363  max = i;
1364  } else {
1365  min = i;
1366  }
1367  }
1368  } else if (type == CPL_TYPE_INT) {
1369  const int *data = cpl_array_get_data_int_const(aArray);
1370  while (max - min > 1) {
1371  int i = (max + min)/2;
1372  if (data[i] > aValue) {
1373  max = i;
1374  } else {
1375  min = i;
1376  }
1377  }
1378  } else {
1379  cpl_msg_error(__func__, "illegal type %i", type);
1380  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
1381  return 0;
1382  }
1383  return min;
1384 }
1385 
1386 /*----------------------------------------------------------------------------*/
1401 /*----------------------------------------------------------------------------*/
1402 cpl_boolean
1403 muse_cplarray_has_duplicate(const cpl_array *aArray)
1404 {
1405  cpl_ensure(aArray, CPL_ERROR_NULL_INPUT, CPL_FALSE);
1406  cpl_type type = cpl_array_get_type(aArray);
1407  switch (type) {
1408  case CPL_TYPE_INT:
1409  case CPL_TYPE_LONG:
1410  case CPL_TYPE_LONG_LONG:
1411  case CPL_TYPE_SIZE:
1412  break;
1413  default:
1414  cpl_error_set(__func__, CPL_ERROR_UNSUPPORTED_MODE);
1415  return CPL_FALSE;
1416  }
1417 
1418  cpl_size idx, n = cpl_array_get_size(aArray);
1419  for (idx = 0; idx < n - 1; idx++) {
1420  int err;
1421  cpl_size v1 = cpl_array_get(aArray, idx, &err);
1422  if (err) { /* invalid somehow, skip this one */
1423  continue;
1424  }
1425  cpl_size idx2;
1426  for (idx2 = idx + 1; idx2 < n; idx2++) {
1427  cpl_size v2 = cpl_array_get(aArray, idx2, &err);
1428  if (err) { /* invalid somehow, skip this one */
1429  continue;
1430  }
1431  if (v2 == v1) {
1432 #if 0
1433  cpl_msg_debug(__func__, "entry[%"CPL_SIZE_FORMAT"] == entry[%"
1434  CPL_SIZE_FORMAT"] == %"CPL_SIZE_FORMAT, idx, idx2, v1);
1435 #endif
1436  return CPL_TRUE;
1437  }
1438  } /* for idx2 (array indices starting after idx) */
1439  } /* for idx (all array indices but the last) */
1440  return CPL_FALSE;
1441 } /* muse_cplarray_has_duplicate() */
1442 
1443 /*----------------------------------------------------------------------------*/
1456 /*----------------------------------------------------------------------------*/
1457 cpl_array *
1458 muse_cplarray_extract(cpl_array *aArray, cpl_size aStart, cpl_size aCount)
1459 {
1460  cpl_size nrows = cpl_array_get_size(aArray);
1461  if (aCount > nrows - aStart) {
1462  aCount = nrows - aStart;
1463  }
1464  cpl_type type = cpl_array_get_type(aArray);
1465  if (type == CPL_TYPE_DOUBLE) {
1466  return cpl_array_wrap_double(cpl_array_get_data_double(aArray) + aStart,
1467  aCount);
1468  } else if (type == CPL_TYPE_FLOAT) {
1469  return cpl_array_wrap_float(cpl_array_get_data_float(aArray) + aStart,
1470  aCount);
1471  } else if (type == CPL_TYPE_INT) {
1472  return cpl_array_wrap_int(cpl_array_get_data_int(aArray) + aStart,
1473  aCount);
1474  } else {
1475  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
1476  return NULL;
1477  }
1478 }
1479 /*----------------------------------------------------------------------------*/
1493 /*----------------------------------------------------------------------------*/
1494 cpl_error_code
1495 muse_cplarray_add_window(cpl_array *aDest, cpl_size aStart,
1496  const cpl_array *aArray)
1497 {
1498  cpl_ensure_code(aDest && aArray, CPL_ERROR_NULL_INPUT);
1499  cpl_size count = cpl_array_get_size(aArray);
1500  cpl_array *destArray = muse_cplarray_extract(aDest, aStart, count);
1501  if (destArray == NULL) {
1502  return CPL_ERROR_ILLEGAL_INPUT;
1503  }
1504  cpl_array_add(destArray, aArray);
1505  cpl_array_unwrap(destArray);
1506 
1507  return CPL_ERROR_NONE;
1508 }
1509 
1510 /*----------------------------------------------------------------------------*/
1520 /*----------------------------------------------------------------------------*/
1521 cpl_array *
1522 muse_cplarray_diff(const cpl_array *aArray, int aOffset)
1523 {
1524  cpl_ensure(aArray, CPL_ERROR_NULL_INPUT, NULL);
1525  cpl_ensure(aOffset > 0, CPL_ERROR_ILLEGAL_INPUT, NULL);
1526  cpl_size nrows = cpl_array_get_size(aArray);
1527 
1528  cpl_array *a1 = cpl_array_extract(aArray, 0, nrows - aOffset);
1529  cpl_array *a2 = cpl_array_extract(aArray, aOffset, nrows - aOffset);
1530  if (a1 == NULL || a2 == NULL) {
1531  cpl_array_delete(a1);
1532  cpl_array_delete(a2);
1533  return NULL;
1534  }
1535  cpl_array_subtract(a2, a1);
1536  cpl_array_delete(a1);
1537  return a2;
1538 }
1539 
1540 /*----------------------------------------------------------------------------*/
1553 /*----------------------------------------------------------------------------*/
1554 cpl_error_code
1555 muse_cplarray_erf(cpl_array *aArray)
1556 {
1557  cpl_ensure_code(aArray, CPL_ERROR_NULL_INPUT);
1558  cpl_type type = cpl_array_get_type(aArray);
1559  cpl_size n = cpl_array_get_size(aArray);
1560  if (type == CPL_TYPE_DOUBLE) {
1561  double *d = cpl_array_get_data_double(aArray);
1562  cpl_size i;
1563  for (i = 0; i < n; i++, d++) {
1564  *d = erf(*d);
1565  }
1566  } else if (type == CPL_TYPE_FLOAT) {
1567  float *d = cpl_array_get_data_float(aArray);
1568  cpl_size i;
1569  for (i = 0; i < n; i++, d++) {
1570  *d = erf(*d);
1571  }
1572  } else {
1573  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
1574  return CPL_ERROR_ILLEGAL_INPUT;
1575  }
1576  return CPL_ERROR_NONE;
1577 }
1578 
1579 /*----------------------------------------------------------------------------*/
1592 /*----------------------------------------------------------------------------*/
1593 cpl_error_code
1594 muse_cplarray_exp(cpl_array *aArray)
1595 {
1596  cpl_ensure_code(aArray, CPL_ERROR_NULL_INPUT);
1597  cpl_type type = cpl_array_get_type(aArray);
1598  cpl_size n = cpl_array_get_size(aArray);
1599  if (type == CPL_TYPE_DOUBLE) {
1600  double *d = cpl_array_get_data_double(aArray);
1601  cpl_size i;
1602  for (i = 0; i < n; i++, d++) {
1603  *d = exp(*d);
1604  }
1605  } else if (type == CPL_TYPE_FLOAT) {
1606  float *d = cpl_array_get_data_float(aArray);
1607  cpl_size i;
1608  for (i = 0; i < n; i++, d++) {
1609  *d = expf(*d);
1610  }
1611  } else {
1612  cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
1613  return CPL_ERROR_ILLEGAL_INPUT;
1614  }
1615  return CPL_ERROR_NONE;
1616 }
1617 
1618 /*----------------------------------------------------------------------------*/
1642 /*----------------------------------------------------------------------------*/
1643 cpl_array *
1644 muse_cplarray_interpolate_linear(const cpl_array *aTargetAbscissa,
1645  const cpl_array *aSourceAbscissa,
1646  const cpl_array *aSourceOrdinate)
1647 {
1648  cpl_ensure(aTargetAbscissa && aSourceAbscissa && aSourceOrdinate,
1649  CPL_ERROR_NULL_INPUT, NULL);
1650 
1651  double *targetX = cpl_array_get_data_double((cpl_array *)aTargetAbscissa);
1652  double *srcX = cpl_array_get_data_double((cpl_array *)aSourceAbscissa);
1653  double *srcY = cpl_array_get_data_double((cpl_array *)aSourceOrdinate);
1654  cpl_ensure(targetX && srcX && srcY, CPL_ERROR_ILLEGAL_INPUT, NULL);
1655 
1656  cpl_array *targetOrdinate = cpl_array_duplicate(aTargetAbscissa);
1657  double *targetY = cpl_array_get_data_double(targetOrdinate);
1658 
1659  cpl_size n_src = cpl_array_get_size(aSourceAbscissa);
1660  cpl_vector *srcX_vec = cpl_vector_wrap(n_src, srcX);
1661  cpl_vector *srcY_vec = cpl_vector_wrap(n_src, srcY);
1662  cpl_bivector *src_vec = cpl_bivector_wrap_vectors(srcX_vec, srcY_vec);
1663 
1664  cpl_size offset = (srcX[0] <= targetX[0])?0:
1665  muse_cplarray_find_sorted(aTargetAbscissa, srcX[0]) + 1;
1666  cpl_size n_target =
1667  muse_cplarray_find_sorted(aTargetAbscissa, srcX[n_src-1]) - offset + 1;
1668 
1669  cpl_vector *targetX_vec = cpl_vector_wrap(n_target, targetX + offset);
1670  cpl_vector *targetY_vec = cpl_vector_wrap(n_target, targetY + offset);
1671  cpl_bivector *target_vec = cpl_bivector_wrap_vectors(targetX_vec,
1672  targetY_vec);
1673  if (offset > 0) {
1674  cpl_array_fill_window_invalid(targetOrdinate, 0, offset);
1675  }
1676  if (offset + n_target < (unsigned)cpl_array_get_size(targetOrdinate)) {
1677  cpl_array_fill_window_invalid(targetOrdinate, offset + n_target,
1678  cpl_array_get_size(targetOrdinate)
1679  - (offset + n_target));
1680  }
1681  cpl_bivector_interpolate_linear(target_vec, src_vec);
1682  cpl_bivector_unwrap_vectors(target_vec);
1683  cpl_vector_unwrap(targetX_vec);
1684  cpl_vector_unwrap(targetY_vec);
1685  cpl_bivector_unwrap_vectors(src_vec);
1686  cpl_vector_unwrap(srcX_vec);
1687  cpl_vector_unwrap(srcY_vec);
1688 
1689  return targetOrdinate;
1690 }
1691 
1692 /*----------------------------------------------------------------------------*/
1711 /*----------------------------------------------------------------------------*/
1712 cpl_array *
1713 muse_cplarray_interpolate_table_linear(const cpl_array *aTargetAbscissa,
1714  const cpl_table *aSrcTable,
1715  const char *aSrcAbscissa,
1716  const char *aSrcOrdinate)
1717 {
1718  cpl_array *sabs = muse_cpltable_extract_column((cpl_table *)aSrcTable,
1719  aSrcAbscissa);
1720  cpl_array *sord = muse_cpltable_extract_column((cpl_table *)aSrcTable,
1721  aSrcOrdinate);
1722  cpl_array *ord = muse_cplarray_interpolate_linear(aTargetAbscissa, sabs, sord);
1723  cpl_array_unwrap(sabs);
1724  cpl_array_unwrap(sord);
1725  return ord;
1726 }
1727 
1728 /*---------------------------------------------------------------------------*/
1742 /*---------------------------------------------------------------------------*/
1743 cpl_array *
1744 muse_cplarray_new_from_delimited_string(const char *aString, const char *aDelim)
1745 {
1746  cpl_ensure(aString && aDelim, CPL_ERROR_NULL_INPUT, NULL);
1747  /* duplicate the string to be able to work on it */
1748  char *string = cpl_strdup(aString);
1749 
1750  /* loop to find delimiters and save sub-strings in array */
1751  char *prev = string, *next;
1752  cpl_array *out = cpl_array_new(0, CPL_TYPE_STRING);
1753  int ntok = 0;
1754  do {
1755  next = strstr(prev, aDelim);
1756  if (next) {
1757  *next = '\0'; /* terminate this token starting at |prev| */
1758  }
1759  if (strlen(prev)) { /* don't want to add non-empty strings */
1760  cpl_array_set_size(out, ++ntok);
1761  cpl_array_set_string(out, ntok - 1, prev);
1762  }
1763  prev = next + strlen(aDelim);
1764  } while (next);
1765  cpl_free(string);
1766 
1767 #if 0
1768  printf("Input string %s and delimiter %s resulted in output\n",
1769  aString, aDelim);
1770  cpl_array_dump(out, 0, cpl_array_get_size(out), stdout);
1771  fflush(stdout);
1772 #endif
1773  return out;
1774 } /* muse_cplarray_new_from_delimited_string() */
1775 
1776 /*---------------------------------------------------------------------------*/
1791 /*---------------------------------------------------------------------------*/
1792 cpl_array *
1793 muse_cplarray_string_to_double(const cpl_array *aArray)
1794 {
1795  cpl_ensure(aArray, CPL_ERROR_NULL_INPUT, NULL);
1796  cpl_ensure(cpl_array_get_type(aArray) == CPL_TYPE_STRING,
1797  CPL_ERROR_ILLEGAL_INPUT, NULL);
1798 
1799  cpl_size i, n = cpl_array_get_size(aArray);
1800  cpl_array *darray = cpl_array_new(n, CPL_TYPE_DOUBLE);
1801  for (i = 0; i < n; i++) {
1802  const char *string = cpl_array_get_string(aArray, i);
1803  if (!string) {
1804  continue;
1805  }
1806  cpl_array_set_double(darray, i, atof(string));
1807  } /* for i (array elements) */
1808  return darray;
1809 } /* muse_cplarray_string_to_double() */
1810 
1811 /*---------------------------------------------------------------------------*/
1825 /*---------------------------------------------------------------------------*/
1826 cpl_parameter *
1827 muse_cplparamerterlist_find_prefix(cpl_parameterlist *aParameters,
1828  const char *aPrefix, const char *aName)
1829 {
1830  char *fullname = cpl_sprintf("%s.%s", aPrefix, aName);
1831  cpl_parameter *p = cpl_parameterlist_find(aParameters, fullname);
1832  cpl_free(fullname);
1833  return p;
1834 }
1835 
1836 /*----------------------------------------------------------------------------*/
1854 /*----------------------------------------------------------------------------*/
1855 cpl_error_code
1856 muse_cplpropertylist_update_long_long(cpl_propertylist *aHeader,
1857  const char *aKeyword, cpl_size aValue)
1858 {
1859  cpl_ensure_code(aHeader && aKeyword, CPL_ERROR_NULL_INPUT);
1860  cpl_property *p = cpl_propertylist_get_property(aHeader, aKeyword);
1861  cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
1862  cpl_error_code rc = CPL_ERROR_NONE;
1863  switch (cpl_property_get_type(p)) {
1864  case CPL_TYPE_LONG_LONG:
1865  rc = cpl_property_set_long_long(p, aValue);
1866  break;
1867  case CPL_TYPE_LONG:
1868  rc = cpl_property_set_long(p, aValue);
1869  break;
1870  default:
1871  rc = cpl_property_set_int(p, aValue);
1872  } /* switch */
1873  return rc;
1874 } /* muse_cplpropertylist_update_long_long() */
1875 
1876 /*----------------------------------------------------------------------------*/
1887 /*----------------------------------------------------------------------------*/
1888 cpl_error_code
1889 muse_cplframeset_erase_all(cpl_frameset *aFrames)
1890 {
1891  cpl_ensure_code(aFrames, CPL_ERROR_NULL_INPUT);
1892  cpl_error_code rc = CPL_ERROR_NONE;
1893  /* always get and erase the first frame until we are done */
1894  while (cpl_frameset_get_size(aFrames) > 0 && rc == CPL_ERROR_NONE) {
1895  cpl_frame *frame = cpl_frameset_get_position(aFrames, 0);
1896  rc = cpl_frameset_erase_frame(aFrames, frame);
1897  } /* while */
1898  return rc;
1899 } /* muse_cplframeset_erase_all() */
1900 
1901 /*----------------------------------------------------------------------------*/
1918 /*----------------------------------------------------------------------------*/
1919 cpl_error_code
1920 muse_cplframeset_erase_duplicate(cpl_frameset *aFrames)
1921 {
1922  cpl_ensure_code(aFrames, CPL_ERROR_NULL_INPUT);
1923 #if 0
1924  printf("\n\n\n%s input frameset (with duplicates):\n", __func__);
1925  cpl_frameset_dump(aFrames, stdout);
1926  printf("---------------------------------------------------------------------------\n");
1927  fflush(stdout);
1928 #endif
1929  cpl_error_code rc = CPL_ERROR_NONE;
1930  /* Loop through all frames but the last, and compare all frame properties *
1931  * to all following frames. Delete the frame if they are all the same. */
1932  cpl_size i;
1933  for (i = 0; i < cpl_frameset_get_size(aFrames) - 1; i++) {
1934  cpl_frame *fref = cpl_frameset_get_position(aFrames, i);
1935  cpl_size j;
1936  for (j = i + 1; j < cpl_frameset_get_size(aFrames); j++) {
1937  cpl_frame *fother = cpl_frameset_get_position(aFrames, j);
1938  cpl_boolean areequal = CPL_FALSE;
1939  cpl_errorstate state = cpl_errorstate_get();
1940  const char *fn1 = cpl_frame_get_filename(fref),
1941  *fn2 = cpl_frame_get_filename(fother);
1942  if (!cpl_errorstate_is_equal(state)) {
1943  cpl_errorstate_set(state);
1944  }
1945  if ((!fn1 && fn2) || (fn1 && !fn2)) {
1946  areequal = CPL_FALSE;
1947  } else if (!fn1 && !fn2) {
1948  areequal = CPL_TRUE;
1949  } else {
1950  areequal = !strcmp(fn1, fn2);
1951  }
1952  areequal = areequal
1953  && !strcmp(cpl_frame_get_tag(fref), cpl_frame_get_tag(fother));
1954  areequal = areequal
1955  && (cpl_frame_get_group(fref) == cpl_frame_get_group(fother));
1956  areequal = areequal
1957  && (cpl_frame_get_level(fref) == cpl_frame_get_level(fother));
1958  areequal = areequal
1959  && (cpl_frame_get_type(fref) == cpl_frame_get_type(fother));
1960  if (areequal) {
1961 #if 0
1962  printf("%ld/%ld are equal: %s/%s, %s/%s, %d/%d, %d/%d, %d/%d\n", i, j,
1963  fn1, fn2, tag1, tag2,
1964  cpl_frame_get_group(fref), cpl_frame_get_group(fother),
1965  cpl_frame_get_level(fref), cpl_frame_get_level(fother),
1966  cpl_frame_get_type(fref), cpl_frame_get_type(fother));
1967  fflush(stdout);
1968 #endif
1969  /* would really like to erase the other frame, *
1970  * but it's not possible to delete by position! */
1971  rc = cpl_frameset_erase_frame(aFrames, fref);
1972  i--; /* stay at the same reference position in the frameset */
1973  break;
1974  } /* if equal */
1975  } /* for j (all following frames) */
1976  } /* for i (all frames but the last) */
1977 #if 0
1978  printf("---------------------------------------------------------------------------\n");
1979  printf("%s input frameset (without duplicates):\n", __func__);
1980  cpl_frameset_dump(aFrames, stdout);
1981  printf("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n\n");
1982  fflush(stdout);
1983 #endif
1984  return rc;
1985 } /* muse_cplframeset_erase_duplicate() */
1986 
1987 /*----------------------------------------------------------------------------*/
1999 /*----------------------------------------------------------------------------*/
2000 void
2001 muse_cplerrorstate_dump_some(unsigned aCurrent, unsigned aFirst, unsigned aLast)
2002 {
2003  const cpl_boolean is_reverse = aFirst > aLast ? CPL_TRUE : CPL_FALSE;
2004  const char *revmsg = is_reverse ? " in reverse order" : "";
2005  const unsigned newest = is_reverse ? aFirst : aLast,
2006  nmax = labs(aLast - aFirst) + 1;
2007  unsigned ndump = 20;
2008  if (getenv("MUSE_CPL_ERRORSTATE_NDUMP") &&
2009  atoi(getenv("MUSE_CPL_ERRORSTATE_NDUMP")) > 0) {
2010  ndump = atoi(getenv("MUSE_CPL_ERRORSTATE_NDUMP"));
2011  }
2012  ndump = nmax < ndump ? nmax : ndump;
2013 
2014  if (newest) { /* there are errors to dump */
2015  if (aCurrent == aLast - (ndump-1)) {
2016  cpl_msg_error(__func__, "Dumping the %u most recent error(s) out of a "
2017  "total of %u errors%s:", ndump, newest, revmsg);
2018  cpl_msg_indent_more();
2019  }
2020  if (aCurrent >= aLast - (ndump-1)) {
2021  cpl_msg_error(__func__, "[%u/%u] '%s' (%u) at %s", aCurrent, newest,
2022  cpl_error_get_message(), cpl_error_get_code(),
2023  cpl_error_get_where());
2024  }
2025  if (aCurrent == aLast) {
2026  cpl_msg_indent_less();
2027  }
2028  } else {
2029  cpl_msg_info(__func__, "No error(s) to dump");
2030  }
2031 } /* muse_cplerrorstate_dump_some() */
2032 
2033 
2034 /*----------------------------------------------------------------------------*/
2047 /*----------------------------------------------------------------------------*/
2049 #ifdef HAVE_READLINK
2050  char buffer[FILENAME_MAX] = "\0";
2051  int length = readlink("/proc/self/exe", buffer, sizeof(buffer) - 1);
2052  if (length != -1) {
2053  buffer[length] = '\0';
2054  }
2055  if (strstr(buffer, "esorex")) {
2056  return MUSE_CPLFRAMEWORK_ESOREX;
2057  } else if (strstr(buffer, "python")) {
2059  } else if (strstr(buffer, "jre")) {
2061  } else {
2063  }
2064 #else
2066 #endif
2067 }
2068 
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_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_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)