UVES Pipeline Reference Manual  5.4.0
uves_dfs.c
1 /*
2  * This file is part of the UVES Pipeline
3  * Copyright (C) 2002, 2003, 2004, 2005 European Southern Observatory
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
18  */
19 
20 /*
21  * $Author: amodigli $
22  * $Date: 2013-04-16 15:48:48 $
23  * $Revision: 1.272 $
24  * $Name: not supported by cvs2svn $
25  *
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 /*----------------------------------------------------------------------------*/
39 /*----------------------------------------------------------------------------*/
40 
41 /*-----------------------------------------------------------------------------
42  Includes
43  -----------------------------------------------------------------------------*/
44 
45 #include <uves_dfs.h>
46 
47 #include <uves_utils.h>
48 #include <uves_wavecal_utils.h>
49 #include <uves_pfits.h>
50 #include <uves_dump.h>
51 #include <uves_qclog.h>
52 #include <uves.h>
53 #include <uves_utils_wrappers.h>
54 #include <uves_error.h>
55 #include <uves_msg.h>
56 
57 #include <irplib_utils.h>
58 
59 #include <cpl.h>
60 
61 #include <uves_time.h> /* iso time */
62 
63 #include <float.h>
64 #include <string.h>
65 /*-----------------------------------------------------------------------------
66  Defines
67  -----------------------------------------------------------------------------*/
68 #define FITS_MAGIC_SZ 6
69 
70 /*-----------------------------------------------------------------------------
71  Prototypes
72  -----------------------------------------------------------------------------*/
73 
74 static polynomial *load_polynomial(const char* filename, int extension);
75 static char *int_to_string(int i);
76 
77 static cpl_error_code
78 load_raw_image(const char *filename,
79  cpl_type type, bool flames, bool blue,
80  cpl_image *raw_image[2],
81  uves_propertylist *raw_header[2],
82  uves_propertylist *rotated_header[2]);
83 
84 static int uves_is_fits_file(const char *filename);
92 int uves_check_rec_status(const int val) {
93  if(cpl_error_get_code() != CPL_ERROR_NONE) {
94  uves_msg_error("error before %d",val);
95  uves_msg_error("%s", (char* ) cpl_error_get_message());
96  uves_msg_error("%s", (char* ) cpl_error_get_where());
97  return -1;
98  }
99  return 0;
100 }
101 
102 /*-------------------------------------------------------------------------*/
113 /*--------------------------------------------------------------------------*/
114 
115 static int uves_is_fits_file(const char *filename)
116 {
117  FILE *fp ;
118  char *magic ;
119  int isfits ;
120 
121  if ((fp = fopen(filename, "r"))==NULL) {
122  uves_msg_error("cannot open file [%s]", filename) ;
123  return -1 ;
124  }
125 
126  magic = cpl_calloc(FITS_MAGIC_SZ+1, sizeof(char)) ;
127  (void)fread(magic, 1, FITS_MAGIC_SZ, fp) ;
128  (void)fclose(fp) ;
129  magic[FITS_MAGIC_SZ] = (char)0 ;
130  if (strstr(magic, "SIMPLE")!=NULL)
131  isfits = 1 ;
132  else
133  isfits = 0 ;
134  cpl_free(magic) ;
135  return isfits ;
136 }
137 
138 /*----------------------------------------------------------------------------*/
148 /*----------------------------------------------------------------------------*/
149 static int
150 uves_dfs_files_dont_exist(cpl_frameset *frameset)
151 {
152  const char *func = "dfs_files_dont_exist";
153  cpl_frame *frame;
154 
155 
156  if (frameset == NULL) {
157  cpl_error_set(func, CPL_ERROR_NULL_INPUT);
158  return 1;
159  }
160 
161  if (cpl_frameset_is_empty(frameset)) {
162  return 0;
163  }
164 
165  frame = cpl_frameset_get_first(frameset);
166 
167  while (frame) {
168  if (access(cpl_frame_get_filename(frame), F_OK)) {
169  cpl_msg_error(func, "File %s (%s) was not found",
170  cpl_frame_get_filename(frame),
171  cpl_frame_get_tag(frame));
172  cpl_error_set(func, CPL_ERROR_FILE_NOT_FOUND);
173  }
174 
175  frame = cpl_frameset_get_next(frameset);
176  }
177 
178  if (cpl_error_get_code())
179  return 1;
180 
181  return 0;
182 }
183 
184 
185 
186 /*----------------------------------------------------------------------------*/
195 /*----------------------------------------------------------------------------*/
196 
197 int
198 uves_contains_frames_kind(cpl_frameset * sof,
199  cpl_frameset* raw,
200  const char* type)
201 {
202  char* tag=NULL;
203  char* name=NULL;
204  cpl_frame* frame = NULL;
205  cpl_frame* frame_dup = NULL;
206 
207  int nsof=0;
208  int i=0;
209  nsof = cpl_frameset_get_size(sof);
210  for (i=0 ; i<nsof ; i++) {
211  frame = cpl_frameset_get_frame(sof,i);
212  name= (char*) cpl_frame_get_filename(frame);
213  if(uves_is_fits_file(name) == 1) {
214  /* to go on the file must exist */
215  if(cpl_frame_get_tag(frame) != NULL) {
216  /* If the frame has a tag we process it. Else it is an object */
217  tag= (char*) cpl_frame_get_tag(frame);
218  /* uves_msg("name=%s tag=%s type=%s\n",name,tag,type); */
219  if(strstr(tag,type) != NULL) {
220  /* uves_msg("Match name=%s tag=%s type=%s\n",name,tag,type); */
221  frame_dup = cpl_frame_duplicate(frame);
222  cpl_frameset_insert(raw,frame_dup);
223  /* uves_msg("inserted\n"); */
224  }
225  }
226  }
227  }
228  return 0;
229 }
230 
231 /*----------------------------------------------------------------------------*/
248 /*----------------------------------------------------------------------------*/
249 polynomial *
250 uves_polynomial_convert_from_plist_midas(const uves_propertylist *plist,
251  const char *regression_name,
252  const int index)
253 {
254  polynomial *result = NULL;
255  cpl_polynomial *pol = NULL;
256  int N = strlen(regression_name);
257  const char *coeffi_name = NULL;
258  cpl_type type;
259  int length;
260  int *coeffi = NULL;
261  int degree1 = -1;
262  int degree2 = -1;
263  bool found = false;
264  const long int plist_size = uves_propertylist_get_size(plist);
265  int i;
266 
267  char cind=' ';
268 
269  if (index == -1) {
270  coeffi_name = cpl_sprintf("%sI", regression_name);
271  }
272  else {
273 
274  switch(index) {
275 
276  case 1: cind='1'; break;
277  case 2: cind='2'; break;
278  case 3: cind='3'; break;
279  case 4: cind='4'; break;
280  case 5: cind='5'; break;
281  case 6: cind='6'; break;
282  case 7: cind='7'; break;
283  case 8: cind='8'; break;
284  case 9: cind='9'; break;
285  default:
286  assure( false, CPL_ERROR_ILLEGAL_INPUT,
287  "Illegal index %d, 1-9 expected", index);
288  break;
289  }
290 
291 
292  coeffi_name = cpl_sprintf("%sI%d", regression_name, index);
293  }
294 
295  check_nomsg( coeffi = uves_read_midas_array(plist, coeffi_name, &length, &type, NULL));
296 
297 
298  assure( type == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
299  "Type of array %s is %s, integer expected",
300  coeffi_name, uves_tostring_cpl_type(type));
301  /*
302  assure( length == 7, CPL_ERROR_ILLEGAL_INPUT,
303  "Wrong array length = %d, 7 expected",
304  length);
305  */
306  /* ignore OUTPUTI(1)- N,no.of data, */
307 
308  /* OUTPUTI(2)- M,no.of ind.var. */
309 
310  assure( coeffi[1] == 2, CPL_ERROR_UNSUPPORTED_MODE,
311  "Regressions is %d-dimensional (2D expected)",
312  coeffi[1]);
313 
314  /* ignore OUTPUTI(3-5) (column number of variables)
315  (3)- col.no. of dep.var.
316  (4)- col.no. of indep.var.
317  (5)-
318  */
319 
320  /* Read degree of first and second variable
321  (6)- degree (ND) */
322 
323  degree1 = coeffi[5];
324  degree2 = coeffi[6];
325 
326  uves_msg_debug("Degree of 2D regression %s is (%d, %d)",
327  regression_name, degree1, degree2);
328 
329  /* The degree of the regression is now known. Next, read the coefficients */
330 
331  pol = cpl_polynomial_new(2);
332 
333  /* Search for <regression_name>D */
334  found = false;
335  for (i = 0; !found && i < plist_size; i++){
336  const cpl_property *p = uves_propertylist_get_const(plist, i);
337  const char *name = cpl_property_get_name(p);
338 
339  if (strcmp(name, "HISTORY") == 0) {
340  const char *value;
341  check( value = cpl_property_get_string(p),
342  "Error reading property value");
343 
344  /* match the string "'<regression_name>D'" */
345 
346  if (
347 
348  (((index < 0) &&
349  (int)strlen(value) >= 1+N+2 &&
350  value[0] == '\'' &&
351  value[1+N] == 'D' &&
352  value[1+N+1] == '\'')
353 
354  ||
355 
356  ((index > 0) &&
357  (int)strlen(value) >= 1+N+3 &&
358  value[0] == '\'' &&
359  value[1+N] == 'D' &&
360  value[1+N+1] == cind &&
361  value[1+N+2] == '\'') )
362 
363  &&
364 
365  strncmp(value+1, regression_name, N) == 0
366  ) {
367  double coeff;
368  char *next;
369  cpl_size power[2];
370  int j = i; /* points to the property currently being read */
371 
372  power[0] = 0; /* Current degree */
373  power[1] = 0;
374 
375  found = true;
376  value = "dummy"; /* This will make strtod fail the first time */
377 
378  while (power[1] <= degree2){
379  /* Read coefficient */
380  coeff = strtod(value, &next);
381 
382  if (next != value) {
383  /* A prefix of the string was successfully converted to double */
384  cpl_polynomial_set_coeff(pol, power, coeff);
385  uves_msg_debug("Polynomial coefficient of order (%" CPL_SIZE_FORMAT ", %" CPL_SIZE_FORMAT ") is %e",
386  power[0], power[1], coeff);
387 
388  power[0]++;
389  if (power[0] > degree1){
390  power[0] = 0;
391  power[1]++;
392  }
393  value = next;
394  }
395  else {
396  /* No more doubles could be read from the string,
397  so move to the next property in the plist */
398  j = j + 1;
399 
400  assure(j < plist_size, CPL_ERROR_ILLEGAL_INPUT,
401  "Missing header data");
402 
403  p = uves_propertylist_get_const(plist, j);
404  assure( cpl_property_get_type(p) == CPL_TYPE_STRING &&
405  strcmp(cpl_property_get_name(p), "HISTORY") == 0,
406  CPL_ERROR_ILLEGAL_INPUT, "Error parsing polynomial");
407 
408  value = cpl_property_get_string(p);
409 
410 
411  uves_msg_debug("Parsing string '%s'", value);
412  }
413  } /* Read coefficients */
414  } /* string was "'...D'" */
415  } /* Keyword was HISTORY */
416  }/* for i... */
417 
418  assure( found, CPL_ERROR_ILLEGAL_INPUT, "Could not find '%sD' in property list",
419  regression_name);
420 
421  /* Create a new polynomial from the cpl_polynomial */
422  result = uves_polynomial_new(pol);
423 
424  cleanup:
425  uves_free_int(&coeffi);
426  uves_free_string_const(&coeffi_name);
427  uves_free_polynomial(&pol);
428  if (cpl_error_get_code() != CPL_ERROR_NONE)
429  {
430  uves_polynomial_delete(&result);
431  }
432 
433  return result;
434 }
435 
436 
437 /*----------------------------------------------------------------------------*/
444 /*----------------------------------------------------------------------------*/
445 cpl_error_code
446 uves_frameset_merge(cpl_frameset * set1, const cpl_frameset* set2)
447 {
448 
449  const cpl_frame* frm_tmp=NULL;
450  cpl_frame* frm_dup=NULL;
451 
452  passure(set1 != NULL, "Wrong input set");
453  passure(set2 != NULL, "Wrong input set");
454 
455  for (frm_tmp = cpl_frameset_get_first_const(set2);
456  frm_tmp != NULL;
457  frm_tmp = cpl_frameset_get_next_const(set2))
458  {
459  frm_dup = cpl_frame_duplicate(frm_tmp);
460  cpl_frameset_insert(set1, frm_dup);
461  }
462 
463  cleanup:
464  return cpl_error_get_code();
465 }
466 
467 /*----------------------------------------------------------------------------*/
475 /*----------------------------------------------------------------------------*/
476 
477 cpl_error_code
478 uves_extract_frames_group_type(const cpl_frameset * set, cpl_frameset** ext, cpl_frame_group type)
479 {
480  const cpl_frame* frm_tmp=NULL;
481  cpl_frame* frm_dup=NULL;
482  cpl_frame_group g;
483 
484  check_nomsg(*ext = cpl_frameset_new());
485  check_nomsg(frm_tmp = cpl_frameset_get_first_const(set));
486  while (frm_tmp != NULL)
487  {
488  g=cpl_frame_get_group(frm_tmp);
489  if(g == type) {
490  frm_dup=cpl_frame_duplicate(frm_tmp);
491  cpl_frameset_insert(*ext,frm_dup);
492  uves_msg_debug("group %d insert file %s ",type,cpl_frame_get_filename(frm_dup));
493  }
494  frm_tmp = cpl_frameset_get_next_const(set);
495  }
496 
497  cleanup:
498  return cpl_error_get_code();
499 }
500 
501 /*----------------------------------------------------------------------------*/
509 /*----------------------------------------------------------------------------*/
510 cpl_error_code
511 uves_sflats_get_encoder_steps(const cpl_frameset * set, cpl_table** enc, int* nset)
512 {
513  /* Input */
514  const cpl_frame* frm=NULL;
515  int x1enc=0;
516  int x2enc=0;
517  int ref_x1enc=0;
518  int ref_x2enc=0;
519  int i=0;
520  int ndata=0;
521  const int threshold=5;
522  int status=0;
523  uves_propertylist* plist=NULL;
524  cpl_table* encoder_tbl=NULL;
525  ndata = cpl_frameset_get_size(set);
526  encoder_tbl=cpl_table_new(ndata);
527  cpl_table_new_column(encoder_tbl,"x1enc",CPL_TYPE_INT);
528  cpl_table_new_column(encoder_tbl,"x2enc",CPL_TYPE_INT);
529  cpl_table_new_column(encoder_tbl,"flag",CPL_TYPE_INT);
530 
531  for(i=0;i<cpl_frameset_get_size(set);i++)
532  {
533  check_nomsg(frm=cpl_frameset_get_frame_const(set,i));
534  check_nomsg(plist=uves_propertylist_load(cpl_frame_get_filename(frm),0));
537  check_nomsg(cpl_table_set_int(encoder_tbl,"x1enc",i,x1enc));
538  check_nomsg(cpl_table_set_int(encoder_tbl,"x2enc",i,x2enc));
539  uves_free_propertylist(&plist);
540  }
541 
542  check_nomsg(uves_sort_table_2(encoder_tbl,"x1enc","x2enc",false,true));
543 
544  check_nomsg(ref_x1enc=cpl_table_get_int(encoder_tbl,"x1enc",0,&status));
545  check_nomsg(ref_x2enc=cpl_table_get_int(encoder_tbl,"x2enc",0,&status));
546  *nset=1;
547  *enc=cpl_table_new(1);
548  cpl_table_new_column(*enc,"x1enc",CPL_TYPE_INT);
549  cpl_table_new_column(*enc,"x2enc",CPL_TYPE_INT);
550  check_nomsg(cpl_table_set_int(*enc,"x1enc",0,ref_x1enc));
551  check_nomsg(cpl_table_set_int(*enc,"x2enc",0,ref_x2enc));
552 
553  for(i=1;i<cpl_table_get_nrow(encoder_tbl);i++) {
554  check_nomsg(x1enc=cpl_table_get_int(encoder_tbl,"x1enc",i,&status));
555  check_nomsg(x2enc=cpl_table_get_int(encoder_tbl,"x2enc",i,&status));
556  if( (fabs(ref_x1enc -x1enc) > threshold) ||
557  (fabs(ref_x2enc -x2enc) > threshold) ) {
558 
559  ref_x1enc = x1enc;
560  ref_x2enc = x2enc;
561  cpl_table_set_size(*enc,(*nset+1));
562  check_nomsg(cpl_table_set_int(*enc,"x1enc",*nset,ref_x1enc));
563  check_nomsg(cpl_table_set_int(*enc,"x2enc",*nset,ref_x2enc));
564  *nset=*nset+1;
565 
566  }
567  }
568  uves_msg("Number of sets = %d",*nset);
569 
570  cleanup:
571  uves_free_table(&encoder_tbl);
572  uves_free_propertylist(&plist);
573  return cpl_error_get_code();
574 }
575 
576 
577 /*----------------------------------------------------------------------------*/
583 /*----------------------------------------------------------------------------*/
584 cpl_error_code
585 uves_dfs_set_groups(cpl_frameset * set)
586 {
587  cpl_frame * cur_frame ;
588  int nframes ;
589 
590  /* Check entries */
591  assure(set != NULL, CPL_ERROR_NULL_INPUT, "Null input");
592 
593  /* Initialize */
594  check( nframes = cpl_frameset_get_size(set), "Could not read frameset size");
595 
596  /* Loop on frames */
597  for (cur_frame = cpl_frameset_get_first(set);
598  cur_frame != NULL;
599  cur_frame = cpl_frameset_get_next(set))
600  {
601  bool is_raw = false;
602  bool is_calib = false;
603  bool is_recognized = false;
604  bool blue;
605  enum uves_chip chip;
606  const char * tag = cpl_frame_get_tag(cur_frame);
607 
608  assure( tag != NULL && strcmp(tag, "") != 0, CPL_ERROR_ILLEGAL_INPUT,
609  "Frame has no tag!");
610 
611  blue = false;
612  do {
613  bool flames = false;
614  do {
615  /* RAW frames */
616  is_raw = is_raw ||
617  (strcmp(tag, UVES_ORDER_FLAT (flames,blue)) == 0 ||
618  strcmp(tag, UVES_BIAS (blue)) == 0 ||
619  strcmp(tag, UVES_DARK (blue)) == 0 ||
620  strcmp(tag, UVES_PDARK (blue)) == 0 ||
621  strcmp(tag, UVES_FLAT (blue)) == 0 ||
622  strcmp(tag, UVES_IFLAT (blue)) == 0 ||
623  strcmp(tag, UVES_DFLAT (blue)) == 0 ||
624  strcmp(tag, UVES_SFLAT (blue)) == 0 ||
625  strcmp(tag, UVES_TFLAT (blue)) == 0 ||
626  strcmp(tag, UVES_SCREEN_FLAT (blue)) == 0 ||
627  strcmp(tag, UVES_CD_ALIGN (blue)) == 0 ||
628  strcmp(tag, UVES_FORMATCHECK (flames,blue)) == 0 ||
629  strcmp(tag, UVES_STD_STAR (blue)) == 0 ||
630  strcmp(tag, UVES_SCIENCE (blue)) == 0 ||
631  strcmp(tag, UVES_SCI_EXTND (blue)) == 0 ||
632  strcmp(tag, UVES_SCI_POINT (blue)) == 0 ||
633  strcmp(tag, UVES_SCI_SLICER (blue)) == 0 ||
634  strcmp(tag, UVES_ARC_LAMP (flames,blue)) == 0 ||
635  strcmp(tag, UVES_ECH_ARC_LAMP(blue)) == 0 ||
636  strcmp(tag, RAW_IMA) == 0 ||
637  strcmp(tag, FLAMES_SCI_RED) == 0 ||
638  strcmp(tag, FLAMES_SCI_SIM_RED) == 0 ||
639  strcmp(tag, FLAMES_SCI_COM_RED) == 0 ||
640  strcmp(tag, FLAMES_FIB_FF_ODD) == 0 ||
641  strcmp(tag, FLAMES_FIB_FF_EVEN) == 0 ||
642  strcmp(tag, FLAMES_FIB_FF_ALL) == 0);
643 
644  /* CALIB frames */
645 
646  /* Loop through all (1 or 2) blue or red chips */
647  for (chip = uves_chip_get_first(blue);
648  chip != UVES_CHIP_INVALID;
649  chip = uves_chip_get_next(chip))
650  {
651  int window;
652 
653  is_calib = is_calib ||
654  (strcmp(tag, UVES_DRS_SETUP(flames, chip)) == 0 ||
655  strcmp(tag, UVES_ORDER_TABLE(flames, chip)) == 0 ||
656  strcmp(tag, UVES_GUESS_ORDER_TABLE(flames,chip)) == 0 ||
657  strcmp(tag, UVES_MASTER_BIAS (chip)) == 0 ||
658  strcmp(tag, UVES_MASTER_DARK (chip)) == 0 ||
659  strcmp(tag, UVES_MASTER_PDARK (chip)) == 0 ||
660  strcmp(tag, UVES_MASTER_FLAT (chip)) == 0 ||
661  strcmp(tag, UVES_MASTER_DFLAT (chip)) == 0 ||
662  strcmp(tag, UVES_MASTER_SFLAT (chip)) == 0 ||
663  strcmp(tag, UVES_MASTER_IFLAT (chip)) == 0 ||
664  strcmp(tag, UVES_MASTER_TFLAT (chip)) == 0 ||
665  strcmp(tag, UVES_REF_TFLAT (chip)) == 0 ||
666  strcmp(tag, UVES_ORD_TAB(flames,chip)) == 0 ||
667  strcmp(tag, UVES_MASTER_SCREEN_FLAT(chip)) == 0 ||
668  strcmp(tag, UVES_MASTER_ARC_FORM(chip)) == 0 ||
669  strcmp(tag, UVES_WEIGHTS(chip)) == 0 ||
670  strcmp(tag, UVES_LINE_TABLE(flames,chip)) == 0 ||
671  strcmp(tag, UVES_GUESS_LINE_TABLE(flames,chip)) == 0 ||
672  strcmp(tag, UVES_INSTR_RESPONSE(chip)) == 0 ||
673  strcmp(tag, UVES_MASTER_RESPONSE(chip)) == 0 ||
674  strcmp(tag, UVES_LINE_REFER_TABLE ) == 0 ||
675  strcmp(tag, UVES_LINE_INTMON_TABLE ) == 0 ||
676  strcmp(tag, UVES_FLUX_STD_TABLE ) == 0 ||
677  strcmp(tag, UVES_EXTCOEFF_TABLE ) == 0 ||
678  strcmp(tag, FLAMES_LINE_TABLE(chip)) == 0 ||
679  strcmp(tag, FLAMES_SLIT_FF_DT1(chip)) == 0 ||
680  strcmp(tag, FLAMES_SLIT_FF_DT2(chip)) == 0 ||
681  strcmp(tag, FLAMES_SLIT_FF_DT3(chip)) == 0 ||
682  strcmp(tag, FLAMES_SLIT_FF_DTC(chip)) == 0 ||
683  strcmp(tag, FLAMES_SLIT_FF_BP1(chip)) == 0 ||
684  strcmp(tag, FLAMES_SLIT_FF_BP2(chip)) == 0 ||
685  strcmp(tag, FLAMES_SLIT_FF_BP3(chip)) == 0 ||
686  strcmp(tag, FLAMES_SLIT_FF_BPC(chip)) == 0 ||
687  strcmp(tag, FLAMES_SLIT_FF_BN1(chip)) == 0 ||
688  strcmp(tag, FLAMES_SLIT_FF_BN2(chip)) == 0 ||
689  strcmp(tag, FLAMES_SLIT_FF_BN3(chip)) == 0 ||
690  strcmp(tag, FLAMES_SLIT_FF_BNC(chip)) == 0 ||
691  strcmp(tag, FLAMES_SLIT_FF_SG1(chip)) == 0 ||
692  strcmp(tag, FLAMES_SLIT_FF_SG2(chip)) == 0 ||
693  strcmp(tag, FLAMES_SLIT_FF_SG3(chip)) == 0 ||
694  strcmp(tag, FLAMES_SLIT_FF_SGC(chip)) == 0 ||
695  strcmp(tag, FLAMES_SLIT_FF_COM(chip)) == 0 ||
696  strcmp(tag, FLAMES_SLIT_FF_NOR(chip)) == 0 ||
697  strcmp(tag, FLAMES_SLIT_FF_NSG(chip)) == 0 ||
698  strcmp(tag, FLAMES_FIB_FF_DT1(chip)) == 0 ||
699  strcmp(tag, FLAMES_FIB_FF_DT2(chip)) == 0 ||
700  strcmp(tag, FLAMES_FIB_FF_DT3(chip)) == 0 ||
701  strcmp(tag, FLAMES_FIB_FF_DTC(chip)) == 0 ||
702  strcmp(tag, FLAMES_FIB_FF_BP1(chip)) == 0 ||
703  strcmp(tag, FLAMES_FIB_FF_BP2(chip)) == 0 ||
704  strcmp(tag, FLAMES_FIB_FF_BP3(chip)) == 0 ||
705  strcmp(tag, FLAMES_FIB_FF_BPC(chip)) == 0 ||
706  strcmp(tag, FLAMES_FIB_FF_BN1(chip)) == 0 ||
707  strcmp(tag, FLAMES_FIB_FF_BN2(chip)) == 0 ||
708  strcmp(tag, FLAMES_FIB_FF_BN3(chip)) == 0 ||
709  strcmp(tag, FLAMES_FIB_FF_BNC(chip)) == 0 ||
710  strcmp(tag, FLAMES_FIB_FF_SG1(chip)) == 0 ||
711  strcmp(tag, FLAMES_FIB_FF_SG2(chip)) == 0 ||
712  strcmp(tag, FLAMES_FIB_FF_SG3(chip)) == 0 ||
713  strcmp(tag, FLAMES_FIB_FF_SGC(chip)) == 0 ||
714  strcmp(tag, FLAMES_FIB_FF_COM(chip)) == 0 ||
715  strcmp(tag, FLAMES_FIB_FF_NOR(chip)) == 0 ||
716  strcmp(tag, FLAMES_FIB_FF_NSG(chip)) == 0 ||
717  strcmp(tag, FLAMES_ORDEF(flames,chip)) == 0 ||
718  strcmp(tag, FLAMES_CORVEL_MASK) == 0);
719 
720  for (window = 1; window <= 3; window++)
721  {
722  is_calib = is_calib ||
723  strcmp(tag, UVES_LINE_TABLE_MIDAS(chip, window)) == 0;
724  }
725 
726  if (!flames && strcmp(tag, UVES_BACKGR_TABLE(chip)) == 0)
727  {
728  uves_msg_warning("Background table %s has been deprecated. "
729  "Inter-order positions will be inferred "
730  "from the order table %s. "
731  "Use recipe parameters to define "
732  "measuring method ",
733  UVES_BACKGR_TABLE(chip),
734  UVES_ORDER_TABLE(flames, chip));
735 
736  is_recognized = true;
737  }
738 
739  if (strcmp(tag, UVES_DRS_SETUP(flames, chip)) == 0)
740  {
741  uves_msg_warning("DRS setup table %s has been deprecated. "
742  "Use recipe parameters "
743  "to define data reduction parameters ",
744  UVES_DRS_SETUP(flames, chip));
745 
746  is_recognized = true;
747  }
748  }
749  flames = !flames;
750  } while (flames);
751  blue = !blue;
752  }
753  while (blue);
754 
755  is_recognized = is_recognized || is_raw || is_calib;
756 
757  if (is_raw)
758  {
759  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW) ;
760  }
761  else if (is_calib)
762  {
763  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_CALIB) ;
764  }
765  else if (!is_recognized)
766  {
767  uves_msg_warning("Unrecognized tag %s", tag);
768  }
769  }
770 
771  uves_dfs_files_dont_exist(set);
772 
773 
774  cleanup:
775  return cpl_error_get_code();
776 }
777 
778 
779 /*----------------------------------------------------------------------------*/
788 /*----------------------------------------------------------------------------*/
789 static void
790 remove_pre_over_scan(uves_propertylist *pl)
791 {
792  bool blue, new_format;
793  enum uves_chip chip;
794 
795  new_format = false;
796  do {
797  blue = false;
798  do {
799  for (chip = uves_chip_get_first(blue);
800  chip != UVES_CHIP_INVALID;
801  chip = uves_chip_get_next(chip))
802  {
803  int n_erase_px = 0; /* Number of erased properties */
804  int n_erase_py = 0;
805  int n_erase_ox = 0;
806  int n_erase_oy = 0;
807 
808  do {
809  /* This function erases only one property at a time,
810  * therefore call it until it returns 0
811  */
812  check( n_erase_px =
813  uves_propertylist_erase(pl, UVES_PRESCANX(new_format, chip)),
814  "Error erasing keyword '%s'", UVES_PRESCANX(new_format, chip));
815 
816  check( n_erase_py =
817  uves_propertylist_erase(pl, UVES_PRESCANY(new_format, chip)),
818  "Error erasing keyword '%s'", UVES_PRESCANY(new_format, chip));
819 
820  check( n_erase_ox =
821  uves_propertylist_erase(pl, UVES_OVRSCANX(new_format, chip)),
822  "Error erasing keyword '%s'", UVES_OVRSCANX(new_format, chip));
823 
824  check( n_erase_oy =
825  uves_propertylist_erase(pl, UVES_OVRSCANY(new_format, chip)),
826  "Error erasing keyword '%s'", UVES_OVRSCANY(new_format, chip));
827  }
828  while (n_erase_px > 0 ||
829  n_erase_py > 0 ||
830  n_erase_ox > 0 ||
831  n_erase_oy > 0);
832  }
833  blue = !blue;
834  }
835  while (blue);
836 
837  new_format = !new_format;
838  }
839  while (new_format);
840 
841  cleanup:
842  return;
843 }
844 
845 
846 /*----------------------------------------------------------------------------*/
856 /*----------------------------------------------------------------------------*/
857 
858 void
859 uves_copy_if_possible(uves_propertylist *to, const uves_propertylist *from,
860  const char *name)
861 {
862  if (!uves_propertylist_contains(to, name) &&
863  uves_propertylist_contains(from, name))
864  {
865  uves_msg_debug("Propagating keyword %s", name);
866 
867  check_nomsg( uves_propertylist_copy_property(to, from, name) );
868  }
869  else
870  {
871  uves_msg_debug("Keyword %s not propagated", name);
872  }
873 
874  cleanup:
875  return;
876 }
877 
878 /*----------------------------------------------------------------------------*/
922 /*----------------------------------------------------------------------------*/
923 cpl_error_code
924 uves_frameset_insert(cpl_frameset *frames,
925  void *object,
926  cpl_frame_group group,
927  cpl_frame_type type,
928  cpl_frame_level level,
929  const char *filename,
930  const char *tag,
931  const uves_propertylist *raw_header,
932  const uves_propertylist *primary_header,
933  const uves_propertylist *table_header,
934  const cpl_parameterlist *parameters,
935  const char *recipe,
936  const char *pipeline,
937  cpl_table **qc,
938  const char *start_time,
939  bool dump_paf,
940  unsigned stats_mask)
941 {
942  cpl_frame *f = NULL;
943  uves_propertylist *pl = NULL;
944  const char *origin = "";
945 
946  passure( !(type == CPL_FRAME_TYPE_IMAGE && table_header != NULL), " ");
947  passure( raw_header != NULL, " ");
948  passure( primary_header != NULL, " ");
949 
950  assure( type == CPL_FRAME_TYPE_IMAGE || stats_mask == 0,
951  CPL_ERROR_INCOMPATIBLE_INPUT,
952  "Cannot compute image statistics on table product" );
953 
954  /* Insert the object (image or table) into frameset */
955  check(( f = cpl_frame_new(),
956  cpl_frame_set_filename(f, filename), /* local filename */
957  cpl_frame_set_tag (f, tag), /* e.g. ORDER_TABLE_BLUE */
958  cpl_frame_set_type (f, type), /* e.g. table */
959  cpl_frame_set_group (f, group), /* e.g. raw/product */
960  cpl_frame_set_level (f, level), /* e.g. temporary/final */
961  cpl_frameset_insert(frames, f)), "Could not insert frame into frameset");
962 
963  /* Pipeline id format is <PACKAGE "/" PACKAGE_VERSION>; */
964  if (strchr(pipeline, '/') == NULL)
965  {
966  uves_msg_warning("Pipeline ID '%s' is not of format: "
967  "Pipeline-name/version", pipeline);
968  }
969 
970  /* Copy provided keywords in 'primary_header' to 'pl' */
971  pl = uves_propertylist_new();
972  if(uves_propertylist_contains(primary_header,UVES_BSCALE)) {
973  uves_msg("inside has bscale");
974  }
975  if (!uves_propertylist_is_empty(primary_header))
976  {
977  if (0)
978  /* This takes (n*m) time */
979  {
980  /* The regexp "" matches any string (because any string has
981  the empty string as a sub-string),
982  except on Mac, where it is an illegal regexp (for whatever reason).
983  Therefore, use ".*" to match any string */
984 
985  check( uves_propertylist_copy_property_regexp(pl, primary_header, ".*", 0),
986  "Could not copy keywords");
987  }
988  else
989  check( uves_propertylist_append(pl, primary_header),
990  "Could not copy keywords");
991  }
992 
993  /* Propagate/create DFS keywords */
994  UVES_TIME_START("cpl_dfs_setup_product_header");
995  check( uves_dfs_setup_product_header(pl,
996  f,
997  frames,
998  parameters,
999  recipe,
1000  pipeline,
1001  DICTIONARY),
1002  "Error setting up product header");
1003  UVES_TIME_END;
1004 
1005  /* Change origin to 'ESO' if it says 'ESO-MIDAS'
1006  * NOST-Definition: "The value field shall contain a character string
1007  * identifying the organization or institution responsible
1008  * for creating the FITS file."
1009  */
1010 
1011  check( uves_get_property_value(pl, "ORIGIN", CPL_TYPE_STRING, &origin),
1012  "Error reading ORIGIN from product header");
1013 
1014  if (strcmp(origin, "ESO-MIDAS") == 0)
1015  {
1016  uves_propertylist_set_string(pl, "ORIGIN", "ESO");
1017  }
1018 
1019  /* Add statistics keywords */
1020  if (type == CPL_FRAME_TYPE_IMAGE && stats_mask != 0)
1021  {
1022  check( uves_dfs_write_statistics((cpl_image *) object, pl, stats_mask),
1023  "Error adding image statistics keywords");
1024  }
1025 
1026  /* Propagate ESO.DET keywords from 'raw_header',
1027  * This is necessary because cpl_dfs_setup_product_header() copies
1028  * only from the primary extension of the first input frames
1029  */
1030  check( uves_propertylist_copy_property_regexp(pl, raw_header, "^ESO DET ", 0),
1031  "Could not propagate 'ESO DET*' keywords");
1032 
1033  /* But remove prescan, overscan keywords.
1034  (Since these areas are not present in any products.) */
1035  check( remove_pre_over_scan(pl),
1036  "Error removing pre-, overscan keywords from product header");
1037 
1038  /* Propagate certain keywords from 'raw_header'
1039  (only if available and if not already present in product header) */
1040  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_AIRMASS) );
1041  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_IMAGETYP) );
1042  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_UT) );
1043  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_ST) );
1044  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_EXPTIME) );
1045  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_EXTNAME) );
1046  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_DATE) );
1047  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_DATAMEAN) );
1048  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_DATAMED) );
1049  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_DATARMS) );
1050  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_OS_EXPOI) );
1051 
1052  /* MIDAS internal(?): check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_TMSTART) ); */
1053 
1054  if (0)
1055  /* uves_propertylist_copy_property_regexp() is slow */
1056  {
1057  check( uves_propertylist_copy_property_regexp(pl, raw_header, "^GRAT[0-9]*$", 0),
1058  "Could not propagate 'GRATi' keywords");
1059  check( uves_propertylist_copy_property_regexp(pl, raw_header, "^FILTER[0-9]*$", 0),
1060  "Could not propagate 'FILTERi' keywords");
1061  check( uves_propertylist_copy_property_regexp(pl, raw_header, "^WLEN[0-9]*$", 0),
1062  "Could not propagate 'WLENi' keywords");
1063  }
1064  else
1065  {
1067  pl, raw_header, "^((GRAT|FILTER|WLEN)[0-9]*)$", 0),
1068  "Could not propagate GRATi, FILTERi and WLENi keywords");
1069  }
1070 
1071  /* If RA,DEC do not exist, invent them and set to zero, like MIDAS */
1072  if ( !uves_propertylist_contains(pl, UVES_RA) )
1073  {
1074  uves_pfits_set_ra(pl, 0);
1075  }
1076  if ( !uves_propertylist_contains(pl, UVES_DEC) )
1077  {
1078  uves_pfits_set_dec(pl, 0);
1079  }
1080 
1081  /*
1082  * REDLEVEL and STATUS have been deprecated, so delete them
1083  * along with inherited MIDAS specific keywords
1084  */
1085  {
1086  bool invert = false;
1088  "ESO PRO (REDLEVEL|REC[0-9]+ STATUS)|"
1089  "TM-START|MIDASFTP|FILENAME)$", invert);
1090  }
1091 
1092  check( uves_pfits_set_starttime(pl, start_time),
1093  "Could not write recipe start time");
1094 
1096  "Could not write recipe stop time");
1097 
1098  /* Create paf file from each QC table, and transfer
1099  all QC parameters to product header
1100  */
1101  if (qc != NULL)
1102  {
1103  int i;
1104  for (i = 0; qc[i] != NULL; i++)
1105  {
1106  uves_pfits_put_qc(pl, qc[i]);
1107 
1108  if (dump_paf)
1109  {
1110  /* Exception! This is a hack */
1111  if (strcmp(recipe, make_str(UVES_TFLAT_ID)) == 0 && i == 1)
1112  {
1113  /* Don't dump the science QC again */
1114  }
1115  else
1116  {
1117  /*
1118  uves_save_paf(filename, i, recipe, qc[i],
1119  pl, raw_header, tag);
1120  */
1121  }
1122  }
1123  }
1124  }
1125 
1126  UVES_TIME_START("save product");
1127 
1128  /* Now save with the correct header */
1129  if (type == CPL_FRAME_TYPE_IMAGE)
1130  {
1131  bool use_bitpix16_for_int = (strcmp(recipe, make_str(FLAMES_CAL_ORDERPOS)) == 0);
1132 
1133  check( uves_save_image((cpl_image *) object, filename, pl,
1134  use_bitpix16_for_int, true),
1135  "Error saving image to file %s", filename);
1136  }
1137  else if (type == CPL_FRAME_TYPE_TABLE) /* Table */
1138  {
1139  check( uves_table_save((cpl_table *) object,
1140  pl, /* Primary header */
1141  table_header, /* Table header */
1142  filename,
1143  CPL_IO_DEFAULT), /* Create new file */
1144  "Error saving table to file '%s'", filename);
1145  }
1146  else
1147  {
1148  assure(false, CPL_ERROR_UNSUPPORTED_MODE, "Unsupported frame type");
1149  }
1150 
1151  UVES_TIME_END;
1152 
1153  cleanup:
1154  uves_free_propertylist(&pl);
1155 
1156  return cpl_error_get_code();
1157 }
1158 
1159 
1160 /*----------------------------------------------------------------------------*/
1169 /*----------------------------------------------------------------------------*/
1170 void
1171 uves_dfs_write_statistics(const cpl_image *image, uves_propertylist *header,
1172  unsigned stats_mask)
1173 {
1174  cpl_stats *stats = NULL;
1175 
1176  /* Only these bits are supported, all others must be zero */
1177  assure( (stats_mask & (CPL_STATS_MEAN | CPL_STATS_STDEV | CPL_STATS_MEDIAN |
1178  CPL_STATS_MIN | CPL_STATS_MAX)) == stats_mask,
1179  CPL_ERROR_UNSUPPORTED_MODE, "Cannot compute mask %d",
1180  stats_mask );
1181 
1182  UVES_TIME_START("calculate stats");
1183 
1184  check( stats = cpl_stats_new_from_image(
1185  image, stats_mask),
1186  "Error reading image statistics");
1187 
1188  UVES_TIME_END;
1189 
1190  if (stats_mask & CPL_STATS_MEDIAN)
1191  {
1192  check( uves_pfits_set_data_median (header, cpl_stats_get_median(stats) ),
1193  "Could not write median flux");
1194  }
1195  if (stats_mask & CPL_STATS_MEAN)
1196  {
1197  check( uves_pfits_set_data_average(header, cpl_stats_get_mean (stats) ),
1198  "Could not write average flux");
1199  }
1200  if (stats_mask & CPL_STATS_STDEV)
1201  {
1202  check( uves_pfits_set_data_stddev (header, cpl_stats_get_stdev (stats) ),
1203  "Could not write flux stdev");
1204  }
1205  if (stats_mask & CPL_STATS_MIN)
1206  {
1207  check( uves_pfits_set_data_min (header, cpl_stats_get_min (stats) ),
1208  "Could not write min flux");
1209  }
1210  if (stats_mask & CPL_STATS_MIN)
1211  {
1212  check( uves_pfits_set_data_max (header, cpl_stats_get_max (stats) ),
1213  "Could not write max flux");
1214  }
1215 
1216  cleanup:
1217  uves_free_stats(&stats);
1218  return;
1219 }
1220 
1221 
1222 /*----------------------------------------------------------------------------*/
1257 /*----------------------------------------------------------------------------*/
1258 void *
1259 uves_read_midas_array(const uves_propertylist *plist, const char *name,
1260  int *length, cpl_type *type, int *ncards)
1261 {
1262  void *result = NULL;
1263  unsigned result_size;
1264  int N = strlen(name);
1265  bool found = false;
1266  const char *value;
1267  int size;
1268  int i;
1269  const long int plist_size = uves_propertylist_get_size(plist);
1270 
1271  assure_nomsg( length != NULL, CPL_ERROR_NULL_INPUT );
1272  assure_nomsg( type != NULL, CPL_ERROR_NULL_INPUT );
1273  for (i = 0; !found && i < plist_size; i++)
1274  {
1275  const cpl_property *p = uves_propertylist_get_const(plist, i);
1276  value = cpl_property_get_name(p);
1277 
1278  if (strcmp(value, "HISTORY") == 0)
1279  {
1280 
1281  check( value = cpl_property_get_string(p),
1282  "Error reading property value");
1283 
1284  /* match the string "'<name>','t" */
1285 
1286  if ((int)strlen(value) >= 1+N+4 &&
1287  value[0] == '\'' &&
1288  value[N+1] == '\'' &&
1289  value[N+2] == ',' &&
1290  value[N+3] == '\'' &&
1291  strncmp(value+1, name, N) == 0
1292  )
1293  {
1294  switch(value[N+4]) {
1295  case 'R':
1296  /* Distinguish between
1297  "'<name>','R*4'" and
1298  "'<name>','R*8'"
1299  */
1300  *type = CPL_TYPE_DOUBLE;
1301 
1302  if ((int)strlen(value) >= 1+N+4+2 && value[N+4+1] == '*')
1303  {
1304  switch(value[N+4+2]) {
1305  case '4': *type = CPL_TYPE_FLOAT; break;
1306  case '8': *type = CPL_TYPE_DOUBLE; break;
1307  default:
1308  assure( false, CPL_ERROR_ILLEGAL_INPUT,
1309  "Unrecognized MIDAS type: 'R*%c'",
1310  value[N+4+2]);
1311  break;
1312  }
1313  }
1314  break;
1315  case 'I': *type = CPL_TYPE_INT ; size = sizeof(int); break;
1316  case 'C': *type = CPL_TYPE_STRING; size = sizeof(char); break;
1317  default:
1318  assure( false, CPL_ERROR_UNSUPPORTED_MODE,
1319  "Unrecognized type '%c'", value[N+4]);
1320  break;
1321  }
1322  found = true;
1323  }
1324  }
1325  }
1326 
1327  assure( found, CPL_ERROR_ILLEGAL_INPUT, "Could not find '%s' in property list", name);
1328 
1329  /* 'i' is now the row immediately after first occurence of 'HISTORY '<name>... */
1330  result_size = sizeof(double) * 100; /* realloc when/if out of memory */
1331  result = cpl_malloc(result_size);
1332 
1333  *length = 0;
1334  if (ncards != NULL) *ncards = 2; /* First HISTORY entry + termination HISTORY entry */
1335  do {
1336  const cpl_property *p;
1337 
1338  if (ncards != NULL) *ncards += 1;
1339 
1340  assure(i < plist_size,
1341  CPL_ERROR_ILLEGAL_INPUT, "Missing header data");
1342  p = uves_propertylist_get_const(plist, i);
1343  assure( cpl_property_get_type(p) == CPL_TYPE_STRING &&
1344  strcmp(cpl_property_get_name(p), "HISTORY") == 0,
1345  CPL_ERROR_ILLEGAL_INPUT, "Error parsing array");
1346  value = cpl_property_get_string(uves_propertylist_get_const(plist, i));
1347 
1348  uves_msg_debug("Parsing '%s'", value);
1349 
1350  if (*type == CPL_TYPE_STRING)
1351  {
1352  assure( strlen(value) < 100, CPL_ERROR_UNSUPPORTED_MODE,
1353  "String too long. Max size is 100");
1354 
1355  /* Remove any blanks from the string
1356  (e.g. convert "0 1 2" to "012")
1357  */
1358  {
1359  int len = strlen(value);
1360  int j = 0;
1361  int k;
1362  for (k = 0; k <= len; k++) /* including final '\0' */
1363  {
1364  //if (value[k] != ' '){
1365  ((char*)result)[j] = value[k];
1366  j++;
1367  // }
1368  }
1369  *length = j-1;
1370  }
1371 
1372  uves_msg_debug("Converted '%s' to '%s'",
1373  value, (char*)result);
1374 
1375  /* done parsing */
1376  value = "";
1377  }
1378 
1379  else { /* numerical types */
1380  if (strcmp(value, "") != 0) {
1381  double numberd = -1; /* suppres warning */
1382  int numberi = -1;
1383  float numberf = -1;
1384  const int base = 10;
1385  char *next = (char *) value;
1386 
1387  do {
1388  /* ignore OUTPUTI(1)- N,no.of data, */
1389  switch(*type) {
1390  case CPL_TYPE_DOUBLE:
1391  numberd = strtod(value, &next);
1392  uves_msg_debug("Got %g, remaining: '%s'", numberd, next);
1393  break;
1394  case CPL_TYPE_FLOAT:
1395  numberf = strtod(value, &next); // C99: strtof(value, &next);
1396  uves_msg_debug("Got %g, remaining: '%s'", numberf, next);
1397  break;
1398  case CPL_TYPE_INT:
1399  numberi = strtol(value, &next, base);
1400  uves_msg_debug("Got %d, remaining: '%s'", numberi, next);
1401  break;
1402  default:
1403  passure(false, " ");
1404  }
1405 
1406  if (next != value)
1407  {
1408  /* A prefix of the string could be converted */
1409  (*length)++;
1410  if (*length * sizeof(double) > result_size)
1411  {
1412  result_size *= 2;
1413  result = cpl_realloc(result, result_size);
1414  }
1415 
1416  switch(*type) {
1417  case CPL_TYPE_DOUBLE:
1418  ((double *)result)[*length-1] = numberd;
1419  break;
1420  case CPL_TYPE_FLOAT:
1421  ((float *)result)[*length-1] = numberf;
1422  break;
1423  case CPL_TYPE_INT:
1424  ((int *)result)[*length-1] = numberi;
1425  break;
1426  default:
1427  passure(false, " ");
1428  }
1429 
1430  value = next;
1431 
1432  switch(*type) {
1433  case CPL_TYPE_DOUBLE:
1434  numberd = strtod(value, &next);
1435  uves_msg_debug("Got %g, remaining: '%s'", numberd, next);
1436  break;
1437  case CPL_TYPE_FLOAT:
1438  numberf = strtod(value, &next); // C99: strtof(value, &next);
1439  uves_msg_debug("Got %g, remaining: '%s'", numberf, next);
1440  break;
1441  case CPL_TYPE_INT:
1442  numberi = strtol(value, &next, base);
1443  uves_msg_debug("Got %d, remaining: '%s'", numberi, next);
1444  break;
1445  default:
1446  passure(false, " ");
1447  }
1448  }
1449  } while (next != value);
1450  }
1451  }/* if numerical type */
1452 
1453  i++;
1454 
1455  assure( strcmp(value, "") == 0, CPL_ERROR_ILLEGAL_INPUT,
1456  "Cannot parse %s descriptor %s, remaining string: '%s'",
1457  uves_tostring_cpl_type(*type), name, value);
1458 
1459  /* Find out if we can continue parsing the next HISTORY keyword */
1460  if (i < plist_size)
1461  {
1462  p = uves_propertylist_get_const(plist, i);
1463  if (cpl_property_get_type(p) == CPL_TYPE_STRING &&
1464  strcmp(cpl_property_get_name(p), "HISTORY") == 0)
1465  {
1466  value = cpl_property_get_string(
1467  uves_propertylist_get_const(plist, i));
1468 
1469  if (*type == CPL_TYPE_STRING)
1470  {
1471  if (strcmp(value, "") != 0) {
1472  uves_msg_debug("String array %s with length > 1 found. Ignoring remaining values", name);
1473  while (strcmp(value, "") != 0 && i+1 < plist_size) {
1474  i++;
1475  p = uves_propertylist_get_const(plist, i);
1476  value = cpl_property_get_string(
1477  uves_propertylist_get_const(plist, i));
1478  if (ncards != NULL) *ncards += 1;
1479  }
1480  }
1481  }
1482  }
1483  }
1484 
1485  } while (strcmp(value, "") != 0);
1486 
1487  cleanup:
1488  if (cpl_error_get_code() != CPL_ERROR_NONE)
1489  {
1490  cpl_free(result); result = NULL;
1491  }
1492  return result;
1493 }
1494 
1495 
1496 /*----------------------------------------------------------------------------*/
1514 /*----------------------------------------------------------------------------*/
1515 cpl_error_code
1516 uves_save_table_local(const char *description, const char *filename_prefix,
1517  const cpl_table *table,
1518  enum uves_chip chip, int trace, int window,
1519  const uves_propertylist *pheader, const uves_propertylist *eheader)
1520 {
1521  char *filename = NULL;
1522 
1523  check( filename = uves_local_filename(filename_prefix, chip, trace, window),
1524  "Error getting filename");
1525 
1526  check( uves_table_save(table, pheader, eheader, filename, CPL_IO_DEFAULT),
1527  "Error saving table to file '%s'", filename);
1528 
1529  if (description != NULL) uves_msg("%s saved to '%s'", description, filename);
1530 
1531  cleanup:
1532  cpl_free(filename);
1533  return cpl_error_get_code();
1534 }
1535 
1536 /*----------------------------------------------------------------------------*/
1557 /*----------------------------------------------------------------------------*/
1558 cpl_error_code
1559 uves_save_image_local(const char *description, const char *filename_prefix,
1560  const cpl_image *image,
1561  enum uves_chip chip, int trace, int window,
1562  const uves_propertylist *plist,
1563  bool use_bitpix16_for_int)
1564 {
1565  char *filename = NULL;
1566 
1567  check( filename = uves_local_filename(filename_prefix, chip, trace, window),
1568  "Error getting filename");
1569 
1570  check( uves_save_image(image, filename, plist, use_bitpix16_for_int, true),
1571  "Error saving image to file '%s'", filename);
1572  if (description != NULL) uves_msg("%s saved to '%s'", description, filename);
1573 
1574  cleanup:
1575  cpl_free(filename);
1576  return cpl_error_get_code();
1577 }
1578 
1579 
1580 /*----------------------------------------------------------------------------*/
1590 /*----------------------------------------------------------------------------*/
1591 cpl_image *uves_load_image(const cpl_frame *f,
1592  int plane,
1593  int extension,
1594  uves_propertylist **header)
1595 {
1596  cpl_image *image = NULL;
1597  uves_propertylist *plist = NULL;
1598  const char *filename;
1599  int bitpix;
1600  cpl_type type;
1601  int naxis=0;
1602  cpl_vector * vector=NULL;
1603 
1604 
1605  assure_nomsg( f != NULL, CPL_ERROR_NULL_INPUT );
1606 
1607  assure( cpl_frame_get_type(f) == CPL_FRAME_TYPE_IMAGE,
1608  CPL_ERROR_TYPE_MISMATCH, "Wrong type: %s",
1609  uves_tostring_cpl_frame_type(cpl_frame_get_type(f)));
1610 
1611  filename = cpl_frame_get_filename(f);
1612 
1613  check( plist = uves_propertylist_load(filename, extension),
1614  "Could not load header from %s extension %d",
1615  filename, extension);
1616 
1617  check( bitpix = uves_pfits_get_bitpix(plist),
1618  "Could not read BITPIX from %s extension %d",
1619  filename, extension);
1620 
1621  if (bitpix == -32) type = CPL_TYPE_FLOAT;
1622  else if (bitpix == -64) type = CPL_TYPE_DOUBLE;
1623  else if (bitpix == 32) type = CPL_TYPE_INT;
1624  else if (bitpix == 16) type = CPL_TYPE_INT;
1625  else
1626  {
1627  assure( false, CPL_ERROR_UNSUPPORTED_MODE,
1628  "No CPL type to represent BITPIX = %d", bitpix);
1629  }
1630 
1631  check( naxis = uves_pfits_get_naxis(plist),
1632  "could not get NAXIS" );
1633 
1634  if( naxis == 1) {
1635 
1636  check( vector = cpl_vector_load(filename,extension),
1637  "Could not load vector from extension %d of file '%s' ",
1638  extension, filename);
1639  cknull(image=uves_vector_to_image(vector,type),
1640  "could not convert vector to image");
1641  } else {
1642 
1643 
1644  check( image = cpl_image_load(filename,
1645  type,
1646  plane,
1647  extension),
1648  "Could not load image from extension %d of file '%s' ",
1649  extension, filename);
1650 
1651  }
1652 
1653  if (header != NULL)
1654  {
1655  *header = uves_propertylist_duplicate(plist);
1656  }
1657 
1658  cleanup:
1659  uves_free_vector(&vector);
1660  uves_free_propertylist(&plist);
1661  return image;
1662 }
1663 /*----------------------------------------------------------------------------*/
1667 /*----------------------------------------------------------------------------*/
1668 
1669 cpl_image *uves_load_image_file(const char *filename,
1670  int plane,
1671  int extension,
1672  uves_propertylist **header)
1673 {
1674  cpl_image *i;
1675  cpl_frame *f = cpl_frame_new();
1676  cpl_frame_set_filename(f, filename);
1677  cpl_frame_set_type(f, CPL_FRAME_TYPE_IMAGE);
1678 
1679  i = uves_load_image(f, plane, extension, header);
1680 
1681  uves_free_frame(&f);
1682 
1683  return i;
1684 }
1685 
1686 /*----------------------------------------------------------------------------*/
1711 /*----------------------------------------------------------------------------*/
1712 void
1713 uves_save_image(const cpl_image *image, const char *filename, const uves_propertylist *plist,
1714  bool use_bitpix16_for_int, bool save1d)
1715 {
1716  cpl_type_bpp bpp;
1717  cpl_type t;
1718  const cpl_vector *image_1d = NULL;
1719  uves_propertylist *header = NULL;
1720  cpl_image *thresholded = NULL;
1721  cpl_image *thresholded_double = NULL;
1722 
1723  if (image == NULL) {
1724  check( uves_image_save(image, filename, CPL_BPP_IEEE_FLOAT, plist, CPL_IO_DEFAULT),
1725  "Error saving NULL image to file '%s'", filename);
1726  }
1727  else {
1728  check( t = cpl_image_get_type(image), "Error reading image type");
1729  if (t == CPL_TYPE_FLOAT ) bpp = CPL_BPP_IEEE_FLOAT;
1730  else if (t == CPL_TYPE_DOUBLE) bpp = CPL_BPP_IEEE_FLOAT;
1731  /* Internal computations in double precision,
1732  save as single precision */
1733 
1734  /* Some FLAMES images are BITPIX=16 (ORDEF),
1735  some are 32 SLIT_FF_COM_REDL
1736  */
1737  else if (t == CPL_TYPE_INT ) {
1738  if (use_bitpix16_for_int) bpp = CPL_BPP_16_UNSIGNED;
1739  else bpp = CPL_BPP_32_SIGNED;
1740  }
1741  else assure(false, CPL_ERROR_UNSUPPORTED_MODE,
1742  "Unsupported image type '%s'", uves_tostring_cpl_type(t));
1743 
1744 
1745  thresholded = cpl_image_duplicate(image);
1746  assure_mem( thresholded );
1747 
1748  if (t == CPL_TYPE_DOUBLE)
1749  {
1750  passure( bpp == CPL_BPP_IEEE_FLOAT, "%d", bpp);
1751 
1752  /* Avoid infinities that would happen when casting
1753  double -> float
1754  by thresholding the image to +-FLT_MAX (or, better
1755  a little less than FLT_MAX just to be sure).
1756 
1757  (This is not a really nice solution because it solves the
1758  problem (too large/small values) after it is introduced
1759  (rather than avoiding it), but a general solution of the
1760  problem would probably mean guarding every arithmetic
1761  operation with range checks.)
1762  */
1763 
1764  check_nomsg( cpl_image_threshold(thresholded,
1765  -FLT_MAX, FLT_MAX,
1766  -FLT_MAX, FLT_MAX) );
1767 
1768  /* Also get rid of NaN, set to zero (what else?) */
1769  {
1770  double *data = cpl_image_get_data_double(thresholded);
1771  int nx = cpl_image_get_size_x(thresholded);
1772  int ny = cpl_image_get_size_y(thresholded);
1773  int x, y;
1774 
1775  for (y = 0; y < ny; y++)
1776  for (x = 0; x < nx; x++)
1777  {
1778  if (irplib_isnan(data[x + y*nx]))
1779  {
1780  data[x + y*nx] = 0;
1781  }
1782  }
1783  }
1784  }
1785 
1786  if (save1d &&
1787  cpl_image_get_size_y(thresholded) == 1 &&
1788  (t == CPL_TYPE_DOUBLE ||
1789  t == CPL_TYPE_FLOAT)) {
1790 
1791  bool invert = false;
1792  if (plist != NULL)
1793  {
1794  header = uves_propertylist_duplicate(plist);
1795 
1796  uves_propertylist_erase_regexp(header, "^CDELT2$", invert);
1797  uves_propertylist_erase_regexp(header, "^CRPIX2$", invert);
1798  uves_propertylist_erase_regexp(header, "^CRVAL2$", invert);
1799  uves_propertylist_erase_regexp(header, "^CTYPE2$", invert);
1800  }
1801  else
1802  {
1803  header = NULL;
1804  }
1805 
1806  /* Image type must be double, before wrapping it
1807  in a vector */
1808  if (t == CPL_TYPE_FLOAT) {
1809  thresholded_double = cpl_image_cast(thresholded, CPL_TYPE_DOUBLE);
1810  }
1811  else {
1812  thresholded_double = cpl_image_duplicate(thresholded);
1813  }
1814 
1815  passure( cpl_image_get_type(thresholded_double) == CPL_TYPE_DOUBLE, "%d",
1816  cpl_image_get_type(thresholded_double));
1817 
1818  image_1d = cpl_vector_wrap(
1819  cpl_image_get_size_x(thresholded_double),
1820  cpl_image_get_data_double(thresholded_double));
1821 
1822  check( uves_vector_save(image_1d, filename, bpp, header, CPL_IO_DEFAULT),
1823  "Error saving vector to file '%s'", filename );
1824  }
1825  else
1826  {
1827  check( uves_image_save(thresholded, filename, bpp, plist, CPL_IO_DEFAULT),
1828  "Error saving image to file '%s'", filename);
1829  }
1830  }
1831 
1832  cleanup:
1833  uves_unwrap_vector_const(&image_1d);
1834  uves_free_propertylist(&header);
1835  uves_free_image(&thresholded);
1836  uves_free_image(&thresholded_double);
1837 
1838  return;
1839 }
1840 
1841 
1842 /*----------------------------------------------------------------------------*/
1862 /*----------------------------------------------------------------------------*/
1863 void
1864 uves_save_imagelist(const cpl_imagelist *iml, const char *filename, const uves_propertylist *plist)
1865 {
1866  const cpl_image* img=NULL;
1867  cpl_type_bpp bpp;
1868  cpl_type t;
1869  const cpl_vector *image_1d = NULL;
1870  uves_propertylist *header = NULL;
1871  cpl_imagelist *thresholded = NULL;
1872 
1873  int nx = 0;
1874  int ny = 0;
1875  int nz = 0;
1876 
1877 
1878  cknull(iml,"Null input image");
1879  check(img=cpl_imagelist_get_const(iml,0),"error reading image");
1880 
1881  check_nomsg( nx = cpl_image_get_size_x(img));
1882  check_nomsg( ny = cpl_image_get_size_y(img));
1883  check_nomsg( nz = cpl_imagelist_get_size(iml));
1884 
1885  check( t = cpl_image_get_type(img), "Error reading image type");
1886  if (t == CPL_TYPE_FLOAT ) bpp = CPL_BPP_IEEE_FLOAT;
1887  else if (t == CPL_TYPE_DOUBLE) bpp = CPL_BPP_IEEE_FLOAT;
1888  /* Internal computations in double precision,
1889  save as single precision */
1890  else if (t == CPL_TYPE_INT ) bpp = CPL_BPP_16_UNSIGNED;
1891  else assure(false, CPL_ERROR_UNSUPPORTED_MODE,
1892  "Unsupported image type '%s'", uves_tostring_cpl_type(t));
1893 
1894 
1895  thresholded = cpl_imagelist_duplicate(iml);
1896  assure_mem( thresholded );
1897 
1898  if (t == CPL_TYPE_DOUBLE)
1899  {
1900  passure( bpp == CPL_BPP_IEEE_FLOAT, "%d", bpp);
1901 
1902  /* Avoid infinities that would happen when casting
1903  double -> float
1904  by thresholding the image to +-FLT_MAX (or, better
1905  a little less than FLT_MAX just to be sure).
1906 
1907  (This is not a really nice solution because it solves the
1908  problem (too large/small values) after it is introduced
1909  (rather than avoiding it), but a general solution of the
1910  problem would probably mean guarding every arithmetic
1911  operation with range checks.)
1912  */
1913 
1914  check_nomsg( cpl_imagelist_threshold(thresholded,
1915  -FLT_MAX, FLT_MAX,
1916  -FLT_MAX, FLT_MAX) );
1917 
1918 
1919 
1920  /* Also get rid of NaN, set to zero (what else?) */
1921  {
1922  int x, y, z;
1923  double* data=NULL;
1924  cpl_image* ima=NULL;
1925  for (z = 0; z < nz; z++) {
1926  ima=cpl_imagelist_get(thresholded,z);
1927  data = cpl_image_get_data_double(ima);
1928 
1929  for (y = 0; y < ny; y++) {
1930  for (x = 0; x < nx; x++) {
1931  if (irplib_isnan(data[x + y*nx])) {
1932  data[x + y*nx] = 0;
1933  }
1934  }
1935  }
1936  }
1937  }
1938  }
1939  if (nz == 1 && t == CPL_TYPE_DOUBLE)
1940  /* To support other types (float, int) we would
1941  need to convert to double first */
1942  {
1943  bool invert = false;
1944  if (plist != NULL)
1945  {
1946  header = uves_propertylist_duplicate(plist);
1947 
1948  uves_propertylist_erase_regexp(header, "^CDELT3$", invert);
1949  uves_propertylist_erase_regexp(header, "^CRPIX3$", invert);
1950  uves_propertylist_erase_regexp(header, "^CRVAL3$", invert);
1951  uves_propertylist_erase_regexp(header, "^CTYPE3$", invert);
1952  }
1953  else
1954  {
1955  header = NULL;
1956  }
1957  /*
1958  image_1d = cpl_vector_wrap(nx,
1959  cpl_image_get_data_double_const(thresholded));
1960 
1961  check( uves_vector_save(image_1d, filename, bpp, header, CPL_IO_DEFAULT),
1962  "Error saving vector to file '%s'", filename );
1963  */
1964 
1965  }
1966  else
1967  {
1968  check( uves_imagelist_save(thresholded, filename, bpp, plist, CPL_IO_DEFAULT),
1969  "Error saving image to file '%s'", filename);
1970  }
1971 
1972  cleanup:
1973  uves_unwrap_vector_const(&image_1d);
1974  uves_free_propertylist(&header);
1975  uves_free_imagelist(&thresholded);
1976 
1977  return;
1978 }
1979 
1980 /*----------------------------------------------------------------------------*/
1994 /*----------------------------------------------------------------------------*/
1995 cpl_error_code
1996 uves_save_polynomial(polynomial *p, const char *filename, const uves_propertylist *header)
1997 {
1998  cpl_table *t = NULL;
1999 
2000  check( t = uves_polynomial_convert_to_table(p), "Error converting polynomial to table");
2001 
2002  check( uves_table_save(t,
2003  NULL, /* Primary header, ignored when
2004  mode = CPL_IO_EXTEND */
2005  header, /* Table header */
2006  filename,
2007  CPL_IO_EXTEND), /* Append to existing file */
2008  "Error saving table to file '%s'", filename);
2009 
2010  cleanup:
2011  uves_free_table(&t);
2012  return cpl_error_get_code();
2013 }
2014 
2015 
2016 /*----------------------------------------------------------------------------*/
2024 /*----------------------------------------------------------------------------*/
2025 static polynomial *
2026 load_polynomial(const char* filename, int extension)
2027 {
2028  polynomial *p = NULL; /* Result */
2029  cpl_table *t = NULL;
2030 
2031  check(t = cpl_table_load(filename,
2032  extension,
2033  1), /* Mark identified
2034  invalid null values (1=yes) */
2035  "Error loading polynomial from extension %d of file '%s'", extension, filename);
2036 
2037  assure( uves_erase_invalid_table_rows(t, NULL) == 0,
2038  CPL_ERROR_ILLEGAL_INPUT, "Table contains invalid rows");
2039 
2040  check(p = uves_polynomial_convert_from_table(t), "Error converting table to polynomial");
2041 
2042  cleanup:
2043  uves_free_table(&t);
2044  if (cpl_error_get_code() != CPL_ERROR_NONE)
2046  return p;
2047 }
2048 /*----------------------------------------------------------------------------*/
2063 /*----------------------------------------------------------------------------*/
2064 static const char *
2065 identify_arm(const cpl_frameset *frames, const char *blue_tag, const char *red_tag,
2066  bool *blue)
2067 {
2068  const char *tag = NULL; /* Result */
2069 
2070  const cpl_frame *frame = NULL;
2071 
2072  passure( frames != NULL, "");
2073  assure (!cpl_frameset_is_empty(frames), CPL_ERROR_ILLEGAL_INPUT, "No input frames");
2074 
2075  /* Identify blue/red arm */
2076  frame = cpl_frameset_find_const(frames, blue_tag);
2077  *blue = (frame != NULL);
2078 
2079  if (frame == NULL)
2080  {
2081  frame = cpl_frameset_find_const(frames, red_tag);
2082  }
2083 
2084  assure( frame != NULL, CPL_ERROR_ILLEGAL_INPUT,
2085  "No valid input frames "
2086  "('%s' or '%s') in frame set",
2087  blue_tag, red_tag);
2088 
2089  assure( cpl_frameset_find_const(frames, blue_tag) == NULL ||
2090  cpl_frameset_find_const(frames, red_tag) == NULL,
2091  CPL_ERROR_INCOMPATIBLE_INPUT,
2092  "Multiple types of input frames ('%s' and '%s') in frame set",
2093  blue_tag, red_tag);
2094 
2095  tag = cpl_frame_get_tag(frame);
2096 
2097  uves_msg("Input frames are '%s'", tag);
2098 
2099 
2100  cleanup:
2101  return tag;
2102 }
2103 
2104 /*----------------------------------------------------------------------------*/
2122 /*----------------------------------------------------------------------------*/
2123 cpl_image *
2124 uves_crop_and_rotate(const cpl_image *image, const uves_propertylist *header,
2125  enum uves_chip chip,
2126  const uves_propertylist *redl_header,
2127  bool new_format, uves_propertylist **out_header)
2128 {
2129  cpl_image *result = NULL;
2130  int prescanx, ovrscanx;
2131  cpl_size nx, ny;
2132  int x_0, y_0, x_1, y_1; /* Extracted area (inclusive) in
2133  FITS convention (i.e. counting from 1) */
2134 
2135  const char *ctype1, *ctype2; /* Geometry */
2136  const char *cunit1, *cunit2; /* Units */
2137  const char *bunit;
2138  double bscale=0;
2139  double crval1, crval2;
2140  double crpix1, crpix2;
2141  double cdelt1, cdelt2;
2142 
2143 
2144  passure( image != NULL, " ");
2145  passure( header != NULL, " ");
2146  passure( out_header != NULL, " ");
2147 
2148  nx = cpl_image_get_size_x(image);
2149  ny = cpl_image_get_size_y(image);
2150 
2151 
2152  /* Determine pre- and overscan areas */
2153  check( prescanx = uves_pfits_get_prescanx(header, chip), "Could not read x-prescan info" );
2154  check( ovrscanx = uves_pfits_get_ovrscanx(header, chip), "Could not read x-overscan info");
2155 
2156  /* Don't try to read the y pre- and overscan regions, which should be zero for UVES.
2157  The keywords are not present in older UVES data. */
2158 
2159  /* Read geometry */
2160  check( ctype1 = uves_pfits_get_ctype1(header), "Error reading keyword");
2161  check( ctype2 = uves_pfits_get_ctype2(header), "Error reading keyword");
2162  check( crval1 = uves_pfits_get_crval1(header), "Error reading keyword");
2163  check( crval2 = uves_pfits_get_crval2(header), "Error reading keyword");
2164  check( crpix1 = uves_pfits_get_crpix1(header), "Error reading keyword");
2165  check( crpix2 = uves_pfits_get_crpix2(header), "Error reading keyword");
2166  check( cdelt1 = uves_pfits_get_cdelt1(header), "Error reading keyword");
2167  check( cdelt2 = uves_pfits_get_cdelt2(header), "Error reading keyword");
2168  if (uves_propertylist_contains(header, UVES_BUNIT))
2169  {
2170  bunit = uves_pfits_get_bunit(header);
2171  }
2172  else
2173  {
2174  bunit = " ";
2175  }
2176  if (uves_propertylist_contains(header, UVES_BSCALE))
2177  {
2178  bscale = uves_pfits_get_bscale(header);
2179  }
2180  else
2181  {
2182  bscale = 0;
2183  }
2184 
2185  if (uves_propertylist_contains(header, UVES_CUNIT1))
2186  {
2187  cunit1 = uves_pfits_get_cunit1(header);
2188  }
2189  else
2190  {
2191  cunit1 = " ";
2192  }
2193  if (uves_propertylist_contains(header, UVES_CUNIT2))
2194  {
2195  cunit2 = uves_pfits_get_cunit2(header);
2196  }
2197  else
2198  {
2199  cunit2 = " ";
2200  }
2201 
2202 
2203  /* Crop the image */
2204  {
2205  y_0 = 1;
2206  y_1 = ny;
2207  if (new_format || chip == UVES_CHIP_BLUE)
2208  {
2209  x_0 = prescanx + 1;
2210  x_1 = nx - ovrscanx;
2211  }
2212  else /* red, old format */
2213  {
2214  if (chip == UVES_CHIP_REDU)
2215  {
2216  x_0 = prescanx + 1;
2217  x_1 = nx/2 - ovrscanx;
2218  }
2219  else
2220  { /* lower */
2221  x_0 = nx/2 + prescanx + 1;
2222  x_1 = nx - ovrscanx;
2223  }
2224  }
2225  check( result = cpl_image_extract(image, x_0, y_0, x_1, y_1), "Could not crop image");
2226  crpix1 = crpix1 - (x_0 - 1);
2227  crpix2 = crpix2 - (y_0 - 1);
2228  nx = (x_1 - x_0) + 1;
2229  ny = (y_1 - y_0) + 1;
2230  }
2231 
2232  UVES_TIME_START("Rotation");
2233  /* ... is a bit slow, and there's probably nothing to
2234  do about as it involves moving data between remote
2235  places in memory.
2236  */
2237 
2238  /* Rotate the image into standard orientation */
2239  {
2240  int crpix1_old = crpix1;
2241  int crpix2_old = crpix2;
2242  int crval1_old = crval1;
2243  int crval2_old = crval2;
2244  int cdelt1_old = cdelt1;
2245  int cdelt2_old = cdelt2;
2246  const char *ctype1_old = ctype1;
2247  const char *ctype2_old = ctype2;
2248 
2249  if (chip == UVES_CHIP_BLUE)
2250  {
2251  /* 90 deg counterclockwise rotation */
2252  check( cpl_image_turn(result, -1), "Could not turn image");
2253 
2254  crpix1 = ny - (crpix2_old - 1); /* Note: old value of ny */
2255  crpix2 = crpix1_old;
2256  crval1 = crval2_old;
2257  crval2 = crval1_old;
2258  }
2259  else
2260  {
2261  /* Red */
2262  /* Flip image around y=-x */
2263  check( cpl_image_flip(result, 3), "Could not flip image");
2264 
2265  crpix1 = ny - (crpix2_old - 1); /* Note: old value of nx, ny */
2266  crpix2 = nx - (crpix1_old - 1);
2267  crval1 = crval2_old;
2268  crval2 = crval1_old;
2269  }
2270 
2271 
2272  /* Always swap these ones */
2273  ctype1 = ctype2_old;
2274  ctype2 = ctype1_old;
2275  cdelt1 = cdelt2_old;
2276  cdelt2 = cdelt1_old;
2277  }
2278 
2279  UVES_TIME_END;
2280 
2281  /* Here we should use the CROTAi keywords to
2282  properly describe the new rotation */
2283 
2284  /* Instead, redefine CRVAL as in the following, on request from DFO */
2285 
2286  crpix1 = 1;
2287  crpix2 = 1;
2288  if (chip == UVES_CHIP_BLUE || chip == UVES_CHIP_REDL)
2289  {
2290  crval1 = 1;
2291  crval2 = 1;
2292  }
2293  else
2294  {
2295  int physical_gap_between_chips = 64; /* Pixels. Unbinned. Hardcoded. */
2296 
2297 
2298  passure( chip == UVES_CHIP_REDU , "%d", chip );
2299 
2300  crval1 = 1;
2301 
2302  /* Set CRVAL2 = REDL_height - REDL_overscan - REDL_prescan + gap. */
2303  if (new_format)
2304  {
2305 
2306  check( crval2 = 1 +
2307  (uves_pfits_get_naxis1(redl_header) -
2308  uves_pfits_get_ovrscanx(redl_header, UVES_CHIP_REDL) -
2309  uves_pfits_get_prescanx(redl_header, UVES_CHIP_REDL)) *
2310  uves_pfits_get_cdelt1(redl_header) +
2311  physical_gap_between_chips,
2312  "Error reading REDL chip geometry");
2313 
2314  uves_msg_debug("Setting CRVAL2 = 1 + (%d - %d - %d) * %f + %d = %f",
2315  uves_pfits_get_naxis1(redl_header),
2316  uves_pfits_get_ovrscanx(redl_header, UVES_CHIP_REDL),
2317  uves_pfits_get_prescanx(redl_header, UVES_CHIP_REDL),
2318  uves_pfits_get_cdelt1(redl_header),
2319  physical_gap_between_chips, crval2);
2320  }
2321  else
2322  {
2323 
2324  /* old format */
2325  check( crval2 = 1 +
2326  (uves_pfits_get_naxis1(header)/2 -
2327  uves_pfits_get_ovrscanx(redl_header, UVES_CHIP_REDL) -
2328  uves_pfits_get_prescanx(redl_header, UVES_CHIP_REDL)) *
2329  uves_pfits_get_cdelt1(redl_header) +
2330  physical_gap_between_chips,
2331  "Error reading REDL chip geometry");
2332 
2333  uves_msg_debug("Setting CRVAL2 = 1 + (%d - %d - %d) * %f + %d = %f",
2334  uves_pfits_get_naxis1(header)/2,
2335  uves_pfits_get_ovrscanx(redl_header, UVES_CHIP_REDL),
2336  uves_pfits_get_prescanx(redl_header, UVES_CHIP_REDL),
2337  uves_pfits_get_cdelt1(redl_header),
2338  physical_gap_between_chips, crval2);
2339  }
2340 
2341  }
2342 
2343 
2344  /* Update header with new geometry */
2345  check( *out_header = uves_initialize_image_header(ctype1, ctype2,
2346  cunit1, cunit2,
2347  bunit,bscale,
2348  crval1, crval2,
2349  crpix1, crpix2,
2350  cdelt1, cdelt2),
2351  "Error initializing header");
2352 
2353  //check(uves_propertylist_copy_property_regexp(*out_header, header,
2354  // "^ESO ", 0),
2355  // "Error copying hieararch keys");
2356 
2357 
2358  uves_msg("Raw image cropped and rotated from %" CPL_SIZE_FORMAT "x%" CPL_SIZE_FORMAT " to %" CPL_SIZE_FORMAT "x%" CPL_SIZE_FORMAT "",
2359  nx, ny,
2360  cpl_image_get_size_x(result),
2361  cpl_image_get_size_y(result));
2362 
2363  cleanup:
2364  if (cpl_error_get_code() != CPL_ERROR_NONE)
2365  {
2366  uves_free_image(&result);
2367  if (out_header != NULL)
2368  {
2369  uves_free_propertylist(out_header);
2370  }
2371  }
2372 
2373  return result;
2374 }
2375 
2376 /*----------------------------------------------------------------------------*/
2390 /*----------------------------------------------------------------------------*/
2391 void
2392 uves_warn_if_chip_names_dont_match(const uves_propertylist *calib_header,
2393  const char *raw_chip_name, enum uves_chip chip)
2394 {
2395  const char *calib_chip_name;
2396  bool mismatch = false;
2397 
2398  check( calib_chip_name = uves_pfits_get_chipid(calib_header, chip),
2399  "Could not read chip name of calibration data");
2400 
2401 
2402  /* Ignore leading/trailing blanks when comparing name strings.
2403  * (The following is O(n^2) where n is the string length,
2404  * but that's ok because the strings stored in a FITS card are short).
2405  */
2406  {
2407  unsigned int calib_first, calib_last; /* inclusive */
2408  unsigned int raw_first, raw_last;
2409 
2410  calib_first = 0;
2411  raw_first = 0;
2412  while (calib_chip_name[calib_first] == ' ' && calib_first < strlen(calib_chip_name) - 1)
2413  {
2414  calib_first++;
2415  }
2416  while (raw_chip_name[raw_first] == ' ' && raw_first < strlen(raw_chip_name) - 1)
2417  {
2418  raw_first++;
2419  }
2420 
2421  calib_last = strlen(calib_chip_name) - 1;
2422  raw_last = strlen(raw_chip_name) - 1;
2423  while (calib_chip_name[calib_last] == ' ' && calib_last > 0)
2424  {
2425  calib_last--;
2426  }
2427  while (raw_chip_name[raw_last] == ' ' && raw_last > 0)
2428  {
2429  raw_last--;
2430  }
2431 
2432  /* Compare substrings */
2433  if (calib_last - calib_first != raw_last - raw_first)
2434  {
2435  mismatch = true;
2436  }
2437  else
2438  {
2439  unsigned int i;
2440 
2441  for (i = 0; i <= (calib_last - calib_first); i++)
2442  {
2443  if (raw_chip_name[raw_first + i] !=
2444  calib_chip_name[calib_first + i])
2445  {
2446  mismatch = true;
2447  }
2448  }
2449  }
2450  }
2451 
2452 
2453  if (mismatch)
2454  {
2455  uves_msg_warning("Calibration frame chip ID '%s' does "
2456  "not match raw frame chip ID '%s'",
2457  calib_chip_name, raw_chip_name);
2458  }
2459 
2460  cleanup:
2461  return;
2462 }
2463 
2464 
2465 /*----------------------------------------------------------------------------*/
2487 /*----------------------------------------------------------------------------*/
2488 
2489 static cpl_error_code
2490 load_raw_image(const char *filename,
2491  cpl_type type,
2492  bool flames,
2493  bool blue,
2494  cpl_image *raw_image[2],
2495  uves_propertylist *raw_header[2],
2496  uves_propertylist *rotated_header[2])
2497 {
2498 
2499 
2500  cpl_image *image = NULL;
2501  uves_propertylist *primary_header = NULL;
2502  uves_propertylist *ext_header = NULL;
2503  int extension, nextensions;
2504  bool new_format;
2505  int plane = 0; /* Only one plane in FLAMES/UVES raw files */
2506 
2507  cpl_image* image1=NULL;
2508  cpl_image* image2=NULL;
2509  int sx=0;
2510  int sy=0;
2511 
2512 
2513  /* Initialize parameters */
2514  raw_image[0] = NULL;
2515  raw_image[1] = NULL;
2516  raw_header[0] = NULL;
2517  raw_header[1] = NULL;
2518  rotated_header[0] = NULL;
2519  rotated_header[1] = NULL;
2520 
2521  check( nextensions = uves_get_nextensions(filename),
2522  "Error reading number of extensions of file '%s'", filename);
2523 
2524  /* Find out if new/old format */
2525  extension = 0;
2526  check( primary_header = uves_propertylist_load(filename,
2527  extension),
2528  "Could not load header from extension %d of file '%s'",
2529  extension, filename);
2530 
2531  check( new_format = uves_format_is_new(primary_header),
2532  "Error determining new/old format of file %s", filename);
2533 
2534  uves_msg_low("Raw frame is %s, %s format, file '%s' has %d extensions",
2535  (blue) ? "blue" : "red", (new_format) ? "new" : "old",
2536  filename, nextensions);
2537 
2538  /* If the raw frame is blue, or if it's an old format red frame */
2539  if (blue || !new_format)
2540  {
2541  enum uves_chip chip;
2542 
2543  uves_msg_debug("Frame is blue or old format");
2544 
2545  assure( nextensions == 0 ||
2546  (blue && nextensions == 2) ||
2547  (flames && nextensions == 2),
2548  CPL_ERROR_ILLEGAL_INPUT,
2549  "Unrecognized format of file '%s'. %d extensions expected. %d found.",
2550  filename,
2551  ((flames||blue) && (nextensions ==2)) ? 2 : 0, nextensions);
2552 
2553  /* FLAMES: the 2 extensions contain OzPoz table and FLAMES FIBRE table */
2554 
2555  /* Load the header */
2556  check( raw_header[0] = uves_propertylist_load(filename,
2557  extension),
2558  "Could not load header from extension %d of file '%s'",
2559  extension, filename);
2560 
2561 
2562  extension = 0;
2563  if(blue && nextensions == 2) {
2564  extension = 1;
2565  check( raw_header[1] = uves_propertylist_load(filename,
2566  extension),
2567  "Could not load header from extension %d of file '%s'",
2568  extension, filename);
2569  check( uves_propertylist_append(raw_header[0],raw_header[1]),
2570  "Could not collate header from extension 1 to 0 of file '%s'",filename);
2571  uves_free_propertylist(&raw_header[1]);
2572 
2573  check( image1 = cpl_image_load(filename,
2574  type,
2575  plane,
2576  extension
2577  ), "Could not load image from extension %d of file '%s' ",
2578  extension, filename);
2579  cpl_image_save(image1, "ima1.fits", CPL_BPP_IEEE_FLOAT,
2580  NULL,CPL_IO_DEFAULT);
2581 
2582  extension = 2;
2583  check( image2 = cpl_image_load(filename,
2584  type,
2585  plane,
2586  extension
2587  ), "Could not load image from extension %d of file '%s' ",
2588  extension, filename);
2589  check_nomsg(sx=cpl_image_get_size_x(image1));
2590  check_nomsg(sy=cpl_image_get_size_y(image1));
2591 
2592  check_nomsg(image=cpl_image_new(2*sx,sy,type));
2593  check_nomsg(cpl_image_copy(image,image1,1,1));
2594  check_nomsg(cpl_image_copy(image,image2,1+sx,1));
2595 
2596 
2597  uves_free_image(&image1);
2598  uves_free_image(&image2);
2599 
2600  extension = 1;
2601 
2602 
2603 
2604  } else {
2605 
2606 
2607  check( image = cpl_image_load(filename,
2608  type,
2609  plane,
2610  extension
2611  ), "Could not load image from extension %d of file '%s' ",
2612  extension, filename);
2613  }
2614 
2615  /* Get blue (or lower red) chip */
2616  chip = (blue) ? UVES_CHIP_BLUE : UVES_CHIP_REDL;
2617  check( raw_image[0] = uves_crop_and_rotate(image, raw_header[0],
2618  chip, raw_header[0],
2619  new_format,
2620  &rotated_header[0]),
2621  "Error splitting image");
2622 
2623  if (!blue)
2624  {
2625  const uves_propertylist *redl_header;
2626 
2627  /* Upper red chip, use again the primary header */
2628  check( raw_header[1] = uves_propertylist_duplicate(raw_header[0]),
2629  "Error duplicating FITS header");
2630 
2631  /* Get upper red chip */
2632  chip = UVES_CHIP_REDU;
2633  redl_header = raw_header[0];
2634  check( raw_image[1] = uves_crop_and_rotate(image, raw_header[1],
2635  chip, redl_header,
2636  new_format,
2637  &rotated_header[1]),
2638  "Error splitting red image");
2639  }
2640  else
2641  {
2642  raw_image[1] = NULL;
2643  raw_header[1] = NULL;
2644  rotated_header[1] = NULL;
2645  }
2646  }
2647  else
2648  /* New red format. UVES must have 2 extensions,
2649  * FLAMES must have 2 or more extensions
2650  */
2651  {
2652  uves_msg_debug("Frame is red, new format");
2653 
2654  assure( nextensions >= 2, CPL_ERROR_UNSUPPORTED_MODE,
2655  "File '%s' (red frame) has %d extensions. 2+ extensions expected "
2656  "for new format",
2657  filename, nextensions);
2658 
2659  uves_msg_debug("New red format, %s frame",
2660  (nextensions > 2) ? "FLAMES" : "FLAMES/UVES");
2661 
2662 
2663  /* Images always in extension 1 and 2. First load just the headers */
2664  for (extension = 1; extension <= 2; extension++)
2665  {
2666  /* In the FITS file, REDU is stored
2667  in extension 1, and REDL is stored in
2668  extension 2 */
2669  enum uves_chip chip = (extension == 1) ? UVES_CHIP_REDU : UVES_CHIP_REDL;
2670  int indx = uves_chip_get_index(chip);
2671 
2672  /* Load the extension header */
2673  uves_free_propertylist(&ext_header);
2674  check( ext_header = uves_propertylist_load(filename,
2675  extension),
2676  "Could not load header from extension %d of file '%s'",
2677  extension, filename);
2678 
2679  /* Merge with primary header */
2680  check( raw_header[indx] = uves_propertylist_duplicate(primary_header),
2681  "Error cloning primary header");
2682 
2683  if (!uves_propertylist_is_empty(ext_header))
2684  {
2686  ext_header, ".*", 0),
2687  "Error merging primary header with extension %d header",
2688  extension);
2689  }
2690  }
2691 
2692 
2693  /* Remove pre-, overscan areas (we needed to load both image headers for this) */
2694  for (extension = 1; extension <= 2; extension++)
2695  {
2696  enum uves_chip chip = (extension == 1) ? UVES_CHIP_REDU : UVES_CHIP_REDL;
2697  int indx = uves_chip_get_index(chip);
2698  int indx_redl = uves_chip_get_index(UVES_CHIP_REDL);
2699 
2700  const uves_propertylist *redl_header = raw_header[indx_redl];
2701 
2702  uves_free_image(&image);
2703  check( image = cpl_image_load(filename,
2704  type,
2705  plane,
2706  extension),
2707  "Could not load image from extension %d of file '%s' ",
2708  extension, filename);
2709 
2710  check( raw_image[indx] = uves_crop_and_rotate(image,
2711  raw_header[indx],
2712  chip, redl_header,
2713  new_format,
2714  &rotated_header[indx]),
2715  "Error splitting red image");
2716  }
2717 
2718 
2719  }/* if new format */
2720 
2721 
2722  cleanup:
2723  uves_free_image(&image);
2724  uves_free_image(&image1);
2725  uves_free_image(&image2);
2726 
2727  uves_free_propertylist(&primary_header);
2728  uves_free_propertylist(&ext_header);
2729 
2730  if (cpl_error_get_code() != CPL_ERROR_NONE)
2731  {
2732  uves_free_image (&raw_image[0]);
2733  uves_free_image (&raw_image[1]);
2734  uves_free_propertylist(&raw_header[0]);
2735  uves_free_propertylist(&raw_header[1]);
2736  uves_free_propertylist(&rotated_header[0]);
2737  uves_free_propertylist(&rotated_header[1]);
2738  }
2739 
2740  return cpl_error_get_code();
2741 }
2742 
2743 
2744 /*----------------------------------------------------------------------------*/
2772 /*----------------------------------------------------------------------------*/
2773 cpl_error_code
2774 uves_load_raw_imagelist(const cpl_frameset *frames,
2775  bool flames,
2776  const char *blue_tag, const char *red_tag, cpl_type type,
2777  cpl_imagelist *images[2],
2778  uves_propertylist **raw_headers[2], uves_propertylist *rotated_header[2],
2779  bool *blue)
2780 {
2781  const char *tag = NULL;
2782  const cpl_frame *frame = NULL;
2783  cpl_image *temp_image[2] = {NULL, NULL};
2784  uves_propertylist *temp_header[2] = {NULL, NULL};
2785  cpl_size number_of_frames = 0;
2786  int frameset_size = 0; /* Keeps track of number of raw_header pointers allocated */
2787  int nchips;
2788  int chip;
2789 
2790  raw_headers[0] = NULL;
2791  raw_headers[1] = NULL;
2792 
2793  check( frameset_size = cpl_frameset_get_size(frames),
2794  "Error reading frameset size");
2795 
2796  check( tag = identify_arm(frames, blue_tag, red_tag, blue),
2797  "Could not identify chip type");
2798 
2799  nchips = (*blue) ? 1 : 2;
2800  for(chip = 0; chip < nchips; chip++)
2801  {
2802  images[chip] = NULL;
2803  rotated_header[chip] = NULL;
2804 
2805  images[chip] = cpl_imagelist_new();
2806  raw_headers[chip] = cpl_calloc(frameset_size, sizeof(uves_propertylist *));
2807  }
2808 
2809  /* Load all input images with correct tag,
2810  split,
2811  insert into image list(s) */
2812 
2813  number_of_frames = 0;
2814  for(frame = cpl_frameset_get_first_const(frames);
2815  frame != NULL;
2816  frame = cpl_frameset_get_next_const(frames))
2817  {
2818  /* If match */
2819  if ( strcmp(cpl_frame_get_tag(frame), tag) == 0)
2820  {
2821  const char *filename = cpl_frame_get_filename(frame);
2822 
2823  /* Load image + header */
2824  uves_free_propertylist(&rotated_header[0]);
2825  uves_free_propertylist(&rotated_header[1]);
2826 
2827  check( load_raw_image(filename,
2828  type,
2829  flames,
2830  *blue,
2831  temp_image,
2832  temp_header,
2833  rotated_header),
2834  "Could not load image from file '%s'", filename);
2835 
2836  /* Append to image lists */
2837  for(chip = 0; chip < nchips; chip++)
2838  {
2839  raw_headers[chip][number_of_frames] = temp_header[chip];
2840  temp_header[chip] = NULL;
2841 
2842  check( cpl_imagelist_set(images[chip],
2843  temp_image[chip],
2844  /* Position */
2845  cpl_imagelist_get_size(images[chip])
2846  ),
2847  "Could not insert image into image list");
2848 
2849  /* Don't deallocate image or header */
2850  temp_image[chip] = NULL;
2851  }
2852 
2853  number_of_frames += 1;
2854  }
2855  }
2856 
2857  /* Check that image sizes are identical */
2858 
2859  for(chip = 0; chip < nchips; chip++)
2860  {
2861  /* This function returns zero iff the list is uniform */
2862  assure (cpl_imagelist_is_uniform(images[chip]) == 0,
2863  CPL_ERROR_INCOMPATIBLE_INPUT,
2864  "Input images are not of same size and type");
2865 
2866  passure( cpl_imagelist_get_size(images[chip]) == number_of_frames,
2867  "%" CPL_SIZE_FORMAT " %" CPL_SIZE_FORMAT"", cpl_imagelist_get_size(images[0]), number_of_frames);
2868 
2869  }
2870 
2871 
2872  /* Check central wavelengths (not bias/dark) */
2873  if ( strcmp(UVES_BIAS (*blue), tag) != 0 &&
2874  strcmp(UVES_DARK (*blue), tag) != 0 &&
2875  strcmp(UVES_PDARK(*blue), tag) != 0) {
2876  enum uves_chip chip_id;
2877  int i;
2878  double wlen = 0;
2879 
2880  for (chip_id = uves_chip_get_first(*blue);
2881  chip_id != UVES_CHIP_INVALID;
2882  chip_id = uves_chip_get_next(chip_id)) {
2883  for (i = 0; i < number_of_frames; i++) {
2884  if (i == 0) {
2886  raw_headers[uves_chip_get_index(chip_id)][i], chip_id),
2887  "Error reading central wavelength of input frame number %d", i+1);
2888  }
2889  else {
2890  double w;
2891 
2893  raw_headers[uves_chip_get_index(chip_id)][i], chip_id),
2894  "Error reading central wavelength of input frame number %d", i+1);
2895 
2896  assure( fabs((w-wlen)/wlen) < 0.01, CPL_ERROR_INCOMPATIBLE_INPUT,
2897  "Mis-matching input frame central wavelengths: "
2898  "%e (frame 1) != %e (frame %d)", wlen, w, i+1);
2899  }
2900  }
2901  }
2902  }
2903 
2904  cleanup:
2905  uves_free_image(&temp_image[0]);
2906  uves_free_image(&temp_image[1]);
2907  uves_free_propertylist(&temp_header[0]);
2908  uves_free_propertylist(&temp_header[1]);
2909 
2910  if (cpl_error_get_code() != CPL_ERROR_NONE) {
2911  if (raw_headers[0] != NULL) {
2912  int i;
2913  for (i = 0; i < frameset_size; i++) {
2914  if (raw_headers[0] != NULL) uves_free_propertylist(&raw_headers[0][i]);
2915  if (raw_headers[1] != NULL) uves_free_propertylist(&raw_headers[1][i]);
2916  }
2917  }
2918  cpl_free(raw_headers[0]); raw_headers[0] = NULL;
2919  cpl_free(raw_headers[1]); raw_headers[1] = NULL;
2920 
2921  uves_free_imagelist(&images[0]);
2922  uves_free_imagelist(&images[1]);
2923 
2924  uves_free_propertylist(&rotated_header[0]);
2925  uves_free_propertylist(&rotated_header[1]);
2926  }
2927 
2928  return cpl_error_get_code();
2929 }
2930 
2931 
2932 /*----------------------------------------------------------------------------*/
2949 /*----------------------------------------------------------------------------*/
2950 cpl_error_code
2951 uves_load_orderpos(const cpl_frameset *frames,
2952  bool flames,
2953  const char **raw_filename,
2954  cpl_image *raw_image[2],
2955  uves_propertylist *raw_header[2],
2956  uves_propertylist *rotated_header[2], bool *blue)
2957 {
2958  const char *tags[4];
2959 
2960  int number_of_tags = sizeof(tags) / sizeof(char *);
2961  int indx;
2962 
2963  /* Warning: Duplicate logic. The number of tags must match the size of the
2964  tags array defined above */
2965  tags[0] = UVES_ORDER_FLAT(flames, false); /* red */
2966  tags[1] = UVES_ORDER_FLAT(flames, true); /* blue */
2967  tags[2] = UVES_STD_STAR(false);
2968  tags[3] = UVES_STD_STAR(true);
2969 
2970  if (flames)
2971  {
2972  *blue = false;
2973  number_of_tags = 1;
2974 
2975  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx,
2976  NULL),
2977  "Could not find raw frame (%s) in SOF",
2978  tags[0]);
2979 
2980  }
2981  else
2982  {
2983  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx,
2984  NULL),
2985  "Could not find raw frame (%s, %s, %s, or %s) in SOF",
2986  tags[0], tags[1], tags[2], tags[3]);
2987 
2988  *blue = (indx == 1) || (indx == 3);
2989  }
2990 
2991  /* Load the image */
2992  check( load_raw_image(*raw_filename,
2993  CPL_TYPE_DOUBLE,
2994  flames,
2995  *blue,
2996  raw_image,
2997  raw_header,
2998  rotated_header),
2999  "Error loading image from file '%s'", *raw_filename);
3000 
3001  passure( !flames || !(*blue), "%d %d",
3002  flames, *blue );
3003 
3004  cleanup:
3005  if (cpl_error_get_code() != CPL_ERROR_NONE)
3006  {
3007  *raw_filename = NULL;
3008  }
3009 
3010  return cpl_error_get_code();
3011 }
3012 
3013 /*----------------------------------------------------------------------------*/
3029 /*----------------------------------------------------------------------------*/
3030 cpl_error_code
3031 uves_load_formatcheck(const cpl_frameset *frames,
3032  bool flames,
3033  const char **raw_filename,
3034  cpl_image *raw_image[2],
3035  uves_propertylist *raw_header[2],
3036  uves_propertylist *rotated_header[2], bool *blue)
3037 {
3038  const char *tags[2];
3039  int number_of_tags = sizeof(tags) / sizeof(char *);
3040  int indx;
3041 
3042  tags[0] = UVES_FORMATCHECK(flames, false); /* red */
3043  tags[1] = UVES_FORMATCHECK(flames, true); /* blue */
3044  if (flames)
3045  {
3046  *blue = false;
3047  number_of_tags = 1;
3048 
3049  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3050  "Could not find raw frame (%s) in SOF",
3051  tags[0]);
3052  }
3053  else
3054  {
3055  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3056  "Could not find raw frame (%s or %s) in SOF",
3057  tags[0], tags[1]);
3058 
3059  *blue = (indx == 1);
3060  }
3061 
3062  /* Load the image */
3063  check( load_raw_image(*raw_filename,
3064  CPL_TYPE_DOUBLE,
3065  flames,
3066  *blue,
3067  raw_image,
3068  raw_header,
3069  rotated_header),
3070  "Error loading image from file '%s'", *raw_filename);
3071 
3072  cleanup:
3073  if (cpl_error_get_code() != CPL_ERROR_NONE)
3074  {
3075  *raw_filename = NULL;
3076  }
3077  return cpl_error_get_code();
3078 }
3079 
3080 /*----------------------------------------------------------------------------*/
3099 /*----------------------------------------------------------------------------*/
3100 void uves_load_cd_align(const cpl_frameset *frames,
3101  const char **raw_filename1,
3102  const char **raw_filename2,
3103  cpl_image *raw_image1[2],
3104  cpl_image *raw_image2[2],
3105  uves_propertylist *raw_header1[2],
3106  uves_propertylist *raw_header2[2],
3107  uves_propertylist *rotated_header1[2],
3108  uves_propertylist *rotated_header2[2],
3109  bool *blue)
3110 {
3111  const char *tags[2];
3112  int number_of_tags = sizeof(tags) / sizeof(char *);
3113  int indx;
3114  bool flames = false;
3115  const cpl_frame *frame;
3116 
3117  tags[0] = UVES_CD_ALIGN(false); /* red */
3118  tags[1] = UVES_CD_ALIGN(true); /* blue */
3119 
3120  check( *raw_filename1 = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3121  "Could not find raw frame (%s or %s) in SOF",
3122  tags[0], tags[1]);
3123 
3124  *blue = (indx == 1);
3125 
3126  assure( cpl_frameset_count_tags(frames, tags[indx]) == 2,
3127  CPL_ERROR_ILLEGAL_INPUT,
3128  "%d %s frames found. Exactly 2 required",
3129  cpl_frameset_count_tags(frames, tags[indx]), tags[indx] );
3130 
3131  /* Load the two frames */
3132  {
3133  int n = 1;
3134  for (frame = cpl_frameset_get_first_const(frames);
3135  frame != NULL;
3136  frame = cpl_frameset_get_next_const(frames))
3137  {
3138  if (strcmp(cpl_frame_get_tag(frame), tags[indx]) == 0)
3139  {
3140  if (n == 1)
3141  {
3142  *raw_filename1 = cpl_frame_get_filename(frame);
3143  }
3144  else
3145  {
3146  *raw_filename2 = cpl_frame_get_filename(frame);
3147  }
3148 
3149  check( load_raw_image(n == 1 ?
3150  *raw_filename1 :
3151  *raw_filename2,
3152  CPL_TYPE_DOUBLE,
3153  flames,
3154  *blue,
3155  n == 1 ?
3156  raw_image1 :
3157  raw_image2,
3158  n == 1 ?
3159  raw_header1 :
3160  raw_header2,
3161  n == 1 ?
3162  rotated_header1 :
3163  rotated_header2),
3164  "Error loading image from file '%s'",
3165  n == 1 ? *raw_filename1 : *raw_filename2);
3166 
3167  n++;
3168  }
3169  }
3170  }
3171 
3172  cleanup:
3173  if (cpl_error_get_code() != CPL_ERROR_NONE)
3174  {
3175  *raw_filename1 = NULL;
3176  *raw_filename2 = NULL;
3177  }
3178 
3179  return;
3180 }
3181 
3182 
3183 /*----------------------------------------------------------------------------*/
3204 /*----------------------------------------------------------------------------*/
3205 void
3206 uves_load_arclamp(const cpl_frameset *frames,
3207  bool flames,
3208  const char **raw_filename,
3209  cpl_image *raw_image[2], uves_propertylist *raw_header[2],
3210  uves_propertylist *rotated_header[2], bool *blue,
3211  bool *sim_cal)
3212 {
3213  const char *tags[4];
3214 
3215  int number_of_tags = sizeof(tags) / sizeof(char *);
3216  int indx;
3217 
3218  /* Warning: duplicate logic. Array size above must match */
3219  if (flames)
3220  {
3221  assure_nomsg( sim_cal != NULL, CPL_ERROR_NULL_INPUT );
3222 
3223  tags[0] = UVES_ARC_LAMP(flames, true); /* blue flag not used */
3224  tags[1] = FLAMES_FIB_SCI_SIM;
3225 
3226  number_of_tags = 2;
3227  *blue = false;
3228 
3229  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3230  "Could not find raw frame (%s or %s) in SOF",
3231  tags[0], tags[1]);
3232 
3233  *sim_cal = (indx == 1);
3234  }
3235  else
3236  {
3237  tags[0] = UVES_ARC_LAMP(flames, true);
3238  tags[1] = UVES_ARC_LAMP(flames, false);
3239  tags[2] = UVES_ECH_ARC_LAMP(true);
3240  tags[3] = UVES_ECH_ARC_LAMP(false);
3241 
3242  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3243  "Could not find raw frame (%s, %s, %s or %s) in SOF",
3244  tags[0], tags[1], tags[2], tags[3]);
3245 
3246  *blue = (indx == 0 || indx == 2);
3247  }
3248 
3249  /* Load the image */
3250  check( load_raw_image(*raw_filename,
3251  CPL_TYPE_DOUBLE,
3252  flames,
3253  *blue,
3254  raw_image,
3255  raw_header,
3256  rotated_header),
3257  "Error loading image from file '%s'", *raw_filename);
3258 
3259  cleanup:
3260  if (cpl_error_get_code() != CPL_ERROR_NONE) {
3261  *raw_filename = NULL;
3262  uves_free_image (raw_image);
3263  uves_free_propertylist(raw_header);
3264  }
3265  return;
3266 }
3267 
3268 /*----------------------------------------------------------------------------*/
3283 /*----------------------------------------------------------------------------*/
3284 cpl_error_code
3285 uves_load_science(const cpl_frameset *frames, const char **raw_filename,
3286  cpl_image *raw_image[2],
3287  uves_propertylist *raw_header[2],
3288  uves_propertylist *rotated_header[2],
3289  bool *blue,
3290  const char **sci_type)
3291 {
3292  /* Note: the two following arrays must match */
3293  const char *tags[] =
3294  {
3295  UVES_SCIENCE(true), UVES_SCIENCE(false),
3296  UVES_SCI_EXTND(true), UVES_SCI_EXTND(false),
3297  UVES_SCI_POINT(true), UVES_SCI_POINT(false),
3298  UVES_SCI_SLICER(true), UVES_SCI_SLICER(false),
3299  UVES_TFLAT(true), UVES_TFLAT(false)
3300  };
3301 
3302  const char *type[] =
3303  {
3304  "SCIENCE", "SCIENCE",
3305  "SCI_EXTND", "SCI_EXTND",
3306  "SCI_POINT", "SCI_POINT",
3307  "SCI_SLICER", "SCI_SLICER",
3308  "TFLAT", "TFLAT",
3309  };
3310 
3311  int number_of_tags = sizeof(tags) / sizeof(char *);
3312  int indx;
3313  bool flames = false;
3314 
3315  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3316  "No science frame (%s, %s, %s, %s, %s, %s, %s, %s, %s or %s) in SOF",
3317  tags[0], tags[1], tags[2], tags[3],
3318  tags[4], tags[5], tags[6], tags[7], tags[7], tags[8]);
3319 
3320  *blue = (indx % 2 == 0);
3321  *sci_type = type[indx];
3322 
3323  /* Load the image */
3324  check( load_raw_image(*raw_filename,
3325  CPL_TYPE_DOUBLE,
3326  flames,
3327  *blue,
3328  raw_image,
3329  raw_header,
3330  rotated_header),
3331  "Error loading image from file '%s'", *raw_filename);
3332  cleanup:
3333  if (cpl_error_get_code() != CPL_ERROR_NONE)
3334  {
3335  *raw_filename = NULL;
3336  uves_free_image (raw_image);
3337  uves_free_propertylist(raw_header);
3338  }
3339  return cpl_error_get_code();
3340 }
3341 
3342 /*----------------------------------------------------------------------------*/
3359 /*----------------------------------------------------------------------------*/
3360 cpl_error_code
3361 uves_load_standard(const cpl_frameset *frames, const char **raw_filename,
3362  cpl_image *raw_image[2],
3363  uves_propertylist *raw_header[2],
3364  uves_propertylist *rotated_header[2], bool *blue)
3365 {
3366  const char *tags[] = { UVES_STD_STAR(true), UVES_STD_STAR(false) };
3367  int number_of_tags = sizeof(tags) / sizeof(char *);
3368  int indx;
3369  bool flames = false;
3370 
3371  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3372  "Could not identify raw frame (%s or %s) in SOF", tags[0], tags[1]);
3373 
3374  *blue = (indx == 0);
3375 
3376  /* Load the image */
3377  check( load_raw_image(*raw_filename,
3378  CPL_TYPE_DOUBLE,
3379  flames,
3380  *blue,
3381  raw_image,
3382  raw_header,
3383  rotated_header),
3384  "Error loading image from file '%s'", *raw_filename);
3385 
3386  cleanup:
3387  if (cpl_error_get_code() != CPL_ERROR_NONE)
3388  {
3389  *raw_filename = NULL;
3390  uves_free_image (raw_image);
3391  uves_free_propertylist(raw_header);
3392  }
3393  return cpl_error_get_code();
3394 }
3395 
3396 /*----------------------------------------------------------------------------*/
3412 /*----------------------------------------------------------------------------*/
3413 
3414 cpl_error_code
3415 uves_load_drs(const cpl_frameset *frames,
3416  bool flames,
3417  const char *chip_name,
3418  const char **drs_filename,
3419  uves_propertylist **drs_header,
3420  enum uves_chip chip)
3421 {
3422  const char *tags[1];
3423  int number_of_tags = sizeof(tags) / sizeof(char *);
3424  int extension;
3425  int indx;
3426 
3427  *drs_header = NULL;
3428  tags[0] = UVES_DRS_SETUP(flames, chip);
3429  extension = UVES_DRS_SETUP_EXTENSION(chip);
3430 
3431  check( *drs_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3432  "Could not find DRS table (%s) in SOF", tags[0]);
3433 
3434  /* Load the header */
3435  check( *drs_header = uves_propertylist_load(*drs_filename,
3436  extension),
3437  "Could not load header from extension %d of file '%s'", extension, *drs_filename);
3438 
3439  check_nomsg( uves_warn_if_chip_names_dont_match(*drs_header, chip_name, chip) );
3440 
3441  cleanup:
3442  if (cpl_error_get_code() != CPL_ERROR_NONE) {
3443  *drs_filename = NULL;
3444  uves_free_propertylist(drs_header);
3445  }
3446  return cpl_error_get_code();
3447 }
3448 
3449 /*----------------------------------------------------------------------------*/
3457 /*----------------------------------------------------------------------------*/
3458 cpl_image *
3459 uves_load_weights(const cpl_frameset *frames, const char **weights_filename,
3460  enum uves_chip chip)
3461 {
3462  cpl_image *weights = NULL;
3463  const char *tags[1];
3464  int number_of_tags = sizeof(tags) / sizeof(char *);
3465  int extension = 0;
3466  int indx;
3467 
3468  assure( weights_filename != NULL, CPL_ERROR_NULL_INPUT, "Null filename");
3469 
3470  tags[0] = UVES_WEIGHTS(chip);
3471 
3472  check( *weights_filename = uves_find_frame(frames,
3473  tags, number_of_tags, &indx, NULL),
3474  "Could not find '%s' in frame set", tags[0]);
3475 
3476  check( weights = cpl_image_load(*weights_filename,
3477  CPL_TYPE_DOUBLE, /* Convert to this type */
3478  0, /* plane number */
3479  extension /* Extension number */
3480  ),
3481  "Could not load master bias from extension %d of file '%s'",
3482  extension, *weights_filename);
3483 
3484  cleanup:
3485  return weights;
3486 }
3487 
3488 
3489 /*----------------------------------------------------------------------------*/
3505 /*----------------------------------------------------------------------------*/
3506 
3507 cpl_error_code
3508 uves_load_mbias(const cpl_frameset *frames, const char *chip_name,
3509  const char **mbias_filename,
3510  cpl_image **mbias, uves_propertylist **mbias_header, enum uves_chip chip)
3511 {
3512  const char *tags[1];
3513  int number_of_tags = sizeof(tags) / sizeof(char *);
3514  int extension;
3515  int indx;
3516 
3517  *mbias = NULL;
3518  *mbias_header = NULL;
3519 
3520  tags[0] = UVES_MASTER_BIAS (chip);
3521  extension = UVES_MASTER_BIAS_EXTENSION(chip);
3522 
3523  check( *mbias_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3524  "Could not find '%s' in frame set", tags[0]);
3525 
3526  /* Load the mbias image */
3527  check( *mbias = cpl_image_load(*mbias_filename,
3528  CPL_TYPE_DOUBLE, /* Convert to this type */
3529  0, /* plane number */
3530  extension /* Extension number */
3531  ),
3532  "Could not load master bias from extension %d of file '%s'",
3533  extension, *mbias_filename);
3534 
3535  /* Load the header */
3536  check( *mbias_header = uves_propertylist_load(*mbias_filename,
3537  extension),
3538  "Could not load header from extension %d of file '%s'",
3539  extension, *mbias_filename);
3540 
3541  check_nomsg( uves_warn_if_chip_names_dont_match(*mbias_header, chip_name, chip) );
3542 
3543  cleanup:
3544  if (cpl_error_get_code() != CPL_ERROR_NONE)
3545  {
3546  *mbias_filename = NULL;
3547  uves_free_image(mbias);
3548  uves_free_propertylist(mbias_header);
3549  }
3550  return cpl_error_get_code();
3551 }
3552 
3553 
3554 /*----------------------------------------------------------------------------*/
3570 /*----------------------------------------------------------------------------*/
3571 
3572 cpl_error_code
3573 uves_load_master_formatcheck(const cpl_frameset *frames, const char *chip_name,
3574  const char **mform_filename,
3575  cpl_image **mform, uves_propertylist **mform_header, enum uves_chip chip)
3576 {
3577  const char *tags[1];
3578  int number_of_tags = sizeof(tags) / sizeof(char *);
3579  int extension;
3580  int indx;
3581 
3582  *mform = NULL;
3583  *mform_header = NULL;
3584 
3585  tags[0] = UVES_MASTER_ARC_FORM (chip);
3586  extension = UVES_MASTER_ARC_FORM_EXTENSION(chip);
3587 
3588  check( *mform_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3589  "Could not find '%s' in frame set", tags[0]);
3590 
3591  /* Load the mbias image */
3592  check( *mform = cpl_image_load(*mform_filename,
3593  CPL_TYPE_DOUBLE, /* Convert to this type */
3594  0, /* plane number */
3595  extension /* Extension number */
3596  ),
3597  "Could not load master formatcheck from extension %d of file '%s'",
3598  extension, *mform_filename);
3599 
3600  /* Load the header */
3601 
3602  check( *mform_header = uves_propertylist_load(*mform_filename,
3603  extension),
3604  "Could not load header from extension %d of file '%s'",
3605  extension, *mform_filename);
3606 
3607  check_nomsg( uves_warn_if_chip_names_dont_match(*mform_header, chip_name, chip) );
3608 
3609  cleanup:
3610  if (cpl_error_get_code() != CPL_ERROR_NONE)
3611  {
3612  *mform_filename = NULL;
3613  uves_free_image(mform);
3614  uves_free_propertylist(mform_header);
3615  }
3616  return cpl_error_get_code();
3617 }
3618 
3619 /*----------------------------------------------------------------------------*/
3635 /*----------------------------------------------------------------------------*/
3636 
3637 cpl_error_code
3638 uves_load_mdark(const cpl_frameset *frames, const char *chip_name,
3639  const char **mdark_filename, cpl_image **mdark,
3640  uves_propertylist **mdark_header, enum uves_chip chip)
3641 {
3642  const char *tags[2];
3643  int number_of_tags = sizeof(tags) / sizeof(char *);
3644  int extension;
3645  int indx;
3646 
3647  *mdark = NULL;
3648  *mdark_header = NULL;
3649 
3650  tags[0] = UVES_MASTER_DARK (chip);
3651  tags[1] = UVES_MASTER_PDARK (chip);
3652  extension = UVES_MASTER_DARK_EXTENSION(chip);
3653 
3654  check( *mdark_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3655  "Could not find %s or %s in frame set", tags[0], tags[1]);
3656 
3657  /* Load the mdark image */
3658  check( *mdark = cpl_image_load(*mdark_filename,
3659  CPL_TYPE_DOUBLE, /* Convert to this type */
3660  0, /* plane number */
3661  extension /* Extension number */
3662  ),
3663  "Could not load master dark from extension %d of file '%s'",
3664  extension, *mdark_filename);
3665 
3666  /* Load the header */
3667  check( *mdark_header = uves_propertylist_load(*mdark_filename,
3668  extension),
3669  "Could not load header from extension %d of file '%s'",
3670  extension, *mdark_filename);
3671 
3672  check_nomsg( uves_warn_if_chip_names_dont_match(*mdark_header, chip_name, chip) );
3673 
3674  cleanup:
3675  if (cpl_error_get_code() != CPL_ERROR_NONE)
3676  {
3677  *mdark_filename = NULL;
3678  uves_free_image(mdark);
3679  uves_free_propertylist(mdark_header);
3680  }
3681  return cpl_error_get_code();
3682 }
3683 /*----------------------------------------------------------------------------*/
3699 /*----------------------------------------------------------------------------*/
3700 void
3701 uves_load_ref_flat(const cpl_frameset *frames, const char *chip_name,
3702  const char **filename, cpl_image **rflat,
3703  uves_propertylist **rflat_header, enum uves_chip chip)
3704 {
3705  const char *tags[1];
3706  int number_of_tags = sizeof(tags) / sizeof(char *);
3707  int extension;
3708  int indx;
3709 
3710  *rflat = NULL;
3711  *rflat_header = NULL;
3712 
3713  tags[0] = UVES_REF_TFLAT(chip);
3714  extension = UVES_MASTER_FLAT_EXTENSION(chip);
3715 
3716  check( *filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3717  "Could not find %s in frame set", tags[0]);
3718 
3719  check( *rflat = cpl_image_load(*filename,
3720  CPL_TYPE_DOUBLE, /* Convert to this type */
3721  0, /* plane number */
3722  extension /* Extension number */
3723  ),
3724  "Could not load reference dark from extension %d of file '%s'",
3725  extension, *filename);
3726 
3727  check( *rflat_header = uves_propertylist_load(*filename,
3728  extension),
3729  "Could not load header from extension %d of file '%s'",
3730  extension, *filename);
3731 
3732  check_nomsg( uves_warn_if_chip_names_dont_match(*rflat_header, chip_name, chip) );
3733 
3734  cleanup:
3735  if (cpl_error_get_code() != CPL_ERROR_NONE)
3736  {
3737  *filename = NULL;
3738  uves_free_image(rflat);
3739  uves_free_propertylist(rflat_header);
3740  }
3741 
3742  return;
3743 }
3744 
3745 /*----------------------------------------------------------------------------*/
3761 /*----------------------------------------------------------------------------*/
3762 
3763 cpl_error_code
3764 uves_load_mflat_const(const cpl_frameset *frames, const char *chip_name,
3765  const char **mflat_filename,
3766  cpl_image **mflat, uves_propertylist **mflat_header,
3767  enum uves_chip chip,
3768  const cpl_frame **mflat_frame)
3769 {
3770  const char *tags[6];
3771  int number_of_tags = sizeof(tags) / sizeof(char *);
3772  int extension;
3773  int indx;
3774 
3775  *mflat = NULL;
3776  *mflat_header = NULL;
3777 
3778  tags[0] = UVES_REF_TFLAT (chip); /* Use REF TFLAT, rather than MASTER_TFLAT */
3779  tags[1] = UVES_MASTER_FLAT (chip);
3780  tags[2] = UVES_MASTER_DFLAT (chip);
3781  tags[3] = UVES_MASTER_IFLAT (chip);
3782  tags[4] = UVES_MASTER_TFLAT (chip);
3783  tags[5] = UVES_MASTER_SCREEN_FLAT (chip);
3784  extension = UVES_MASTER_FLAT_EXTENSION(chip);
3785 
3786  check( *mflat_filename = uves_find_frame(frames, tags, number_of_tags, &indx,
3787  mflat_frame),
3788  "Could not find '%s', '%s', '%s', '%s' or '%s' in frame set",
3789  tags[0], tags[1], tags[2], tags[3], tags[4]);
3790 
3791  /* Load the mflat image */
3792  check( *mflat = cpl_image_load(*mflat_filename,
3793  CPL_TYPE_DOUBLE, /* Convert to this type */
3794  0, /* plane number */
3795  extension /* Extension number */
3796  ),
3797  "Could not load master flat from extension %d of file '%s'",
3798  extension, *mflat_filename);
3799 
3800  /* Load the header */
3801  check( *mflat_header = uves_propertylist_load(*mflat_filename,
3802  extension),
3803  "Could not load header from extension %d of file '%s'",
3804  extension, *mflat_filename);
3805 
3806  check_nomsg( uves_warn_if_chip_names_dont_match(*mflat_header, chip_name, chip) );
3807 
3808  cleanup:
3809  if (cpl_error_get_code() != CPL_ERROR_NONE)
3810  {
3811  *mflat_filename = NULL;
3812  uves_free_image(mflat);
3813  uves_free_propertylist(mflat_header);
3814  }
3815  return cpl_error_get_code();
3816 }
3817 
3818 /*----------------------------------------------------------------------------*/
3833 /*----------------------------------------------------------------------------*/
3834 cpl_error_code
3835 uves_load_mflat(cpl_frameset *frames, const char *chip_name,
3836  const char **mflat_filename,
3837  cpl_image **mflat, uves_propertylist **mflat_header, enum uves_chip chip,
3838  cpl_frame **mflat_frame)
3839 {
3840  return uves_load_mflat_const((const cpl_frameset *)frames,
3841  chip_name,
3842  mflat_filename,
3843  mflat, mflat_header, chip,
3844  (const cpl_frame **) mflat_frame);
3845 }
3846 
3847 /*----------------------------------------------------------------------------*/
3879 /*----------------------------------------------------------------------------*/
3880 cpl_error_code
3881 uves_load_ordertable(const cpl_frameset *frames,
3882  bool flames,
3883  const char *chip_name,
3884  const char **ordertable_filename,
3885  cpl_table **ordertable,
3886  uves_propertylist **ordertable_header,
3887  uves_propertylist **ordertable_xheader,
3888  polynomial **order_locations,
3889  cpl_table **traces,
3890  int *tab_in_out_oshift,
3891  double *tab_in_out_yshift,
3892  int ** fib_msk,
3893  double ** fib_pos,
3894  enum uves_chip chip,
3895  bool guess_table)
3896 {
3897  uves_propertylist *midas_header = NULL; /* Table header if midas format */
3898  uves_propertylist *prime_header = NULL; /* Prime header if flames */
3899  const char *tags[1];
3900  int number_of_tags = sizeof(tags) / sizeof(char *);
3901  bool format_is_midas;
3902  int *tioo = NULL;
3903  double *tioy = NULL;
3904  int indx;
3905 
3906  double *fibre_pos = NULL;
3907  int *fibre_mask = NULL;
3908 
3909  if (guess_table)
3910  {
3911  tags[0] = UVES_GUESS_ORDER_TABLE(flames, chip);
3912  }
3913  else
3914  {
3915  tags[0] = UVES_ORDER_TABLE(flames, chip);
3916  }
3917 
3918  check( *ordertable_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3919  "No order table (%s) found in SOF", tags[0]);
3920 
3921  check( *ordertable = cpl_table_load(*ordertable_filename,
3922  UVES_ORDER_TABLE_EXTENSION,
3923  1), /* Mark identified
3924  invalid values? (1=yes) */
3925  "Error loading order table from extension %d of file '%s'",
3926  UVES_ORDER_TABLE_EXTENSION, *ordertable_filename);
3927 
3928  assure(ordertable_header != NULL,CPL_ERROR_NULL_INPUT,
3929  "NULL primary header uves_propertylist variable header");
3930  check( *ordertable_header = uves_propertylist_load(*ordertable_filename, 0),
3931  "Could not load header from extension 0 of '%s'", *ordertable_filename);
3932 
3933  if(ordertable_xheader != NULL) {
3934 
3935  check( *ordertable_xheader = uves_propertylist_load(*ordertable_filename, 1),
3936  "Could not load header from extension 1 of '%s'", *ordertable_filename);
3937 
3938 
3939 
3940  }
3941  check_nomsg( uves_warn_if_chip_names_dont_match(*ordertable_header, chip_name, chip) );
3942 
3943  check(uves_check_if_format_is_midas(*ordertable_header,&format_is_midas),
3944  "Error getting FITS format");
3945 
3946 
3947  if (!format_is_midas && !flames)
3948  {
3949  /* The format check and order position recipes create order tables
3950  with different column names. Rename if necessary.
3951 
3952  This is a workaround for the problem that different recipes
3953  create the same products (order tables and line tables).
3954  The true solution would be to remove the format check recipe from
3955  the recution cascade, and use the theoretical physical model to
3956  bootstrap the order definition and wavelength calibration.
3957  */
3958  if (cpl_table_has_column(*ordertable, "ORDER"))
3959  {
3960  cpl_table_name_column(*ordertable, "ORDER", "Order");
3961  }
3962  if (cpl_table_has_column(*ordertable, "YFIT"))
3963  {
3964  cpl_table_name_column(*ordertable, "YFIT", "Yfit");
3965  }
3966 
3967  if (order_locations != NULL)
3968  {
3969  check( *order_locations =
3970  load_polynomial(*ordertable_filename, UVES_ORDER_TABLE_EXTENSION_POLY),
3971  "Could not read polynomial from extension %d of file '%s'",
3972  UVES_ORDER_TABLE_EXTENSION_POLY, *ordertable_filename);
3973  }
3974 
3975  if (traces != NULL)
3976  {
3977  check( *traces = cpl_table_load(*ordertable_filename,
3978  UVES_ORDER_TABLE_EXTENSION_FIBRE,
3979  1), /* Mark identified
3980  invalid values? (1=yes) */
3981  "Error loading fibre table from extension %d of file '%s'",
3982  UVES_ORDER_TABLE_EXTENSION_FIBRE, *ordertable_filename);
3983  }
3984  }
3985  else
3986  /* MIDAS format, or FLAMES */
3987  {
3988  /* Rename */
3989  check(( cpl_table_cast_column (*ordertable, "ORDER", "Order", CPL_TYPE_INT),
3990  cpl_table_erase_column(*ordertable, "ORDER")),
3991  "Error casting and renaming column 'ORDER'");
3992 
3993  check( cpl_table_name_column(*ordertable, "YFIT", "Yfit"),
3994  "Error renaming column 'YFIT'");
3995 
3996  //check( midas_header = uves_propertylist_load(*ordertable_filename, 1),
3997  // "Could not load header from extension 1 of '%s'",
3998  // *ordertable_filename);
3999  check(midas_header = uves_propertylist_load(*ordertable_filename, 1),
4000  "Could not load header from extension 1 of '%s'",
4001  *ordertable_filename);
4002 
4003  if(flames) {
4004  check(prime_header = uves_propertylist_load(*ordertable_filename, 0),
4005  "Could not load header from extension 0 of '%s'",
4006  *ordertable_filename);
4007  check_nomsg(uves_propertylist_append(midas_header,prime_header));
4008  }
4009 
4010  /* Load polynomial named 'COEFF' from descriptors in extension 1 */
4011  if (order_locations != NULL)
4012  {
4013  check( *order_locations =
4014  uves_polynomial_convert_from_plist_midas(midas_header, "COEFF",-1),
4015  "Error reading polynomial from %s", *ordertable_filename);
4016  }
4017 
4018 
4019  if (flames && tab_in_out_oshift != NULL )
4020  {
4021  /* Get tab_in_out_oshift */
4022  int tioo_length;
4023  cpl_type tioo_type;
4024 
4025  check( tioo = uves_read_midas_array(
4026  midas_header, "TAB_IN_OUT_OSHIFT", &tioo_length,
4027  &tioo_type, NULL),
4028  "Error reading TAB_IN_OUT_OSHIFT from MIDAS header");
4029 
4030  assure( tioo_type == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
4031  "Type of TAB_IN_OUT_OSHIFT is %s, double expected",
4032  uves_tostring_cpl_type(tioo_type));
4033 
4034  if (tioo_length != 1)
4035  {
4036  uves_msg_warning("Length of TAB_IN_OUT_OSHIFT array is %d; "
4037  "%d expected", tioo_length, 1);
4038  }
4039 
4040  *tab_in_out_oshift = tioo[0];
4041 
4042  uves_msg_debug("TAB_IN_OUT_OSHIFT = %d", *tab_in_out_oshift);
4043 
4044  }
4045 
4046  if (flames && tab_in_out_yshift != NULL)
4047  {
4048  /* Get tab_in_out_yshift */
4049  int tioy_length;
4050  cpl_type tioy_type;
4051 
4052  check( tioy = uves_read_midas_array(
4053  midas_header, "TAB_IN_OUT_YSHIFT", &tioy_length,
4054  &tioy_type, NULL),
4055  "Error reading TAB_IN_OUT_YSHIFT from MIDAS header");
4056 
4057  assure( tioy_type == CPL_TYPE_DOUBLE, CPL_ERROR_TYPE_MISMATCH,
4058  "Type of TAB_IN_OUT_YSHIFT is %s, double expected",
4059  uves_tostring_cpl_type(tioy_type));
4060 
4061  if (tioy_length != 1)
4062  {
4063  uves_msg_warning("Length of TAB_IN_OUT_YSHIFT array is %d; "
4064  "%d expected", tioy_length, 1);
4065  }
4066 
4067  *tab_in_out_yshift = tioy[0];
4068 
4069  uves_msg_debug("TAB_IN_OUT_YSHIFT = %f", *tab_in_out_yshift);
4070  }
4071 
4072  if (traces != NULL)
4073  {
4074  *traces = uves_ordertable_traces_new();
4075 
4076  if (!flames)
4077  /* UVES: one trace with zero offset */
4078  {
4079  int fibre_ID = 0;
4080  double fibre_offset = 0.0;
4081  int fibre_msk = 1;
4082  uves_ordertable_traces_add(*traces,
4083  fibre_ID,
4084  fibre_offset,
4085  fibre_msk);
4086  }
4087  else
4088  /* FLAMES */
4089  {
4090 
4091  int fibre_pos_length;
4092  int fibre_mask_length;
4093  cpl_type fibre_pos_type;
4094  cpl_type fibre_mask_type;
4095  int fibre_ID;
4096 
4097  check( fibre_pos = uves_read_midas_array(
4098  midas_header, "FIBREPOS", &fibre_pos_length,
4099  &fibre_pos_type, NULL),
4100  "Error reading FIBREPOS from MIDAS header");
4101 
4102  assure( fibre_pos_type == CPL_TYPE_DOUBLE, CPL_ERROR_TYPE_MISMATCH,
4103  "Type of FIBREPOS is %s, double expected",
4104  uves_tostring_cpl_type(fibre_pos_type));
4105 
4106  check( fibre_mask = uves_read_midas_array(
4107  midas_header, "FIBREMASK", &fibre_mask_length,
4108  &fibre_mask_type, NULL),
4109  "Error reading FIBREMASK from MIDAS header");
4110 
4111  assure( fibre_mask_type == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
4112  "Type of FIBREMASK is %s, double expected",
4113  uves_tostring_cpl_type(fibre_mask_type));
4114 
4115  assure( fibre_pos_length == fibre_mask_length,
4116  CPL_ERROR_INCOMPATIBLE_INPUT,
4117  "FIBREMASK has length %d, but "
4118  "FIBREPOS has length %d",
4119  fibre_mask_length, fibre_pos_length );
4120 
4121  *fib_pos= cpl_malloc(sizeof(double) * fibre_pos_length);
4122  *fib_msk= cpl_malloc(sizeof(int) * fibre_mask_length);
4123 
4124  for (fibre_ID = 0; fibre_ID < fibre_mask_length; fibre_ID++)
4125  {
4126  uves_msg_debug("Found trace %d, position %f (%s)",
4127  fibre_ID, fibre_pos[fibre_ID],
4128  fibre_mask[fibre_ID] ?
4129  "enabled" : "disabled");
4130  uves_ordertable_traces_add(*traces,
4131  fibre_ID,
4132  fibre_pos[fibre_ID],
4133  fibre_mask[fibre_ID]);
4134  (*fib_pos)[fibre_ID]=fibre_pos[fibre_ID];
4135  (*fib_msk)[fibre_ID]=fibre_mask[fibre_ID];
4136  }
4137  }
4138  }
4139  }
4140 
4141  cleanup:
4142  uves_free_propertylist(&midas_header);
4143  uves_free_double(&fibre_pos);
4144  uves_free_int(&fibre_mask);
4145  uves_free_int(&tioo);
4146  uves_free_double(&tioy);
4147  uves_free_propertylist(&prime_header);
4148 
4149  if (cpl_error_get_code() != CPL_ERROR_NONE)
4150  {
4151  *ordertable_filename = NULL;
4152  uves_free_table (ordertable);
4153  uves_free_propertylist(ordertable_header);
4154  if (order_locations != NULL) uves_polynomial_delete(order_locations);
4155  if (traces != NULL) uves_free_table (traces);
4156  }
4157  return cpl_error_get_code();
4158 }
4159 
4160 
4161 
4162 /*--------------------------------------------------------------------------*/
4171 /*--------------------------------------------------------------------------*/
4172 
4173 
4174 cpl_error_code
4175 uves_check_if_format_is_midas(uves_propertylist* header, bool* format_is_midas)
4176 {
4177 
4178  /* Determine format of order table and read the polynomial */
4179  if (uves_propertylist_contains(header, UVES_DRS_ID)) {
4180 
4181 
4182  const char* drs_id=NULL;
4183 
4184  check( drs_id = uves_pfits_get_drs_id(header), "Error reading DRS ID");
4185  if (strstr(drs_id, "CPL") != NULL ||
4186  strstr(drs_id, "cpl") != NULL) {
4187  *format_is_midas = false;
4188  uves_msg_debug("Order table was written by CPL");
4189  } else if (strstr(drs_id, "MIDAS") != NULL ||
4190  strstr(drs_id, "midas") != NULL) {
4191  *format_is_midas = true;
4192  uves_msg_low("Order table was written by MIDAS");
4193  } else {
4194  assure ( false, CPL_ERROR_ILLEGAL_INPUT,
4195  "Unrecognized order table format, DRS_ID = '%s'", drs_id);
4196  }
4197  } else {
4198 
4199  *format_is_midas = true;
4200  uves_msg_debug("No '%s' keyword found. Assuming MIDAS format", UVES_DRS_ID);
4201  }
4202 
4203  cleanup:
4204  return cpl_error_get_code();
4205 
4206 }
4207 
4208 /*--------------------------------------------------------------------------*/
4218 /*--------------------------------------------------------------------------*/
4219 
4220 static cpl_error_code
4221 create_column_pixelsize(cpl_table *linetable)
4222 {
4223  polynomial *p = NULL;
4224  cpl_table *t = NULL;
4225  double d1, d2;
4226  int i;
4227  int degree = 3;
4228 
4229  /* Remove rows with Ident = 0 (unidentified lines) */
4230  check( t = uves_extract_table_rows(linetable, "Ident", CPL_GREATER_THAN, 0.1),
4231  "Error deleting rows with Ident=0");
4232 
4233  /* Create column Aux := Ident * Order */
4234  check(( cpl_table_duplicate_column(t, "Aux", t, "Ident"),
4235  cpl_table_multiply_columns(t, "Aux", "Order")),
4236  "Error creating 'Aux' column");
4237 
4239  "X", "Aux", NULL,
4240  degree,
4241  NULL, NULL,
4242  NULL,
4243  -1),
4244  "Regression failed");
4245 
4246  check( d1 = uves_polynomial_get_coeff_1d(p, 1),
4247  "Error reading polynomial coefficient");
4248 
4249  check( d2 = uves_polynomial_get_coeff_1d(p, 2),
4250  "Error reading polynomial coefficient");
4251 
4252  cpl_table_new_column(linetable, LINETAB_PIXELSIZE, CPL_TYPE_DOUBLE);
4253 
4254  for (i = 0; i < cpl_table_get_nrow(linetable); i++)
4255  {
4256  int x;
4257  int order;
4258  double pixelsize;
4259  double ident;
4260 
4261  check(( x = cpl_table_get_double(linetable, "X", i, NULL),
4262  order = cpl_table_get_int (linetable, "Order", i, NULL),
4263  ident = cpl_table_get_double(linetable, "Ident", i, NULL)),
4264  "Error reading line table");
4265 
4266  assure( order != 0, CPL_ERROR_ILLEGAL_INPUT, "Illegal order number: %d", order);
4267 
4268  /*
4269  * MIDAS approximates
4270  * d(lambda m)/dx (x,m) = d1 + 2*d2*x
4271  *
4272  * where the polynomial itself is ... + d1*x + d2*x^2 + ...
4273  */
4274  pixelsize = (d1 + 2*d2* x) / order;
4275 // pixelsize = uves_polynomial_derivative_2d(dispersion_relation, x, order, 1)/order;
4276 
4277  if (ident > 0.01)
4278  {
4279  cpl_table_set_double(linetable, LINETAB_PIXELSIZE, i, pixelsize);
4280  }
4281  else
4282  {
4283  cpl_table_set_invalid(linetable, LINETAB_PIXELSIZE, i);
4284  }
4285  }
4286 
4287  cleanup:
4288  uves_free_table(&t);
4290  return cpl_error_get_code();
4291 }
4292 
4293 
4294 
4295 /*----------------------------------------------------------------------------*/
4322 /*----------------------------------------------------------------------------*/
4323 static void
4324 align_order_line_table(cpl_table *linetable, const polynomial *absolute_order,
4325  uves_propertylist **linetable_header,
4326  const polynomial *order_locations, int minorder, int maxorder)
4327 {
4328  polynomial *absord = NULL;
4329 
4330  assure ( order_locations != NULL, CPL_ERROR_NULL_INPUT,
4331  "Null order locations polynomial!");
4332 
4333  assure ( absolute_order != NULL, CPL_ERROR_NULL_INPUT,
4334  "Null absolute order pllynomial!");
4335  assure( cpl_table_has_column(linetable, "X" ), CPL_ERROR_DATA_NOT_FOUND,
4336  "Missing line table column 'X'");
4337  assure( cpl_table_has_column(linetable, "Ynew"), CPL_ERROR_DATA_NOT_FOUND,
4338  "Missing line table column 'Ynew'");
4339  assure( cpl_table_has_column(linetable, "Order"), CPL_ERROR_DATA_NOT_FOUND,
4340  "Missing line table column 'Order'");
4341 
4342  assure( cpl_table_get_column_type(linetable, "X") == CPL_TYPE_DOUBLE,
4343  CPL_ERROR_TYPE_MISMATCH, "Line table column 'X' has type %s (double expected))",
4344  uves_tostring_cpl_type(cpl_table_get_column_type(linetable, "X")) );
4345 
4346  assure( cpl_table_get_column_type(linetable, "Ynew") == CPL_TYPE_DOUBLE,
4347  CPL_ERROR_TYPE_MISMATCH, "Line table column 'Ynew' has type %s (double expected))",
4348  uves_tostring_cpl_type(cpl_table_get_column_type(linetable, "Ynew")) );
4349 
4350  assure( cpl_table_get_column_type(linetable, "Y") == CPL_TYPE_INT,
4351  CPL_ERROR_TYPE_MISMATCH, "Line table column 'Y' has type %s (integer expected))",
4352  uves_tostring_cpl_type(cpl_table_get_column_type(linetable, "Y")) );
4353 
4354 
4355  if (linetable_header != NULL)
4356  /* then correct first/abs order keywords */
4357  {
4358  int line_first, line_last;
4359  int ord_first, ord_last;
4360  {
4361 
4362  int maxx;
4363  int minx;
4364  int x, y, order, absorder; /* At chip center */
4365  int coeff;
4366 
4367 
4368  maxx = uves_round_double(cpl_table_get_column_max(linetable, "X"));
4369 
4370  minx = uves_round_double(cpl_table_get_column_min(linetable, "X"));
4371 
4372  assure( 1 <= minx && minx <= maxx, CPL_ERROR_ILLEGAL_INPUT,
4373  "Illegal min/max line x positions: %d/%d, must be > 1",
4374  minx, maxx);
4375 
4376  /* Center of chip */
4377  x = (minx + maxx) / 2;
4378  order = (minorder + maxorder) / 2;
4379 
4380  y = uves_polynomial_evaluate_2d(order_locations, x, order);
4381  if (uves_polynomial_derivative_2d(absolute_order, x, y, 2) > 0) {
4382  coeff = +1;
4383  }
4384  else {
4385  coeff = -1;
4386  }
4387 
4388  assure ( order_locations != NULL, CPL_ERROR_NULL_INPUT,
4389  "Null order locations polynomial!");
4390 
4391 
4392  absorder = uves_round_double(uves_polynomial_evaluate_2d(absolute_order, x, y));
4393 
4394 
4395  uves_msg_debug("Absolute order polynomial at (%d, %d) = %f, "
4396  "rounding to %d", x, y,
4397  uves_polynomial_evaluate_2d(absolute_order, x, y), absorder);
4398 
4399  ord_first = absorder + (minorder - order) * coeff;
4400  ord_last = absorder + (maxorder - order) * coeff;
4401  }
4402 
4403  check( line_first =
4404  uves_pfits_get_firstabsorder(*linetable_header),
4405  "Could not read order number from line table header");
4406 
4407  check( line_last =
4408  uves_pfits_get_lastabsorder (*linetable_header),
4409  "Could not read order number from line table header");
4410 
4411  uves_msg_debug("Order table range: %d - %d. Line table range: %d - %d",
4412  ord_first, ord_last, line_first, line_last);
4413 
4414  if (line_first != ord_first ||
4415  line_last != ord_last)
4416  {
4417  uves_msg_warning("Provided line and order tables are incompatible. "
4418  "Line table contains orders %d - %d. "
4419  "Order table contains orders %d - %d. "
4420  "Correcting on the fly",
4421  line_first, line_last, ord_first, ord_last);
4422 
4423  check( uves_pfits_set_firstabsorder(*linetable_header,
4424  ord_first),
4425  "Could not write corrected first absolute order number");
4426  check( uves_pfits_set_lastabsorder(*linetable_header,
4427  ord_last),
4428  "Could not write corrected first absolute order number");
4429 
4430  uves_msg_debug("Setting line table order range = %d - %d",
4431  ord_first, ord_last);
4432  }
4433  }
4434  /* This 'Y' column is the relative order number in linetables
4435  but the absolute order number (and therefore equal to
4436  the 'order' column) in line guess tables (!!)
4437  */
4438 
4439  {
4440  double epsilon = 0.01; /* Must be larger than machine precision but
4441  less than the typical difference between
4442  absolute/relative numbering (~100)
4443  */
4444 
4445  if (fabs(cpl_table_get_column_median(linetable, "Y") -
4446  cpl_table_get_column_median(linetable, "Order")) > epsilon)
4447 
4448  /* If column 'Y' is different from 'Order',
4449  then 'Y' is the relative order number and
4450  should be corrected (if there is an inconsistency).
4451 
4452  For now, simply delete the 'Y' column because it is
4453  not used later. If the 'Y' column will be used later,
4454  it must be corrected at this place.
4455  */
4456  {
4457  uves_msg_debug("Removing line table column 'Y'");
4458  cpl_table_erase_column(linetable, "Y");
4459  }
4460  }
4461 
4462  cleanup:
4463  uves_polynomial_delete(&absord);
4464 }
4465 
4466 
4467 /*----------------------------------------------------------------------------*/
4506 /*----------------------------------------------------------------------------*/
4507 void
4508 uves_load_linetable(const cpl_frameset *frames,
4509  bool flames,
4510  const char *chip_name,
4511  const polynomial *order_locations, int minorder, int maxorder,
4512  const char **linetable_filename,
4513  cpl_table **linetable,
4514  uves_propertylist **linetable_header,
4515  polynomial **dispersion_relation,
4516  polynomial **absolute_order,
4517  enum uves_chip chip, int trace_id, int window)
4518 {
4519  uves_propertylist *primary_header = NULL;
4520  uves_propertylist *header = NULL;
4521  uves_propertylist *midas_header = NULL; /* MIDAS extension header */
4522  int *absorders = NULL; /* Absolute order numbers */
4523  cpl_table *temp = NULL;
4524  polynomial *absolute_order_local = NULL;
4525  const char *tags[3];
4526  int number_of_tags = sizeof(tags) / sizeof(char *);
4527  const char *drs_id;
4528  bool format_is_midas; /* Was file written by CPL or MIDAS? */
4529  int base_extension; /* Last extension (e.g. 0) before
4530  extension with line table */
4531  int indx;
4532 
4533  if (flames)
4534  {
4535  tags[0] = UVES_GUESS_LINE_TABLE(flames, chip);
4536  tags[1] = UVES_LINE_TABLE(flames, chip);
4537  tags[2] = UVES_LINE_TABLE(flames, chip);
4538  number_of_tags = 3;
4539 
4540  check( *linetable_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
4541  "No line table (%s, %s or %s) found in SOF", tags[0], tags[1], tags[2]);
4542  }
4543  else
4544  {
4545  tags[0] = UVES_LINE_TABLE(flames, chip);
4546  tags[1] = UVES_LINE_TABLE(flames, chip);
4547  tags[2] = UVES_GUESS_LINE_TABLE(flames, chip);
4548 
4549  /* For backwards compatibility with MIDAS,
4550  also look for LINE_TABLE_chip%d */
4551  if (cpl_frameset_find_const(frames, tags[0]) == NULL &&
4552  cpl_frameset_find_const(frames, tags[1]) == NULL &&
4553  cpl_frameset_find_const(frames, tags[2]) == NULL)
4554  {
4555  uves_msg_debug("No %s", tags[0]);
4556 
4557  if (window >= 1)
4558  {
4559  /* Look for LINE_TABLE_BLUEwindow */
4560 
4561  tags[0] = UVES_LINE_TABLE_MIDAS(chip, window);
4562  tags[1] = UVES_LINE_TABLE_MIDAS(chip, window);
4563  tags[2] = UVES_LINE_TABLE_MIDAS(chip, window);
4564 
4565  uves_msg_debug("Trying %s", tags[0]);
4566  }
4567  if (window <= 0)
4568  {
4569  /* Look for any LINE_TABLE_BLUEi */
4570  tags[0] = UVES_LINE_TABLE_MIDAS(chip, 1);
4571  tags[1] = UVES_LINE_TABLE_MIDAS(chip, 2);
4572  tags[2] = UVES_LINE_TABLE_MIDAS(chip, 3);
4573 
4574  uves_msg_debug("Trying %s, %s or %s", tags[0], tags[1], tags[2]);
4575  }
4576  }
4577 
4578  check( *linetable_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
4579  "No line table (%s, %s or %s) found in SOF", tags[0], tags[1], tags[2]);
4580  }
4581 
4582  /* Read primary header */
4583  check( primary_header = uves_propertylist_load(*linetable_filename, 0),
4584  "Could not load primary header of '%s'", *linetable_filename);
4585 
4586  check_nomsg( uves_warn_if_chip_names_dont_match(primary_header, chip_name, chip) );
4587 
4588  /* Determine format of line table */
4589  if (uves_propertylist_contains(primary_header, UVES_DRS_ID))
4590  {
4591  check( drs_id = uves_pfits_get_drs_id(primary_header), "Error reading DRS ID");
4592  if (strstr(drs_id, "CPL") != NULL || strstr(drs_id, "cpl") != NULL)
4593  {
4594  format_is_midas = false;
4595  uves_msg_debug("Line table was written by CPL");
4596  }
4597  else if (strstr(drs_id, "MIDAS") != NULL || strstr(drs_id, "midas") != NULL)
4598  {
4599  format_is_midas = true;
4600  uves_msg_debug("Line table was written by MIDAS");
4601  }
4602  else
4603  {
4604  assure ( false,
4605  CPL_ERROR_ILLEGAL_INPUT,
4606  "Unrecognized line table format, DRS_ID = '%s'", drs_id);
4607  }
4608  }
4609  else
4610  {
4611  format_is_midas = true;
4612  uves_msg_debug("No '%s' keyword found. Assuming MIDAS format", UVES_DRS_ID);
4613  }
4614 
4615  if (format_is_midas || flames)
4616  {
4617  if (!flames)
4618  {
4619  assure( trace_id == 0 && (window == -1 || (1 <= window && window <= 3)),
4620  CPL_ERROR_UNSUPPORTED_MODE,
4621  "Cannot read (fibre, window) = (%d, %d) from MIDAS line table",
4622  trace_id, window);
4623 
4624  base_extension = 0;
4625  }
4626  else
4627  {
4628 
4629  if(trace_id > 0) {
4630 
4631  assure( ((1<= trace_id && trace_id <= 9) && (window == -1)),
4632  CPL_ERROR_UNSUPPORTED_MODE,
4633  "Cannot read (fibre, window) = (%d, %d) from MIDAS line table",
4634  trace_id, window);
4635 
4636  base_extension = 0;
4637 
4638 
4639  } else {
4640 
4641  uves_msg_warning("Assuming line table is guess table");
4642  base_extension = 0;
4643  }
4644  }
4645  }
4646  else
4647  /* Find table extension containing the line table for the specified trace and window */
4648  {
4649  int nextensions;
4650  bool found;
4651 
4652  check( nextensions = uves_get_nextensions(*linetable_filename),
4653  "Error reading number of extensions of file '%s'", *linetable_filename);
4654  header = NULL;
4655  found = false;
4656 
4657  uves_msg_debug("Number of extensions = %d", nextensions);
4658 
4659  for (base_extension = 1; base_extension < nextensions && !found; base_extension++)
4660  {
4661  int header_trace;
4662  int header_window;
4663 
4664  /* Read header trace & window info */
4665  check(( uves_free_propertylist(&header),
4666  header = uves_propertylist_load(*linetable_filename, base_extension)),
4667  "Could not header of extension %d of '%s'",
4668  base_extension, *linetable_filename);
4669 
4670  check( header_trace = uves_pfits_get_traceid (header),
4671  "Error reading trace ID from header of extension %d of '%s'",
4672  base_extension, *linetable_filename);
4673 
4674  check( header_window = uves_pfits_get_windownumber(header),
4675  "Error reading window number from header of extension %d of '%s'",
4676  base_extension, *linetable_filename);
4677 
4678  uves_msg_debug("Found (trace, window) = (%d, %d), need (%d, %d)",
4679  header_trace, header_window,
4680  trace_id, window);
4681 
4682  found = ( (trace_id == header_trace) &&
4683  (window == -1 || window == header_window) );
4684  }
4685 
4686  assure( found,
4687  CPL_ERROR_ILLEGAL_INPUT,
4688  "Line table (trace, window) = (%d, %d) is not present in file '%s'",
4689  trace_id, window, *linetable_filename);
4690 
4691  /* Let 'base_extension' be the first extension before
4692  the proper extension was found (0, 3, 6, ...) */
4693  base_extension -= 2;
4694  /* ...and incremented in for-loop */
4695  }
4696 
4697  check( *linetable = cpl_table_load(*linetable_filename,
4698  base_extension + UVES_LINE_TABLE_EXTENSION,
4699  1), /* Mark identified
4700  invalid values? (1=yes) */
4701  "Error loading line table from extension %d of file '%s'",
4702  base_extension + UVES_LINE_TABLE_EXTENSION, *linetable_filename);
4703 
4704  /* Read header of table extension if requested */
4705  if (linetable_header != NULL)
4706  {
4707  check( *linetable_header =
4708  uves_propertylist_load(*linetable_filename,
4709  base_extension + UVES_LINE_TABLE_EXTENSION),
4710  "Could not load header of extension %d of '%s'",
4711  base_extension + UVES_LINE_TABLE_EXTENSION, *linetable_filename);
4712 
4713  if (format_is_midas)
4714  {
4715  int size = 0;
4716  cpl_type type;
4717  absorders = uves_read_midas_array(*linetable_header, "ORDER", &size,
4718  &type, NULL);
4719 
4720  assure( type == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
4721  "Type of ORDER is %s, int expected",
4722  uves_tostring_cpl_type(type));
4723 
4724  assure( size == 2,
4725  CPL_ERROR_ILLEGAL_INPUT,
4726  "'ORDER' array has size %d. Size 2 expected.", size);
4727  check(( uves_pfits_set_firstabsorder(*linetable_header, absorders[0]),
4728  uves_pfits_set_lastabsorder(*linetable_header, absorders[1])),
4729  "Error updating table header");
4730  }
4731  }
4732 
4733  /* Read the polynomials if requested */
4734  if (format_is_midas)
4735  {
4736  /* Rename & cast order/ident/X columns */
4737  check(( cpl_table_cast_column(*linetable, "X", "xxxx", CPL_TYPE_DOUBLE),
4738  cpl_table_erase_column(*linetable, "X"),
4739  cpl_table_name_column(*linetable, "xxxx", "X")),
4740  "Error casting and renaming column 'X'");
4741 
4742  check(( cpl_table_cast_column(*linetable, "YNEW", "xxxx", CPL_TYPE_DOUBLE),
4743  cpl_table_erase_column(*linetable, "YNEW"),
4744  cpl_table_name_column(*linetable, "xxxx", "Ynew")),
4745  "Error casting and renaming column 'YNEW'");
4746 
4747  check(( cpl_table_cast_column(*linetable, "Y", "xxxx", CPL_TYPE_INT),
4748  cpl_table_erase_column(*linetable, "Y"),
4749  cpl_table_name_column(*linetable, "xxxx", "Y")),
4750  "Error casting and renaming column 'Y'");
4751 
4752  check(( cpl_table_cast_column(*linetable, "ORDER", "Order", CPL_TYPE_INT),
4753  cpl_table_erase_column(*linetable, "ORDER")),
4754  "Error casting and renaming column 'ORDER'");
4755 
4756  check( cpl_table_name_column(*linetable, "IDENT", "Ident"),
4757  "Error renaming column 'IDENT'");
4758 
4759  check( midas_header = uves_propertylist_load(
4760  *linetable_filename,
4761  base_extension + UVES_LINE_TABLE_EXTENSION),
4762  "Could not load header of extension %d of '%s'",
4763  base_extension + UVES_LINE_TABLE_EXTENSION, *linetable_filename);
4764 
4765  if (dispersion_relation != NULL) {
4766  if (trace_id > 0) {
4767  check( *dispersion_relation =
4768  uves_polynomial_convert_from_plist_midas(midas_header,
4769  "REGR", trace_id),
4770  "Error reading polynomial 'REGR%d' from '%s'",
4771  trace_id,
4772  *linetable_filename);
4773  }
4774  else {
4775  check( *dispersion_relation =
4776  uves_polynomial_convert_from_plist_midas(midas_header,
4777  "REGR", -1),
4778  "Error reading polynomial 'REGR' from '%s'",
4779  *linetable_filename);
4780  }
4781  }
4782 
4783 
4784  check( absolute_order_local =
4785  uves_polynomial_convert_from_plist_midas(midas_header, "RORD",-1),
4786  "Error reading polynomial 'RORD' from '%s'", *linetable_filename);
4787 
4788  /* For FLAMES data, it seems that the polynomial is half an order shifted
4789  (for unknown reasons) */
4790  if (flames)
4791  {
4792  check_nomsg( uves_polynomial_shift(absolute_order_local, 0, 0.5) );
4793  }
4794  }
4795  else
4796  /* CPL format */
4797  {
4798  /* physmod + wavecal recipes use different naming conventions,
4799  workaround for this:
4800  */
4801  if (cpl_table_has_column(*linetable, "YNEW"))
4802  {
4803  cpl_table_name_column(*linetable, "YNEW", "Ynew");
4804  }
4805 
4806  if (dispersion_relation != NULL)
4807  {
4808  check( *dispersion_relation = load_polynomial(
4809  *linetable_filename,
4810  base_extension + UVES_LINE_TABLE_EXTENSION_DISPERSION),
4811  "Could not read polynomial from extension %d of file '%s'",
4812  base_extension + UVES_LINE_TABLE_EXTENSION_DISPERSION,
4813  *linetable_filename);
4814  }
4815 
4816  check( absolute_order_local =
4817  load_polynomial(*linetable_filename,
4818  base_extension + UVES_LINE_TABLE_EXTENSION_ABSORDER),
4819  "Could not read polynomial from extension %d of file '%s'",
4820  base_extension + UVES_LINE_TABLE_EXTENSION_ABSORDER, *linetable_filename);
4821  }
4822 
4823  if (absolute_order != NULL)
4824  {
4825  *absolute_order = uves_polynomial_duplicate(absolute_order_local);
4826  }
4827 
4828 
4829  check( align_order_line_table(
4830  *linetable, absolute_order_local, linetable_header,
4831  order_locations, minorder, maxorder),
4832  "Error while aligning line/order tables");
4833 
4834 
4835  /* Remove all other columns than 'Ident', 'Order', 'X', 'Pixelsize' */
4836  {
4837  const char *colname;
4838 
4839  /* Loop through all columns */
4840 
4841  /* It is undefined behaviour (for a reason!) to loop through
4842  columns while deleting some of them. Therefore, copy the
4843  structure of the linetable to another (empty) table */
4844 
4845  uves_free_table(&temp);
4846  check(( temp = cpl_table_new(0),
4847  cpl_table_copy_structure(temp, *linetable)),
4848  "Error duplicating line table column structure");
4849 
4850  colname = cpl_table_get_column_name(temp);
4851  while (colname != NULL)
4852  {
4853  if (!(strcmp(colname, "X" ) == 0 ||
4854  strcmp(colname, "Order" ) == 0 ||
4855  strcmp(colname, "Ident" ) == 0 ||
4856  strcmp(colname, "FIBRE" ) == 0 ||
4857  strcmp(colname, "Fibre" ) == 0 ||
4858  strcmp(colname, LINETAB_PIXELSIZE) == 0))
4859  {
4860  cpl_table_erase_column(*linetable, colname);
4861  uves_msg_debug("Removing unused column '%s'", colname);
4862  }
4863 
4864  /* Call with NULL argument to get the next column name */
4865  colname = cpl_table_get_column_name(NULL);
4866  }
4867  }
4868 
4869  /* support MIDAS
4870  * Calculate 'Pixel' column (lower case) for MIDAS tables
4871  */
4872  if ( !cpl_table_has_column(*linetable, LINETAB_PIXELSIZE) )
4873  {
4874  check( create_column_pixelsize(*linetable),
4875  "Error adding 'Pixelsize' column");
4876  }
4877 
4878  /* Remove un-identified lines (where Ident = invalid or Ident = zero) ... */
4879  check( uves_erase_invalid_table_rows(*linetable, "Ident"),
4880  "Error deleting rows with illegal 'Ident' value");
4881 
4882  check( uves_erase_table_rows(*linetable, "Ident", CPL_LESS_THAN, 0.01),
4883  "Error deleting rows with illegal 'Ident' value");
4884 
4885  /* Check for any other invalid value */
4886  assure( uves_erase_invalid_table_rows(*linetable, NULL) == 0, CPL_ERROR_ILLEGAL_INPUT,
4887  "After deleting rows with invalid 'Ident' values, "
4888  "the table in extension %d of file '%s' still contains invalid rows",
4889  base_extension + UVES_LINE_TABLE_EXTENSION, *linetable_filename);
4890 
4891  /* Sort line table by 'Order' (ascending), then 'X' (ascending) */
4892  check( uves_sort_table_2(*linetable, "Order", "X", false, false), "Error sorting line table");
4893 
4894  cleanup:
4895  uves_free_propertylist(&primary_header);
4896  uves_free_propertylist(&header);
4897  uves_free_propertylist(&midas_header);
4898  uves_free_table(&temp);
4899  uves_polynomial_delete(&absolute_order_local);
4900  cpl_free(absorders);
4901  if (cpl_error_get_code() != CPL_ERROR_NONE) {
4902  *linetable_filename = NULL;
4903  uves_free_table(linetable);
4904  if (dispersion_relation != NULL) uves_polynomial_delete(dispersion_relation);
4905  if (absolute_order != NULL) uves_polynomial_delete(absolute_order);
4906  }
4907  return;
4908 }
4909 
4910 /*----------------------------------------------------------------------------*/
4914 /*----------------------------------------------------------------------------*/
4915 void
4916 uves_load_linetable_const(const cpl_frameset *frames,
4917  bool flames,
4918  const char *chip_name,
4919  const polynomial *order_locations, int minorder, int maxorder,
4920  const char **linetable_filename,
4921  const cpl_table **linetable,
4922  const uves_propertylist **linetable_header,
4923  const polynomial **dispersion_relation,
4924  polynomial **absolute_order,
4925  enum uves_chip chip, int trace_id, int window)
4926 {
4927  uves_load_linetable(frames, flames, chip_name, order_locations,
4928  minorder, maxorder,
4929  linetable_filename,
4930  (cpl_table **)linetable,
4931  (uves_propertylist **)linetable_header,
4932  (polynomial **)dispersion_relation,
4933  absolute_order,
4934  chip, trace_id, window);
4935 }
4936 
4937 
4938 
4939 /*----------------------------------------------------------------------------*/
4954 /*----------------------------------------------------------------------------*/
4955 
4956 cpl_error_code
4957 uves_load_response_curve(const cpl_frameset *frames, const char *chip_name,
4958  const char **response_filename,
4959  cpl_image **response_curve,
4960  cpl_table **master_response,
4961  uves_propertylist **response_header, enum uves_chip chip)
4962 {
4963  const char *tags[2];
4964  int number_of_tags = sizeof(tags) / sizeof(char *);
4965  int extension;
4966  int indx;
4967 
4968  *response_curve = NULL;
4969  *response_header = NULL;
4970  *master_response = NULL;
4971 
4972  tags[0] = UVES_INSTR_RESPONSE (chip);
4973  tags[1] = UVES_MASTER_RESPONSE(chip);
4974 
4975  check( *response_filename = uves_find_frame(frames, tags, number_of_tags, &indx,
4976  NULL),
4977  "Could not find '%s' in frame set", tags[0]);
4978 
4979 
4980  if (indx == 0)
4981  {
4982  extension = UVES_INSTR_RESPONSE_EXTENSION(chip);
4983 
4984  /* Load the response image
4985 
4986  Note: Even if the response curve was saved as
4987  a FITS file with NAXIS=1, cpl_image_load() will
4988  create an image of size nx1, which is just
4989  what we want
4990  */
4991  check( *response_curve = uves_load_image_file(*response_filename,
4992  /* CPL_TYPE_DOUBLE, Convert to this type */
4993  0, /* plane number */
4994  extension, /* Extension number */
4995 
4996 response_header
4997  ),
4998  "Could not load response curve from extension %d of file '%s'",
4999  extension, *response_filename);
5000 
5001  /* Load the header */
5002 /*
5003  check( *response_header = uves_propertylist_load(*response_filename,
5004  extension),
5005  "Could not load header from extension %d of file '%s'",
5006  extension, *response_filename);
5007 */
5008  check_nomsg( uves_warn_if_chip_names_dont_match(*response_header, chip_name, chip) );
5009  }
5010  else
5011  /* Master response */
5012  {
5013  extension = UVES_MASTER_RESPONSE_EXTENSION(chip);
5014 
5015  check( *master_response = cpl_table_load(*response_filename,
5016  UVES_LINE_INTMON_TABLE_EXTENSION,
5017  1), /* Mark identified
5018  invalid values? (1=yes) */
5019  "Error master response curve from extension %d of file '%s'",
5020  extension, *response_filename);
5021 
5022  /* Convert columns to double */
5023  check(( cpl_table_cast_column(*master_response, "LAMBDA", "LAMBDA_double",
5024  CPL_TYPE_DOUBLE),
5025  cpl_table_erase_column(*master_response, "LAMBDA"),
5026  cpl_table_name_column(*master_response, "LAMBDA_double", "LAMBDA")),
5027  "Could not cast column 'LAMBDA'");
5028 
5029  check(( cpl_table_cast_column(*master_response, "FLUX_CONV", "FLUX_CONV_double",
5030  CPL_TYPE_DOUBLE),
5031  cpl_table_erase_column(*master_response, "FLUX_CONV"),
5032  cpl_table_name_column(*master_response, "FLUX_CONV_double", "FLUX_CONV")),
5033  "Could not cast column 'FLUX_CONV'");
5034 
5035  /* Do not need the header, which also does not contain
5036  keywords needed for uves_warn_if_chip_names_dont_match() */
5037  }
5038 
5039  cleanup:
5040  if (cpl_error_get_code() != CPL_ERROR_NONE)
5041  {
5042  *response_filename = NULL;
5043  uves_free_image(response_curve);
5044  uves_free_propertylist(response_header);
5045  }
5046  return cpl_error_get_code();
5047 }
5048 
5049 
5050 /*----------------------------------------------------------------------------*/
5060 /*----------------------------------------------------------------------------*/
5061 cpl_error_code uves_load_lineintmon(const cpl_frameset *frames,
5062  const char **line_intmon_filename,
5063  cpl_table **line_intmon)
5064 {
5065  const char *tags[1] = {UVES_LINE_INTMON_TABLE};
5066 
5067  int number_of_tags = sizeof(tags) / sizeof(char *);
5068  int indx;
5069 
5070  /* Get filename */
5071  check( *line_intmon_filename = uves_find_frame(frames, tags, number_of_tags,
5072  &indx, NULL),
5073  "No line intensity table (%s) found in SOF", tags[0]);
5074 
5075  /* Load table */
5076  check( *line_intmon = cpl_table_load(*line_intmon_filename,
5077  UVES_LINE_INTMON_TABLE_EXTENSION,
5078  1), /* Mark identified
5079  invalid values? (1=yes) */
5080  "Error loading line reference table from extension %d of file '%s'",
5081  UVES_LINE_INTMON_TABLE_EXTENSION, *line_intmon_filename);
5082 
5083  check(( cpl_table_cast_column(*line_intmon, "WAVE", "Wave", CPL_TYPE_DOUBLE),
5084  cpl_table_erase_column(*line_intmon, "WAVE")),
5085  "Could not cast and rename column");
5086 
5087  /* Sort table by 'Wave' (ascending) */
5088  check( uves_sort_table_1(*line_intmon, "Wave", false), "Error sorting table");
5089 
5090  cleanup:
5091  if (cpl_error_get_code() != CPL_ERROR_NONE)
5092  {
5093  *line_intmon_filename = NULL;
5094  uves_free_table(line_intmon);
5095  }
5096  return cpl_error_get_code();
5097 }
5098 
5099 
5100 /*----------------------------------------------------------------------------*/
5112 /*----------------------------------------------------------------------------*/
5113 void
5114 uves_load_corvel(const cpl_frameset *frames,
5115  cpl_table **corvel,
5116  uves_propertylist **corvel_header,
5117  const char **corvel_filename)
5118 {
5119  const char *tags[1];
5120  int number_of_tags = sizeof(tags) / sizeof(char *);
5121  int indx;
5122  int extension;
5123 
5124  tags[0] = FLAMES_CORVEL_MASK;
5125 
5126  assure_nomsg( corvel != NULL, CPL_ERROR_NULL_INPUT );
5127  assure_nomsg( corvel_filename != NULL, CPL_ERROR_NULL_INPUT );
5128 
5129  /* Get filename */
5130  check( *corvel_filename = uves_find_frame(frames, tags, number_of_tags,
5131  &indx, NULL),
5132  "No velocity correction table (%s) found in SOF", tags[0]);
5133 
5134  /* Load table */
5135  extension = 1;
5136  check( *corvel = cpl_table_load(*corvel_filename,
5137  extension,
5138  1), /* Mark identified
5139  invalid values? (1=yes) */
5140  "Error loading line reference table from extension %d of file '%s'",
5141  extension, *corvel_filename);
5142 
5143  /* Load header */
5144  if (corvel_header != NULL)
5145  {
5146  extension = 0;
5147  check( *corvel_header = uves_propertylist_load(*corvel_filename,
5148  extension),
5149  "Could not load header from extension %d of file %s",
5150  extension, *corvel_filename);
5151 
5152  }
5153 
5154  cleanup:
5155  if (cpl_error_get_code() != CPL_ERROR_NONE)
5156  {
5157  *corvel_filename = NULL;
5158  uves_free_table(corvel);
5159  }
5160  return;
5161 }
5162 
5163 /*----------------------------------------------------------------------------*/
5179 /*----------------------------------------------------------------------------*/
5180 cpl_error_code
5181 uves_load_linerefertable(const cpl_frameset *frames,
5182  const char **line_refer_filename,
5183  cpl_table **line_refer, uves_propertylist **line_refer_header)
5184 {
5185  const char *tags[1] = {UVES_LINE_REFER_TABLE};
5186 
5187  int number_of_tags = sizeof(tags) / sizeof(char *);
5188  int indx;
5189 
5190  /* Get filename */
5191  check( *line_refer_filename = uves_find_frame(frames, tags, number_of_tags,
5192  &indx, NULL),
5193  "No line reference table (%s) found in SOF", tags[0]);
5194 
5195  /* Load table */
5196  check( *line_refer = cpl_table_load(*line_refer_filename,
5197  UVES_LINE_REFER_TABLE_EXTENSION,
5198  1), /* Mark identified
5199  invalid values? (1=yes) */
5200  "Error loading line reference table from extension %d of file '%s'",
5201  UVES_LINE_REFER_TABLE_EXTENSION, *line_refer_filename);
5202 
5203  /* Load header if requested */
5204  if (line_refer_header != NULL)
5205  {
5206  check( *line_refer_header = uves_propertylist_load(*line_refer_filename, 0),
5207  "Could not load header of line_refer table in '%s'", *line_refer_filename);
5208  }
5209 
5210  assure( uves_erase_invalid_table_rows(*line_refer, NULL) == 0, CPL_ERROR_ILLEGAL_INPUT,
5211  "Table in extension %d of file '%s' contains invalid rows",
5212  UVES_LINE_REFER_TABLE_EXTENSION, *line_refer_filename);
5213 
5214  check(( cpl_table_cast_column(*line_refer, "WAVE", "Wave", CPL_TYPE_DOUBLE),
5215  cpl_table_erase_column(*line_refer, "WAVE")),
5216  "Could not cast and rename column");
5217 
5218  /* Write uncertainties of wavelengths.
5219  The value 0.002 is finetuned/retro-fitted to get a chi_sq ~ 1 when
5220  using the new catalogue from
5221 
5222  M. T. Murphy, P. Tzanavaris, J. K. Webb, C. Lovis
5223  "Selection of ThAr lines for wavelength calibration of echelle
5224  spectra and implications for variations in the fine-structure constant",
5225  Submitted to MNRAS
5226  */
5227 
5228 #if 0
5229  check(( cpl_table_duplicate_column(*line_refer, "dWave", *line_refer, "Wave"),
5230  cpl_table_divide_scalar (*line_refer, "dWave", 300000*10)),
5231  "Error writing wavelength uncertainties");
5232 #else
5233  /* we should do this */
5234  check(( cpl_table_new_column(*line_refer, "dWave", CPL_TYPE_DOUBLE),
5235  cpl_table_fill_column_window(*line_refer,
5236  "dWave",
5237  0,
5238  cpl_table_get_nrow(*line_refer), 0.002)),
5239  "Error writing wavelength uncertainties");
5240 #endif
5241 
5242  /* Sort table by 'Wave' (ascending) */
5243  check( uves_sort_table_1(*line_refer, "Wave", false), "Error sorting table");
5244 
5245  cleanup:
5246  if (cpl_error_get_code() != CPL_ERROR_NONE) {
5247  *line_refer_filename = NULL;
5248  uves_free_table (line_refer);
5249  if (line_refer_header != NULL) uves_free_propertylist(line_refer_header);
5250  }
5251  return cpl_error_get_code();
5252 }
5253 
5254 /*----------------------------------------------------------------------------*/
5268 /*----------------------------------------------------------------------------*/
5269 cpl_error_code
5270 uves_load_flux_table(const cpl_frameset *frames, const char **flux_table_filename,
5271  cpl_table **flux_table)
5272 {
5273  const char *tags[1] = {UVES_FLUX_STD_TABLE};
5274 
5275  int number_of_tags = sizeof(tags) / sizeof(char *);
5276  int indx;
5277 
5278  /* Get filename */
5279  check( *flux_table_filename = uves_find_frame(frames, tags, number_of_tags,
5280  &indx, NULL),
5281  "No standard star flux table (%s) in SOF", tags[0]);
5282 
5283  /* Load table */
5284  check( *flux_table = cpl_table_load(*flux_table_filename,
5285  UVES_FLUX_STD_TABLE_EXTENSION,
5286  1), /* Mark identified
5287  invalid values? (1=yes) */
5288  "Error loading flux table from extension %d of file '%s'",
5289  UVES_FLUX_STD_TABLE_EXTENSION, *flux_table_filename);
5290 
5291  if (false)
5292  /* Don't do this, it will remove one std (LTT2415) from the table which has TYPE = NULL.
5293  Instead, set type to "NULL" (this is only used for messages)
5294  */
5295  {
5296  if (uves_erase_invalid_table_rows(*flux_table, NULL) != 0)
5297  {
5298  uves_msg_warning("Table in extension %d of file '%s' contains null values",
5299  UVES_FLUX_STD_TABLE_EXTENSION, *flux_table_filename);
5300  }
5301  }
5302  else
5303  {
5304  int i;
5305  for (i = 0; i < cpl_table_get_nrow(*flux_table); i++)
5306  {
5307  if (cpl_table_get_string(*flux_table, "TYPE", i) == NULL)
5308  {
5309  cpl_table_set_string(*flux_table, "TYPE", i, "NULL");
5310  }
5311  }
5312  }
5313 
5314 
5315  cleanup:
5316  if (cpl_error_get_code() != CPL_ERROR_NONE)
5317  {
5318  *flux_table_filename = NULL;
5319  uves_free_table(flux_table);
5320  }
5321  return cpl_error_get_code();
5322 }
5323 
5324 
5325 /*----------------------------------------------------------------------------*/
5339 /*----------------------------------------------------------------------------*/
5340 cpl_error_code
5341 uves_load_atmo_ext(const cpl_frameset *frames, const char **atmext_table_filename,
5342  cpl_table **atmext_table)
5343 {
5344  const char *tags[1] = {UVES_EXTCOEFF_TABLE};
5345 
5346  int number_of_tags = sizeof(tags) / sizeof(char *);
5347  int indx;
5348 
5349  /* Get filename */
5350  check( *atmext_table_filename = uves_find_frame(frames, tags, number_of_tags,
5351  &indx, NULL),
5352  "No atmospheric extinction table (%s) found in SOF", tags[0]);
5353 
5354  /* Load table */
5355  check( *atmext_table = cpl_table_load(*atmext_table_filename,
5356  UVES_EXTCOEFF_TABLE_EXTENSION,
5357  1), /* Mark identified
5358  invalid values? (1=yes) */
5359  "Error loading atmospheric extinction table from extension %d of file '%s'",
5360  UVES_EXTCOEFF_TABLE_EXTENSION, *atmext_table_filename);
5361 
5362  assure( uves_erase_invalid_table_rows(*atmext_table, NULL) == 0, CPL_ERROR_ILLEGAL_INPUT,
5363  "Table in extension %d of file '%s' contains invalid rows",
5364  UVES_EXTCOEFF_TABLE_EXTENSION, *atmext_table_filename);
5365 
5366  check( uves_sort_table_1(*atmext_table, "LAMBDA", false),
5367  "Error sorting table");
5368 
5369  /* Convert columns to double */
5370  check(( cpl_table_cast_column(*atmext_table, "LAMBDA", "LAMBDA_double", CPL_TYPE_DOUBLE),
5371  cpl_table_erase_column(*atmext_table, "LAMBDA"),
5372  cpl_table_name_column(*atmext_table, "LAMBDA_double", "LAMBDA")),
5373  "Could not cast column 'LAMBDA'");
5374 
5375  check(( cpl_table_cast_column(*atmext_table, "LA_SILLA", "LA_SILLA_double", CPL_TYPE_DOUBLE),
5376  cpl_table_erase_column(*atmext_table, "LA_SILLA"),
5377  cpl_table_name_column(*atmext_table, "LA_SILLA_double", "LA_SILLA")),
5378  "Could not cast column 'LA_SILLA'");
5379 
5380  cleanup:
5381  if (cpl_error_get_code() != CPL_ERROR_NONE)
5382  {
5383  *atmext_table_filename = NULL;
5384  uves_free_table(atmext_table);
5385  }
5386  return cpl_error_get_code();
5387 }
5388 /*----------------------------------------------------------------------------*/
5396 /*----------------------------------------------------------------------------*/
5397 char *
5398 uves_guess_order_table_filename(enum uves_chip chip)
5399 {
5400  return uves_local_filename("orderguesstable", chip, -1, -1);
5401 }
5402 
5403 /*----------------------------------------------------------------------------*/
5411 /*----------------------------------------------------------------------------*/
5412 char *
5413 uves_order_table_filename(enum uves_chip chip)
5414 {
5415  return uves_local_filename("ordertable", chip, -1, -1);
5416 }
5417 
5418 /*----------------------------------------------------------------------------*/
5425 /*----------------------------------------------------------------------------*/
5426 char *uves_ordef_filename(enum uves_chip chip)
5427 {
5428  return uves_local_filename("order_def", chip, -1, -1);
5429 }
5430 
5431 /*----------------------------------------------------------------------------*/
5439 /*----------------------------------------------------------------------------*/
5440 char *
5441 uves_masterdark_filename(enum uves_chip chip)
5442 {
5443  return uves_local_filename("masterdark", chip, -1, -1);
5444 }
5445 
5446 
5447 /*----------------------------------------------------------------------------*/
5453 /*----------------------------------------------------------------------------*/
5454 char *
5455 uves_flat_ratio_filename(enum uves_chip chip)
5456 {
5457  return uves_local_filename("ratio", chip, -1, -1);
5458 }
5459 
5460 /*----------------------------------------------------------------------------*/
5467 /*----------------------------------------------------------------------------*/
5468 char *uves_cd_align_filename(enum uves_chip chip)
5469 {
5470  return uves_local_filename("cd_align", chip, -1, -1);
5471 }
5472 
5473 /*----------------------------------------------------------------------------*/
5481 /*----------------------------------------------------------------------------*/
5482 char *
5483 uves_masterflat_filename(enum uves_chip chip)
5484 {
5485  return uves_local_filename("masterflat", chip, -1, -1);
5486 }
5487 /*----------------------------------------------------------------------------*/
5495 /*----------------------------------------------------------------------------*/
5496 char *
5497 uves_masterflat_bkg_filename(enum uves_chip chip)
5498 {
5499  return uves_local_filename("masterflat_bkg", chip, -1, -1);
5500 }
5501 
5502 /*----------------------------------------------------------------------------*/
5510 /*----------------------------------------------------------------------------*/
5511 char *
5512 uves_masterbias_filename(enum uves_chip chip)
5513 {
5514  return uves_local_filename("masterbias", chip, -1, -1);
5515 }
5516 
5517 /*----------------------------------------------------------------------------*/
5525 /*----------------------------------------------------------------------------*/
5526 char *
5527 uves_guess_line_table_filename(enum uves_chip chip)
5528 {
5529  return uves_local_filename("lineguesstable", chip, -1, -1);
5530 }
5531 /*----------------------------------------------------------------------------*/
5539 /*----------------------------------------------------------------------------*/
5540 char *
5541 uves_line_table_filename(enum uves_chip chip)
5542 {
5543  return uves_local_filename("linetable", chip, -1, -1);
5544 }
5545 
5546 /*----------------------------------------------------------------------------*/
5554 /*----------------------------------------------------------------------------*/
5555 char *
5556 uves_line_table_filename_paf(enum uves_chip chip)
5557 {
5558  return uves_local_filename("linetable_paf", chip, -1, -1);
5559 }
5560 
5561 /*----------------------------------------------------------------------------*/
5569 /*----------------------------------------------------------------------------*/
5570 char *
5571 uves_response_curve_filename(enum uves_chip chip)
5572 {
5573  return uves_local_filename("response", chip, -1, -1);
5574 }
5575 
5576 /*----------------------------------------------------------------------------*/
5584 /*----------------------------------------------------------------------------*/
5585 char *
5586 uves_response_curve_2d_filename(enum uves_chip chip)
5587 {
5588  return uves_local_filename("response_2d", chip, -1, -1);
5589 }
5590 
5591 /*----------------------------------------------------------------------------*/
5599 /*----------------------------------------------------------------------------*/
5600 char *
5601 uves_response_red_standard_filename(enum uves_chip chip)
5602 {
5603  return uves_local_filename("red_std", chip, -1, -1);
5604 }
5605 
5606 
5607 /*----------------------------------------------------------------------------*/
5615 /*----------------------------------------------------------------------------*/
5616 char *
5617 uves_response_red_noappend_standard_filename(enum uves_chip chip)
5618 {
5619  return uves_local_filename("red_nonmerged", chip, -1, -1);
5620 }
5621 
5622 /*----------------------------------------------------------------------------*/
5630 /*----------------------------------------------------------------------------*/
5631 char *
5632 uves_response_bkg_standard_filename(enum uves_chip chip)
5633 {
5634  return uves_local_filename("bkg_std", chip, -1, -1);
5635 }
5636 
5637 
5638 /*----------------------------------------------------------------------------*/
5646 /*----------------------------------------------------------------------------*/
5647 char *
5648 uves_order_extract_qc_standard_filename(enum uves_chip chip)
5649 {
5650  return uves_local_filename("order_extract_qc", chip, -1, -1);
5651 }
5652 
5653 /*----------------------------------------------------------------------------*/
5661 /*----------------------------------------------------------------------------*/
5662 char *
5663 uves_response_efficiency_filename(enum uves_chip chip)
5664 {
5665  return uves_local_filename("efficiency", chip, -1, -1);
5666 }
5667 
5668 /*----------------------------------------------------------------------------*/
5676 /*----------------------------------------------------------------------------*/
5677 
5678 char *
5679 uves_scired_red_2d_science_filename(enum uves_chip chip)
5680 {
5681  return uves_local_filename("red_2d_science", chip, -1, -1);
5682 }
5683 
5691 /*----------------------------------------------------------------------------*/
5692 
5693 
5694 
5695 char *
5696 uves_scired_red_science_filename(enum uves_chip chip)
5697 {
5698  return uves_local_filename("red_science", chip, -1, -1);
5699 }
5707 /*----------------------------------------------------------------------------*/
5708 
5709 
5710 
5711 char *
5712 uves_scired_red_noappend_science_filename(enum uves_chip chip)
5713 {
5714  return uves_local_filename("red_nonmerged_science", chip, -1, -1);
5715 }
5716 /*----------------------------------------------------------------------------*/
5724 /*----------------------------------------------------------------------------*/
5725 char *
5726 uves_scired_red_error_filename(enum uves_chip chip)
5727 {
5728  return uves_local_filename("error_red_science", chip, -1, -1);
5729 }
5730 
5731 /*----------------------------------------------------------------------------*/
5739 /*----------------------------------------------------------------------------*/
5740 char *
5741 uves_scired_red_noappend_error_filename(enum uves_chip chip)
5742 {
5743  return uves_local_filename("error_red_nonmerged_science", chip, -1, -1);
5744 }
5745 
5746 /*----------------------------------------------------------------------------*/
5754 /*----------------------------------------------------------------------------*/
5755 char *
5756 uves_scired_red_2d_error_filename(enum uves_chip chip)
5757 {
5758  return uves_local_filename("error_2d_science", chip, -1, -1);
5759 }
5760 
5761 
5762 /*----------------------------------------------------------------------------*/
5770 /*----------------------------------------------------------------------------*/
5771 char *
5772 uves_scired_fluxcal_science_filename(enum uves_chip chip)
5773 {
5774  return uves_local_filename("fluxcal_science", chip, -1, -1);
5775 }
5776 
5777 
5778 /*----------------------------------------------------------------------------*/
5786 /*----------------------------------------------------------------------------*/
5787 char *
5788 uves_scired_fluxcal_science_noappend_filename(enum uves_chip chip)
5789 {
5790  return uves_local_filename("fluxcal_nonmerged_science", chip, -1, -1);
5791 }
5792 /*----------------------------------------------------------------------------*/
5800 /*----------------------------------------------------------------------------*/
5801 char *
5802 uves_scired_fluxcal_error_filename(enum uves_chip chip)
5803 {
5804  return uves_local_filename("fluxcal_error_science", chip, -1, -1);
5805 }
5806 
5807 
5808 /*----------------------------------------------------------------------------*/
5816 /*----------------------------------------------------------------------------*/
5817 char *
5818 uves_scired_fluxcal_error_noappend_filename(enum uves_chip chip)
5819 {
5820  return uves_local_filename("fluxcal_error_nonmerged_science", chip, -1, -1);
5821 }
5822 
5823 
5824 
5832 /*----------------------------------------------------------------------------*/
5833 char *
5834 uves_scired_fluxcal_science_2d_filename(enum uves_chip chip)
5835 {
5836  return uves_local_filename("fluxcal_2d_science", chip, -1, -1);
5837 }
5838 /*----------------------------------------------------------------------------*/
5846 /*----------------------------------------------------------------------------*/
5847 char *
5848 uves_scired_fluxcal_error_2d_filename(enum uves_chip chip)
5849 {
5850  return uves_local_filename("fluxcal_error_2d_science", chip, -1, -1);
5851 }
5852 /*----------------------------------------------------------------------------*/
5860 /*----------------------------------------------------------------------------*/
5861 char *
5862 uves_scired_ff_variance_filename(enum uves_chip chip)
5863 {
5864  return uves_local_filename("variance_ff_science", chip, -1, -1);
5865 }
5866 
5867 /*----------------------------------------------------------------------------*/
5875 /*----------------------------------------------------------------------------*/
5876 char *
5877 uves_scired_ff_variance_2d_filename(enum uves_chip chip)
5878 {
5879  return uves_local_filename("variance_ff_2d_science", chip, -1, -1);
5880 }
5881 
5882 /*----------------------------------------------------------------------------*/
5889 /*----------------------------------------------------------------------------*/
5890 char *
5891 uves_scired_merged_2d_science_filename(enum uves_chip chip)
5892 {
5893  return uves_local_filename("merged_2d_science", chip, -1, -1);
5894 }
5895 
5903 /*----------------------------------------------------------------------------*/
5904 char *
5905 uves_scired_merged_science_filename(enum uves_chip chip)
5906 {
5907  return uves_local_filename("merged_science", chip, -1, -1);
5908 }
5909 /*----------------------------------------------------------------------------*/
5917 /*----------------------------------------------------------------------------*/
5918 char *
5919 uves_scired_merged_sky_filename(enum uves_chip chip)
5920 {
5921  return uves_local_filename("merged_sky", chip, -1, -1);
5922 }
5923 
5924 /*----------------------------------------------------------------------------*/
5932 /*----------------------------------------------------------------------------*/
5933 char *
5934 uves_scired_background_filename(enum uves_chip chip)
5935 {
5936  return uves_local_filename("background", chip, -1, -1);
5937 }
5938 
5939 /*----------------------------------------------------------------------------*/
5947 /*----------------------------------------------------------------------------*/
5948 char *
5949 uves_scired_resampled_filename(enum uves_chip chip)
5950 {
5951  return uves_local_filename("resampled_science", chip, -1, -1);
5952 }
5953 
5954 
5955 
5956 /*----------------------------------------------------------------------------*/
5964 /*----------------------------------------------------------------------------*/
5965 char *
5966 uves_scired_resampled_2d_filename(enum uves_chip chip)
5967 {
5968  return uves_local_filename("resampled_2d_science", chip, -1, -1);
5969 }
5970 
5971 
5972 /*----------------------------------------------------------------------------*/
5980 /*----------------------------------------------------------------------------*/
5981 char *
5982 uves_scired_resampledmf_filename(enum uves_chip chip)
5983 {
5984  return uves_local_filename("resampled_mflat", chip, -1, -1);
5985 }
5986 
5987 /*----------------------------------------------------------------------------*/
5996 /*----------------------------------------------------------------------------*/
5997 char *
5998 uves_scired_rebinned_filename(enum uves_chip chip)
5999 {
6000  return uves_local_filename("resampled_ff_science", chip, -1, -1);
6001 }
6002 
6003 
6012 /*----------------------------------------------------------------------------*/
6013 char *
6014 uves_scired_rebinned_2d_filename(enum uves_chip chip)
6015 {
6016  return uves_local_filename("resampled_ff_2d_science", chip, -1, -1);
6017 }
6018 /*----------------------------------------------------------------------------*/
6026 /*----------------------------------------------------------------------------*/
6027 char *
6028 uves_scired_ordertrace_filename(enum uves_chip chip)
6029 {
6030  return uves_local_filename("ordertrace", chip, -1, -1);
6031 }
6032 
6033 /*----------------------------------------------------------------------------*/
6041 /*----------------------------------------------------------------------------*/
6042 char *
6043 uves_scired_crmask_filename(enum uves_chip chip)
6044 {
6045  return uves_local_filename("cr_mask", chip, -1, -1);
6046 }
6047 
6048 /*----------------------------------------------------------------------------*/
6056 /*----------------------------------------------------------------------------*/
6057 char *
6058 uves_scired_wmap_filename(enum uves_chip chip)
6059 {
6060  return uves_local_filename("wave_map", chip, -1, -1);
6061 }
6062 
6063 /*----------------------------------------------------------------------------*/
6071 /*----------------------------------------------------------------------------*/
6072 char *uves_scired_ext2d_filename(enum uves_chip chip)
6073 {
6074  return uves_local_filename("ext_2d_science", chip, -1, -1);
6075 }
6076 
6077 /*----------------------------------------------------------------------------*/
6085 /*----------------------------------------------------------------------------*/
6086 char *uves_scired_ff2d_filename(enum uves_chip chip)
6087 {
6088  return uves_local_filename("ff_2d_science", chip, -1, -1);
6089 }
6090 
6091 /*----------------------------------------------------------------------------*/
6112 /*----------------------------------------------------------------------------*/
6113 char *
6114 uves_local_filename(const char *prefix, enum uves_chip chip, int trace, int window)
6115 {
6116  char *result = NULL;
6117  const char *chip_string;
6118  const char *suffix = ".fits"; /* Always */
6119  char *t = NULL;
6120  char *w = NULL;
6121 
6122  assure( (trace < 0 && window < 0) || /* Empty suffix */
6123  (trace < 0 && window > 0) || /* Window only suffix */
6124  (trace >= 0 && window > 0), /* Trace & window suffix */
6125  CPL_ERROR_ILLEGAL_INPUT, "Illegal trace and window numbers: (%d, %d)",
6126  trace, window);
6127 
6128  /* Chip */
6129  chip_string = uves_chip_tostring_lower(chip);
6130 
6131  /* Trace and window number (possibly empty string) */
6132  check(( t = int_to_string(trace),
6133  w = int_to_string(window)),
6134  "Error creating substrings");
6135 
6136 /* old code:
6137  result = cpl_calloc(strlen(prefix) + 1 +
6138  strlen(chip_string) + strlen(t) + strlen(w) + strlen(suffix) + 1,
6139  sizeof(char));
6140 
6141  assure_mem( result );
6142 
6143  strcpy(result, prefix);
6144  strcat(result, "_");
6145  strcat(result, chip_string);
6146  strcat(result, t);
6147  strcat(result, w);
6148  strcat(result, suffix);
6149 */
6150  result = uves_sprintf("%s_%s%s%s%s", prefix, chip_string, t, w, suffix);
6151  assure_mem( result );
6152 
6153  cleanup:
6154  cpl_free(t);
6155  cpl_free(w);
6156  if (cpl_error_get_code() != CPL_ERROR_NONE)
6157  {
6158  cpl_free(result); result = NULL;
6159  }
6160  return result;
6161 }
6162 
6163 /*----------------------------------------------------------------------------*/
6174 /*----------------------------------------------------------------------------*/
6175 static char *
6176 int_to_string(int i)
6177 {
6178  char *result = NULL;
6179 
6180  assure( -1 <= i, CPL_ERROR_ILLEGAL_INPUT, "Illegal number (%d)", i);
6181 
6182  if (i == -1)
6183  {
6184  /* Empty string */
6185  result = cpl_calloc(1, sizeof(char));
6186  assure_mem( result );
6187  }
6188  else
6189  {
6190  result = uves_sprintf("_%d", i);
6191  }
6192 
6193  cleanup:
6194  if (cpl_error_get_code() != CPL_ERROR_NONE){
6195  cpl_free(result); result = NULL;
6196  }
6197  return result;
6198 }
6199 
6200 
6201 /*----------------------------------------------------------------------------*/
6211 /*----------------------------------------------------------------------------*/
6212 
6213 cpl_image*
6214 uves_vector_to_image(const cpl_vector* vector,cpl_type type)
6215 {
6216  int i=0;
6217  cpl_image* image=NULL;
6218  int size=0;
6219  const double* pv=NULL;
6220  int* pi=NULL;
6221  float* pf=NULL;
6222  double* pd=NULL;
6223 
6224 
6225  size=cpl_vector_get_size(vector);
6226  image=cpl_image_new(size,1,type);
6227  pv=cpl_vector_get_data_const(vector);
6228  if(type == CPL_TYPE_INT) {
6229  pi=cpl_image_get_data_int(image);
6230  for(i=0;i<size;i++) {
6231  pi[i]=pv[i];
6232  }
6233  } else if (type == CPL_TYPE_FLOAT) {
6234  pf=cpl_image_get_data_float(image);
6235  for(i=0;i<size;i++) {
6236  pf[i]=pv[i];
6237  }
6238  } else if (type == CPL_TYPE_DOUBLE) {
6239  pd=cpl_image_get_data_double(image);
6240  for(i=0;i<size;i++) {
6241  pd[i]=pv[i];
6242  }
6243  } else {
6244  assure( false, CPL_ERROR_INVALID_TYPE,
6245  "No CPL type to represent BITPIX = %d", type);
6246  }
6247 
6248  cleanup:
6249  if (cpl_error_get_code() != CPL_ERROR_NONE){
6250  uves_free_image(&image);
6251  }
6252 
6253  return image;
6254 
6255 }