SINFONI Pipeline Reference Manual  2.5.2
irplib_utils.c
1 /* $Id: irplib_utils.c,v 1.85 2013-07-04 12:10:55 jtaylor Exp $
2  *
3  * This file is part of the irplib package
4  * Copyright (C) 2002,2003 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: jtaylor $
23  * $Date: 2013-07-04 12:10:55 $
24  * $Revision: 1.85 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 /*-----------------------------------------------------------------------------
33  Includes
34  -----------------------------------------------------------------------------*/
35 #include "irplib_utils.h"
36 
37 #include <cpl.h>
38 #include <math.h>
39 
40 #include <string.h>
41 #include <assert.h>
42 #include <stdlib.h>
43 #include <errno.h>
44 
45 
46 
47 /*-----------------------------------------------------------------------------
48  Defines
49  -----------------------------------------------------------------------------*/
50 
51 /* TEMPORARY SUPPORT OF CPL 5.x */
52 #ifndef CPL_SIZE_FORMAT
53 #define CPL_SIZE_FORMAT "d"
54 #define cpl_size int
55 #endif
56 /* END TEMPORARY SUPPORT OF CPL 5.x */
57 
58 #ifndef inline
59 #define inline /* inline */
60 #endif
61 
62 /*-----------------------------------------------------------------------------
63  Missing Function Prototypes
64  -----------------------------------------------------------------------------*/
65 
66 /*-----------------------------------------------------------------------------
67  Private Function Prototypes
68  -----------------------------------------------------------------------------*/
69 
70 inline static double irplib_data_get_double(const void *, cpl_type, int)
71 #ifdef CPL_HAVE_GNUC_NONNULL
72  __attribute__((nonnull))
73 #endif
74  ;
75 
76 inline static void irplib_data_set_double(void *, cpl_type, int, double)
77 #ifdef CPL_HAVE_GNUC_NONNULL
78  __attribute__((nonnull))
79 #endif
80  ;
81 
82 
83 static
84 void irplib_errorstate_dump_one_level(void (*)(const char *,
85  const char *, ...)
86  #ifdef __GNUC__
87  __attribute__((format (printf, 2, 3)))
88  #endif
89  , unsigned, unsigned, unsigned);
90 static double frame_get_exptime(const cpl_frame * pframe);
91 static void quicksort(int* index, double* exptime, int left, int right);
92 
93 static cpl_error_code irplib_dfs_product_save(cpl_frameset *,
94  cpl_propertylist *,
95  const cpl_parameterlist *,
96  const cpl_frameset *,
97  const cpl_frame *,
98  const cpl_imagelist *,
99  const cpl_image *,
100  cpl_type,
101  const cpl_table *,
102  const cpl_propertylist *,
103  const char *,
104  const cpl_propertylist *,
105  const char *,
106  const char *,
107  const char *);
108 
109 /*----------------------------------------------------------------------------*/
113 /*----------------------------------------------------------------------------*/
117 /*----------------------------------------------------------------------------*/
129 /*----------------------------------------------------------------------------*/
130 void irplib_errorstate_dump_warning(unsigned self, unsigned first,
131  unsigned last)
132 {
133 
134  irplib_errorstate_dump_one_level(&cpl_msg_warning, self, first, last);
135 
136 }
137 
138 static cpl_polynomial * irplib_polynomial_fit_1d_create_common(
139  const cpl_vector * x_pos,
140  const cpl_vector * values,
141  int degree,
142  double * mse,
143  double * rechisq
144  );
145 
146 /*----------------------------------------------------------------------------*/
156 /*----------------------------------------------------------------------------*/
157 void irplib_errorstate_dump_info(unsigned self, unsigned first,
158  unsigned last)
159 {
160 
161  irplib_errorstate_dump_one_level(&cpl_msg_info, self, first, last);
162 
163 }
164 
165 
166 /*----------------------------------------------------------------------------*/
176 /*----------------------------------------------------------------------------*/
177 void irplib_errorstate_dump_debug(unsigned self, unsigned first,
178  unsigned last)
179 {
180 
181  irplib_errorstate_dump_one_level(&cpl_msg_debug, self, first, last);
182 
183 }
184 
185 
186 /*----------------------------------------------------------------------------*/
207 /*----------------------------------------------------------------------------*/
208 cpl_error_code irplib_dfs_save_image(cpl_frameset * allframes,
209  const cpl_parameterlist * parlist,
210  const cpl_frameset * usedframes,
211  const cpl_image * image,
212  cpl_type_bpp bpp,
213  const char * recipe,
214  const char * procat,
215  const cpl_propertylist * applist,
216  const char * remregexp,
217  const char * pipe_id,
218  const char * filename)
219 {
220  cpl_errorstate prestate = cpl_errorstate_get();
221  cpl_propertylist * prolist = applist ? cpl_propertylist_duplicate(applist)
222  : cpl_propertylist_new();
223 
224  cpl_propertylist_update_string(prolist, CPL_DFS_PRO_CATG, procat);
225 
226  irplib_dfs_save_image_(allframes, NULL, parlist, usedframes, NULL, image,
227  bpp, recipe, prolist, remregexp, pipe_id, filename);
228 
229  cpl_propertylist_delete(prolist);
230 
231  cpl_ensure_code(cpl_errorstate_is_equal(prestate), cpl_error_get_code());
232 
233  return CPL_ERROR_NONE;
234 
235 }
236 
237 /*----------------------------------------------------------------------------*/
254 /*----------------------------------------------------------------------------*/
255 cpl_error_code
256 irplib_dfs_save_propertylist(cpl_frameset * allframes,
257  const cpl_parameterlist * parlist,
258  const cpl_frameset * usedframes,
259  const char * recipe,
260  const char * procat,
261  const cpl_propertylist * applist,
262  const char * remregexp,
263  const char * pipe_id,
264  const char * filename)
265 {
266  cpl_errorstate prestate = cpl_errorstate_get();
267  cpl_propertylist * prolist = applist ? cpl_propertylist_duplicate(applist)
268  : cpl_propertylist_new();
269 
270  cpl_propertylist_update_string(prolist, CPL_DFS_PRO_CATG, procat);
271 
272  cpl_dfs_save_propertylist(allframes, NULL, parlist, usedframes, NULL,
273  recipe, prolist, remregexp, pipe_id, filename);
274 
275  cpl_propertylist_delete(prolist);
276 
277  cpl_ensure_code(cpl_errorstate_is_equal(prestate), cpl_error_get_code());
278 
279  return CPL_ERROR_NONE;
280 
281 }
282 
283 /*----------------------------------------------------------------------------*/
302 /*----------------------------------------------------------------------------*/
303 cpl_error_code irplib_dfs_save_imagelist(cpl_frameset * allframes,
304  const cpl_parameterlist * parlist,
305  const cpl_frameset * usedframes,
306  const cpl_imagelist * imagelist,
307  cpl_type_bpp bpp,
308  const char * recipe,
309  const char * procat,
310  const cpl_propertylist * applist,
311  const char * remregexp,
312  const char * pipe_id,
313  const char * filename)
314 {
315  cpl_errorstate prestate = cpl_errorstate_get();
316  cpl_propertylist * prolist = applist ? cpl_propertylist_duplicate(applist)
317  : cpl_propertylist_new();
318 
319  cpl_propertylist_update_string(prolist, CPL_DFS_PRO_CATG, procat);
320 
321  cpl_dfs_save_imagelist(allframes, NULL, parlist, usedframes, NULL,
322  imagelist, bpp, recipe, prolist, remregexp, pipe_id,
323  filename);
324 
325  cpl_propertylist_delete(prolist);
326 
327  cpl_ensure_code(cpl_errorstate_is_equal(prestate), cpl_error_get_code());
328 
329  return CPL_ERROR_NONE;
330 }
331 
332 /*----------------------------------------------------------------------------*/
350 /*----------------------------------------------------------------------------*/
351 cpl_error_code irplib_dfs_save_table(cpl_frameset * allframes,
352  const cpl_parameterlist * parlist,
353  const cpl_frameset * usedframes,
354  const cpl_table * table,
355  const cpl_propertylist * tablelist,
356  const char * recipe,
357  const char * procat,
358  const cpl_propertylist * applist,
359  const char * remregexp,
360  const char * pipe_id,
361  const char * filename)
362 {
363 
364  cpl_errorstate prestate = cpl_errorstate_get();
365  cpl_propertylist * prolist = applist ? cpl_propertylist_duplicate(applist)
366  : cpl_propertylist_new();
367 
368  cpl_propertylist_update_string(prolist, CPL_DFS_PRO_CATG, procat);
369 
370  cpl_dfs_save_table(allframes, NULL, parlist, usedframes, NULL,
371  table, tablelist, recipe, prolist, remregexp,
372  pipe_id, filename);
373 
374  cpl_propertylist_delete(prolist);
375 
376  cpl_ensure_code(cpl_errorstate_is_equal(prestate), cpl_error_get_code());
377 
378  return CPL_ERROR_NONE;
379 }
380 
381 
382 
383 /*----------------------------------------------------------------------------*/
410 /*----------------------------------------------------------------------------*/
411 cpl_error_code irplib_dfs_save_image_(cpl_frameset * allframes,
412  cpl_propertylist * header,
413  const cpl_parameterlist * parlist,
414  const cpl_frameset * usedframes,
415  const cpl_frame * inherit,
416  const cpl_image * image,
417  cpl_type type,
418  const char * recipe,
419  const cpl_propertylist * applist,
420  const char * remregexp,
421  const char * pipe_id,
422  const char * filename)
423 {
424  return
425  irplib_dfs_product_save(allframes, header, parlist, usedframes, inherit,
426  NULL, image, type, NULL, NULL, recipe,
427  applist, remregexp, pipe_id, filename)
428  ? cpl_error_set_where(cpl_func) : CPL_ERROR_NONE;
429 
430 }
431 
432 
433 /*----------------------------------------------------------------------------*/
457 /*----------------------------------------------------------------------------*/
458 
459 static
460 cpl_error_code irplib_dfs_product_save(cpl_frameset * allframes,
461  cpl_propertylist * header,
462  const cpl_parameterlist * parlist,
463  const cpl_frameset * usedframes,
464  const cpl_frame * inherit,
465  const cpl_imagelist * imagelist,
466  const cpl_image * image,
467  cpl_type type,
468  const cpl_table * table,
469  const cpl_propertylist * tablelist,
470  const char * recipe,
471  const cpl_propertylist * applist,
472  const char * remregexp,
473  const char * pipe_id,
474  const char * filename) {
475 
476  const char * procat;
477  cpl_propertylist * plist;
478  cpl_frame * product_frame;
479  /* Inside this function the product-types are numbered:
480  0: imagelist
481  1: table
482  2: image
483  3: propertylist only
484  */
485  const unsigned pronum
486  = imagelist != NULL ? 0 : table != NULL ? 1 : (image != NULL ? 2 : 3);
487  const char * proname[] = {"imagelist", "table", "image",
488  "propertylist"};
489  /* FIXME: Define a frame type for an imagelist and when data-less */
490  const int protype[] = {CPL_FRAME_TYPE_ANY, CPL_FRAME_TYPE_TABLE,
491  CPL_FRAME_TYPE_IMAGE, CPL_FRAME_TYPE_ANY};
492  cpl_error_code error = CPL_ERROR_NONE;
493 
494 
495  /* No more than one of imagelist, table and image may be non-NULL */
496  /* tablelist may only be non-NULL when table is non-NULL */
497  if (imagelist != NULL) {
498  assert(pronum == 0);
499  assert(image == NULL);
500  assert(table == NULL);
501  assert(tablelist == NULL);
502  } else if (table != NULL) {
503  assert(pronum == 1);
504  assert(imagelist == NULL);
505  assert(image == NULL);
506  } else if (image != NULL) {
507  assert(pronum == 2);
508  assert(imagelist == NULL);
509  assert(table == NULL);
510  assert(tablelist == NULL);
511  } else {
512  assert(pronum == 3);
513  assert(imagelist == NULL);
514  assert(table == NULL);
515  assert(tablelist == NULL);
516  assert(image == NULL);
517  }
518 
519  cpl_ensure_code(allframes != NULL, CPL_ERROR_NULL_INPUT);
520  cpl_ensure_code(parlist != NULL, CPL_ERROR_NULL_INPUT);
521  cpl_ensure_code(usedframes != NULL, CPL_ERROR_NULL_INPUT);
522  cpl_ensure_code(recipe != NULL, CPL_ERROR_NULL_INPUT);
523  cpl_ensure_code(applist != NULL, CPL_ERROR_NULL_INPUT);
524  cpl_ensure_code(pipe_id != NULL, CPL_ERROR_NULL_INPUT);
525  cpl_ensure_code(filename != NULL, CPL_ERROR_NULL_INPUT);
526 
527  procat = cpl_propertylist_get_string(applist, CPL_DFS_PRO_CATG);
528 
529  cpl_ensure_code(procat != NULL, cpl_error_get_code());
530 
531  cpl_msg_info(cpl_func, "Writing FITS %s product(%s): %s", proname[pronum],
532  procat, filename);
533 
534  product_frame = cpl_frame_new();
535 
536  /* Create product frame */
537  error |= cpl_frame_set_filename(product_frame, filename);
538  error |= cpl_frame_set_tag(product_frame, procat);
539  error |= cpl_frame_set_type(product_frame, protype[pronum]);
540  error |= cpl_frame_set_group(product_frame, CPL_FRAME_GROUP_PRODUCT);
541  error |= cpl_frame_set_level(product_frame, CPL_FRAME_LEVEL_FINAL);
542 
543  if (error) {
544  cpl_frame_delete(product_frame);
545  return cpl_error_set_where(cpl_func);
546  }
547 
548  if (header != NULL) {
549  cpl_propertylist_empty(header);
550  plist = header;
551  } else {
552  plist = cpl_propertylist_new();
553  }
554 
555  /* Add any QC parameters here */
556  if (applist != NULL) error = cpl_propertylist_copy_property_regexp(plist,
557  applist,
558  ".", 0);
559 
560  /* Add DataFlow keywords */
561  if (!error)
562  error = cpl_dfs_setup_product_header(plist, product_frame, usedframes,
563  parlist, recipe, pipe_id,
564  "PRO-1.15", inherit);
565 
566  if (remregexp != NULL && !error) {
567  cpl_errorstate prestate = cpl_errorstate_get();
568  (void)cpl_propertylist_erase_regexp(plist, remregexp, 0);
569  if (!cpl_errorstate_is_equal(prestate)) error = cpl_error_get_code();
570  }
571 
572  if (!error) {
573  switch (pronum) {
574  case 0:
575  error = cpl_imagelist_save(imagelist, filename, type, plist,
576  CPL_IO_CREATE);
577  break;
578  case 1:
579  error = cpl_table_save(table, plist, tablelist, filename,
580  CPL_IO_CREATE);
581  break;
582  case 2:
583  error = cpl_image_save(image, filename, type, plist,
584  CPL_IO_CREATE);
585  break;
586  default:
587  /* case 3: */
588  error = cpl_propertylist_save(plist, filename, CPL_IO_CREATE);
589  }
590  }
591 
592  if (!error) {
593  /* Insert the frame of the saved file in the input frameset */
594  error = cpl_frameset_insert(allframes, product_frame);
595 
596  } else {
597  cpl_frame_delete(product_frame);
598  }
599 
600  if (plist != header) cpl_propertylist_delete(plist);
601 
602  cpl_ensure_code(!error, error);
603 
604  return CPL_ERROR_NONE;
605 
606 }
607 
608 
609 /*----------------------------------------------------------------------------*/
664 /*----------------------------------------------------------------------------*/
665 cpl_error_code irplib_image_split(const cpl_image * self,
666  cpl_image * im_low,
667  cpl_image * im_mid,
668  cpl_image * im_high,
669  double th_low,
670  cpl_boolean isleq_low,
671  double th_high,
672  cpl_boolean isgeq_high,
673  double alt_low,
674  double alt_high,
675  cpl_boolean isbad_low,
676  cpl_boolean isbad_mid,
677  cpl_boolean isbad_high)
678 {
679 
680  const void * selfdata = cpl_image_get_data_const(self);
681  /* hasbpm reduces check-overhead if self does not have a bpm, and if
682  self is also passed as an output image, that ends up with bad pixels */
683  /* FIXME: Need a proper way to know if a bpm has been allocated :-((((((( */
684  const cpl_boolean hasbpm
685  = cpl_image_count_rejected(self) ? CPL_TRUE : CPL_FALSE;
686  const cpl_binary * selfbpm = hasbpm
687  ? cpl_mask_get_data_const(cpl_image_get_bpm_const(self)) : NULL;
688  const cpl_type selftype = cpl_image_get_type(self);
689  const int nx = cpl_image_get_size_x(self);
690  const int ny = cpl_image_get_size_y(self);
691  const int npix = nx * ny;
692  const cpl_boolean do_low = im_low != NULL;
693  const cpl_boolean do_mid = im_mid != NULL;
694  const cpl_boolean do_high = im_high != NULL;
695  void * lowdata = NULL;
696  void * middata = NULL;
697  void * highdata = NULL;
698  cpl_binary * lowbpm = NULL;
699  cpl_binary * midbpm = NULL;
700  cpl_binary * highbpm = NULL;
701  const cpl_type lowtype
702  = do_low ? cpl_image_get_type(im_low) : CPL_TYPE_INVALID;
703  const cpl_type midtype
704  = do_mid ? cpl_image_get_type(im_mid) : CPL_TYPE_INVALID;
705  const cpl_type hightype
706  = do_high ? cpl_image_get_type(im_high) : CPL_TYPE_INVALID;
707  int i;
708 
709 
710  cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
711  cpl_ensure_code(do_low || do_mid || do_high, CPL_ERROR_NULL_INPUT);
712  cpl_ensure_code(th_low <= th_high, CPL_ERROR_ILLEGAL_INPUT);
713 
714  if (do_low) {
715  cpl_ensure_code(cpl_image_get_size_x(im_low) == nx,
716  CPL_ERROR_INCOMPATIBLE_INPUT);
717  cpl_ensure_code(cpl_image_get_size_y(im_low) == ny,
718  CPL_ERROR_INCOMPATIBLE_INPUT);
719  lowdata = cpl_image_get_data(im_low);
720  }
721 
722  if (do_mid) {
723  cpl_ensure_code(cpl_image_get_size_x(im_mid) == nx,
724  CPL_ERROR_INCOMPATIBLE_INPUT);
725  cpl_ensure_code(cpl_image_get_size_y(im_mid) == ny,
726  CPL_ERROR_INCOMPATIBLE_INPUT);
727  middata = cpl_image_get_data(im_mid);
728  }
729 
730  if (do_high) {
731  cpl_ensure_code(cpl_image_get_size_x(im_high) == nx,
732  CPL_ERROR_INCOMPATIBLE_INPUT);
733  cpl_ensure_code(cpl_image_get_size_y(im_high) == ny,
734  CPL_ERROR_INCOMPATIBLE_INPUT);
735  highdata = cpl_image_get_data(im_high);
736  }
737 
738  /* From this point a failure would indicate a serious bug in CPL */
739 
740  for (i = 0; i < npix; i++) {
741  const double value = irplib_data_get_double(selfdata, selftype, i);
742  cpl_boolean isalt_low = do_low;
743  cpl_boolean isalt_mid = do_mid;
744  cpl_boolean isalt_high = do_high;
745  cpl_boolean setbad_low = do_low;
746  cpl_boolean setbad_mid = do_mid;
747  cpl_boolean setbad_high = do_high;
748  const void * setdata = NULL;
749  double alt_mid = 0.0; /* Avoid (false) uninit warning */
750 
751  if (isleq_low ? value <= th_low : value < th_low) {
752  if (do_low) {
753  isalt_low = CPL_FALSE;
754  irplib_data_set_double(lowdata, lowtype, i, value);
755  setbad_low = hasbpm && selfbpm[i];
756  setdata = lowdata;
757  }
758  alt_mid = alt_low;
759  } else if (isgeq_high ? value >= th_high : value > th_high) {
760  if (do_high) {
761  isalt_high = CPL_FALSE;
762  irplib_data_set_double(highdata, hightype, i, value);
763  setbad_high = hasbpm && selfbpm[i];
764  setdata = highdata;
765  }
766  alt_mid = alt_high;
767  } else if (do_mid) {
768  isalt_mid = CPL_FALSE;
769  irplib_data_set_double(middata, midtype, i, value);
770  setbad_mid = hasbpm && selfbpm[i];
771  setdata = middata;
772  }
773 
774  if (isalt_low && lowdata != setdata) {
775  irplib_data_set_double(lowdata, lowtype, i, alt_low);
776  setbad_low = isbad_low;
777  }
778  if (isalt_mid && middata != setdata) {
779  irplib_data_set_double(middata, midtype, i, alt_mid);
780  setbad_mid = isbad_mid;
781  }
782  if (isalt_high && highdata != setdata) {
783  irplib_data_set_double(highdata, hightype, i, alt_high);
784  setbad_high = isbad_high;
785  }
786 
787  if (setbad_low) {
788  if (lowbpm == NULL) lowbpm
789  = cpl_mask_get_data(cpl_image_get_bpm(im_low));
790  lowbpm[i] = CPL_BINARY_1;
791  }
792  if (setbad_mid) {
793  if (midbpm == NULL) midbpm
794  = cpl_mask_get_data(cpl_image_get_bpm(im_mid));
795  midbpm[i] = CPL_BINARY_1;
796  }
797  if (setbad_high) {
798  if (highbpm == NULL) highbpm
799  = cpl_mask_get_data(cpl_image_get_bpm(im_high));
800  highbpm[i] = CPL_BINARY_1;
801  }
802  }
803 
804  return CPL_ERROR_NONE;
805 
806 }
807 
808 
809 /*----------------------------------------------------------------------------*/
857 /*----------------------------------------------------------------------------*/
858 
859 cpl_error_code
860 irplib_dfs_table_convert(cpl_table * self,
861  cpl_frameset * allframes,
862  const cpl_frameset * useframes,
863  int maxlinelen,
864  char commentchar,
865  const char * product_name,
866  const char * procatg,
867  const cpl_parameterlist * parlist,
868  const char * recipe_name,
869  const cpl_propertylist * mainlist,
870  const cpl_propertylist * extlist,
871  const char * remregexp,
872  const char * instrume,
873  const char * pipe_id,
874  cpl_boolean (*table_set_row)
875  (cpl_table *, const char *, int,
876  const cpl_frame *,
877  const cpl_parameterlist *),
878  cpl_error_code (*table_check)
879  (cpl_table *,
880  const cpl_frameset *,
881  const cpl_parameterlist *))
882 {
883 
884  const char * filename;
885  cpl_propertylist * applist = NULL;
886  cpl_errorstate prestate = cpl_errorstate_get();
887  cpl_error_code error;
888  char * fallback_filename = NULL;
889 
890  cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
891  cpl_ensure_code(allframes != NULL, CPL_ERROR_NULL_INPUT);
892  cpl_ensure_code(useframes != NULL, CPL_ERROR_NULL_INPUT);
893  cpl_ensure_code(procatg != NULL, CPL_ERROR_NULL_INPUT);
894  cpl_ensure_code(parlist != NULL, CPL_ERROR_NULL_INPUT);
895  cpl_ensure_code(recipe_name != NULL, CPL_ERROR_NULL_INPUT);
896  cpl_ensure_code(instrume != NULL, CPL_ERROR_NULL_INPUT);
897  cpl_ensure_code(pipe_id != NULL, CPL_ERROR_NULL_INPUT);
898 
899  cpl_ensure_code(!irplib_table_read_from_frameset(self, useframes,
900  maxlinelen,
901  commentchar,
902  parlist,
903  table_set_row),
904  cpl_error_get_code());
905 
906  if (table_check != NULL && (table_check(self, useframes, parlist) ||
907  !cpl_errorstate_is_equal(prestate))) {
908  return cpl_error_set_message(cpl_func, cpl_error_get_code(),
909  "Consistency check of table failed");
910  }
911 
912  fallback_filename = cpl_sprintf("%s" CPL_DFS_FITS, recipe_name);
913  filename = product_name != NULL ? product_name : fallback_filename;
914 
915  applist = mainlist == NULL
916  ? cpl_propertylist_new() : cpl_propertylist_duplicate(mainlist);
917 
918  error = cpl_propertylist_update_string(applist, "INSTRUME", instrume);
919 
920  if (!error)
921  error = irplib_dfs_save_table(allframes, parlist, useframes, self,
922  extlist, recipe_name, procatg, applist,
923  remregexp, pipe_id, filename);
924 
925  cpl_propertylist_delete(applist);
926  cpl_free(fallback_filename);
927 
928  /* Propagate the error, if any */
929  cpl_ensure_code(!error, error);
930 
931  return CPL_ERROR_NONE;
932 
933 }
934 
935 
936 
937 /*----------------------------------------------------------------------------*/
986 /*----------------------------------------------------------------------------*/
987 
988 cpl_error_code
990  const cpl_frameset * useframes,
991  int maxlinelen,
992  char commentchar,
993  const cpl_parameterlist * parlist,
994  cpl_boolean (*table_set_row)
995  (cpl_table *, const char *, int,
996  const cpl_frame *,
997  const cpl_parameterlist *))
998 {
999 
1000  const cpl_frame * rawframe;
1001  char * linebuffer = NULL;
1002  FILE * stream = NULL;
1003  int nfiles = 0;
1004  int nrow = cpl_table_get_nrow(self);
1005  int irow = 0;
1006  cpl_errorstate prestate = cpl_errorstate_get();
1007 
1008  cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
1009  cpl_ensure_code(useframes != NULL, CPL_ERROR_NULL_INPUT);
1010  cpl_ensure_code(maxlinelen > 0, CPL_ERROR_ILLEGAL_INPUT);
1011  cpl_ensure_code(parlist != NULL, CPL_ERROR_NULL_INPUT);
1012  cpl_ensure_code(table_set_row != NULL, CPL_ERROR_NULL_INPUT);
1013 
1014  linebuffer = cpl_malloc(maxlinelen);
1015 
1016  for (rawframe = cpl_frameset_get_first_const(useframes);
1017  rawframe != NULL;
1018  rawframe = cpl_frameset_get_next_const(useframes), nfiles++) {
1019 
1020  const char * rawfile = cpl_frame_get_filename(rawframe);
1021  const char * done; /* Indicate when the reading is done */
1022  const int irowpre = irow;
1023  int iirow = 0;
1024  int ierror;
1025 
1026  if (rawfile == NULL) break; /* Should not happen... */
1027 
1028  stream = fopen(rawfile, "r");
1029 
1030  if (stream == NULL) {
1031 #if defined CPL_HAVE_VA_ARGS && CPL_HAVE_VA_ARGS != 0
1032  cpl_error_set_message(cpl_func, CPL_ERROR_FILE_IO, "Could not "
1033  "open %s for reading", rawfile);
1034 #else
1035  cpl_error_set_message(cpl_func, CPL_ERROR_FILE_IO, "Could not "
1036  "open file for reading");
1037 #endif
1038  break;
1039  }
1040 
1041  for (;(done = fgets(linebuffer, maxlinelen, stream)) != NULL; iirow++) {
1042 
1043  if (linebuffer[0] != commentchar) {
1044  cpl_boolean didset;
1045 #if defined CPL_HAVE_VA_ARGS && CPL_HAVE_VA_ARGS != 0
1046  const int prerow = irow;
1047 #endif
1048 
1049  if (irow == nrow) {
1050  nrow += nrow ? nrow : 1;
1051  if (cpl_table_set_size(self, nrow)) break;
1052  }
1053 
1054  didset = table_set_row(self, linebuffer, irow, rawframe,
1055  parlist);
1056  if (didset) irow++;
1057 
1058  if (!cpl_errorstate_is_equal(prestate)) {
1059  if (didset)
1060 #if defined CPL_HAVE_VA_ARGS && CPL_HAVE_VA_ARGS != 0
1061  cpl_error_set_message(cpl_func, cpl_error_get_code(),
1062  "Failed to set table row %d "
1063  "using line %d from %d. file %s",
1064  1+prerow, iirow+1,
1065  nfiles+1, rawfile);
1066  else
1067  cpl_error_set_message(cpl_func, cpl_error_get_code(),
1068  "Failure with line %d from %d. "
1069  "file %s", iirow+1,
1070  nfiles+1, rawfile);
1071 #else
1072  cpl_error_set_message(cpl_func, cpl_error_get_code(),
1073  "Failed to set table row"
1074  "using catalogue line");
1075  else
1076  cpl_error_set_message(cpl_func, cpl_error_get_code(),
1077  "Failure with catalogue line");
1078 #endif
1079 
1080  break;
1081  }
1082  }
1083  }
1084  if (done != NULL) break;
1085 
1086  ierror = fclose(stream);
1087  stream = NULL;
1088  if (ierror) break;
1089 
1090 
1091  if (irow == irowpre)
1092  cpl_msg_warning(cpl_func, "No usable lines in the %d. file: %s",
1093  1+nfiles, rawfile);
1094  }
1095 
1096  cpl_free(linebuffer);
1097  if (stream != NULL) fclose(stream);
1098 
1099  /* Check for premature end */
1100  cpl_ensure_code(rawframe == NULL, cpl_error_get_code());
1101 
1102  if (irow == 0) {
1103 #if defined CPL_HAVE_VA_ARGS && CPL_HAVE_VA_ARGS != 0
1104  return cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
1105  "No usable lines in the %d input "
1106  "frame(s)", nfiles);
1107 #else
1108  return cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
1109  "No usable lines in the input frame(s)");
1110 #endif
1111  }
1112 
1113  /* Resize the table to the actual number of rows set */
1114  cpl_ensure_code(!cpl_table_set_size(self, irow), cpl_error_get_code());
1115 
1116  return CPL_ERROR_NONE;
1117 }
1118 
1119 
1120 
1121 /*----------------------------------------------------------------------------*/
1133 /*----------------------------------------------------------------------------*/
1134 void irplib_reset(void)
1135 {
1136  return;
1137 }
1138 
1139 /*----------------------------------------------------------------------------*/
1146 /*----------------------------------------------------------------------------*/
1148  cpl_frame * frame1,
1149  cpl_frame * frame2)
1150 {
1151  const char * v1 ;
1152  const char * v2 ;
1153 
1154  /* Test entries */
1155  if (frame1==NULL || frame2==NULL) return -1 ;
1156 
1157  /* Get the tags */
1158  if ((v1 = cpl_frame_get_tag(frame1)) == NULL) return -1 ;
1159  if ((v2 = cpl_frame_get_tag(frame2)) == NULL) return -1 ;
1160 
1161  /* Compare the tags */
1162  if (strcmp(v1, v2)) return 0 ;
1163  else return 1 ;
1164 }
1165 
1166 /*----------------------------------------------------------------------------*/
1182 /*----------------------------------------------------------------------------*/
1183 const char * irplib_frameset_find_file(const cpl_frameset * self,
1184  const char * tag)
1185 {
1186  const cpl_frame * frame = cpl_frameset_find_const(self, tag);
1187 
1188 
1189  cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), NULL);
1190 
1191  if (frame == NULL) return NULL;
1192 
1193  if (cpl_frameset_find_const(self, NULL))
1194  cpl_msg_warning(cpl_func,
1195  "Frameset has more than one file with tag: %s",
1196  tag);
1197 
1198  return cpl_frame_get_filename(frame);
1199 
1200 }
1201 
1202 /*----------------------------------------------------------------------------*/
1212 /*----------------------------------------------------------------------------*/
1213 const
1214 cpl_frame * irplib_frameset_get_first_from_group(const cpl_frameset * self,
1215  cpl_frame_group group)
1216 {
1217  const cpl_frame * frame;
1218 
1219  cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, NULL);
1220 
1221  for (frame = cpl_frameset_get_first_const(self); frame != NULL ;
1222  frame = cpl_frameset_get_next_const(self)) {
1223  if (cpl_frame_get_group(frame) == group) break;
1224  }
1225  return frame;
1226 }
1227 
1228 /*----------------------------------------------------------------------------*/
1247 /*----------------------------------------------------------------------------*/
1248 cpl_error_code irplib_apertures_find_max_flux(const cpl_apertures * self,
1249  int * ind, int nfind)
1250 {
1251  const int nsize = cpl_apertures_get_size(self);
1252  int ifind;
1253 
1254 
1255  cpl_ensure_code(nsize > 0, cpl_error_get_code());
1256  cpl_ensure_code(ind, CPL_ERROR_NULL_INPUT);
1257  cpl_ensure_code(nfind > 0, CPL_ERROR_ILLEGAL_INPUT);
1258  cpl_ensure_code(nfind <= nsize, CPL_ERROR_ILLEGAL_INPUT);
1259 
1260  for (ifind=0; ifind < nfind; ifind++) {
1261  double maxflux = -1;
1262  int maxind = -1;
1263  int i;
1264  for (i=1; i <= nsize; i++) {
1265  int k;
1266 
1267  /* The flux has to be the highest among those not already found */
1268  for (k=0; k < ifind; k++) if (ind[k] == i) break;
1269 
1270  if (k == ifind) {
1271  /* i has not been inserted into ind */
1272  const double flux = cpl_apertures_get_flux(self, i);
1273 
1274  if (maxind < 0 || flux > maxflux) {
1275  maxind = i;
1276  maxflux = flux;
1277  }
1278  }
1279  }
1280  ind[ifind] = maxind;
1281  }
1282 
1283  return CPL_ERROR_NONE;
1284 
1285 }
1286 
1291 /*----------------------------------------------------------------------------*/
1302 /*----------------------------------------------------------------------------*/
1303 inline static
1304 double irplib_data_get_double(const void * self, cpl_type type, int i)
1305 {
1306 
1307  double value;
1308 
1309 
1310  switch (type) {
1311  case CPL_TYPE_FLOAT:
1312  {
1313  const float * pself = (const float*)self;
1314  value = (double)pself[i];
1315  break;
1316  }
1317  case CPL_TYPE_INT:
1318  {
1319  const int * pself = (const int*)self;
1320  value = (double)pself[i];
1321  break;
1322  }
1323  default: /* case CPL_TYPE_DOUBLE */
1324  {
1325  const double * pself = (const double*)self;
1326  value = pself[i];
1327  break;
1328  }
1329  }
1330 
1331  return value;
1332 
1333 }
1334 
1335 
1336 /*----------------------------------------------------------------------------*/
1347 /*----------------------------------------------------------------------------*/
1348 inline static
1349 void irplib_data_set_double(void * self, cpl_type type, int i, double value)
1350 {
1351 
1352  switch (type) {
1353  case CPL_TYPE_FLOAT:
1354  {
1355  float * pself = (float*)self;
1356  pself[i] = (float)value;
1357  break;
1358  }
1359  case CPL_TYPE_INT:
1360  {
1361  int * pself = (int*)self;
1362  pself[i] = (int)value;
1363  break;
1364  }
1365  default: /* case CPL_TYPE_DOUBLE */
1366  {
1367  double * pself = (double*)self;
1368  pself[i] = value;
1369  break;
1370  }
1371  }
1372 }
1373 
1374 
1375 
1376 
1377 
1378 /*----------------------------------------------------------------------------*/
1389 /*----------------------------------------------------------------------------*/
1390 static
1391 void irplib_errorstate_dump_one_level(void (*messenger)(const char *,
1392  const char *, ...),
1393  unsigned self, unsigned first,
1394  unsigned last)
1395 {
1396 
1397  const cpl_boolean is_reverse = first > last ? CPL_TRUE : CPL_FALSE;
1398  const unsigned newest = is_reverse ? first : last;
1399  const unsigned oldest = is_reverse ? last : first;
1400  const char * revmsg = is_reverse ? " in reverse order" : "";
1401 
1402 
1403  /*
1404  cx_assert( messenger != NULL );
1405  cx_assert( oldest <= self );
1406  cx_assert( newest >= self );
1407  */
1408 
1409  if (newest == 0) {
1410  messenger(cpl_func, "No error(s) to dump");
1411  /* cx_assert( oldest == 0); */
1412  } else {
1413  /*
1414  cx_assert( oldest > 0);
1415  cx_assert( newest >= oldest);
1416  */
1417  if (self == first) {
1418  if (oldest == 1) {
1419  messenger(cpl_func, "Dumping all %u error(s)%s:", newest,
1420  revmsg);
1421  } else {
1422  messenger(cpl_func, "Dumping the %u most recent error(s) "
1423  "out of a total of %u errors%s:",
1424  newest - oldest + 1, newest, revmsg);
1425  }
1426  cpl_msg_indent_more();
1427  }
1428 
1429  messenger(cpl_func, "[%u/%u] '%s' (%u) at %s", self, newest,
1430  cpl_error_get_message(), cpl_error_get_code(),
1431  cpl_error_get_where());
1432 
1433  if (self == last) cpl_msg_indent_less();
1434  }
1435 }
1436 
1437 cpl_polynomial * irplib_polynomial_fit_1d_create_chiq(
1438  const cpl_vector * x_pos,
1439  const cpl_vector * values,
1440  int degree,
1441  double * rechisq
1442  )
1443  {
1444  return irplib_polynomial_fit_1d_create_common(x_pos, values, degree, NULL, rechisq);
1445  }
1446 cpl_polynomial * irplib_polynomial_fit_1d_create(
1447  const cpl_vector * x_pos,
1448  const cpl_vector * values,
1449  int degree,
1450  double * mse
1451  )
1452 {
1453 
1454  return irplib_polynomial_fit_1d_create_common(x_pos, values, degree, mse, NULL);
1455 }
1456 static cpl_polynomial * irplib_polynomial_fit_1d_create_common(
1457  const cpl_vector * x_pos,
1458  const cpl_vector * values,
1459  int degree,
1460  double * mse,
1461  double * rechisq
1462  )
1463 {
1464  cpl_polynomial * fit1d = NULL;
1465  cpl_size loc_degree = (cpl_size)degree ;
1466  int x_size = 0;
1467  fit1d = cpl_polynomial_new(1);
1468  x_size = cpl_vector_get_size(x_pos);
1469  if(fit1d != NULL && x_size > 1)
1470  {
1471  cpl_matrix * samppos = NULL;
1472  cpl_vector * fitresidual = NULL;
1473  cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), NULL);
1474  samppos = cpl_matrix_wrap(1, x_size,
1475  (double*)cpl_vector_get_data_const(x_pos));
1476  cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), NULL);
1477  fitresidual = cpl_vector_new(x_size);
1478  cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), NULL);
1479  cpl_polynomial_fit(fit1d, samppos, NULL, values, NULL,
1480  CPL_FALSE, NULL, &loc_degree);
1481  cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), NULL);
1482  cpl_vector_fill_polynomial_fit_residual(fitresidual, values, NULL,
1483  fit1d, samppos, rechisq);
1484  cpl_ensure(!cpl_error_get_code(), cpl_error_get_code(), NULL);
1485  if (mse)
1486  {
1487  *mse = cpl_vector_product(fitresidual, fitresidual)
1488  / cpl_vector_get_size(fitresidual);
1489  }
1490  cpl_matrix_unwrap(samppos);
1491  cpl_vector_delete(fitresidual);
1492  }
1493  return fit1d;
1494 }
1495 
1496 static void quicksort(int* iindex, double* exptime, int left, int right)
1497 {
1498  int i = left;
1499  int j = right;
1500  int pivot = (i + j) / 2;
1501  double index_value = exptime[pivot];
1502  do
1503  {
1504  while(exptime[i] < index_value) i++;
1505  while(exptime[j] > index_value) j--;
1506  if (i <= j)
1507  {
1508  if(i < j)
1509  {
1510  int tmp = iindex[i];
1511  double dtmp = exptime[i];
1512  iindex[i]=iindex[j];
1513  iindex[j]=tmp;
1514  exptime[i] = exptime[j];
1515  exptime[j] = dtmp;
1516  }
1517  i++;
1518  j--;
1519  }
1520  } while (i <= j);
1521 
1522  if (i < right)
1523  {
1524  quicksort(iindex, exptime, i, right);
1525  }
1526  if (left < j)
1527  {
1528  quicksort(iindex, exptime,left, j);
1529  }
1530 }
1531 cpl_error_code irplib_frameset_sort(const cpl_frameset * self, int* iindex, double* exptime)
1532 {
1533  int sz = 0;
1534  int i = 0;
1535  const cpl_frame* tmp_frame = 0;
1536  cpl_error_code error = CPL_ERROR_NONE;
1537  sz = cpl_frameset_get_size(self);
1538 
1539  /* 1. get an array of frames */
1540  tmp_frame = cpl_frameset_get_first_const(self);
1541  while(tmp_frame)
1542  {
1543  exptime[i] = frame_get_exptime(tmp_frame);
1544  iindex[i] = i;
1545  tmp_frame = cpl_frameset_get_next_const(self);
1546  i++;
1547  }
1548  /* 2.sort */
1549  quicksort(iindex, exptime, 0, sz - 1);
1550 
1551  return error;
1552 }
1553 
1554 static double frame_get_exptime(const cpl_frame * pframe)
1555 {
1556  double dval = 0;
1557  cpl_propertylist * plist =
1558  cpl_propertylist_load_regexp(cpl_frame_get_filename(pframe), 0,
1559  "EXPTIME", CPL_FALSE);
1560  if(plist) {
1561  dval = cpl_propertylist_get_double(plist, "EXPTIME");
1562  if (cpl_error_get_code() != CPL_ERROR_NONE) {
1563  cpl_msg_error(cpl_func, "error during reading EXPTIME key from "
1564  "the frame [%s]", cpl_frame_get_filename(pframe));
1565  }
1566  }
1567  /* Free and return */
1568  cpl_propertylist_delete(plist);
1569  return dval;
1570 }
1571 
1572 
1573 /*----------------------------------------------------------------------------*/
1587 /*----------------------------------------------------------------------------*/
1588 void * irplib_aligned_malloc(size_t alignment, size_t size)
1589 {
1590 #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112L
1591  return aligned_alloc(alignment, size);
1592 #elif defined HAVE_POSIX_MEMALIGN && defined HAVE_DECL_POSIX_MEMALIGN
1593  void *ptr;
1594  if (alignment == 1)
1595  return malloc (size);
1596  if (alignment == 2 || (sizeof (void *) == 8 && alignment == 4))
1597  alignment = sizeof (void *);
1598  if (posix_memalign (&ptr, alignment, size) == 0)
1599  return ptr;
1600  else
1601  return NULL;
1602 #else
1603  /* copied from gmm_malloc.h in gcc-4.8 */
1604  void * malloc_ptr;
1605  void * aligned_ptr;
1606 
1607  /* Error if align is not a power of two. */
1608  if (alignment & (alignment - 1)) {
1609  errno = EINVAL;
1610  return NULL;
1611  }
1612 
1613  if (size == 0)
1614  return NULL;
1615 
1616  /* Assume malloc'd pointer is aligned at least to sizeof (void*).
1617  If necessary, add another sizeof (void*) to store the value
1618  returned by malloc. Effectively this enforces a minimum alignment
1619  of sizeof double. */
1620  if (alignment < 2 * sizeof (void *))
1621  alignment = 2 * sizeof (void *);
1622 
1623  malloc_ptr = malloc (size + alignment);
1624  if (!malloc_ptr)
1625  return NULL;
1626 
1627  /* Align We have at least sizeof (void *) space below malloc'd ptr. */
1628  aligned_ptr = (void *) (((size_t) malloc_ptr + alignment)
1629  & ~((size_t) (alignment) - 1));
1630 
1631  /* Store the original pointer just before p. */
1632  *(((void **) aligned_ptr) - 1) = malloc_ptr;
1633 
1634  return aligned_ptr;
1635 #endif
1636 }
1637 
1638 
1639 /*----------------------------------------------------------------------------*/
1649 /*----------------------------------------------------------------------------*/
1650 void * irplib_aligned_calloc(size_t alignment, size_t nelem, size_t nbytes)
1651 {
1652  void * buffer = irplib_aligned_malloc(alignment, nelem * nbytes);
1653  if (buffer == NULL)
1654  return NULL;
1655  /* cast to aligned pointer helps compilers to emit better (builtin) code */
1656  memset((size_t *)buffer, 0, nelem * nbytes);
1657  return buffer;
1658 }
1659 
1660 
1661 /*----------------------------------------------------------------------------*/
1669 /*----------------------------------------------------------------------------*/
1670 void irplib_aligned_free (void * aligned_ptr)
1671 {
1672 #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112L
1673  free(aligned_ptr);
1674 #elif defined HAVE_POSIX_MEMALIGN && defined HAVE_DECL_POSIX_MEMALIGN
1675  free(aligned_ptr);
1676 #else
1677  if (aligned_ptr)
1678  free (*(((void **) aligned_ptr) - 1));
1679 #endif
1680 }