UVES Pipeline Reference Manual  5.5.1
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 
154  if (frameset == NULL) {
155  cpl_error_set(func, CPL_ERROR_NULL_INPUT);
156  return 1;
157  }
158 
159  if (cpl_frameset_is_empty(frameset)) {
160  return 0;
161  }
162 
163  cpl_frameset_iterator* it = cpl_frameset_iterator_new(frameset);
164  cpl_frame* frame = cpl_frameset_iterator_get(it);
165 
166  while (frame) {
167  if (access(cpl_frame_get_filename(frame), F_OK)) {
168  cpl_msg_error(func, "File %s (%s) was not found",
169  cpl_frame_get_filename(frame),
170  cpl_frame_get_tag(frame));
171  cpl_error_set(func, CPL_ERROR_FILE_NOT_FOUND);
172  }
173 
174  cpl_frameset_iterator_advance(it, 1);
175  frame = cpl_frameset_iterator_get(it);
176 
177  }
178  cpl_frameset_iterator_delete(it);
179  if (cpl_error_get_code())
180  return 1;
181 
182  return 0;
183 }
184 
185 
186 
187 /*----------------------------------------------------------------------------*/
196 /*----------------------------------------------------------------------------*/
197 
198 int
199 uves_contains_frames_kind(cpl_frameset * sof,
200  cpl_frameset* raw,
201  const char* type)
202 {
203  char* tag=NULL;
204  char* name=NULL;
205  cpl_frame* frame = NULL;
206  cpl_frame* frame_dup = NULL;
207 
208  int nsof=0;
209  int i=0;
210  nsof = cpl_frameset_get_size(sof);
211  for (i=0 ; i<nsof ; i++) {
212  frame = cpl_frameset_get_frame(sof,i);
213  name= (char*) cpl_frame_get_filename(frame);
214  if(uves_is_fits_file(name) == 1) {
215  /* to go on the file must exist */
216  if(cpl_frame_get_tag(frame) != NULL) {
217  /* If the frame has a tag we process it. Else it is an object */
218  tag= (char*) cpl_frame_get_tag(frame);
219  /* uves_msg("name=%s tag=%s type=%s\n",name,tag,type); */
220  if(strstr(tag,type) != NULL) {
221  /* uves_msg("Match name=%s tag=%s type=%s\n",name,tag,type); */
222  frame_dup = cpl_frame_duplicate(frame);
223  cpl_frameset_insert(raw,frame_dup);
224  /* uves_msg("inserted\n"); */
225  }
226  }
227  }
228  }
229  return 0;
230 }
231 
232 /*----------------------------------------------------------------------------*/
249 /*----------------------------------------------------------------------------*/
250 polynomial *
251 uves_polynomial_convert_from_plist_midas(const uves_propertylist *plist,
252  const char *regression_name,
253  const int index)
254 {
255  polynomial *result = NULL;
256  cpl_polynomial *pol = NULL;
257  int N = strlen(regression_name);
258  const char *coeffi_name = NULL;
259  cpl_type type;
260  int length;
261  int *coeffi = NULL;
262  int degree1 = -1;
263  int degree2 = -1;
264  bool found = false;
265  const long int plist_size = uves_propertylist_get_size(plist);
266  int i;
267 
268  char cind=' ';
269 
270  if (index == -1) {
271  coeffi_name = cpl_sprintf("%sI", regression_name);
272  }
273  else {
274 
275  switch(index) {
276 
277  case 1: cind='1'; break;
278  case 2: cind='2'; break;
279  case 3: cind='3'; break;
280  case 4: cind='4'; break;
281  case 5: cind='5'; break;
282  case 6: cind='6'; break;
283  case 7: cind='7'; break;
284  case 8: cind='8'; break;
285  case 9: cind='9'; break;
286  default:
287  assure( false, CPL_ERROR_ILLEGAL_INPUT,
288  "Illegal index %d, 1-9 expected", index);
289  break;
290  }
291 
292 
293  coeffi_name = cpl_sprintf("%sI%d", regression_name, index);
294  }
295 
296  check_nomsg( coeffi = uves_read_midas_array(plist, coeffi_name, &length, &type, NULL));
297 
298 
299  assure( type == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
300  "Type of array %s is %s, integer expected",
301  coeffi_name, uves_tostring_cpl_type(type));
302  /*
303  assure( length == 7, CPL_ERROR_ILLEGAL_INPUT,
304  "Wrong array length = %d, 7 expected",
305  length);
306  */
307  /* ignore OUTPUTI(1)- N,no.of data, */
308 
309  /* OUTPUTI(2)- M,no.of ind.var. */
310 
311  assure( coeffi[1] == 2, CPL_ERROR_UNSUPPORTED_MODE,
312  "Regressions is %d-dimensional (2D expected)",
313  coeffi[1]);
314 
315  /* ignore OUTPUTI(3-5) (column number of variables)
316  (3)- col.no. of dep.var.
317  (4)- col.no. of indep.var.
318  (5)-
319  */
320 
321  /* Read degree of first and second variable
322  (6)- degree (ND) */
323 
324  degree1 = coeffi[5];
325  degree2 = coeffi[6];
326 
327  uves_msg_debug("Degree of 2D regression %s is (%d, %d)",
328  regression_name, degree1, degree2);
329 
330  /* The degree of the regression is now known. Next, read the coefficients */
331 
332  pol = cpl_polynomial_new(2);
333 
334  /* Search for <regression_name>D */
335  found = false;
336  for (i = 0; !found && i < plist_size; i++){
337  const cpl_property *p = uves_propertylist_get_const(plist, i);
338  const char *name = cpl_property_get_name(p);
339 
340  if (strcmp(name, "HISTORY") == 0) {
341  const char *value;
342  check( value = cpl_property_get_string(p),
343  "Error reading property value");
344 
345  /* match the string "'<regression_name>D'" */
346 
347  if (
348 
349  (((index < 0) &&
350  (int)strlen(value) >= 1+N+2 &&
351  value[0] == '\'' &&
352  value[1+N] == 'D' &&
353  value[1+N+1] == '\'')
354 
355  ||
356 
357  ((index > 0) &&
358  (int)strlen(value) >= 1+N+3 &&
359  value[0] == '\'' &&
360  value[1+N] == 'D' &&
361  value[1+N+1] == cind &&
362  value[1+N+2] == '\'') )
363 
364  &&
365 
366  strncmp(value+1, regression_name, N) == 0
367  ) {
368  double coeff;
369  char *next;
370  cpl_size power[2];
371  int j = i; /* points to the property currently being read */
372 
373  power[0] = 0; /* Current degree */
374  power[1] = 0;
375 
376  found = true;
377  value = "dummy"; /* This will make strtod fail the first time */
378 
379  while (power[1] <= degree2){
380  /* Read coefficient */
381  coeff = strtod(value, &next);
382 
383  if (next != value) {
384  /* A prefix of the string was successfully converted to double */
385  cpl_polynomial_set_coeff(pol, power, coeff);
386  uves_msg_debug("Polynomial coefficient of order (%" CPL_SIZE_FORMAT ", %" CPL_SIZE_FORMAT ") is %e",
387  power[0], power[1], coeff);
388 
389  power[0]++;
390  if (power[0] > degree1){
391  power[0] = 0;
392  power[1]++;
393  }
394  value = next;
395  }
396  else {
397  /* No more doubles could be read from the string,
398  so move to the next property in the plist */
399  j = j + 1;
400 
401  assure(j < plist_size, CPL_ERROR_ILLEGAL_INPUT,
402  "Missing header data");
403 
404  p = uves_propertylist_get_const(plist, j);
405  assure( cpl_property_get_type(p) == CPL_TYPE_STRING &&
406  strcmp(cpl_property_get_name(p), "HISTORY") == 0,
407  CPL_ERROR_ILLEGAL_INPUT, "Error parsing polynomial");
408 
409  value = cpl_property_get_string(p);
410 
411 
412  uves_msg_debug("Parsing string '%s'", value);
413  }
414  } /* Read coefficients */
415  } /* string was "'...D'" */
416  } /* Keyword was HISTORY */
417  }/* for i... */
418 
419  assure( found, CPL_ERROR_ILLEGAL_INPUT, "Could not find '%sD' in property list",
420  regression_name);
421 
422  /* Create a new polynomial from the cpl_polynomial */
423  result = uves_polynomial_new(pol);
424 
425  cleanup:
426  uves_free_int(&coeffi);
427  uves_free_string_const(&coeffi_name);
428  uves_free_polynomial(&pol);
429  if (cpl_error_get_code() != CPL_ERROR_NONE)
430  {
431  uves_polynomial_delete(&result);
432  }
433 
434  return result;
435 }
436 
437 
438 /*----------------------------------------------------------------------------*/
445 /*----------------------------------------------------------------------------*/
446 cpl_error_code
447 uves_frameset_merge(cpl_frameset * set1, const cpl_frameset* set2)
448 {
449 
450  const cpl_frame* frm_tmp=NULL;
451  cpl_frame* frm_dup=NULL;
452  int i=0;
453  int nfrm;
454  passure(set1 != NULL, "Wrong input set");
455  passure(set2 != NULL, "Wrong input set");
456  nfrm=cpl_frameset_get_size(set2);
457  for (i = 0; i < nfrm; i++ ) {
458  frm_tmp=cpl_frameset_get_frame(set2,i);
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 
481  cpl_frame* frm_dup=NULL;
482  cpl_frame_group g;
483 
484  check_nomsg(*ext = cpl_frameset_new());
485  cpl_frameset_iterator* it = cpl_frameset_iterator_new(set);
486  const cpl_frame *frm_tmp = cpl_frameset_iterator_get_const(it);
487 
488  while (frm_tmp != NULL)
489  {
490  g=cpl_frame_get_group(frm_tmp);
491  if(g == type) {
492  frm_dup=cpl_frame_duplicate(frm_tmp);
493  cpl_frameset_insert(*ext,frm_dup);
494  uves_msg_debug("group %d insert file %s ",type,cpl_frame_get_filename(frm_dup));
495  }
496  cpl_frameset_iterator_advance(it, 1);
497  frm_tmp = cpl_frameset_iterator_get_const(it);
498  }
499  cpl_frameset_iterator_delete(it);
500  cleanup:
501  return cpl_error_get_code();
502 }
503 
504 /*----------------------------------------------------------------------------*/
512 /*----------------------------------------------------------------------------*/
513 cpl_error_code
514 uves_sflats_get_encoder_steps(const cpl_frameset * set, cpl_table** enc, int* nset)
515 {
516  /* Input */
517  const cpl_frame* frm=NULL;
518  int x1enc=0;
519  int x2enc=0;
520  int ref_x1enc=0;
521  int ref_x2enc=0;
522  int i=0;
523  int ndata=0;
524  const int threshold=5;
525  int status=0;
526  uves_propertylist* plist=NULL;
527  cpl_table* encoder_tbl=NULL;
528  ndata = cpl_frameset_get_size(set);
529  encoder_tbl=cpl_table_new(ndata);
530  cpl_table_new_column(encoder_tbl,"x1enc",CPL_TYPE_INT);
531  cpl_table_new_column(encoder_tbl,"x2enc",CPL_TYPE_INT);
532  cpl_table_new_column(encoder_tbl,"flag",CPL_TYPE_INT);
533 
534  for(i=0;i<cpl_frameset_get_size(set);i++)
535  {
536  check_nomsg(frm=cpl_frameset_get_frame_const(set,i));
537  check_nomsg(plist=uves_propertylist_load(cpl_frame_get_filename(frm),0));
540  check_nomsg(cpl_table_set_int(encoder_tbl,"x1enc",i,x1enc));
541  check_nomsg(cpl_table_set_int(encoder_tbl,"x2enc",i,x2enc));
542  uves_free_propertylist(&plist);
543  }
544 
545  check_nomsg(uves_sort_table_2(encoder_tbl,"x1enc","x2enc",false,true));
546 
547  check_nomsg(ref_x1enc=cpl_table_get_int(encoder_tbl,"x1enc",0,&status));
548  check_nomsg(ref_x2enc=cpl_table_get_int(encoder_tbl,"x2enc",0,&status));
549  *nset=1;
550  *enc=cpl_table_new(1);
551  cpl_table_new_column(*enc,"x1enc",CPL_TYPE_INT);
552  cpl_table_new_column(*enc,"x2enc",CPL_TYPE_INT);
553  check_nomsg(cpl_table_set_int(*enc,"x1enc",0,ref_x1enc));
554  check_nomsg(cpl_table_set_int(*enc,"x2enc",0,ref_x2enc));
555 
556  for(i=1;i<cpl_table_get_nrow(encoder_tbl);i++) {
557  check_nomsg(x1enc=cpl_table_get_int(encoder_tbl,"x1enc",i,&status));
558  check_nomsg(x2enc=cpl_table_get_int(encoder_tbl,"x2enc",i,&status));
559  if( (fabs(ref_x1enc -x1enc) > threshold) ||
560  (fabs(ref_x2enc -x2enc) > threshold) ) {
561 
562  ref_x1enc = x1enc;
563  ref_x2enc = x2enc;
564  cpl_table_set_size(*enc,(*nset+1));
565  check_nomsg(cpl_table_set_int(*enc,"x1enc",*nset,ref_x1enc));
566  check_nomsg(cpl_table_set_int(*enc,"x2enc",*nset,ref_x2enc));
567  *nset=*nset+1;
568 
569  }
570  }
571  uves_msg("Number of sets = %d",*nset);
572 
573  cleanup:
574  uves_free_table(&encoder_tbl);
575  uves_free_propertylist(&plist);
576  return cpl_error_get_code();
577 }
578 
579 
580 /*----------------------------------------------------------------------------*/
586 /*----------------------------------------------------------------------------*/
587 cpl_error_code
588 uves_dfs_set_groups(cpl_frameset * set)
589 {
590  cpl_frame * cur_frame ;
591  int nframes ;
592 
593  /* Check entries */
594  assure(set != NULL, CPL_ERROR_NULL_INPUT, "Null input");
595 
596  /* Initialize */
597  check( nframes = cpl_frameset_get_size(set), "Could not read frameset size");
598 
599  /* Loop on frames */
600  int i=0;
601  for (i = 0; i< nframes;i++)
602  {
603  cur_frame=cpl_frameset_get_frame(set,i);
604  bool is_raw = false;
605  bool is_calib = false;
606  bool is_recognized = false;
607  bool blue;
608  enum uves_chip chip;
609  const char * tag = cpl_frame_get_tag(cur_frame);
610 
611  assure( tag != NULL && strcmp(tag, "") != 0, CPL_ERROR_ILLEGAL_INPUT,
612  "Frame has no tag!");
613 
614  blue = false;
615  do {
616  bool flames = false;
617  do {
618  /* RAW frames */
619  is_raw = is_raw ||
620  (strcmp(tag, UVES_ORDER_FLAT (flames,blue)) == 0 ||
621  strcmp(tag, UVES_BIAS (blue)) == 0 ||
622  strcmp(tag, UVES_DARK (blue)) == 0 ||
623  strcmp(tag, UVES_PDARK (blue)) == 0 ||
624  strcmp(tag, UVES_FLAT (blue)) == 0 ||
625  strcmp(tag, UVES_IFLAT (blue)) == 0 ||
626  strcmp(tag, UVES_DFLAT (blue)) == 0 ||
627  strcmp(tag, UVES_SFLAT (blue)) == 0 ||
628  strcmp(tag, UVES_TFLAT (blue)) == 0 ||
629  strcmp(tag, UVES_SCREEN_FLAT (blue)) == 0 ||
630  strcmp(tag, UVES_CD_ALIGN (blue)) == 0 ||
631  strcmp(tag, UVES_FORMATCHECK (flames,blue)) == 0 ||
632  strcmp(tag, UVES_STD_STAR (blue)) == 0 ||
633  strcmp(tag, UVES_SCIENCE (blue)) == 0 ||
634  strcmp(tag, UVES_SCI_EXTND (blue)) == 0 ||
635  strcmp(tag, UVES_SCI_POINT (blue)) == 0 ||
636  strcmp(tag, UVES_SCI_SLICER (blue)) == 0 ||
637  strcmp(tag, UVES_ARC_LAMP (flames,blue)) == 0 ||
638  strcmp(tag, UVES_ECH_ARC_LAMP(blue)) == 0 ||
639  strcmp(tag, RAW_IMA) == 0 ||
640  strcmp(tag, FLAMES_SCI_RED) == 0 ||
641  strcmp(tag, FLAMES_SCI_SIM_RED) == 0 ||
642  strcmp(tag, FLAMES_SCI_COM_RED) == 0 ||
643  strcmp(tag, FLAMES_FIB_FF_ODD) == 0 ||
644  strcmp(tag, FLAMES_FIB_FF_EVEN) == 0 ||
645  strcmp(tag, FLAMES_FIB_FF_ALL) == 0);
646 
647  /* CALIB frames */
648 
649  /* Loop through all (1 or 2) blue or red chips */
650  for (chip = uves_chip_get_first(blue);
651  chip != UVES_CHIP_INVALID;
652  chip = uves_chip_get_next(chip))
653  {
654  int window;
655 
656  is_calib = is_calib ||
657  (strcmp(tag, UVES_DRS_SETUP(flames, chip)) == 0 ||
658  strcmp(tag, UVES_ORDER_TABLE(flames, chip)) == 0 ||
659  strcmp(tag, UVES_GUESS_ORDER_TABLE(flames,chip)) == 0 ||
660  strcmp(tag, UVES_MASTER_BIAS (chip)) == 0 ||
661  strcmp(tag, UVES_MASTER_DARK (chip)) == 0 ||
662  strcmp(tag, UVES_MASTER_PDARK (chip)) == 0 ||
663  strcmp(tag, UVES_MASTER_FLAT (chip)) == 0 ||
664  strcmp(tag, UVES_MASTER_DFLAT (chip)) == 0 ||
665  strcmp(tag, UVES_MASTER_SFLAT (chip)) == 0 ||
666  strcmp(tag, UVES_MASTER_IFLAT (chip)) == 0 ||
667  strcmp(tag, UVES_MASTER_TFLAT (chip)) == 0 ||
668  strcmp(tag, UVES_REF_TFLAT (chip)) == 0 ||
669  strcmp(tag, UVES_ORD_TAB(flames,chip)) == 0 ||
670  strcmp(tag, UVES_MASTER_SCREEN_FLAT(chip)) == 0 ||
671  strcmp(tag, UVES_MASTER_ARC_FORM(chip)) == 0 ||
672  strcmp(tag, UVES_WEIGHTS(chip)) == 0 ||
673  strcmp(tag, UVES_LINE_TABLE(flames,chip)) == 0 ||
674  strcmp(tag, UVES_GUESS_LINE_TABLE(flames,chip)) == 0 ||
675  strcmp(tag, UVES_INSTR_RESPONSE(chip)) == 0 ||
676  strcmp(tag, UVES_MASTER_RESPONSE(chip)) == 0 ||
677  strcmp(tag, UVES_LINE_REFER_TABLE ) == 0 ||
678  strcmp(tag, UVES_LINE_INTMON_TABLE ) == 0 ||
679  strcmp(tag, UVES_FLUX_STD_TABLE ) == 0 ||
680  strcmp(tag, UVES_EXTCOEFF_TABLE ) == 0 ||
681  strcmp(tag, FLAMES_LINE_TABLE(chip)) == 0 ||
682  strcmp(tag, FLAMES_SLIT_FF_DT1(chip)) == 0 ||
683  strcmp(tag, FLAMES_SLIT_FF_DT2(chip)) == 0 ||
684  strcmp(tag, FLAMES_SLIT_FF_DT3(chip)) == 0 ||
685  strcmp(tag, FLAMES_SLIT_FF_DTC(chip)) == 0 ||
686  strcmp(tag, FLAMES_SLIT_FF_BP1(chip)) == 0 ||
687  strcmp(tag, FLAMES_SLIT_FF_BP2(chip)) == 0 ||
688  strcmp(tag, FLAMES_SLIT_FF_BP3(chip)) == 0 ||
689  strcmp(tag, FLAMES_SLIT_FF_BPC(chip)) == 0 ||
690  strcmp(tag, FLAMES_SLIT_FF_BN1(chip)) == 0 ||
691  strcmp(tag, FLAMES_SLIT_FF_BN2(chip)) == 0 ||
692  strcmp(tag, FLAMES_SLIT_FF_BN3(chip)) == 0 ||
693  strcmp(tag, FLAMES_SLIT_FF_BNC(chip)) == 0 ||
694  strcmp(tag, FLAMES_SLIT_FF_SG1(chip)) == 0 ||
695  strcmp(tag, FLAMES_SLIT_FF_SG2(chip)) == 0 ||
696  strcmp(tag, FLAMES_SLIT_FF_SG3(chip)) == 0 ||
697  strcmp(tag, FLAMES_SLIT_FF_SGC(chip)) == 0 ||
698  strcmp(tag, FLAMES_SLIT_FF_COM(chip)) == 0 ||
699  strcmp(tag, FLAMES_SLIT_FF_NOR(chip)) == 0 ||
700  strcmp(tag, FLAMES_SLIT_FF_NSG(chip)) == 0 ||
701  strcmp(tag, FLAMES_FIB_FF_DT1(chip)) == 0 ||
702  strcmp(tag, FLAMES_FIB_FF_DT2(chip)) == 0 ||
703  strcmp(tag, FLAMES_FIB_FF_DT3(chip)) == 0 ||
704  strcmp(tag, FLAMES_FIB_FF_DTC(chip)) == 0 ||
705  strcmp(tag, FLAMES_FIB_FF_BP1(chip)) == 0 ||
706  strcmp(tag, FLAMES_FIB_FF_BP2(chip)) == 0 ||
707  strcmp(tag, FLAMES_FIB_FF_BP3(chip)) == 0 ||
708  strcmp(tag, FLAMES_FIB_FF_BPC(chip)) == 0 ||
709  strcmp(tag, FLAMES_FIB_FF_BN1(chip)) == 0 ||
710  strcmp(tag, FLAMES_FIB_FF_BN2(chip)) == 0 ||
711  strcmp(tag, FLAMES_FIB_FF_BN3(chip)) == 0 ||
712  strcmp(tag, FLAMES_FIB_FF_BNC(chip)) == 0 ||
713  strcmp(tag, FLAMES_FIB_FF_SG1(chip)) == 0 ||
714  strcmp(tag, FLAMES_FIB_FF_SG2(chip)) == 0 ||
715  strcmp(tag, FLAMES_FIB_FF_SG3(chip)) == 0 ||
716  strcmp(tag, FLAMES_FIB_FF_SGC(chip)) == 0 ||
717  strcmp(tag, FLAMES_FIB_FF_COM(chip)) == 0 ||
718  strcmp(tag, FLAMES_FIB_FF_NOR(chip)) == 0 ||
719  strcmp(tag, FLAMES_FIB_FF_NSG(chip)) == 0 ||
720  strcmp(tag, FLAMES_ORDEF(flames,chip)) == 0 ||
721  strcmp(tag, FLAMES_CORVEL_MASK) == 0);
722 
723  for (window = 1; window <= 3; window++)
724  {
725  is_calib = is_calib ||
726  strcmp(tag, UVES_LINE_TABLE_MIDAS(chip, window)) == 0;
727  }
728 
729  if (!flames && strcmp(tag, UVES_BACKGR_TABLE(chip)) == 0)
730  {
731  uves_msg_warning("Background table %s has been deprecated. "
732  "Inter-order positions will be inferred "
733  "from the order table %s. "
734  "Use recipe parameters to define "
735  "measuring method ",
736  UVES_BACKGR_TABLE(chip),
737  UVES_ORDER_TABLE(flames, chip));
738 
739  is_recognized = true;
740  }
741 
742  if (strcmp(tag, UVES_DRS_SETUP(flames, chip)) == 0)
743  {
744  uves_msg_warning("DRS setup table %s has been deprecated. "
745  "Use recipe parameters "
746  "to define data reduction parameters ",
747  UVES_DRS_SETUP(flames, chip));
748 
749  is_recognized = true;
750  }
751  }
752  flames = !flames;
753  } while (flames);
754  blue = !blue;
755  }
756  while (blue);
757 
758  is_recognized = is_recognized || is_raw || is_calib;
759 
760  if (is_raw)
761  {
762  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW) ;
763  }
764  else if (is_calib)
765  {
766  cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_CALIB) ;
767  }
768  else if (!is_recognized)
769  {
770  uves_msg_warning("Unrecognized tag %s", tag);
771  }
772  }
773 
774  uves_dfs_files_dont_exist(set);
775 
776 
777  cleanup:
778  return cpl_error_get_code();
779 }
780 
781 
782 /*----------------------------------------------------------------------------*/
791 /*----------------------------------------------------------------------------*/
792 static void
793 remove_pre_over_scan(uves_propertylist *pl)
794 {
795  bool blue, new_format;
796  enum uves_chip chip;
797 
798  new_format = false;
799  do {
800  blue = false;
801  do {
802  for (chip = uves_chip_get_first(blue);
803  chip != UVES_CHIP_INVALID;
804  chip = uves_chip_get_next(chip))
805  {
806  int n_erase_px = 0; /* Number of erased properties */
807  int n_erase_py = 0;
808  int n_erase_ox = 0;
809  int n_erase_oy = 0;
810 
811  do {
812  /* This function erases only one property at a time,
813  * therefore call it until it returns 0
814  */
815  check( n_erase_px =
816  uves_propertylist_erase(pl, UVES_PRESCANX(new_format, chip)),
817  "Error erasing keyword '%s'", UVES_PRESCANX(new_format, chip));
818 
819  check( n_erase_py =
820  uves_propertylist_erase(pl, UVES_PRESCANY(new_format, chip)),
821  "Error erasing keyword '%s'", UVES_PRESCANY(new_format, chip));
822 
823  check( n_erase_ox =
824  uves_propertylist_erase(pl, UVES_OVRSCANX(new_format, chip)),
825  "Error erasing keyword '%s'", UVES_OVRSCANX(new_format, chip));
826 
827  check( n_erase_oy =
828  uves_propertylist_erase(pl, UVES_OVRSCANY(new_format, chip)),
829  "Error erasing keyword '%s'", UVES_OVRSCANY(new_format, chip));
830  }
831  while (n_erase_px > 0 ||
832  n_erase_py > 0 ||
833  n_erase_ox > 0 ||
834  n_erase_oy > 0);
835  }
836  blue = !blue;
837  }
838  while (blue);
839 
840  new_format = !new_format;
841  }
842  while (new_format);
843 
844  cleanup:
845  return;
846 }
847 
848 
849 /*----------------------------------------------------------------------------*/
859 /*----------------------------------------------------------------------------*/
860 
861 void
862 uves_copy_if_possible(uves_propertylist *to, const uves_propertylist *from,
863  const char *name)
864 {
865  if (!uves_propertylist_contains(to, name) &&
866  uves_propertylist_contains(from, name))
867  {
868  uves_msg_debug("Propagating keyword %s", name);
869 
870  check_nomsg( uves_propertylist_copy_property(to, from, name) );
871  }
872  else
873  {
874  uves_msg_debug("Keyword %s not propagated", name);
875  }
876 
877  cleanup:
878  return;
879 }
880 
881 /*----------------------------------------------------------------------------*/
925 /*----------------------------------------------------------------------------*/
926 cpl_error_code
927 uves_frameset_insert(cpl_frameset *frames,
928  void *object,
929  cpl_frame_group group,
930  cpl_frame_type type,
931  cpl_frame_level level,
932  const char *filename,
933  const char *tag,
934  const uves_propertylist *raw_header,
935  const uves_propertylist *primary_header,
936  const uves_propertylist *table_header,
937  const cpl_parameterlist *parameters,
938  const char *recipe,
939  const char *pipeline,
940  cpl_table **qc,
941  const char *start_time,
942  bool dump_paf,
943  unsigned stats_mask)
944 {
945  cpl_frame *f = NULL;
946  uves_propertylist *pl = NULL;
947  const char *origin = "";
948 
949  passure( !(type == CPL_FRAME_TYPE_IMAGE && table_header != NULL), " ");
950  passure( raw_header != NULL, " ");
951  passure( primary_header != NULL, " ");
952 
953  assure( type == CPL_FRAME_TYPE_IMAGE || stats_mask == 0,
954  CPL_ERROR_INCOMPATIBLE_INPUT,
955  "Cannot compute image statistics on table product" );
956 
957  /* Insert the object (image or table) into frameset */
958  check(( f = cpl_frame_new(),
959  cpl_frame_set_filename(f, filename), /* local filename */
960  cpl_frame_set_tag (f, tag), /* e.g. ORDER_TABLE_BLUE */
961  cpl_frame_set_type (f, type), /* e.g. table */
962  cpl_frame_set_group (f, group), /* e.g. raw/product */
963  cpl_frame_set_level (f, level), /* e.g. temporary/final */
964  cpl_frameset_insert(frames, f)), "Could not insert frame into frameset");
965 
966  /* Pipeline id format is <PACKAGE "/" PACKAGE_VERSION>; */
967  if (strchr(pipeline, '/') == NULL)
968  {
969  uves_msg_warning("Pipeline ID '%s' is not of format: "
970  "Pipeline-name/version", pipeline);
971  }
972 
973  /* Copy provided keywords in 'primary_header' to 'pl' */
974  pl = uves_propertylist_new();
975  if(uves_propertylist_contains(primary_header,UVES_BSCALE)) {
976  uves_msg("inside has bscale");
977  }
978  if (!uves_propertylist_is_empty(primary_header))
979  {
980  if (0)
981  /* This takes (n*m) time */
982  {
983  /* The regexp "" matches any string (because any string has
984  the empty string as a sub-string),
985  except on Mac, where it is an illegal regexp (for whatever reason).
986  Therefore, use ".*" to match any string */
987 
988  check( uves_propertylist_copy_property_regexp(pl, primary_header, ".*", 0),
989  "Could not copy keywords");
990  }
991  else
992  check( uves_propertylist_append(pl, primary_header),
993  "Could not copy keywords");
994  }
995 
996  /* Propagate/create DFS keywords */
997  UVES_TIME_START("cpl_dfs_setup_product_header");
998  check( uves_dfs_setup_product_header(pl,
999  f,
1000  frames,
1001  parameters,
1002  recipe,
1003  pipeline,
1004  DICTIONARY),
1005  "Error setting up product header");
1006  UVES_TIME_END;
1007 
1008  /* Change origin to 'ESO' if it says 'ESO-MIDAS'
1009  * NOST-Definition: "The value field shall contain a character string
1010  * identifying the organization or institution responsible
1011  * for creating the FITS file."
1012  */
1013 
1014  check( uves_get_property_value(pl, "ORIGIN", CPL_TYPE_STRING, &origin),
1015  "Error reading ORIGIN from product header");
1016 
1017  if (strcmp(origin, "ESO-MIDAS") == 0)
1018  {
1019  uves_propertylist_set_string(pl, "ORIGIN", "ESO");
1020  }
1021 
1022  /* Add statistics keywords */
1023  if (type == CPL_FRAME_TYPE_IMAGE && stats_mask != 0)
1024  {
1025  check( uves_dfs_write_statistics((cpl_image *) object, pl, stats_mask),
1026  "Error adding image statistics keywords");
1027  }
1028 
1029  /* Propagate ESO.DET keywords from 'raw_header',
1030  * This is necessary because cpl_dfs_setup_product_header() copies
1031  * only from the primary extension of the first input frames
1032  */
1033  check( uves_propertylist_copy_property_regexp(pl, raw_header, "^ESO DET ", 0),
1034  "Could not propagate 'ESO DET*' keywords");
1035 
1036  /* But remove prescan, overscan keywords.
1037  (Since these areas are not present in any products.) */
1038  check( remove_pre_over_scan(pl),
1039  "Error removing pre-, overscan keywords from product header");
1040 
1041  /* Propagate certain keywords from 'raw_header'
1042  (only if available and if not already present in product header) */
1043  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_AIRMASS) );
1044  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_IMAGETYP) );
1045  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_UT) );
1046  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_ST) );
1047  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_EXPTIME) );
1048  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_EXTNAME) );
1049  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_DATE) );
1050  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_DATAMEAN) );
1051  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_DATAMED) );
1052  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_DATARMS) );
1053  check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_OS_EXPOI) );
1054 
1055  /* MIDAS internal(?): check_nomsg( uves_copy_if_possible(pl, raw_header, UVES_TMSTART) ); */
1056  {
1058  pl, raw_header, "^((GRAT|FILTER|WLEN)[0-9]*)$", 0),
1059  "Could not propagate GRATi, FILTERi and WLENi keywords");
1060  }
1061 
1062  /* If RA,DEC do not exist, invent them and set to zero, like MIDAS */
1063  if ( !uves_propertylist_contains(pl, UVES_RA) )
1064  {
1065  uves_pfits_set_ra(pl, 0);
1066  }
1067  if ( !uves_propertylist_contains(pl, UVES_DEC) )
1068  {
1069  uves_pfits_set_dec(pl, 0);
1070  }
1071 
1072  /*
1073  * REDLEVEL and STATUS have been deprecated, so delete them
1074  * along with inherited MIDAS specific keywords
1075  */
1076  {
1077  bool invert = false;
1079  "ESO PRO (REDLEVEL|REC[0-9]+ STATUS)|"
1080  "TM-START|MIDASFTP|FILENAME)$", invert);
1081  }
1082 
1083  if( (strcmp(recipe,"uves_obs_scired") == 0) ||
1084  (strcmp(recipe,"uves_cal_response") == 0) ) {
1085  /* scired products have Angstrom units */
1086  if(cpl_propertylist_has(pl,"WLEN1")) {
1087  double wlen1=uves_pfits_get_wlen1(pl);
1088  wlen1 *=10.;
1089  uves_pfits_set_wlen1(pl,wlen1);
1090  }
1091  }
1092 
1093 
1094 
1095  check( uves_pfits_set_starttime(pl, start_time),
1096  "Could not write recipe start time");
1097 
1099  "Could not write recipe stop time");
1100 
1101  /* Create paf file from each QC table, and transfer
1102  all QC parameters to product header
1103  */
1104  if (qc != NULL)
1105  {
1106  int i;
1107  for (i = 0; qc[i] != NULL; i++)
1108  {
1109  uves_pfits_put_qc(pl, qc[i]);
1110 
1111  if (dump_paf)
1112  {
1113  /* Exception! This is a hack */
1114  if (strcmp(recipe, make_str(UVES_TFLAT_ID)) == 0 && i == 1)
1115  {
1116  /* Don't dump the science QC again */
1117  }
1118  else
1119  {
1120  /*
1121  uves_save_paf(filename, i, recipe, qc[i],
1122  pl, raw_header, tag);
1123  */
1124  }
1125  }
1126  }
1127  }
1128 
1129  UVES_TIME_START("save product");
1130 
1131  /* Now save with the correct header */
1132  if (type == CPL_FRAME_TYPE_IMAGE)
1133  {
1134  bool use_bitpix16_for_int = (strcmp(recipe, make_str(FLAMES_CAL_ORDERPOS)) == 0);
1135 
1136  check( uves_save_image((cpl_image *) object, filename, pl,
1137  use_bitpix16_for_int, true),
1138  "Error saving image to file %s", filename);
1139  }
1140  else if (type == CPL_FRAME_TYPE_TABLE) /* Table */
1141  {
1142  check( uves_table_save((cpl_table *) object,
1143  pl, /* Primary header */
1144  table_header, /* Table header */
1145  filename,
1146  CPL_IO_DEFAULT), /* Create new file */
1147  "Error saving table to file '%s'", filename);
1148  }
1149  else
1150  {
1151  assure(false, CPL_ERROR_UNSUPPORTED_MODE, "Unsupported frame type");
1152  }
1153 
1154  UVES_TIME_END;
1155 
1156  cleanup:
1157  uves_free_propertylist(&pl);
1158 
1159  return cpl_error_get_code();
1160 }
1161 
1162 
1163 /*----------------------------------------------------------------------------*/
1172 /*----------------------------------------------------------------------------*/
1173 void
1174 uves_dfs_write_statistics(const cpl_image *image, uves_propertylist *header,
1175  unsigned stats_mask)
1176 {
1177  cpl_stats *stats = NULL;
1178 
1179  /* Only these bits are supported, all others must be zero */
1180  assure( (stats_mask & (CPL_STATS_MEAN | CPL_STATS_STDEV | CPL_STATS_MEDIAN |
1181  CPL_STATS_MIN | CPL_STATS_MAX)) == stats_mask,
1182  CPL_ERROR_UNSUPPORTED_MODE, "Cannot compute mask %d",
1183  stats_mask );
1184 
1185  UVES_TIME_START("calculate stats");
1186 
1187  check( stats = cpl_stats_new_from_image(
1188  image, stats_mask),
1189  "Error reading image statistics");
1190 
1191  UVES_TIME_END;
1192 
1193  if (stats_mask & CPL_STATS_MEDIAN)
1194  {
1195  check( uves_pfits_set_data_median (header, cpl_stats_get_median(stats) ),
1196  "Could not write median flux");
1197  }
1198  if (stats_mask & CPL_STATS_MEAN)
1199  {
1200  check( uves_pfits_set_data_average(header, cpl_stats_get_mean (stats) ),
1201  "Could not write average flux");
1202  }
1203  if (stats_mask & CPL_STATS_STDEV)
1204  {
1205  check( uves_pfits_set_data_stddev (header, cpl_stats_get_stdev (stats) ),
1206  "Could not write flux stdev");
1207  }
1208  if (stats_mask & CPL_STATS_MIN)
1209  {
1210  check( uves_pfits_set_data_min (header, cpl_stats_get_min (stats) ),
1211  "Could not write min flux");
1212  }
1213  if (stats_mask & CPL_STATS_MIN)
1214  {
1215  check( uves_pfits_set_data_max (header, cpl_stats_get_max (stats) ),
1216  "Could not write max flux");
1217  }
1218 
1219  cleanup:
1220  uves_free_stats(&stats);
1221  return;
1222 }
1223 
1224 
1225 /*----------------------------------------------------------------------------*/
1260 /*----------------------------------------------------------------------------*/
1261 void *
1262 uves_read_midas_array(const uves_propertylist *plist, const char *name,
1263  int *length, cpl_type *type, int *ncards)
1264 {
1265  void *result = NULL;
1266  unsigned result_size;
1267  int N = strlen(name);
1268  bool found = false;
1269  const char *value;
1270  int size;
1271  int i;
1272  const long int plist_size = uves_propertylist_get_size(plist);
1273 
1274  assure_nomsg( length != NULL, CPL_ERROR_NULL_INPUT );
1275  assure_nomsg( type != NULL, CPL_ERROR_NULL_INPUT );
1276  for (i = 0; !found && i < plist_size; i++)
1277  {
1278  const cpl_property *p = uves_propertylist_get_const(plist, i);
1279  value = cpl_property_get_name(p);
1280 
1281  if (strcmp(value, "HISTORY") == 0)
1282  {
1283 
1284  check( value = cpl_property_get_string(p),
1285  "Error reading property value");
1286 
1287  /* match the string "'<name>','t" */
1288 
1289  if ((int)strlen(value) >= 1+N+4 &&
1290  value[0] == '\'' &&
1291  value[N+1] == '\'' &&
1292  value[N+2] == ',' &&
1293  value[N+3] == '\'' &&
1294  strncmp(value+1, name, N) == 0
1295  )
1296  {
1297  switch(value[N+4]) {
1298  case 'R':
1299  /* Distinguish between
1300  "'<name>','R*4'" and
1301  "'<name>','R*8'"
1302  */
1303  *type = CPL_TYPE_DOUBLE;
1304 
1305  if ((int)strlen(value) >= 1+N+4+2 && value[N+4+1] == '*')
1306  {
1307  switch(value[N+4+2]) {
1308  case '4': *type = CPL_TYPE_FLOAT; break;
1309  case '8': *type = CPL_TYPE_DOUBLE; break;
1310  default:
1311  assure( false, CPL_ERROR_ILLEGAL_INPUT,
1312  "Unrecognized MIDAS type: 'R*%c'",
1313  value[N+4+2]);
1314  break;
1315  }
1316  }
1317  break;
1318  case 'I': *type = CPL_TYPE_INT ; size = sizeof(int); break;
1319  case 'C': *type = CPL_TYPE_STRING; size = sizeof(char); break;
1320  default:
1321  assure( false, CPL_ERROR_UNSUPPORTED_MODE,
1322  "Unrecognized type '%c'", value[N+4]);
1323  break;
1324  }
1325  found = true;
1326  }
1327  }
1328  }
1329 
1330  assure( found, CPL_ERROR_ILLEGAL_INPUT, "Could not find '%s' in property list", name);
1331 
1332  /* 'i' is now the row immediately after first occurence of 'HISTORY '<name>... */
1333  result_size = sizeof(double) * 100; /* realloc when/if out of memory */
1334  result = cpl_malloc(result_size);
1335 
1336  *length = 0;
1337  if (ncards != NULL) *ncards = 2; /* First HISTORY entry + termination HISTORY entry */
1338  do {
1339  const cpl_property *p;
1340 
1341  if (ncards != NULL) *ncards += 1;
1342 
1343  assure(i < plist_size,
1344  CPL_ERROR_ILLEGAL_INPUT, "Missing header data");
1345  p = uves_propertylist_get_const(plist, i);
1346  assure( cpl_property_get_type(p) == CPL_TYPE_STRING &&
1347  strcmp(cpl_property_get_name(p), "HISTORY") == 0,
1348  CPL_ERROR_ILLEGAL_INPUT, "Error parsing array");
1349  value = cpl_property_get_string(uves_propertylist_get_const(plist, i));
1350 
1351  uves_msg_debug("Parsing '%s'", value);
1352 
1353  if (*type == CPL_TYPE_STRING)
1354  {
1355  assure( strlen(value) < 100, CPL_ERROR_UNSUPPORTED_MODE,
1356  "String too long. Max size is 100");
1357 
1358  /* Remove any blanks from the string
1359  (e.g. convert "0 1 2" to "012")
1360  */
1361  {
1362  int len = strlen(value);
1363  int j = 0;
1364  int k;
1365  for (k = 0; k <= len; k++) /* including final '\0' */
1366  {
1367  //if (value[k] != ' '){
1368  ((char*)result)[j] = value[k];
1369  j++;
1370  // }
1371  }
1372  *length = j-1;
1373  }
1374 
1375  uves_msg_debug("Converted '%s' to '%s'",
1376  value, (char*)result);
1377 
1378  /* done parsing */
1379  value = "";
1380  }
1381 
1382  else { /* numerical types */
1383  if (strcmp(value, "") != 0) {
1384  double numberd = -1; /* suppres warning */
1385  int numberi = -1;
1386  float numberf = -1;
1387  const int base = 10;
1388  char *next = (char *) value;
1389 
1390  do {
1391  /* ignore OUTPUTI(1)- N,no.of data, */
1392  switch(*type) {
1393  case CPL_TYPE_DOUBLE:
1394  numberd = strtod(value, &next);
1395  uves_msg_debug("Got %g, remaining: '%s'", numberd, next);
1396  break;
1397  case CPL_TYPE_FLOAT:
1398  numberf = strtod(value, &next); // C99: strtof(value, &next);
1399  uves_msg_debug("Got %g, remaining: '%s'", numberf, next);
1400  break;
1401  case CPL_TYPE_INT:
1402  numberi = strtol(value, &next, base);
1403  uves_msg_debug("Got %d, remaining: '%s'", numberi, next);
1404  break;
1405  default:
1406  passure(false, " ");
1407  }
1408 
1409  if (next != value)
1410  {
1411  /* A prefix of the string could be converted */
1412  (*length)++;
1413  if (*length * sizeof(double) > result_size)
1414  {
1415  result_size *= 2;
1416  result = cpl_realloc(result, result_size);
1417  }
1418 
1419  switch(*type) {
1420  case CPL_TYPE_DOUBLE:
1421  ((double *)result)[*length-1] = numberd;
1422  break;
1423  case CPL_TYPE_FLOAT:
1424  ((float *)result)[*length-1] = numberf;
1425  break;
1426  case CPL_TYPE_INT:
1427  ((int *)result)[*length-1] = numberi;
1428  break;
1429  default:
1430  passure(false, " ");
1431  }
1432 
1433  value = next;
1434 
1435  switch(*type) {
1436  case CPL_TYPE_DOUBLE:
1437  numberd = strtod(value, &next);
1438  uves_msg_debug("Got %g, remaining: '%s'", numberd, next);
1439  break;
1440  case CPL_TYPE_FLOAT:
1441  numberf = strtod(value, &next); // C99: strtof(value, &next);
1442  uves_msg_debug("Got %g, remaining: '%s'", numberf, next);
1443  break;
1444  case CPL_TYPE_INT:
1445  numberi = strtol(value, &next, base);
1446  uves_msg_debug("Got %d, remaining: '%s'", numberi, next);
1447  break;
1448  default:
1449  passure(false, " ");
1450  }
1451  }
1452  } while (next != value);
1453  }
1454  }/* if numerical type */
1455 
1456  i++;
1457 
1458  assure( strcmp(value, "") == 0, CPL_ERROR_ILLEGAL_INPUT,
1459  "Cannot parse %s descriptor %s, remaining string: '%s'",
1460  uves_tostring_cpl_type(*type), name, value);
1461 
1462  /* Find out if we can continue parsing the next HISTORY keyword */
1463  if (i < plist_size)
1464  {
1465  p = uves_propertylist_get_const(plist, i);
1466  if (cpl_property_get_type(p) == CPL_TYPE_STRING &&
1467  strcmp(cpl_property_get_name(p), "HISTORY") == 0)
1468  {
1469  value = cpl_property_get_string(
1470  uves_propertylist_get_const(plist, i));
1471 
1472  if (*type == CPL_TYPE_STRING)
1473  {
1474  if (strcmp(value, "") != 0) {
1475  uves_msg_debug("String array %s with length > 1 found. Ignoring remaining values", name);
1476  while (strcmp(value, "") != 0 && i+1 < plist_size) {
1477  i++;
1478  p = uves_propertylist_get_const(plist, i);
1479  value = cpl_property_get_string(
1480  uves_propertylist_get_const(plist, i));
1481  if (ncards != NULL) *ncards += 1;
1482  }
1483  }
1484  }
1485  }
1486  }
1487 
1488  } while (strcmp(value, "") != 0);
1489 
1490  cleanup:
1491  if (cpl_error_get_code() != CPL_ERROR_NONE)
1492  {
1493  cpl_free(result); result = NULL;
1494  }
1495  return result;
1496 }
1497 
1498 
1499 /*----------------------------------------------------------------------------*/
1517 /*----------------------------------------------------------------------------*/
1518 cpl_error_code
1519 uves_save_table_local(const char *description, const char *filename_prefix,
1520  const cpl_table *table,
1521  enum uves_chip chip, int trace, int window,
1522  const uves_propertylist *pheader, const uves_propertylist *eheader)
1523 {
1524  char *filename = NULL;
1525 
1526  check( filename = uves_local_filename(filename_prefix, chip, trace, window),
1527  "Error getting filename");
1528 
1529  check( uves_table_save(table, pheader, eheader, filename, CPL_IO_DEFAULT),
1530  "Error saving table to file '%s'", filename);
1531 
1532  if (description != NULL) uves_msg("%s saved to '%s'", description, filename);
1533 
1534  cleanup:
1535  cpl_free(filename);
1536  return cpl_error_get_code();
1537 }
1538 
1539 /*----------------------------------------------------------------------------*/
1560 /*----------------------------------------------------------------------------*/
1561 cpl_error_code
1562 uves_save_image_local(const char *description, const char *filename_prefix,
1563  const cpl_image *image,
1564  enum uves_chip chip, int trace, int window,
1565  const uves_propertylist *plist,
1566  bool use_bitpix16_for_int)
1567 {
1568  char *filename = NULL;
1569 
1570  check( filename = uves_local_filename(filename_prefix, chip, trace, window),
1571  "Error getting filename");
1572 
1573  check( uves_save_image(image, filename, plist, use_bitpix16_for_int, true),
1574  "Error saving image to file '%s'", filename);
1575  if (description != NULL) uves_msg("%s saved to '%s'", description, filename);
1576 
1577  cleanup:
1578  cpl_free(filename);
1579  return cpl_error_get_code();
1580 }
1581 
1582 
1583 /*----------------------------------------------------------------------------*/
1593 /*----------------------------------------------------------------------------*/
1594 cpl_image *uves_load_image(const cpl_frame *f,
1595  int plane,
1596  int extension,
1597  uves_propertylist **header)
1598 {
1599  cpl_image *image = NULL;
1600  uves_propertylist *plist = NULL;
1601  const char *filename;
1602  int bitpix;
1603  cpl_type type;
1604  int naxis=0;
1605  cpl_vector * vector=NULL;
1606 
1607 
1608  assure_nomsg( f != NULL, CPL_ERROR_NULL_INPUT );
1609 
1610  assure( cpl_frame_get_type(f) == CPL_FRAME_TYPE_IMAGE,
1611  CPL_ERROR_TYPE_MISMATCH, "Wrong type: %s",
1612  uves_tostring_cpl_frame_type(cpl_frame_get_type(f)));
1613 
1614  filename = cpl_frame_get_filename(f);
1615 
1616  check( plist = uves_propertylist_load(filename, extension),
1617  "Could not load header from %s extension %d",
1618  filename, extension);
1619 
1620  check( bitpix = uves_pfits_get_bitpix(plist),
1621  "Could not read BITPIX from %s extension %d",
1622  filename, extension);
1623 
1624  if (bitpix == -32) type = CPL_TYPE_FLOAT;
1625  else if (bitpix == -64) type = CPL_TYPE_DOUBLE;
1626  else if (bitpix == 32) type = CPL_TYPE_INT;
1627  else if (bitpix == 16) type = CPL_TYPE_INT;
1628  else
1629  {
1630  assure( false, CPL_ERROR_UNSUPPORTED_MODE,
1631  "No CPL type to represent BITPIX = %d", bitpix);
1632  }
1633 
1634  check( naxis = uves_pfits_get_naxis(plist),
1635  "could not get NAXIS" );
1636 
1637  if( naxis == 1) {
1638 
1639  check( vector = cpl_vector_load(filename,extension),
1640  "Could not load vector from extension %d of file '%s' ",
1641  extension, filename);
1642  cknull(image=uves_vector_to_image(vector,type),
1643  "could not convert vector to image");
1644  } else {
1645 
1646 
1647  check( image = cpl_image_load(filename,
1648  type,
1649  plane,
1650  extension),
1651  "Could not load image from extension %d of file '%s' ",
1652  extension, filename);
1653 
1654  }
1655 
1656  if (header != NULL)
1657  {
1658  *header = uves_propertylist_duplicate(plist);
1659  }
1660 
1661  cleanup:
1662  uves_free_vector(&vector);
1663  uves_free_propertylist(&plist);
1664  return image;
1665 }
1666 /*----------------------------------------------------------------------------*/
1670 /*----------------------------------------------------------------------------*/
1671 
1672 cpl_image *uves_load_image_file(const char *filename,
1673  int plane,
1674  int extension,
1675  uves_propertylist **header)
1676 {
1677  cpl_image *i;
1678  cpl_frame *f = cpl_frame_new();
1679  cpl_frame_set_filename(f, filename);
1680  cpl_frame_set_type(f, CPL_FRAME_TYPE_IMAGE);
1681 
1682  i = uves_load_image(f, plane, extension, header);
1683 
1684  uves_free_frame(&f);
1685 
1686  return i;
1687 }
1688 
1689 /*----------------------------------------------------------------------------*/
1714 /*----------------------------------------------------------------------------*/
1715 void
1716 uves_save_image(const cpl_image *image, const char *filename, const uves_propertylist *plist,
1717  bool use_bitpix16_for_int, bool save1d)
1718 {
1719  cpl_type_bpp bpp;
1720  cpl_type t;
1721  const cpl_vector *image_1d = NULL;
1722  uves_propertylist *header = NULL;
1723  cpl_image *thresholded = NULL;
1724  cpl_image *thresholded_double = NULL;
1725 
1726  if (image == NULL) {
1727  check( uves_image_save(image, filename, CPL_BPP_IEEE_FLOAT, plist, CPL_IO_DEFAULT),
1728  "Error saving NULL image to file '%s'", filename);
1729  }
1730  else {
1731  check( t = cpl_image_get_type(image), "Error reading image type");
1732  if (t == CPL_TYPE_FLOAT ) bpp = CPL_BPP_IEEE_FLOAT;
1733  else if (t == CPL_TYPE_DOUBLE) bpp = CPL_BPP_IEEE_FLOAT;
1734  /* Internal computations in double precision,
1735  save as single precision */
1736 
1737  /* Some FLAMES images are BITPIX=16 (ORDEF),
1738  some are 32 SLIT_FF_COM_REDL
1739  */
1740  else if (t == CPL_TYPE_INT ) {
1741  if (use_bitpix16_for_int) bpp = CPL_BPP_16_UNSIGNED;
1742  else bpp = CPL_BPP_32_SIGNED;
1743  }
1744  else assure(false, CPL_ERROR_UNSUPPORTED_MODE,
1745  "Unsupported image type '%s'", uves_tostring_cpl_type(t));
1746 
1747 
1748  thresholded = cpl_image_duplicate(image);
1749  assure_mem( thresholded );
1750 
1751  if (t == CPL_TYPE_DOUBLE)
1752  {
1753  passure( bpp == CPL_BPP_IEEE_FLOAT, "%d", bpp);
1754 
1755  /* Avoid infinities that would happen when casting
1756  double -> float
1757  by thresholding the image to +-FLT_MAX (or, better
1758  a little less than FLT_MAX just to be sure).
1759 
1760  (This is not a really nice solution because it solves the
1761  problem (too large/small values) after it is introduced
1762  (rather than avoiding it), but a general solution of the
1763  problem would probably mean guarding every arithmetic
1764  operation with range checks.)
1765  */
1766 
1767  check_nomsg( cpl_image_threshold(thresholded,
1768  -FLT_MAX, FLT_MAX,
1769  -FLT_MAX, FLT_MAX) );
1770 
1771  /* Also get rid of NaN, set to zero (what else?) */
1772  {
1773  double *data = cpl_image_get_data_double(thresholded);
1774  int nx = cpl_image_get_size_x(thresholded);
1775  int ny = cpl_image_get_size_y(thresholded);
1776  int x, y;
1777 
1778  for (y = 0; y < ny; y++)
1779  for (x = 0; x < nx; x++)
1780  {
1781  if (irplib_isnan(data[x + y*nx]))
1782  {
1783  data[x + y*nx] = 0;
1784  }
1785  }
1786  }
1787  }
1788 
1789  if (save1d &&
1790  cpl_image_get_size_y(thresholded) == 1 &&
1791  (t == CPL_TYPE_DOUBLE ||
1792  t == CPL_TYPE_FLOAT)) {
1793 
1794  bool invert = false;
1795  if (plist != NULL)
1796  {
1797  header = uves_propertylist_duplicate(plist);
1798 
1799  uves_propertylist_erase_regexp(header, "^CDELT2$", invert);
1800  uves_propertylist_erase_regexp(header, "^CRPIX2$", invert);
1801  uves_propertylist_erase_regexp(header, "^CRVAL2$", invert);
1802  uves_propertylist_erase_regexp(header, "^CTYPE2$", invert);
1803  if(uves_propertylist_has(plist,"CDELT1")) {
1804  double cdelt1=uves_pfits_get_cdelt1(header);
1805  uves_pfits_set_cd11(header,cdelt1);
1806  }
1807  }
1808  else
1809  {
1810  header = NULL;
1811  }
1812 
1813  /* Image type must be double, before wrapping it
1814  in a vector */
1815  if (t == CPL_TYPE_FLOAT) {
1816  thresholded_double = cpl_image_cast(thresholded, CPL_TYPE_DOUBLE);
1817  }
1818  else {
1819  thresholded_double = cpl_image_duplicate(thresholded);
1820  }
1821 
1822  passure( cpl_image_get_type(thresholded_double) == CPL_TYPE_DOUBLE, "%d",
1823  cpl_image_get_type(thresholded_double));
1824 
1825  image_1d = cpl_vector_wrap(
1826  cpl_image_get_size_x(thresholded_double),
1827  cpl_image_get_data_double(thresholded_double));
1828 
1829  check( uves_vector_save(image_1d, filename, bpp, header, CPL_IO_DEFAULT),
1830  "Error saving vector to file '%s'", filename );
1831  }
1832  else
1833  {
1834 
1835  if (plist != NULL) {
1836  if(uves_propertylist_has(plist,"CDELT1")) {
1837  double cdelt1=uves_pfits_get_cdelt1(plist);
1838  uves_pfits_set_cd11(plist,cdelt1);
1839  uves_pfits_set_cd12(plist,0);
1840  }
1841  if(uves_propertylist_has(plist,"CDELT2")) {
1842  double cdelt2=uves_pfits_get_cdelt2(plist);
1843  uves_pfits_set_cd21(plist,0);
1844  uves_pfits_set_cd22(plist,cdelt2);
1845  }
1846  }
1847 
1848 
1849  check( uves_image_save(thresholded, filename, bpp, plist, CPL_IO_DEFAULT),
1850  "Error saving image to file '%s'", filename);
1851  }
1852  }
1853 
1854  cleanup:
1855  uves_unwrap_vector_const(&image_1d);
1856  uves_free_propertylist(&header);
1857  uves_free_image(&thresholded);
1858  uves_free_image(&thresholded_double);
1859 
1860  return;
1861 }
1862 
1863 
1864 /*----------------------------------------------------------------------------*/
1884 /*----------------------------------------------------------------------------*/
1885 void
1886 uves_save_imagelist(const cpl_imagelist *iml, const char *filename, const uves_propertylist *plist)
1887 {
1888  const cpl_image* img=NULL;
1889  cpl_type_bpp bpp;
1890  cpl_type t;
1891  const cpl_vector *image_1d = NULL;
1892  uves_propertylist *header = NULL;
1893  cpl_imagelist *thresholded = NULL;
1894 
1895  int nx = 0;
1896  int ny = 0;
1897  int nz = 0;
1898 
1899 
1900  cknull(iml,"Null input image");
1901  check(img=cpl_imagelist_get_const(iml,0),"error reading image");
1902 
1903  check_nomsg( nx = cpl_image_get_size_x(img));
1904  check_nomsg( ny = cpl_image_get_size_y(img));
1905  check_nomsg( nz = cpl_imagelist_get_size(iml));
1906 
1907  check( t = cpl_image_get_type(img), "Error reading image type");
1908  if (t == CPL_TYPE_FLOAT ) bpp = CPL_BPP_IEEE_FLOAT;
1909  else if (t == CPL_TYPE_DOUBLE) bpp = CPL_BPP_IEEE_FLOAT;
1910  /* Internal computations in double precision,
1911  save as single precision */
1912  else if (t == CPL_TYPE_INT ) bpp = CPL_BPP_16_UNSIGNED;
1913  else assure(false, CPL_ERROR_UNSUPPORTED_MODE,
1914  "Unsupported image type '%s'", uves_tostring_cpl_type(t));
1915 
1916 
1917  thresholded = cpl_imagelist_duplicate(iml);
1918  assure_mem( thresholded );
1919 
1920  if (t == CPL_TYPE_DOUBLE)
1921  {
1922  passure( bpp == CPL_BPP_IEEE_FLOAT, "%d", bpp);
1923 
1924  /* Avoid infinities that would happen when casting
1925  double -> float
1926  by thresholding the image to +-FLT_MAX (or, better
1927  a little less than FLT_MAX just to be sure).
1928 
1929  (This is not a really nice solution because it solves the
1930  problem (too large/small values) after it is introduced
1931  (rather than avoiding it), but a general solution of the
1932  problem would probably mean guarding every arithmetic
1933  operation with range checks.)
1934  */
1935 
1936  check_nomsg( cpl_imagelist_threshold(thresholded,
1937  -FLT_MAX, FLT_MAX,
1938  -FLT_MAX, FLT_MAX) );
1939 
1940 
1941 
1942  /* Also get rid of NaN, set to zero (what else?) */
1943  {
1944  int x, y, z;
1945  double* data=NULL;
1946  cpl_image* ima=NULL;
1947  for (z = 0; z < nz; z++) {
1948  ima=cpl_imagelist_get(thresholded,z);
1949  data = cpl_image_get_data_double(ima);
1950 
1951  for (y = 0; y < ny; y++) {
1952  for (x = 0; x < nx; x++) {
1953  if (irplib_isnan(data[x + y*nx])) {
1954  data[x + y*nx] = 0;
1955  }
1956  }
1957  }
1958  }
1959  }
1960  }
1961  if (nz == 1 && t == CPL_TYPE_DOUBLE)
1962  /* To support other types (float, int) we would
1963  need to convert to double first */
1964  {
1965  bool invert = false;
1966  if (plist != NULL)
1967  {
1968  header = uves_propertylist_duplicate(plist);
1969 
1970  uves_propertylist_erase_regexp(header, "^CDELT3$", invert);
1971  uves_propertylist_erase_regexp(header, "^CRPIX3$", invert);
1972  uves_propertylist_erase_regexp(header, "^CRVAL3$", invert);
1973  uves_propertylist_erase_regexp(header, "^CTYPE3$", invert);
1974  }
1975  else
1976  {
1977  header = NULL;
1978  }
1979  /*
1980  image_1d = cpl_vector_wrap(nx,
1981  cpl_image_get_data_double_const(thresholded));
1982 
1983  check( uves_vector_save(image_1d, filename, bpp, header, CPL_IO_DEFAULT),
1984  "Error saving vector to file '%s'", filename );
1985  */
1986 
1987  }
1988  else
1989  {
1990  check( uves_imagelist_save(thresholded, filename, bpp, plist, CPL_IO_DEFAULT),
1991  "Error saving image to file '%s'", filename);
1992  }
1993 
1994  cleanup:
1995  uves_unwrap_vector_const(&image_1d);
1996  uves_free_propertylist(&header);
1997  uves_free_imagelist(&thresholded);
1998 
1999  return;
2000 }
2001 
2002 /*----------------------------------------------------------------------------*/
2016 /*----------------------------------------------------------------------------*/
2017 cpl_error_code
2018 uves_save_polynomial(polynomial *p, const char *filename, const uves_propertylist *header)
2019 {
2020  cpl_table *t = NULL;
2021 
2022  check( t = uves_polynomial_convert_to_table(p), "Error converting polynomial to table");
2023 
2024  check( uves_table_save(t,
2025  NULL, /* Primary header, ignored when
2026  mode = CPL_IO_EXTEND */
2027  header, /* Table header */
2028  filename,
2029  CPL_IO_EXTEND), /* Append to existing file */
2030  "Error saving table to file '%s'", filename);
2031 
2032  cleanup:
2033  uves_free_table(&t);
2034  return cpl_error_get_code();
2035 }
2036 
2037 
2038 /*----------------------------------------------------------------------------*/
2046 /*----------------------------------------------------------------------------*/
2047 static polynomial *
2048 load_polynomial(const char* filename, int extension)
2049 {
2050  polynomial *p = NULL; /* Result */
2051  cpl_table *t = NULL;
2052 
2053  check(t = cpl_table_load(filename,
2054  extension,
2055  1), /* Mark identified
2056  invalid null values (1=yes) */
2057  "Error loading polynomial from extension %d of file '%s'", extension, filename);
2058 
2059  assure( uves_erase_invalid_table_rows(t, NULL) == 0,
2060  CPL_ERROR_ILLEGAL_INPUT, "Table contains invalid rows");
2061 
2062  check(p = uves_polynomial_convert_from_table(t), "Error converting table to polynomial");
2063 
2064  cleanup:
2065  uves_free_table(&t);
2066  if (cpl_error_get_code() != CPL_ERROR_NONE)
2068  return p;
2069 }
2070 /*----------------------------------------------------------------------------*/
2085 /*----------------------------------------------------------------------------*/
2086 static const char *
2087 identify_arm(const cpl_frameset *frames, const char *blue_tag, const char *red_tag,
2088  bool *blue)
2089 {
2090  const char *tag = NULL; /* Result */
2091 
2092  const cpl_frame *frame = NULL;
2093 
2094  passure( frames != NULL, "");
2095  assure (!cpl_frameset_is_empty(frames), CPL_ERROR_ILLEGAL_INPUT, "No input frames");
2096 
2097  /* Identify blue/red arm */
2098  frame = cpl_frameset_find_const(frames, blue_tag);
2099  *blue = (frame != NULL);
2100 
2101  if (frame == NULL)
2102  {
2103  frame = cpl_frameset_find_const(frames, red_tag);
2104  }
2105 
2106  assure( frame != NULL, CPL_ERROR_ILLEGAL_INPUT,
2107  "No valid input frames "
2108  "('%s' or '%s') in frame set",
2109  blue_tag, red_tag);
2110 
2111  assure( cpl_frameset_find_const(frames, blue_tag) == NULL ||
2112  cpl_frameset_find_const(frames, red_tag) == NULL,
2113  CPL_ERROR_INCOMPATIBLE_INPUT,
2114  "Multiple types of input frames ('%s' and '%s') in frame set",
2115  blue_tag, red_tag);
2116 
2117  tag = cpl_frame_get_tag(frame);
2118 
2119  uves_msg("Input frames are '%s'", tag);
2120 
2121 
2122  cleanup:
2123  return tag;
2124 }
2125 
2126 /*----------------------------------------------------------------------------*/
2144 /*----------------------------------------------------------------------------*/
2145 cpl_image *
2146 uves_crop_and_rotate(const cpl_image *image, const uves_propertylist *header,
2147  enum uves_chip chip,
2148  const uves_propertylist *redl_header,
2149  bool new_format, uves_propertylist **out_header)
2150 {
2151  cpl_image *result = NULL;
2152  int prescanx, ovrscanx;
2153  cpl_size nx, ny;
2154  int x_0, y_0, x_1, y_1; /* Extracted area (inclusive) in
2155  FITS convention (i.e. counting from 1) */
2156 
2157  const char *ctype1, *ctype2; /* Geometry */
2158  const char *cunit1, *cunit2; /* Units */
2159  const char *bunit;
2160  double bscale=0;
2161  double crval1, crval2;
2162  double crpix1, crpix2;
2163  double cdelt1, cdelt2;
2164 
2165 
2166  passure( image != NULL, " ");
2167  passure( header != NULL, " ");
2168  passure( out_header != NULL, " ");
2169 
2170  nx = cpl_image_get_size_x(image);
2171  ny = cpl_image_get_size_y(image);
2172 
2173 
2174  /* Determine pre- and overscan areas */
2175  check( prescanx = uves_pfits_get_prescanx(header, chip), "Could not read x-prescan info" );
2176  check( ovrscanx = uves_pfits_get_ovrscanx(header, chip), "Could not read x-overscan info");
2177 
2178  /* Don't try to read the y pre- and overscan regions, which should be zero for UVES.
2179  The keywords are not present in older UVES data. */
2180 
2181  /* Read geometry */
2182  check( ctype1 = uves_pfits_get_ctype1(header), "Error reading keyword");
2183  check( ctype2 = uves_pfits_get_ctype2(header), "Error reading keyword");
2184  check( crval1 = uves_pfits_get_crval1(header), "Error reading keyword");
2185  check( crval2 = uves_pfits_get_crval2(header), "Error reading keyword");
2186  check( crpix1 = uves_pfits_get_crpix1(header), "Error reading keyword");
2187  check( crpix2 = uves_pfits_get_crpix2(header), "Error reading keyword");
2188  check( cdelt1 = uves_pfits_get_cdelt1(header), "Error reading keyword");
2189  check( cdelt2 = uves_pfits_get_cdelt2(header), "Error reading keyword");
2190  if (uves_propertylist_contains(header, UVES_BUNIT))
2191  {
2192  bunit = uves_pfits_get_bunit(header);
2193  }
2194  else
2195  {
2196  bunit = " ";
2197  }
2198  if (uves_propertylist_contains(header, UVES_BSCALE))
2199  {
2200  bscale = uves_pfits_get_bscale(header);
2201  }
2202  else
2203  {
2204  bscale = 0;
2205  }
2206 
2207  if (uves_propertylist_contains(header, UVES_CUNIT1))
2208  {
2209  cunit1 = uves_pfits_get_cunit1(header);
2210  }
2211  else
2212  {
2213  cunit1 = " ";
2214  }
2215  if (uves_propertylist_contains(header, UVES_CUNIT2))
2216  {
2217  cunit2 = uves_pfits_get_cunit2(header);
2218  }
2219  else
2220  {
2221  cunit2 = " ";
2222  }
2223 
2224 
2225  /* Crop the image */
2226  {
2227  y_0 = 1;
2228  y_1 = ny;
2229  if (new_format || chip == UVES_CHIP_BLUE)
2230  {
2231  x_0 = prescanx + 1;
2232  x_1 = nx - ovrscanx;
2233  }
2234  else /* red, old format */
2235  {
2236  if (chip == UVES_CHIP_REDU)
2237  {
2238  x_0 = prescanx + 1;
2239  x_1 = nx/2 - ovrscanx;
2240  }
2241  else
2242  { /* lower */
2243  x_0 = nx/2 + prescanx + 1;
2244  x_1 = nx - ovrscanx;
2245  }
2246  }
2247  check( result = cpl_image_extract(image, x_0, y_0, x_1, y_1), "Could not crop image");
2248  crpix1 = crpix1 - (x_0 - 1);
2249  crpix2 = crpix2 - (y_0 - 1);
2250  nx = (x_1 - x_0) + 1;
2251  ny = (y_1 - y_0) + 1;
2252  }
2253 
2254  UVES_TIME_START("Rotation");
2255  /* ... is a bit slow, and there's probably nothing to
2256  do about as it involves moving data between remote
2257  places in memory.
2258  */
2259 
2260  /* Rotate the image into standard orientation */
2261  {
2262  int crpix1_old = crpix1;
2263  int crpix2_old = crpix2;
2264  int crval1_old = crval1;
2265  int crval2_old = crval2;
2266  int cdelt1_old = cdelt1;
2267  int cdelt2_old = cdelt2;
2268  const char *ctype1_old = ctype1;
2269  const char *ctype2_old = ctype2;
2270 
2271  if (chip == UVES_CHIP_BLUE)
2272  {
2273  /* 90 deg counterclockwise rotation */
2274  check( cpl_image_turn(result, -1), "Could not turn image");
2275 
2276  crpix1 = ny - (crpix2_old - 1); /* Note: old value of ny */
2277  crpix2 = crpix1_old;
2278  crval1 = crval2_old;
2279  crval2 = crval1_old;
2280  }
2281  else
2282  {
2283  /* Red */
2284  /* Flip image around y=-x */
2285  check( cpl_image_flip(result, 3), "Could not flip image");
2286 
2287  crpix1 = ny - (crpix2_old - 1); /* Note: old value of nx, ny */
2288  crpix2 = nx - (crpix1_old - 1);
2289  crval1 = crval2_old;
2290  crval2 = crval1_old;
2291  }
2292 
2293 
2294  /* Always swap these ones */
2295  ctype1 = ctype2_old;
2296  ctype2 = ctype1_old;
2297  cdelt1 = cdelt2_old;
2298  cdelt2 = cdelt1_old;
2299  }
2300 
2301  UVES_TIME_END;
2302 
2303  /* Here we should use the CROTAi keywords to
2304  properly describe the new rotation */
2305 
2306  /* Instead, redefine CRVAL as in the following, on request from DFO */
2307 
2308  crpix1 = 1;
2309  crpix2 = 1;
2310  if (chip == UVES_CHIP_BLUE || chip == UVES_CHIP_REDL)
2311  {
2312  crval1 = 1;
2313  crval2 = 1;
2314  }
2315  else
2316  {
2317  int physical_gap_between_chips = 64; /* Pixels. Unbinned. Hardcoded. */
2318 
2319 
2320  passure( chip == UVES_CHIP_REDU , "%d", chip );
2321 
2322  crval1 = 1;
2323 
2324  /* Set CRVAL2 = REDL_height - REDL_overscan - REDL_prescan + gap. */
2325  if (new_format)
2326  {
2327 
2328  check( crval2 = 1 +
2329  (uves_pfits_get_naxis1(redl_header) -
2330  uves_pfits_get_ovrscanx(redl_header, UVES_CHIP_REDL) -
2331  uves_pfits_get_prescanx(redl_header, UVES_CHIP_REDL)) *
2332  uves_pfits_get_cdelt1(redl_header) +
2333  physical_gap_between_chips,
2334  "Error reading REDL chip geometry");
2335 
2336  uves_msg_debug("Setting CRVAL2 = 1 + (%d - %d - %d) * %f + %d = %f",
2337  uves_pfits_get_naxis1(redl_header),
2338  uves_pfits_get_ovrscanx(redl_header, UVES_CHIP_REDL),
2339  uves_pfits_get_prescanx(redl_header, UVES_CHIP_REDL),
2340  uves_pfits_get_cdelt1(redl_header),
2341  physical_gap_between_chips, crval2);
2342  }
2343  else
2344  {
2345 
2346  /* old format */
2347  check( crval2 = 1 +
2348  (uves_pfits_get_naxis1(header)/2 -
2349  uves_pfits_get_ovrscanx(redl_header, UVES_CHIP_REDL) -
2350  uves_pfits_get_prescanx(redl_header, UVES_CHIP_REDL)) *
2351  uves_pfits_get_cdelt1(redl_header) +
2352  physical_gap_between_chips,
2353  "Error reading REDL chip geometry");
2354 
2355  uves_msg_debug("Setting CRVAL2 = 1 + (%d - %d - %d) * %f + %d = %f",
2356  uves_pfits_get_naxis1(header)/2,
2357  uves_pfits_get_ovrscanx(redl_header, UVES_CHIP_REDL),
2358  uves_pfits_get_prescanx(redl_header, UVES_CHIP_REDL),
2359  uves_pfits_get_cdelt1(redl_header),
2360  physical_gap_between_chips, crval2);
2361  }
2362 
2363  }
2364 
2365 
2366  /* Update header with new geometry */
2367  check( *out_header = uves_initialize_image_header(ctype1, ctype2,
2368  cunit1, cunit2,
2369  bunit,bscale,
2370  crval1, crval2,
2371  crpix1, crpix2,
2372  cdelt1, cdelt2),
2373  "Error initializing header");
2374 
2375  //check(uves_propertylist_copy_property_regexp(*out_header, header,
2376  // "^ESO ", 0),
2377  // "Error copying hieararch keys");
2378 
2379 
2380  uves_msg("Raw image cropped and rotated from %" CPL_SIZE_FORMAT "x%" CPL_SIZE_FORMAT " to %" CPL_SIZE_FORMAT "x%" CPL_SIZE_FORMAT "",
2381  nx, ny,
2382  cpl_image_get_size_x(result),
2383  cpl_image_get_size_y(result));
2384 
2385  cleanup:
2386  if (cpl_error_get_code() != CPL_ERROR_NONE)
2387  {
2388  uves_free_image(&result);
2389  if (out_header != NULL)
2390  {
2391  uves_free_propertylist(out_header);
2392  }
2393  }
2394 
2395  return result;
2396 }
2397 
2398 /*----------------------------------------------------------------------------*/
2412 /*----------------------------------------------------------------------------*/
2413 void
2414 uves_warn_if_chip_names_dont_match(const uves_propertylist *calib_header,
2415  const char *raw_chip_name, enum uves_chip chip)
2416 {
2417  const char *calib_chip_name;
2418  bool mismatch = false;
2419 
2420  check( calib_chip_name = uves_pfits_get_chipid(calib_header, chip),
2421  "Could not read chip name of calibration data");
2422 
2423 
2424  /* Ignore leading/trailing blanks when comparing name strings.
2425  * (The following is O(n^2) where n is the string length,
2426  * but that's ok because the strings stored in a FITS card are short).
2427  */
2428  {
2429  unsigned int calib_first, calib_last; /* inclusive */
2430  unsigned int raw_first, raw_last;
2431 
2432  calib_first = 0;
2433  raw_first = 0;
2434  while (calib_chip_name[calib_first] == ' ' && calib_first < strlen(calib_chip_name) - 1)
2435  {
2436  calib_first++;
2437  }
2438  while (raw_chip_name[raw_first] == ' ' && raw_first < strlen(raw_chip_name) - 1)
2439  {
2440  raw_first++;
2441  }
2442 
2443  calib_last = strlen(calib_chip_name) - 1;
2444  raw_last = strlen(raw_chip_name) - 1;
2445  while (calib_chip_name[calib_last] == ' ' && calib_last > 0)
2446  {
2447  calib_last--;
2448  }
2449  while (raw_chip_name[raw_last] == ' ' && raw_last > 0)
2450  {
2451  raw_last--;
2452  }
2453 
2454  /* Compare substrings */
2455  if (calib_last - calib_first != raw_last - raw_first)
2456  {
2457  mismatch = true;
2458  }
2459  else
2460  {
2461  unsigned int i;
2462 
2463  for (i = 0; i <= (calib_last - calib_first); i++)
2464  {
2465  if (raw_chip_name[raw_first + i] !=
2466  calib_chip_name[calib_first + i])
2467  {
2468  mismatch = true;
2469  }
2470  }
2471  }
2472  }
2473 
2474 
2475  if (mismatch)
2476  {
2477  uves_msg_warning("Calibration frame chip ID '%s' does "
2478  "not match raw frame chip ID '%s'",
2479  calib_chip_name, raw_chip_name);
2480  }
2481 
2482  cleanup:
2483  return;
2484 }
2485 
2486 
2487 /*----------------------------------------------------------------------------*/
2509 /*----------------------------------------------------------------------------*/
2510 
2511 static cpl_error_code
2512 load_raw_image(const char *filename,
2513  cpl_type type,
2514  bool flames,
2515  bool blue,
2516  cpl_image *raw_image[2],
2517  uves_propertylist *raw_header[2],
2518  uves_propertylist *rotated_header[2])
2519 {
2520 
2521 
2522  cpl_image *image = NULL;
2523  uves_propertylist *primary_header = NULL;
2524  uves_propertylist *ext_header = NULL;
2525  int extension, nextensions;
2526  bool new_format;
2527  int plane = 0; /* Only one plane in FLAMES/UVES raw files */
2528 
2529  cpl_image* image1=NULL;
2530  cpl_image* image2=NULL;
2531  int sx=0;
2532  int sy=0;
2533 
2534 
2535  /* Initialize parameters */
2536  raw_image[0] = NULL;
2537  raw_image[1] = NULL;
2538  raw_header[0] = NULL;
2539  raw_header[1] = NULL;
2540  rotated_header[0] = NULL;
2541  rotated_header[1] = NULL;
2542 
2543  check( nextensions = uves_get_nextensions(filename),
2544  "Error reading number of extensions of file '%s'", filename);
2545 
2546  /* Find out if new/old format */
2547  extension = 0;
2548  check( primary_header = uves_propertylist_load(filename,
2549  extension),
2550  "Could not load header from extension %d of file '%s'",
2551  extension, filename);
2552 
2553  check( new_format = uves_format_is_new(primary_header),
2554  "Error determining new/old format of file %s", filename);
2555 
2556  uves_msg_low("Raw frame is %s, %s format, file '%s' has %d extensions",
2557  (blue) ? "blue" : "red", (new_format) ? "new" : "old",
2558  filename, nextensions);
2559 
2560  /* If the raw frame is blue, or if it's an old format red frame */
2561  if (blue || !new_format)
2562  {
2563  enum uves_chip chip;
2564 
2565  uves_msg_debug("Frame is blue or old format");
2566 
2567  assure( nextensions == 0 ||
2568  (blue && nextensions == 2) ||
2569  (flames && nextensions == 2),
2570  CPL_ERROR_ILLEGAL_INPUT,
2571  "Unrecognized format of file '%s'. %d extensions expected. %d found.",
2572  filename,
2573  ((flames||blue) && (nextensions ==2)) ? 2 : 0, nextensions);
2574 
2575  /* FLAMES: the 2 extensions contain OzPoz table and FLAMES FIBRE table */
2576 
2577  /* Load the header */
2578  check( raw_header[0] = uves_propertylist_load(filename,
2579  extension),
2580  "Could not load header from extension %d of file '%s'",
2581  extension, filename);
2582 
2583 
2584  extension = 0;
2585  if(blue && nextensions == 2) {
2586  extension = 1;
2587  check( raw_header[1] = uves_propertylist_load(filename,
2588  extension),
2589  "Could not load header from extension %d of file '%s'",
2590  extension, filename);
2591  check( uves_propertylist_append(raw_header[0],raw_header[1]),
2592  "Could not collate header from extension 1 to 0 of file '%s'",filename);
2593  uves_free_propertylist(&raw_header[1]);
2594 
2595  check( image1 = cpl_image_load(filename,
2596  type,
2597  plane,
2598  extension
2599  ), "Could not load image from extension %d of file '%s' ",
2600  extension, filename);
2601  cpl_image_save(image1, "ima1.fits", CPL_BPP_IEEE_FLOAT,
2602  NULL,CPL_IO_DEFAULT);
2603 
2604  extension = 2;
2605  check( image2 = cpl_image_load(filename,
2606  type,
2607  plane,
2608  extension
2609  ), "Could not load image from extension %d of file '%s' ",
2610  extension, filename);
2611  check_nomsg(sx=cpl_image_get_size_x(image1));
2612  check_nomsg(sy=cpl_image_get_size_y(image1));
2613 
2614  check_nomsg(image=cpl_image_new(2*sx,sy,type));
2615  check_nomsg(cpl_image_copy(image,image1,1,1));
2616  check_nomsg(cpl_image_copy(image,image2,1+sx,1));
2617 
2618 
2619  uves_free_image(&image1);
2620  uves_free_image(&image2);
2621 
2622  extension = 1;
2623 
2624 
2625 
2626  } else {
2627 
2628 
2629  check( image = cpl_image_load(filename,
2630  type,
2631  plane,
2632  extension
2633  ), "Could not load image from extension %d of file '%s' ",
2634  extension, filename);
2635  }
2636 
2637  /* Get blue (or lower red) chip */
2638  chip = (blue) ? UVES_CHIP_BLUE : UVES_CHIP_REDL;
2639  check( raw_image[0] = uves_crop_and_rotate(image, raw_header[0],
2640  chip, raw_header[0],
2641  new_format,
2642  &rotated_header[0]),
2643  "Error splitting image");
2644 
2645  if (!blue)
2646  {
2647  const uves_propertylist *redl_header;
2648 
2649  /* Upper red chip, use again the primary header */
2650  check( raw_header[1] = uves_propertylist_duplicate(raw_header[0]),
2651  "Error duplicating FITS header");
2652 
2653  /* Get upper red chip */
2654  chip = UVES_CHIP_REDU;
2655  redl_header = raw_header[0];
2656  check( raw_image[1] = uves_crop_and_rotate(image, raw_header[1],
2657  chip, redl_header,
2658  new_format,
2659  &rotated_header[1]),
2660  "Error splitting red image");
2661  }
2662  else
2663  {
2664  raw_image[1] = NULL;
2665  raw_header[1] = NULL;
2666  rotated_header[1] = NULL;
2667  }
2668  }
2669  else
2670  /* New red format. UVES must have 2 extensions,
2671  * FLAMES must have 2 or more extensions
2672  */
2673  {
2674  uves_msg_debug("Frame is red, new format");
2675 
2676  assure( nextensions >= 2, CPL_ERROR_UNSUPPORTED_MODE,
2677  "File '%s' (red frame) has %d extensions. 2+ extensions expected "
2678  "for new format",
2679  filename, nextensions);
2680 
2681  uves_msg_debug("New red format, %s frame",
2682  (nextensions > 2) ? "FLAMES" : "FLAMES/UVES");
2683 
2684 
2685  /* Images always in extension 1 and 2. First load just the headers */
2686  for (extension = 1; extension <= 2; extension++)
2687  {
2688  /* In the FITS file, REDU is stored
2689  in extension 1, and REDL is stored in
2690  extension 2 */
2691  enum uves_chip chip = (extension == 1) ? UVES_CHIP_REDU : UVES_CHIP_REDL;
2692  int indx = uves_chip_get_index(chip);
2693 
2694  /* Load the extension header */
2695  uves_free_propertylist(&ext_header);
2696  check( ext_header = uves_propertylist_load(filename,
2697  extension),
2698  "Could not load header from extension %d of file '%s'",
2699  extension, filename);
2700 
2701  /* Merge with primary header */
2702  check( raw_header[indx] = uves_propertylist_duplicate(primary_header),
2703  "Error cloning primary header");
2704 
2705  if (!uves_propertylist_is_empty(ext_header))
2706  {
2707  if(cpl_propertylist_has(ext_header,"TM-START") &&
2708  cpl_propertylist_has(primary_header,"TM-START") ) {
2709  uves_propertylist_erase(ext_header,"TM-START");
2710  }
2711  if(cpl_propertylist_has(ext_header,"DATE-OBS") &&
2712  cpl_propertylist_has(primary_header,"DATE-OBS") ) {
2713  uves_propertylist_erase(ext_header,"DATE-OBS");
2714  }
2715  if(cpl_propertylist_has(ext_header,"EXPTIME") &&
2716  cpl_propertylist_has(ext_header,"EXPTIME")) {
2717  uves_propertylist_erase(ext_header,"EXPTIME");
2718  }
2720  ext_header, ".*", 0),
2721  "Error merging primary header with extension %d header",
2722  extension);
2723  }
2724  }
2725 
2726 
2727  /* Remove pre-, overscan areas (we needed to load both image headers for this) */
2728  for (extension = 1; extension <= 2; extension++)
2729  {
2730  enum uves_chip chip = (extension == 1) ? UVES_CHIP_REDU : UVES_CHIP_REDL;
2731  int indx = uves_chip_get_index(chip);
2732  int indx_redl = uves_chip_get_index(UVES_CHIP_REDL);
2733 
2734  const uves_propertylist *redl_header = raw_header[indx_redl];
2735 
2736  uves_free_image(&image);
2737  check( image = cpl_image_load(filename,
2738  type,
2739  plane,
2740  extension),
2741  "Could not load image from extension %d of file '%s' ",
2742  extension, filename);
2743 
2744  check( raw_image[indx] = uves_crop_and_rotate(image,
2745  raw_header[indx],
2746  chip, redl_header,
2747  new_format,
2748  &rotated_header[indx]),
2749  "Error splitting red image");
2750  }
2751 
2752 
2753  }/* if new format */
2754 
2755 
2756  cleanup:
2757  uves_free_image(&image);
2758  uves_free_image(&image1);
2759  uves_free_image(&image2);
2760 
2761  uves_free_propertylist(&primary_header);
2762  uves_free_propertylist(&ext_header);
2763 
2764  if (cpl_error_get_code() != CPL_ERROR_NONE)
2765  {
2766  uves_free_image (&raw_image[0]);
2767  uves_free_image (&raw_image[1]);
2768  uves_free_propertylist(&raw_header[0]);
2769  uves_free_propertylist(&raw_header[1]);
2770  uves_free_propertylist(&rotated_header[0]);
2771  uves_free_propertylist(&rotated_header[1]);
2772  }
2773 
2774  return cpl_error_get_code();
2775 }
2776 
2777 
2778 /*----------------------------------------------------------------------------*/
2806 /*----------------------------------------------------------------------------*/
2807 cpl_error_code
2808 uves_load_raw_imagelist(const cpl_frameset *frames,
2809  bool flames,
2810  const char *blue_tag, const char *red_tag, cpl_type type,
2811  cpl_imagelist *images[2],
2812  uves_propertylist **raw_headers[2], uves_propertylist *rotated_header[2],
2813  bool *blue)
2814 {
2815  const char *tag = NULL;
2816  const cpl_frame *frame = NULL;
2817  cpl_image *temp_image[2] = {NULL, NULL};
2818  uves_propertylist *temp_header[2] = {NULL, NULL};
2819  cpl_size number_of_frames = 0;
2820  int frameset_size = 0; /* Keeps track of number of raw_header pointers allocated */
2821  int nchips;
2822  int chip;
2823 
2824  raw_headers[0] = NULL;
2825  raw_headers[1] = NULL;
2826 
2827  check( frameset_size = cpl_frameset_get_size(frames),
2828  "Error reading frameset size");
2829 
2830  check( tag = identify_arm(frames, blue_tag, red_tag, blue),
2831  "Could not identify chip type");
2832 
2833  nchips = (*blue) ? 1 : 2;
2834  for(chip = 0; chip < nchips; chip++)
2835  {
2836  images[chip] = NULL;
2837  rotated_header[chip] = NULL;
2838 
2839  images[chip] = cpl_imagelist_new();
2840  raw_headers[chip] = cpl_calloc(frameset_size, sizeof(uves_propertylist *));
2841  }
2842 
2843  /* Load all input images with correct tag,
2844  split,
2845  insert into image list(s) */
2846 
2847  number_of_frames = 0;
2848  int i=0;
2849  int nfrm;
2850  nfrm=cpl_frameset_get_size(frames);
2851  for(i=0;i<nfrm;i++)
2852  {
2853  frame=cpl_frameset_get_frame_const(frames,i);
2854  /* If match */
2855  if ( strcmp(cpl_frame_get_tag(frame), tag) == 0)
2856  {
2857  const char *filename = cpl_frame_get_filename(frame);
2858 
2859  /* Load image + header */
2860  uves_free_propertylist(&rotated_header[0]);
2861  uves_free_propertylist(&rotated_header[1]);
2862 
2863  check( load_raw_image(filename,
2864  type,
2865  flames,
2866  *blue,
2867  temp_image,
2868  temp_header,
2869  rotated_header),
2870  "Could not load image from file '%s'", filename);
2871 
2872  /* Append to image lists */
2873  for(chip = 0; chip < nchips; chip++)
2874  {
2875  raw_headers[chip][number_of_frames] = temp_header[chip];
2876  temp_header[chip] = NULL;
2877 
2878  check( cpl_imagelist_set(images[chip],
2879  temp_image[chip],
2880  /* Position */
2881  cpl_imagelist_get_size(images[chip])
2882  ),
2883  "Could not insert image into image list");
2884 
2885  /* Don't deallocate image or header */
2886  temp_image[chip] = NULL;
2887  }
2888 
2889  number_of_frames += 1;
2890  }
2891  }
2892 
2893  /* Check that image sizes are identical */
2894 
2895  for(chip = 0; chip < nchips; chip++)
2896  {
2897  /* This function returns zero iff the list is uniform */
2898  assure (cpl_imagelist_is_uniform(images[chip]) == 0,
2899  CPL_ERROR_INCOMPATIBLE_INPUT,
2900  "Input images are not of same size and type");
2901 
2902  passure( cpl_imagelist_get_size(images[chip]) == number_of_frames,
2903  "%" CPL_SIZE_FORMAT " %" CPL_SIZE_FORMAT"", cpl_imagelist_get_size(images[0]), number_of_frames);
2904 
2905  }
2906 
2907 
2908  /* Check central wavelengths (not bias/dark) */
2909  if ( strcmp(UVES_BIAS (*blue), tag) != 0 &&
2910  strcmp(UVES_DARK (*blue), tag) != 0 &&
2911  strcmp(UVES_PDARK(*blue), tag) != 0) {
2912  enum uves_chip chip_id;
2913  int i;
2914  double wlen = 0;
2915 
2916  for (chip_id = uves_chip_get_first(*blue);
2917  chip_id != UVES_CHIP_INVALID;
2918  chip_id = uves_chip_get_next(chip_id)) {
2919  for (i = 0; i < number_of_frames; i++) {
2920  if (i == 0) {
2922  raw_headers[uves_chip_get_index(chip_id)][i], chip_id),
2923  "Error reading central wavelength of input frame number %d", i+1);
2924  }
2925  else {
2926  double w;
2927 
2929  raw_headers[uves_chip_get_index(chip_id)][i], chip_id),
2930  "Error reading central wavelength of input frame number %d", i+1);
2931 
2932  assure( fabs((w-wlen)/wlen) < 0.01, CPL_ERROR_INCOMPATIBLE_INPUT,
2933  "Mis-matching input frame central wavelengths: "
2934  "%e (frame 1) != %e (frame %d)", wlen, w, i+1);
2935  }
2936  }
2937  }
2938  }
2939 
2940  cleanup:
2941  uves_free_image(&temp_image[0]);
2942  uves_free_image(&temp_image[1]);
2943  uves_free_propertylist(&temp_header[0]);
2944  uves_free_propertylist(&temp_header[1]);
2945 
2946  if (cpl_error_get_code() != CPL_ERROR_NONE) {
2947  if (raw_headers[0] != NULL) {
2948  int i;
2949  for (i = 0; i < frameset_size; i++) {
2950  if (raw_headers[0] != NULL) uves_free_propertylist(&raw_headers[0][i]);
2951  if (raw_headers[1] != NULL) uves_free_propertylist(&raw_headers[1][i]);
2952  }
2953  }
2954  cpl_free(raw_headers[0]); raw_headers[0] = NULL;
2955  cpl_free(raw_headers[1]); raw_headers[1] = NULL;
2956 
2957  uves_free_imagelist(&images[0]);
2958  uves_free_imagelist(&images[1]);
2959 
2960  uves_free_propertylist(&rotated_header[0]);
2961  uves_free_propertylist(&rotated_header[1]);
2962  }
2963 
2964  return cpl_error_get_code();
2965 }
2966 
2967 
2968 /*----------------------------------------------------------------------------*/
2985 /*----------------------------------------------------------------------------*/
2986 cpl_error_code
2987 uves_load_orderpos(const cpl_frameset *frames,
2988  bool flames,
2989  const char **raw_filename,
2990  cpl_image *raw_image[2],
2991  uves_propertylist *raw_header[2],
2992  uves_propertylist *rotated_header[2], bool *blue)
2993 {
2994  const char *tags[4];
2995 
2996  int number_of_tags = sizeof(tags) / sizeof(char *);
2997  int indx;
2998 
2999  /* Warning: Duplicate logic. The number of tags must match the size of the
3000  tags array defined above */
3001  tags[0] = UVES_ORDER_FLAT(flames, false); /* red */
3002  tags[1] = UVES_ORDER_FLAT(flames, true); /* blue */
3003  tags[2] = UVES_STD_STAR(false);
3004  tags[3] = UVES_STD_STAR(true);
3005 
3006  if (flames)
3007  {
3008  *blue = false;
3009  number_of_tags = 1;
3010 
3011  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx,
3012  NULL),
3013  "Could not find raw frame (%s) in SOF",
3014  tags[0]);
3015 
3016  }
3017  else
3018  {
3019  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx,
3020  NULL),
3021  "Could not find raw frame (%s, %s, %s, or %s) in SOF",
3022  tags[0], tags[1], tags[2], tags[3]);
3023 
3024  *blue = (indx == 1) || (indx == 3);
3025  }
3026 
3027  /* Load the image */
3028  check( load_raw_image(*raw_filename,
3029  CPL_TYPE_DOUBLE,
3030  flames,
3031  *blue,
3032  raw_image,
3033  raw_header,
3034  rotated_header),
3035  "Error loading image from file '%s'", *raw_filename);
3036 
3037  passure( !flames || !(*blue), "%d %d",
3038  flames, *blue );
3039 
3040  cleanup:
3041  if (cpl_error_get_code() != CPL_ERROR_NONE)
3042  {
3043  *raw_filename = NULL;
3044  }
3045 
3046  return cpl_error_get_code();
3047 }
3048 
3049 /*----------------------------------------------------------------------------*/
3065 /*----------------------------------------------------------------------------*/
3066 cpl_error_code
3067 uves_load_formatcheck(const cpl_frameset *frames,
3068  bool flames,
3069  const char **raw_filename,
3070  cpl_image *raw_image[2],
3071  uves_propertylist *raw_header[2],
3072  uves_propertylist *rotated_header[2], bool *blue)
3073 {
3074  const char *tags[2];
3075  int number_of_tags = sizeof(tags) / sizeof(char *);
3076  int indx;
3077 
3078  tags[0] = UVES_FORMATCHECK(flames, false); /* red */
3079  tags[1] = UVES_FORMATCHECK(flames, true); /* blue */
3080  if (flames)
3081  {
3082  *blue = false;
3083  number_of_tags = 1;
3084 
3085  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3086  "Could not find raw frame (%s) in SOF",
3087  tags[0]);
3088  }
3089  else
3090  {
3091  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3092  "Could not find raw frame (%s or %s) in SOF",
3093  tags[0], tags[1]);
3094 
3095  *blue = (indx == 1);
3096  }
3097 
3098  /* Load the image */
3099  check( load_raw_image(*raw_filename,
3100  CPL_TYPE_DOUBLE,
3101  flames,
3102  *blue,
3103  raw_image,
3104  raw_header,
3105  rotated_header),
3106  "Error loading image from file '%s'", *raw_filename);
3107 
3108  cleanup:
3109  if (cpl_error_get_code() != CPL_ERROR_NONE)
3110  {
3111  *raw_filename = NULL;
3112  }
3113  return cpl_error_get_code();
3114 }
3115 
3116 /*----------------------------------------------------------------------------*/
3135 /*----------------------------------------------------------------------------*/
3136 void uves_load_cd_align(const cpl_frameset *frames,
3137  const char **raw_filename1,
3138  const char **raw_filename2,
3139  cpl_image *raw_image1[2],
3140  cpl_image *raw_image2[2],
3141  uves_propertylist *raw_header1[2],
3142  uves_propertylist *raw_header2[2],
3143  uves_propertylist *rotated_header1[2],
3144  uves_propertylist *rotated_header2[2],
3145  bool *blue)
3146 {
3147  const char *tags[2];
3148  int number_of_tags = sizeof(tags) / sizeof(char *);
3149  int indx;
3150  bool flames = false;
3151  const cpl_frame *frame;
3152 
3153  tags[0] = UVES_CD_ALIGN(false); /* red */
3154  tags[1] = UVES_CD_ALIGN(true); /* blue */
3155 
3156  check( *raw_filename1 = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3157  "Could not find raw frame (%s or %s) in SOF",
3158  tags[0], tags[1]);
3159 
3160  *blue = (indx == 1);
3161 
3162  assure( cpl_frameset_count_tags(frames, tags[indx]) == 2,
3163  CPL_ERROR_ILLEGAL_INPUT,
3164  "%d %s frames found. Exactly 2 required",
3165  cpl_frameset_count_tags(frames, tags[indx]), tags[indx] );
3166 
3167  /* Load the two frames */
3168  {
3169  int n = 1;
3170  int i=0;
3171  int nfrm=cpl_frameset_get_size(frames);
3172  for (i = 0;i < nfrm;i++)
3173  {
3174  frame=cpl_frameset_get_frame_const(frames,i);
3175  if (strcmp(cpl_frame_get_tag(frame), tags[indx]) == 0)
3176  {
3177  if (n == 1)
3178  {
3179  *raw_filename1 = cpl_frame_get_filename(frame);
3180  }
3181  else
3182  {
3183  *raw_filename2 = cpl_frame_get_filename(frame);
3184  }
3185 
3186  check( load_raw_image(n == 1 ?
3187  *raw_filename1 :
3188  *raw_filename2,
3189  CPL_TYPE_DOUBLE,
3190  flames,
3191  *blue,
3192  n == 1 ?
3193  raw_image1 :
3194  raw_image2,
3195  n == 1 ?
3196  raw_header1 :
3197  raw_header2,
3198  n == 1 ?
3199  rotated_header1 :
3200  rotated_header2),
3201  "Error loading image from file '%s'",
3202  n == 1 ? *raw_filename1 : *raw_filename2);
3203 
3204  n++;
3205  }
3206  }
3207  }
3208 
3209  cleanup:
3210  if (cpl_error_get_code() != CPL_ERROR_NONE)
3211  {
3212  *raw_filename1 = NULL;
3213  *raw_filename2 = NULL;
3214  }
3215 
3216  return;
3217 }
3218 
3219 
3220 /*----------------------------------------------------------------------------*/
3241 /*----------------------------------------------------------------------------*/
3242 void
3243 uves_load_arclamp(const cpl_frameset *frames,
3244  bool flames,
3245  const char **raw_filename,
3246  cpl_image *raw_image[2], uves_propertylist *raw_header[2],
3247  uves_propertylist *rotated_header[2], bool *blue,
3248  bool *sim_cal)
3249 {
3250  const char *tags[4];
3251 
3252  int number_of_tags = sizeof(tags) / sizeof(char *);
3253  int indx;
3254 
3255  /* Warning: duplicate logic. Array size above must match */
3256  if (flames)
3257  {
3258  assure_nomsg( sim_cal != NULL, CPL_ERROR_NULL_INPUT );
3259 
3260  tags[0] = UVES_ARC_LAMP(flames, true); /* blue flag not used */
3261  tags[1] = FLAMES_FIB_SCI_SIM;
3262 
3263  number_of_tags = 2;
3264  *blue = false;
3265 
3266  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3267  "Could not find raw frame (%s or %s) in SOF",
3268  tags[0], tags[1]);
3269 
3270  *sim_cal = (indx == 1);
3271  }
3272  else
3273  {
3274  tags[0] = UVES_ARC_LAMP(flames, true);
3275  tags[1] = UVES_ARC_LAMP(flames, false);
3276  tags[2] = UVES_ECH_ARC_LAMP(true);
3277  tags[3] = UVES_ECH_ARC_LAMP(false);
3278 
3279  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3280  "Could not find raw frame (%s, %s, %s or %s) in SOF",
3281  tags[0], tags[1], tags[2], tags[3]);
3282 
3283  *blue = (indx == 0 || indx == 2);
3284  }
3285 
3286  /* Load the image */
3287  check( load_raw_image(*raw_filename,
3288  CPL_TYPE_DOUBLE,
3289  flames,
3290  *blue,
3291  raw_image,
3292  raw_header,
3293  rotated_header),
3294  "Error loading image from file '%s'", *raw_filename);
3295 
3296  cleanup:
3297  if (cpl_error_get_code() != CPL_ERROR_NONE) {
3298  *raw_filename = NULL;
3299  uves_free_image (raw_image);
3300  uves_free_propertylist(raw_header);
3301  }
3302  return;
3303 }
3304 
3305 /*----------------------------------------------------------------------------*/
3320 /*----------------------------------------------------------------------------*/
3321 cpl_error_code
3322 uves_load_science(const cpl_frameset *frames, const char **raw_filename,
3323  cpl_image *raw_image[2],
3324  uves_propertylist *raw_header[2],
3325  uves_propertylist *rotated_header[2],
3326  bool *blue,
3327  const char **sci_type)
3328 {
3329  /* Note: the two following arrays must match */
3330  const char *tags[] =
3331  {
3332  UVES_SCIENCE(true), UVES_SCIENCE(false),
3333  UVES_SCI_EXTND(true), UVES_SCI_EXTND(false),
3334  UVES_SCI_POINT(true), UVES_SCI_POINT(false),
3335  UVES_SCI_SLICER(true), UVES_SCI_SLICER(false),
3336  UVES_TFLAT(true), UVES_TFLAT(false)
3337  };
3338 
3339  const char *type[] =
3340  {
3341  "SCIENCE", "SCIENCE",
3342  "SCI_EXTND", "SCI_EXTND",
3343  "SCI_POINT", "SCI_POINT",
3344  "SCI_SLICER", "SCI_SLICER",
3345  "TFLAT", "TFLAT",
3346  };
3347 
3348  int number_of_tags = sizeof(tags) / sizeof(char *);
3349  int indx;
3350  bool flames = false;
3351 
3352  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3353  "No science frame (%s, %s, %s, %s, %s, %s, %s, %s, %s or %s) in SOF",
3354  tags[0], tags[1], tags[2], tags[3],
3355  tags[4], tags[5], tags[6], tags[7], tags[7], tags[8]);
3356 
3357  *blue = (indx % 2 == 0);
3358  *sci_type = type[indx];
3359 
3360  /* Load the image */
3361  check( load_raw_image(*raw_filename,
3362  CPL_TYPE_DOUBLE,
3363  flames,
3364  *blue,
3365  raw_image,
3366  raw_header,
3367  rotated_header),
3368  "Error loading image from file '%s'", *raw_filename);
3369  cleanup:
3370  if (cpl_error_get_code() != CPL_ERROR_NONE)
3371  {
3372  *raw_filename = NULL;
3373  uves_free_image (raw_image);
3374  uves_free_propertylist(raw_header);
3375  }
3376  return cpl_error_get_code();
3377 }
3378 
3379 /*----------------------------------------------------------------------------*/
3396 /*----------------------------------------------------------------------------*/
3397 cpl_error_code
3398 uves_load_standard(const cpl_frameset *frames, const char **raw_filename,
3399  cpl_image *raw_image[2],
3400  uves_propertylist *raw_header[2],
3401  uves_propertylist *rotated_header[2], bool *blue)
3402 {
3403  const char *tags[] = { UVES_STD_STAR(true), UVES_STD_STAR(false) };
3404  int number_of_tags = sizeof(tags) / sizeof(char *);
3405  int indx;
3406  bool flames = false;
3407 
3408  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3409  "Could not identify raw frame (%s or %s) in SOF", tags[0], tags[1]);
3410 
3411  *blue = (indx == 0);
3412 
3413  /* Load the image */
3414  check( load_raw_image(*raw_filename,
3415  CPL_TYPE_DOUBLE,
3416  flames,
3417  *blue,
3418  raw_image,
3419  raw_header,
3420  rotated_header),
3421  "Error loading image from file '%s'", *raw_filename);
3422 
3423  cleanup:
3424  if (cpl_error_get_code() != CPL_ERROR_NONE)
3425  {
3426  *raw_filename = NULL;
3427  uves_free_image (raw_image);
3428  uves_free_propertylist(raw_header);
3429  }
3430  return cpl_error_get_code();
3431 }
3432 
3433 /*----------------------------------------------------------------------------*/
3449 /*----------------------------------------------------------------------------*/
3450 
3451 cpl_error_code
3452 uves_load_drs(const cpl_frameset *frames,
3453  bool flames,
3454  const char *chip_name,
3455  const char **drs_filename,
3456  uves_propertylist **drs_header,
3457  enum uves_chip chip)
3458 {
3459  const char *tags[1];
3460  int number_of_tags = sizeof(tags) / sizeof(char *);
3461  int extension;
3462  int indx;
3463 
3464  *drs_header = NULL;
3465  tags[0] = UVES_DRS_SETUP(flames, chip);
3466  extension = UVES_DRS_SETUP_EXTENSION(chip);
3467 
3468  check( *drs_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3469  "Could not find DRS table (%s) in SOF", tags[0]);
3470 
3471  /* Load the header */
3472  check( *drs_header = uves_propertylist_load(*drs_filename,
3473  extension),
3474  "Could not load header from extension %d of file '%s'", extension, *drs_filename);
3475 
3476  check_nomsg( uves_warn_if_chip_names_dont_match(*drs_header, chip_name, chip) );
3477 
3478  cleanup:
3479  if (cpl_error_get_code() != CPL_ERROR_NONE) {
3480  *drs_filename = NULL;
3481  uves_free_propertylist(drs_header);
3482  }
3483  return cpl_error_get_code();
3484 }
3485 
3486 /*----------------------------------------------------------------------------*/
3494 /*----------------------------------------------------------------------------*/
3495 cpl_image *
3496 uves_load_weights(const cpl_frameset *frames, const char **weights_filename,
3497  enum uves_chip chip)
3498 {
3499  cpl_image *weights = NULL;
3500  const char *tags[1];
3501  int number_of_tags = sizeof(tags) / sizeof(char *);
3502  int extension = 0;
3503  int indx;
3504 
3505  assure( weights_filename != NULL, CPL_ERROR_NULL_INPUT, "Null filename");
3506 
3507  tags[0] = UVES_WEIGHTS(chip);
3508 
3509  check( *weights_filename = uves_find_frame(frames,
3510  tags, number_of_tags, &indx, NULL),
3511  "Could not find '%s' in frame set", tags[0]);
3512 
3513  check( weights = cpl_image_load(*weights_filename,
3514  CPL_TYPE_DOUBLE, /* Convert to this type */
3515  0, /* plane number */
3516  extension /* Extension number */
3517  ),
3518  "Could not load master bias from extension %d of file '%s'",
3519  extension, *weights_filename);
3520 
3521  cleanup:
3522  return weights;
3523 }
3524 
3525 
3526 /*----------------------------------------------------------------------------*/
3542 /*----------------------------------------------------------------------------*/
3543 
3544 cpl_error_code
3545 uves_load_mbias(const cpl_frameset *frames, const char *chip_name,
3546  const char **mbias_filename,
3547  cpl_image **mbias, uves_propertylist **mbias_header, enum uves_chip chip)
3548 {
3549  const char *tags[1];
3550  int number_of_tags = sizeof(tags) / sizeof(char *);
3551  int extension;
3552  int indx;
3553 
3554  *mbias = NULL;
3555  *mbias_header = NULL;
3556 
3557  tags[0] = UVES_MASTER_BIAS (chip);
3558  extension = UVES_MASTER_BIAS_EXTENSION(chip);
3559 
3560  check( *mbias_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3561  "Could not find '%s' in frame set", tags[0]);
3562 
3563  /* Load the mbias image */
3564  check( *mbias = cpl_image_load(*mbias_filename,
3565  CPL_TYPE_DOUBLE, /* Convert to this type */
3566  0, /* plane number */
3567  extension /* Extension number */
3568  ),
3569  "Could not load master bias from extension %d of file '%s'",
3570  extension, *mbias_filename);
3571 
3572  /* Load the header */
3573  check( *mbias_header = uves_propertylist_load(*mbias_filename,
3574  extension),
3575  "Could not load header from extension %d of file '%s'",
3576  extension, *mbias_filename);
3577 
3578  check_nomsg( uves_warn_if_chip_names_dont_match(*mbias_header, chip_name, chip) );
3579 
3580  cleanup:
3581  if (cpl_error_get_code() != CPL_ERROR_NONE)
3582  {
3583  *mbias_filename = NULL;
3584  uves_free_image(mbias);
3585  uves_free_propertylist(mbias_header);
3586  }
3587  return cpl_error_get_code();
3588 }
3589 
3590 
3591 /*----------------------------------------------------------------------------*/
3607 /*----------------------------------------------------------------------------*/
3608 
3609 cpl_error_code
3610 uves_load_master_formatcheck(const cpl_frameset *frames, const char *chip_name,
3611  const char **mform_filename,
3612  cpl_image **mform, uves_propertylist **mform_header, enum uves_chip chip)
3613 {
3614  const char *tags[1];
3615  int number_of_tags = sizeof(tags) / sizeof(char *);
3616  int extension;
3617  int indx;
3618 
3619  *mform = NULL;
3620  *mform_header = NULL;
3621 
3622  tags[0] = UVES_MASTER_ARC_FORM (chip);
3623  extension = UVES_MASTER_ARC_FORM_EXTENSION(chip);
3624 
3625  check( *mform_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3626  "Could not find '%s' in frame set", tags[0]);
3627 
3628  /* Load the mbias image */
3629  check( *mform = cpl_image_load(*mform_filename,
3630  CPL_TYPE_DOUBLE, /* Convert to this type */
3631  0, /* plane number */
3632  extension /* Extension number */
3633  ),
3634  "Could not load master formatcheck from extension %d of file '%s'",
3635  extension, *mform_filename);
3636 
3637  /* Load the header */
3638 
3639  check( *mform_header = uves_propertylist_load(*mform_filename,
3640  extension),
3641  "Could not load header from extension %d of file '%s'",
3642  extension, *mform_filename);
3643 
3644  check_nomsg( uves_warn_if_chip_names_dont_match(*mform_header, chip_name, chip) );
3645 
3646  cleanup:
3647  if (cpl_error_get_code() != CPL_ERROR_NONE)
3648  {
3649  *mform_filename = NULL;
3650  uves_free_image(mform);
3651  uves_free_propertylist(mform_header);
3652  }
3653  return cpl_error_get_code();
3654 }
3655 
3656 /*----------------------------------------------------------------------------*/
3672 /*----------------------------------------------------------------------------*/
3673 
3674 cpl_error_code
3675 uves_load_mdark(const cpl_frameset *frames, const char *chip_name,
3676  const char **mdark_filename, cpl_image **mdark,
3677  uves_propertylist **mdark_header, enum uves_chip chip)
3678 {
3679  const char *tags[2];
3680  int number_of_tags = sizeof(tags) / sizeof(char *);
3681  int extension;
3682  int indx;
3683 
3684  *mdark = NULL;
3685  *mdark_header = NULL;
3686 
3687  tags[0] = UVES_MASTER_DARK (chip);
3688  tags[1] = UVES_MASTER_PDARK (chip);
3689  extension = UVES_MASTER_DARK_EXTENSION(chip);
3690 
3691  check( *mdark_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3692  "Could not find %s or %s in frame set", tags[0], tags[1]);
3693 
3694  /* Load the mdark image */
3695  check( *mdark = cpl_image_load(*mdark_filename,
3696  CPL_TYPE_DOUBLE, /* Convert to this type */
3697  0, /* plane number */
3698  extension /* Extension number */
3699  ),
3700  "Could not load master dark from extension %d of file '%s'",
3701  extension, *mdark_filename);
3702 
3703  /* Load the header */
3704  check( *mdark_header = uves_propertylist_load(*mdark_filename,
3705  extension),
3706  "Could not load header from extension %d of file '%s'",
3707  extension, *mdark_filename);
3708 
3709  check_nomsg( uves_warn_if_chip_names_dont_match(*mdark_header, chip_name, chip) );
3710 
3711  cleanup:
3712  if (cpl_error_get_code() != CPL_ERROR_NONE)
3713  {
3714  *mdark_filename = NULL;
3715  uves_free_image(mdark);
3716  uves_free_propertylist(mdark_header);
3717  }
3718  return cpl_error_get_code();
3719 }
3720 /*----------------------------------------------------------------------------*/
3736 /*----------------------------------------------------------------------------*/
3737 void
3738 uves_load_ref_flat(const cpl_frameset *frames, const char *chip_name,
3739  const char **filename, cpl_image **rflat,
3740  uves_propertylist **rflat_header, enum uves_chip chip)
3741 {
3742  const char *tags[1];
3743  int number_of_tags = sizeof(tags) / sizeof(char *);
3744  int extension;
3745  int indx;
3746 
3747  *rflat = NULL;
3748  *rflat_header = NULL;
3749 
3750  tags[0] = UVES_REF_TFLAT(chip);
3751  extension = UVES_MASTER_FLAT_EXTENSION(chip);
3752 
3753  check( *filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3754  "Could not find %s in frame set", tags[0]);
3755 
3756  check( *rflat = cpl_image_load(*filename,
3757  CPL_TYPE_DOUBLE, /* Convert to this type */
3758  0, /* plane number */
3759  extension /* Extension number */
3760  ),
3761  "Could not load reference dark from extension %d of file '%s'",
3762  extension, *filename);
3763 
3764  check( *rflat_header = uves_propertylist_load(*filename,
3765  extension),
3766  "Could not load header from extension %d of file '%s'",
3767  extension, *filename);
3768 
3769  check_nomsg( uves_warn_if_chip_names_dont_match(*rflat_header, chip_name, chip) );
3770 
3771  cleanup:
3772  if (cpl_error_get_code() != CPL_ERROR_NONE)
3773  {
3774  *filename = NULL;
3775  uves_free_image(rflat);
3776  uves_free_propertylist(rflat_header);
3777  }
3778 
3779  return;
3780 }
3781 
3782 /*----------------------------------------------------------------------------*/
3798 /*----------------------------------------------------------------------------*/
3799 
3800 cpl_error_code
3801 uves_load_mflat_const(const cpl_frameset *frames, const char *chip_name,
3802  const char **mflat_filename,
3803  cpl_image **mflat, uves_propertylist **mflat_header,
3804  enum uves_chip chip,
3805  const cpl_frame **mflat_frame)
3806 {
3807  const char *tags[6];
3808  int number_of_tags = sizeof(tags) / sizeof(char *);
3809  int extension;
3810  int indx;
3811 
3812  *mflat = NULL;
3813  *mflat_header = NULL;
3814 
3815  tags[0] = UVES_REF_TFLAT (chip); /* Use REF TFLAT, rather than MASTER_TFLAT */
3816  tags[1] = UVES_MASTER_FLAT (chip);
3817  tags[2] = UVES_MASTER_DFLAT (chip);
3818  tags[3] = UVES_MASTER_IFLAT (chip);
3819  tags[4] = UVES_MASTER_TFLAT (chip);
3820  tags[5] = UVES_MASTER_SCREEN_FLAT (chip);
3821  extension = UVES_MASTER_FLAT_EXTENSION(chip);
3822 
3823  check( *mflat_filename = uves_find_frame(frames, tags, number_of_tags, &indx,
3824  mflat_frame),
3825  "Could not find '%s', '%s', '%s', '%s' or '%s' in frame set",
3826  tags[0], tags[1], tags[2], tags[3], tags[4]);
3827 
3828  /* Load the mflat image */
3829  check( *mflat = cpl_image_load(*mflat_filename,
3830  CPL_TYPE_DOUBLE, /* Convert to this type */
3831  0, /* plane number */
3832  extension /* Extension number */
3833  ),
3834  "Could not load master flat from extension %d of file '%s'",
3835  extension, *mflat_filename);
3836 
3837  /* Load the header */
3838  check( *mflat_header = uves_propertylist_load(*mflat_filename,
3839  extension),
3840  "Could not load header from extension %d of file '%s'",
3841  extension, *mflat_filename);
3842 
3843  check_nomsg( uves_warn_if_chip_names_dont_match(*mflat_header, chip_name, chip) );
3844 
3845  cleanup:
3846  if (cpl_error_get_code() != CPL_ERROR_NONE)
3847  {
3848  *mflat_filename = NULL;
3849  uves_free_image(mflat);
3850  uves_free_propertylist(mflat_header);
3851  }
3852  return cpl_error_get_code();
3853 }
3854 
3855 /*----------------------------------------------------------------------------*/
3870 /*----------------------------------------------------------------------------*/
3871 cpl_error_code
3872 uves_load_mflat(cpl_frameset *frames, const char *chip_name,
3873  const char **mflat_filename,
3874  cpl_image **mflat, uves_propertylist **mflat_header, enum uves_chip chip,
3875  cpl_frame **mflat_frame)
3876 {
3877  return uves_load_mflat_const((const cpl_frameset *)frames,
3878  chip_name,
3879  mflat_filename,
3880  mflat, mflat_header, chip,
3881  (const cpl_frame **) mflat_frame);
3882 }
3883 
3884 /*----------------------------------------------------------------------------*/
3916 /*----------------------------------------------------------------------------*/
3917 cpl_error_code
3918 uves_load_ordertable(const cpl_frameset *frames,
3919  bool flames,
3920  const char *chip_name,
3921  const char **ordertable_filename,
3922  cpl_table **ordertable,
3923  uves_propertylist **ordertable_header,
3924  uves_propertylist **ordertable_xheader,
3925  polynomial **order_locations,
3926  cpl_table **traces,
3927  int *tab_in_out_oshift,
3928  double *tab_in_out_yshift,
3929  int ** fib_msk,
3930  double ** fib_pos,
3931  enum uves_chip chip,
3932  bool guess_table)
3933 {
3934  uves_propertylist *midas_header = NULL; /* Table header if midas format */
3935  uves_propertylist *prime_header = NULL; /* Prime header if flames */
3936  const char *tags[1];
3937  int number_of_tags = sizeof(tags) / sizeof(char *);
3938  bool format_is_midas;
3939  int *tioo = NULL;
3940  double *tioy = NULL;
3941  int indx;
3942 
3943  double *fibre_pos = NULL;
3944  int *fibre_mask = NULL;
3945 
3946  if (guess_table)
3947  {
3948  tags[0] = UVES_GUESS_ORDER_TABLE(flames, chip);
3949  }
3950  else
3951  {
3952  tags[0] = UVES_ORDER_TABLE(flames, chip);
3953  }
3954 
3955  check( *ordertable_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3956  "No order table (%s) found in SOF", tags[0]);
3957 
3958  check( *ordertable = cpl_table_load(*ordertable_filename,
3959  UVES_ORDER_TABLE_EXTENSION,
3960  1), /* Mark identified
3961  invalid values? (1=yes) */
3962  "Error loading order table from extension %d of file '%s'",
3963  UVES_ORDER_TABLE_EXTENSION, *ordertable_filename);
3964 
3965  assure(ordertable_header != NULL,CPL_ERROR_NULL_INPUT,
3966  "NULL primary header uves_propertylist variable header");
3967  check( *ordertable_header = uves_propertylist_load(*ordertable_filename, 0),
3968  "Could not load header from extension 0 of '%s'", *ordertable_filename);
3969 
3970  if(ordertable_xheader != NULL) {
3971 
3972  check( *ordertable_xheader = uves_propertylist_load(*ordertable_filename, 1),
3973  "Could not load header from extension 1 of '%s'", *ordertable_filename);
3974 
3975 
3976 
3977  }
3978  check_nomsg( uves_warn_if_chip_names_dont_match(*ordertable_header, chip_name, chip) );
3979 
3980  check(uves_check_if_format_is_midas(*ordertable_header,&format_is_midas),
3981  "Error getting FITS format");
3982 
3983 
3984  if (!format_is_midas && !flames)
3985  {
3986  /* The format check and order position recipes create order tables
3987  with different column names. Rename if necessary.
3988 
3989  This is a workaround for the problem that different recipes
3990  create the same products (order tables and line tables).
3991  The true solution would be to remove the format check recipe from
3992  the recution cascade, and use the theoretical physical model to
3993  bootstrap the order definition and wavelength calibration.
3994  */
3995  if (cpl_table_has_column(*ordertable, "ORDER"))
3996  {
3997  cpl_table_name_column(*ordertable, "ORDER", "Order");
3998  }
3999  if (cpl_table_has_column(*ordertable, "YFIT"))
4000  {
4001  cpl_table_name_column(*ordertable, "YFIT", "Yfit");
4002  }
4003 
4004  if (order_locations != NULL)
4005  {
4006  check( *order_locations =
4007  load_polynomial(*ordertable_filename, UVES_ORDER_TABLE_EXTENSION_POLY),
4008  "Could not read polynomial from extension %d of file '%s'",
4009  UVES_ORDER_TABLE_EXTENSION_POLY, *ordertable_filename);
4010  }
4011 
4012  if (traces != NULL)
4013  {
4014  check( *traces = cpl_table_load(*ordertable_filename,
4015  UVES_ORDER_TABLE_EXTENSION_FIBRE,
4016  1), /* Mark identified
4017  invalid values? (1=yes) */
4018  "Error loading fibre table from extension %d of file '%s'",
4019  UVES_ORDER_TABLE_EXTENSION_FIBRE, *ordertable_filename);
4020  }
4021  }
4022  else
4023  /* MIDAS format, or FLAMES */
4024  {
4025  /* Rename */
4026  check(( cpl_table_cast_column (*ordertable, "ORDER", "Order", CPL_TYPE_INT),
4027  cpl_table_erase_column(*ordertable, "ORDER")),
4028  "Error casting and renaming column 'ORDER'");
4029 
4030  check( cpl_table_name_column(*ordertable, "YFIT", "Yfit"),
4031  "Error renaming column 'YFIT'");
4032 
4033  //check( midas_header = uves_propertylist_load(*ordertable_filename, 1),
4034  // "Could not load header from extension 1 of '%s'",
4035  // *ordertable_filename);
4036  check(midas_header = uves_propertylist_load(*ordertable_filename, 1),
4037  "Could not load header from extension 1 of '%s'",
4038  *ordertable_filename);
4039 
4040  if(flames) {
4041  check(prime_header = uves_propertylist_load(*ordertable_filename, 0),
4042  "Could not load header from extension 0 of '%s'",
4043  *ordertable_filename);
4044  check_nomsg(uves_propertylist_append(midas_header,prime_header));
4045  }
4046 
4047  /* Load polynomial named 'COEFF' from descriptors in extension 1 */
4048  if (order_locations != NULL)
4049  {
4050  check( *order_locations =
4051  uves_polynomial_convert_from_plist_midas(midas_header, "COEFF",-1),
4052  "Error reading polynomial from %s", *ordertable_filename);
4053  }
4054 
4055 
4056  if (flames && tab_in_out_oshift != NULL )
4057  {
4058  /* Get tab_in_out_oshift */
4059  int tioo_length;
4060  cpl_type tioo_type;
4061 
4062  check( tioo = uves_read_midas_array(
4063  midas_header, "TAB_IN_OUT_OSHIFT", &tioo_length,
4064  &tioo_type, NULL),
4065  "Error reading TAB_IN_OUT_OSHIFT from MIDAS header");
4066 
4067  assure( tioo_type == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
4068  "Type of TAB_IN_OUT_OSHIFT is %s, double expected",
4069  uves_tostring_cpl_type(tioo_type));
4070 
4071  if (tioo_length != 1)
4072  {
4073  uves_msg_warning("Length of TAB_IN_OUT_OSHIFT array is %d; "
4074  "%d expected", tioo_length, 1);
4075  }
4076 
4077  *tab_in_out_oshift = tioo[0];
4078 
4079  uves_msg_debug("TAB_IN_OUT_OSHIFT = %d", *tab_in_out_oshift);
4080 
4081  }
4082 
4083  if (flames && tab_in_out_yshift != NULL)
4084  {
4085  /* Get tab_in_out_yshift */
4086  int tioy_length;
4087  cpl_type tioy_type;
4088 
4089  check( tioy = uves_read_midas_array(
4090  midas_header, "TAB_IN_OUT_YSHIFT", &tioy_length,
4091  &tioy_type, NULL),
4092  "Error reading TAB_IN_OUT_YSHIFT from MIDAS header");
4093 
4094  assure( tioy_type == CPL_TYPE_DOUBLE, CPL_ERROR_TYPE_MISMATCH,
4095  "Type of TAB_IN_OUT_YSHIFT is %s, double expected",
4096  uves_tostring_cpl_type(tioy_type));
4097 
4098  if (tioy_length != 1)
4099  {
4100  uves_msg_warning("Length of TAB_IN_OUT_YSHIFT array is %d; "
4101  "%d expected", tioy_length, 1);
4102  }
4103 
4104  *tab_in_out_yshift = tioy[0];
4105 
4106  uves_msg_debug("TAB_IN_OUT_YSHIFT = %f", *tab_in_out_yshift);
4107  }
4108 
4109  if (traces != NULL)
4110  {
4111  *traces = uves_ordertable_traces_new();
4112 
4113  if (!flames)
4114  /* UVES: one trace with zero offset */
4115  {
4116  int fibre_ID = 0;
4117  double fibre_offset = 0.0;
4118  int fibre_msk = 1;
4119  uves_ordertable_traces_add(*traces,
4120  fibre_ID,
4121  fibre_offset,
4122  fibre_msk);
4123  }
4124  else
4125  /* FLAMES */
4126  {
4127 
4128  int fibre_pos_length;
4129  int fibre_mask_length;
4130  cpl_type fibre_pos_type;
4131  cpl_type fibre_mask_type;
4132  int fibre_ID;
4133 
4134  check( fibre_pos = uves_read_midas_array(
4135  midas_header, "FIBREPOS", &fibre_pos_length,
4136  &fibre_pos_type, NULL),
4137  "Error reading FIBREPOS from MIDAS header");
4138 
4139  assure( fibre_pos_type == CPL_TYPE_DOUBLE, CPL_ERROR_TYPE_MISMATCH,
4140  "Type of FIBREPOS is %s, double expected",
4141  uves_tostring_cpl_type(fibre_pos_type));
4142 
4143  check( fibre_mask = uves_read_midas_array(
4144  midas_header, "FIBREMASK", &fibre_mask_length,
4145  &fibre_mask_type, NULL),
4146  "Error reading FIBREMASK from MIDAS header");
4147 
4148  assure( fibre_mask_type == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
4149  "Type of FIBREMASK is %s, double expected",
4150  uves_tostring_cpl_type(fibre_mask_type));
4151 
4152  assure( fibre_pos_length == fibre_mask_length,
4153  CPL_ERROR_INCOMPATIBLE_INPUT,
4154  "FIBREMASK has length %d, but "
4155  "FIBREPOS has length %d",
4156  fibre_mask_length, fibre_pos_length );
4157 
4158  *fib_pos= cpl_malloc(sizeof(double) * fibre_pos_length);
4159  *fib_msk= cpl_malloc(sizeof(int) * fibre_mask_length);
4160 
4161  for (fibre_ID = 0; fibre_ID < fibre_mask_length; fibre_ID++)
4162  {
4163  uves_msg_debug("Found trace %d, position %f (%s)",
4164  fibre_ID, fibre_pos[fibre_ID],
4165  fibre_mask[fibre_ID] ?
4166  "enabled" : "disabled");
4167  uves_ordertable_traces_add(*traces,
4168  fibre_ID,
4169  fibre_pos[fibre_ID],
4170  fibre_mask[fibre_ID]);
4171  (*fib_pos)[fibre_ID]=fibre_pos[fibre_ID];
4172  (*fib_msk)[fibre_ID]=fibre_mask[fibre_ID];
4173  }
4174  }
4175  }
4176  }
4177 
4178  cleanup:
4179  uves_free_propertylist(&midas_header);
4180  uves_free_double(&fibre_pos);
4181  uves_free_int(&fibre_mask);
4182  uves_free_int(&tioo);
4183  uves_free_double(&tioy);
4184  uves_free_propertylist(&prime_header);
4185 
4186  if (cpl_error_get_code() != CPL_ERROR_NONE)
4187  {
4188  *ordertable_filename = NULL;
4189  uves_free_table (ordertable);
4190  uves_free_propertylist(ordertable_header);
4191  if (order_locations != NULL) uves_polynomial_delete(order_locations);
4192  if (traces != NULL) uves_free_table (traces);
4193  }
4194  return cpl_error_get_code();
4195 }
4196 
4197 
4198 
4199 /*--------------------------------------------------------------------------*/
4208 /*--------------------------------------------------------------------------*/
4209 
4210 
4211 cpl_error_code
4212 uves_check_if_format_is_midas(uves_propertylist* header, bool* format_is_midas)
4213 {
4214 
4215  /* Determine format of order table and read the polynomial */
4216  if (uves_propertylist_contains(header, UVES_DRS_ID)) {
4217 
4218 
4219  const char* drs_id=NULL;
4220 
4221  check( drs_id = uves_pfits_get_drs_id(header), "Error reading DRS ID");
4222  if (strstr(drs_id, "CPL") != NULL ||
4223  strstr(drs_id, "cpl") != NULL) {
4224  *format_is_midas = false;
4225  uves_msg_debug("Order table was written by CPL");
4226  } else if (strstr(drs_id, "MIDAS") != NULL ||
4227  strstr(drs_id, "midas") != NULL) {
4228  *format_is_midas = true;
4229  uves_msg_low("Order table was written by MIDAS");
4230  } else {
4231  assure ( false, CPL_ERROR_ILLEGAL_INPUT,
4232  "Unrecognized order table format, DRS_ID = '%s'", drs_id);
4233  }
4234  } else {
4235 
4236  *format_is_midas = true;
4237  uves_msg_debug("No '%s' keyword found. Assuming MIDAS format", UVES_DRS_ID);
4238  }
4239 
4240  cleanup:
4241  return cpl_error_get_code();
4242 
4243 }
4244 
4245 /*--------------------------------------------------------------------------*/
4255 /*--------------------------------------------------------------------------*/
4256 
4257 static cpl_error_code
4258 create_column_pixelsize(cpl_table *linetable)
4259 {
4260  polynomial *p = NULL;
4261  cpl_table *t = NULL;
4262  double d1, d2;
4263  int i;
4264  int degree = 3;
4265 
4266  /* Remove rows with Ident = 0 (unidentified lines) */
4267  check( t = uves_extract_table_rows(linetable, "Ident", CPL_GREATER_THAN, 0.1),
4268  "Error deleting rows with Ident=0");
4269 
4270  /* Create column Aux := Ident * Order */
4271  check(( cpl_table_duplicate_column(t, "Aux", t, "Ident"),
4272  cpl_table_multiply_columns(t, "Aux", "Order")),
4273  "Error creating 'Aux' column");
4274 
4276  "X", "Aux", NULL,
4277  degree,
4278  NULL, NULL,
4279  NULL,
4280  -1),
4281  "Regression failed");
4282 
4283  check( d1 = uves_polynomial_get_coeff_1d(p, 1),
4284  "Error reading polynomial coefficient");
4285 
4286  check( d2 = uves_polynomial_get_coeff_1d(p, 2),
4287  "Error reading polynomial coefficient");
4288 
4289  cpl_table_new_column(linetable, LINETAB_PIXELSIZE, CPL_TYPE_DOUBLE);
4290 
4291  for (i = 0; i < cpl_table_get_nrow(linetable); i++)
4292  {
4293  int x;
4294  int order;
4295  double pixelsize;
4296  double ident;
4297 
4298  check(( x = cpl_table_get_double(linetable, "X", i, NULL),
4299  order = cpl_table_get_int (linetable, "Order", i, NULL),
4300  ident = cpl_table_get_double(linetable, "Ident", i, NULL)),
4301  "Error reading line table");
4302 
4303  assure( order != 0, CPL_ERROR_ILLEGAL_INPUT, "Illegal order number: %d", order);
4304 
4305  /*
4306  * MIDAS approximates
4307  * d(lambda m)/dx (x,m) = d1 + 2*d2*x
4308  *
4309  * where the polynomial itself is ... + d1*x + d2*x^2 + ...
4310  */
4311  pixelsize = (d1 + 2*d2* x) / order;
4312 // pixelsize = uves_polynomial_derivative_2d(dispersion_relation, x, order, 1)/order;
4313 
4314  if (ident > 0.01)
4315  {
4316  cpl_table_set_double(linetable, LINETAB_PIXELSIZE, i, pixelsize);
4317  }
4318  else
4319  {
4320  cpl_table_set_invalid(linetable, LINETAB_PIXELSIZE, i);
4321  }
4322  }
4323 
4324  cleanup:
4325  uves_free_table(&t);
4327  return cpl_error_get_code();
4328 }
4329 
4330 
4331 
4332 /*----------------------------------------------------------------------------*/
4359 /*----------------------------------------------------------------------------*/
4360 static void
4361 align_order_line_table(cpl_table *linetable, const polynomial *absolute_order,
4362  uves_propertylist **linetable_header,
4363  const polynomial *order_locations, int minorder, int maxorder)
4364 {
4365  polynomial *absord = NULL;
4366 
4367  assure ( order_locations != NULL, CPL_ERROR_NULL_INPUT,
4368  "Null order locations polynomial!");
4369 
4370  assure ( absolute_order != NULL, CPL_ERROR_NULL_INPUT,
4371  "Null absolute order pllynomial!");
4372  assure( cpl_table_has_column(linetable, "X" ), CPL_ERROR_DATA_NOT_FOUND,
4373  "Missing line table column 'X'");
4374  assure( cpl_table_has_column(linetable, "Ynew"), CPL_ERROR_DATA_NOT_FOUND,
4375  "Missing line table column 'Ynew'");
4376  assure( cpl_table_has_column(linetable, "Order"), CPL_ERROR_DATA_NOT_FOUND,
4377  "Missing line table column 'Order'");
4378 
4379  assure( cpl_table_get_column_type(linetable, "X") == CPL_TYPE_DOUBLE,
4380  CPL_ERROR_TYPE_MISMATCH, "Line table column 'X' has type %s (double expected))",
4381  uves_tostring_cpl_type(cpl_table_get_column_type(linetable, "X")) );
4382 
4383  assure( cpl_table_get_column_type(linetable, "Ynew") == CPL_TYPE_DOUBLE,
4384  CPL_ERROR_TYPE_MISMATCH, "Line table column 'Ynew' has type %s (double expected))",
4385  uves_tostring_cpl_type(cpl_table_get_column_type(linetable, "Ynew")) );
4386 
4387  assure( cpl_table_get_column_type(linetable, "Y") == CPL_TYPE_INT,
4388  CPL_ERROR_TYPE_MISMATCH, "Line table column 'Y' has type %s (integer expected))",
4389  uves_tostring_cpl_type(cpl_table_get_column_type(linetable, "Y")) );
4390 
4391 
4392  if (linetable_header != NULL)
4393  /* then correct first/abs order keywords */
4394  {
4395  int line_first, line_last;
4396  int ord_first, ord_last;
4397  {
4398 
4399  int maxx;
4400  int minx;
4401  int x, y, order, absorder; /* At chip center */
4402  int coeff;
4403 
4404 
4405  maxx = uves_round_double(cpl_table_get_column_max(linetable, "X"));
4406 
4407  minx = uves_round_double(cpl_table_get_column_min(linetable, "X"));
4408 
4409  assure( 1 <= minx && minx <= maxx, CPL_ERROR_ILLEGAL_INPUT,
4410  "Illegal min/max line x positions: %d/%d, must be > 1",
4411  minx, maxx);
4412 
4413  /* Center of chip */
4414  x = (minx + maxx) / 2;
4415  order = (minorder + maxorder) / 2;
4416 
4417  y = uves_polynomial_evaluate_2d(order_locations, x, order);
4418  if (uves_polynomial_derivative_2d(absolute_order, x, y, 2) > 0) {
4419  coeff = +1;
4420  }
4421  else {
4422  coeff = -1;
4423  }
4424 
4425  assure ( order_locations != NULL, CPL_ERROR_NULL_INPUT,
4426  "Null order locations polynomial!");
4427 
4428 
4429  absorder = uves_round_double(uves_polynomial_evaluate_2d(absolute_order, x, y));
4430 
4431 
4432  uves_msg_debug("Absolute order polynomial at (%d, %d) = %f, "
4433  "rounding to %d", x, y,
4434  uves_polynomial_evaluate_2d(absolute_order, x, y), absorder);
4435 
4436  ord_first = absorder + (minorder - order) * coeff;
4437  ord_last = absorder + (maxorder - order) * coeff;
4438  }
4439 
4440  check( line_first =
4441  uves_pfits_get_firstabsorder(*linetable_header),
4442  "Could not read order number from line table header");
4443 
4444  check( line_last =
4445  uves_pfits_get_lastabsorder (*linetable_header),
4446  "Could not read order number from line table header");
4447 
4448  uves_msg_debug("Order table range: %d - %d. Line table range: %d - %d",
4449  ord_first, ord_last, line_first, line_last);
4450 
4451  if (line_first != ord_first ||
4452  line_last != ord_last)
4453  {
4454  uves_msg_warning("Provided line and order tables are incompatible. "
4455  "Line table contains orders %d - %d. "
4456  "Order table contains orders %d - %d. "
4457  "Correcting on the fly",
4458  line_first, line_last, ord_first, ord_last);
4459 
4460  check( uves_pfits_set_firstabsorder(*linetable_header,
4461  ord_first),
4462  "Could not write corrected first absolute order number");
4463  check( uves_pfits_set_lastabsorder(*linetable_header,
4464  ord_last),
4465  "Could not write corrected first absolute order number");
4466 
4467  uves_msg_debug("Setting line table order range = %d - %d",
4468  ord_first, ord_last);
4469  }
4470  }
4471  /* This 'Y' column is the relative order number in linetables
4472  but the absolute order number (and therefore equal to
4473  the 'order' column) in line guess tables (!!)
4474  */
4475 
4476  {
4477  double epsilon = 0.01; /* Must be larger than machine precision but
4478  less than the typical difference between
4479  absolute/relative numbering (~100)
4480  */
4481 
4482  if (fabs(cpl_table_get_column_median(linetable, "Y") -
4483  cpl_table_get_column_median(linetable, "Order")) > epsilon)
4484 
4485  /* If column 'Y' is different from 'Order',
4486  then 'Y' is the relative order number and
4487  should be corrected (if there is an inconsistency).
4488 
4489  For now, simply delete the 'Y' column because it is
4490  not used later. If the 'Y' column will be used later,
4491  it must be corrected at this place.
4492  */
4493  {
4494  uves_msg_debug("Removing line table column 'Y'");
4495  cpl_table_erase_column(linetable, "Y");
4496  }
4497  }
4498 
4499  cleanup:
4500  uves_polynomial_delete(&absord);
4501 }
4502 
4503 
4504 /*----------------------------------------------------------------------------*/
4543 /*----------------------------------------------------------------------------*/
4544 void
4545 uves_load_linetable(const cpl_frameset *frames,
4546  bool flames,
4547  const char *chip_name,
4548  const polynomial *order_locations, int minorder, int maxorder,
4549  const char **linetable_filename,
4550  cpl_table **linetable,
4551  uves_propertylist **linetable_header,
4552  polynomial **dispersion_relation,
4553  polynomial **absolute_order,
4554  enum uves_chip chip, int trace_id, int window)
4555 {
4556  uves_propertylist *primary_header = NULL;
4557  uves_propertylist *header = NULL;
4558  uves_propertylist *midas_header = NULL; /* MIDAS extension header */
4559  int *absorders = NULL; /* Absolute order numbers */
4560  cpl_table *temp = NULL;
4561  polynomial *absolute_order_local = NULL;
4562  const char *tags[3];
4563  int number_of_tags = sizeof(tags) / sizeof(char *);
4564  const char *drs_id;
4565  bool format_is_midas; /* Was file written by CPL or MIDAS? */
4566  int base_extension; /* Last extension (e.g. 0) before
4567  extension with line table */
4568  int indx;
4569 
4570  if (flames)
4571  {
4572  tags[0] = UVES_GUESS_LINE_TABLE(flames, chip);
4573  tags[1] = UVES_LINE_TABLE(flames, chip);
4574  tags[2] = UVES_LINE_TABLE(flames, chip);
4575  number_of_tags = 3;
4576 
4577  check( *linetable_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
4578  "No line table (%s, %s or %s) found in SOF", tags[0], tags[1], tags[2]);
4579  }
4580  else
4581  {
4582  tags[0] = UVES_LINE_TABLE(flames, chip);
4583  tags[1] = UVES_LINE_TABLE(flames, chip);
4584  tags[2] = UVES_GUESS_LINE_TABLE(flames, chip);
4585 
4586  /* For backwards compatibility with MIDAS,
4587  also look for LINE_TABLE_chip%d */
4588  if (cpl_frameset_find_const(frames, tags[0]) == NULL &&
4589  cpl_frameset_find_const(frames, tags[1]) == NULL &&
4590  cpl_frameset_find_const(frames, tags[2]) == NULL)
4591  {
4592  uves_msg_debug("No %s", tags[0]);
4593 
4594  if (window >= 1)
4595  {
4596  /* Look for LINE_TABLE_BLUEwindow */
4597 
4598  tags[0] = UVES_LINE_TABLE_MIDAS(chip, window);
4599  tags[1] = UVES_LINE_TABLE_MIDAS(chip, window);
4600  tags[2] = UVES_LINE_TABLE_MIDAS(chip, window);
4601 
4602  uves_msg_debug("Trying %s", tags[0]);
4603  }
4604  if (window <= 0)
4605  {
4606  /* Look for any LINE_TABLE_BLUEi */
4607  tags[0] = UVES_LINE_TABLE_MIDAS(chip, 1);
4608  tags[1] = UVES_LINE_TABLE_MIDAS(chip, 2);
4609  tags[2] = UVES_LINE_TABLE_MIDAS(chip, 3);
4610 
4611  uves_msg_debug("Trying %s, %s or %s", tags[0], tags[1], tags[2]);
4612  }
4613  }
4614 
4615  check( *linetable_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
4616  "No line table (%s, %s or %s) found in SOF", tags[0], tags[1], tags[2]);
4617  }
4618 
4619  /* Read primary header */
4620  check( primary_header = uves_propertylist_load(*linetable_filename, 0),
4621  "Could not load primary header of '%s'", *linetable_filename);
4622 
4623  check_nomsg( uves_warn_if_chip_names_dont_match(primary_header, chip_name, chip) );
4624 
4625  /* Determine format of line table */
4626  if (uves_propertylist_contains(primary_header, UVES_DRS_ID))
4627  {
4628  check( drs_id = uves_pfits_get_drs_id(primary_header), "Error reading DRS ID");
4629  if (strstr(drs_id, "CPL") != NULL || strstr(drs_id, "cpl") != NULL)
4630  {
4631  format_is_midas = false;
4632  uves_msg_debug("Line table was written by CPL");
4633  }
4634  else if (strstr(drs_id, "MIDAS") != NULL || strstr(drs_id, "midas") != NULL)
4635  {
4636  format_is_midas = true;
4637  uves_msg_debug("Line table was written by MIDAS");
4638  }
4639  else
4640  {
4641  assure ( false,
4642  CPL_ERROR_ILLEGAL_INPUT,
4643  "Unrecognized line table format, DRS_ID = '%s'", drs_id);
4644  }
4645  }
4646  else
4647  {
4648  format_is_midas = true;
4649  uves_msg_debug("No '%s' keyword found. Assuming MIDAS format", UVES_DRS_ID);
4650  }
4651 
4652  if (format_is_midas || flames)
4653  {
4654  if (!flames)
4655  {
4656  assure( trace_id == 0 && (window == -1 || (1 <= window && window <= 3)),
4657  CPL_ERROR_UNSUPPORTED_MODE,
4658  "Cannot read (fibre, window) = (%d, %d) from MIDAS line table",
4659  trace_id, window);
4660 
4661  base_extension = 0;
4662  }
4663  else
4664  {
4665 
4666  if(trace_id > 0) {
4667 
4668  assure( ((1<= trace_id && trace_id <= 9) && (window == -1)),
4669  CPL_ERROR_UNSUPPORTED_MODE,
4670  "Cannot read (fibre, window) = (%d, %d) from MIDAS line table",
4671  trace_id, window);
4672 
4673  base_extension = 0;
4674 
4675 
4676  } else {
4677 
4678  uves_msg_warning("Assuming line table is guess table");
4679  base_extension = 0;
4680  }
4681  }
4682  }
4683  else
4684  /* Find table extension containing the line table for the specified trace and window */
4685  {
4686  int nextensions;
4687  bool found;
4688 
4689  check( nextensions = uves_get_nextensions(*linetable_filename),
4690  "Error reading number of extensions of file '%s'", *linetable_filename);
4691  header = NULL;
4692  found = false;
4693 
4694  uves_msg_debug("Number of extensions = %d", nextensions);
4695 
4696  for (base_extension = 1; base_extension < nextensions && !found; base_extension++)
4697  {
4698  int header_trace;
4699  int header_window;
4700 
4701  /* Read header trace & window info */
4702  check(( uves_free_propertylist(&header),
4703  header = uves_propertylist_load(*linetable_filename, base_extension)),
4704  "Could not header of extension %d of '%s'",
4705  base_extension, *linetable_filename);
4706 
4707  check( header_trace = uves_pfits_get_traceid (header),
4708  "Error reading trace ID from header of extension %d of '%s'",
4709  base_extension, *linetable_filename);
4710 
4711  check( header_window = uves_pfits_get_windownumber(header),
4712  "Error reading window number from header of extension %d of '%s'",
4713  base_extension, *linetable_filename);
4714 
4715  uves_msg_debug("Found (trace, window) = (%d, %d), need (%d, %d)",
4716  header_trace, header_window,
4717  trace_id, window);
4718 
4719  found = ( (trace_id == header_trace) &&
4720  (window == -1 || window == header_window) );
4721  }
4722 
4723  assure( found,
4724  CPL_ERROR_ILLEGAL_INPUT,
4725  "Line table (trace, window) = (%d, %d) is not present in file '%s'",
4726  trace_id, window, *linetable_filename);
4727 
4728  /* Let 'base_extension' be the first extension before
4729  the proper extension was found (0, 3, 6, ...) */
4730  base_extension -= 2;
4731  /* ...and incremented in for-loop */
4732  }
4733 
4734  check( *linetable = cpl_table_load(*linetable_filename,
4735  base_extension + UVES_LINE_TABLE_EXTENSION,
4736  1), /* Mark identified
4737  invalid values? (1=yes) */
4738  "Error loading line table from extension %d of file '%s'",
4739  base_extension + UVES_LINE_TABLE_EXTENSION, *linetable_filename);
4740 
4741  /* Read header of table extension if requested */
4742  if (linetable_header != NULL)
4743  {
4744  check( *linetable_header =
4745  uves_propertylist_load(*linetable_filename,
4746  base_extension + UVES_LINE_TABLE_EXTENSION),
4747  "Could not load header of extension %d of '%s'",
4748  base_extension + UVES_LINE_TABLE_EXTENSION, *linetable_filename);
4749 
4750  if (format_is_midas)
4751  {
4752  int size = 0;
4753  cpl_type type;
4754  absorders = uves_read_midas_array(*linetable_header, "ORDER", &size,
4755  &type, NULL);
4756 
4757  assure( type == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
4758  "Type of ORDER is %s, int expected",
4759  uves_tostring_cpl_type(type));
4760 
4761  assure( size == 2,
4762  CPL_ERROR_ILLEGAL_INPUT,
4763  "'ORDER' array has size %d. Size 2 expected.", size);
4764  check(( uves_pfits_set_firstabsorder(*linetable_header, absorders[0]),
4765  uves_pfits_set_lastabsorder(*linetable_header, absorders[1])),
4766  "Error updating table header");
4767  }
4768  }
4769 
4770  /* Read the polynomials if requested */
4771  if (format_is_midas)
4772  {
4773  /* Rename & cast order/ident/X columns */
4774  check(( cpl_table_cast_column(*linetable, "X", "xxxx", CPL_TYPE_DOUBLE),
4775  cpl_table_erase_column(*linetable, "X"),
4776  cpl_table_name_column(*linetable, "xxxx", "X")),
4777  "Error casting and renaming column 'X'");
4778 
4779  check(( cpl_table_cast_column(*linetable, "YNEW", "xxxx", CPL_TYPE_DOUBLE),
4780  cpl_table_erase_column(*linetable, "YNEW"),
4781  cpl_table_name_column(*linetable, "xxxx", "Ynew")),
4782  "Error casting and renaming column 'YNEW'");
4783 
4784  check(( cpl_table_cast_column(*linetable, "Y", "xxxx", CPL_TYPE_INT),
4785  cpl_table_erase_column(*linetable, "Y"),
4786  cpl_table_name_column(*linetable, "xxxx", "Y")),
4787  "Error casting and renaming column 'Y'");
4788 
4789  check(( cpl_table_cast_column(*linetable, "ORDER", "Order", CPL_TYPE_INT),
4790  cpl_table_erase_column(*linetable, "ORDER")),
4791  "Error casting and renaming column 'ORDER'");
4792 
4793  check( cpl_table_name_column(*linetable, "IDENT", "Ident"),
4794  "Error renaming column 'IDENT'");
4795 
4796  check( midas_header = uves_propertylist_load(
4797  *linetable_filename,
4798  base_extension + UVES_LINE_TABLE_EXTENSION),
4799  "Could not load header of extension %d of '%s'",
4800  base_extension + UVES_LINE_TABLE_EXTENSION, *linetable_filename);
4801 
4802  if (dispersion_relation != NULL) {
4803  if (trace_id > 0) {
4804  check( *dispersion_relation =
4805  uves_polynomial_convert_from_plist_midas(midas_header,
4806  "REGR", trace_id),
4807  "Error reading polynomial 'REGR%d' from '%s'",
4808  trace_id,
4809  *linetable_filename);
4810  }
4811  else {
4812  check( *dispersion_relation =
4813  uves_polynomial_convert_from_plist_midas(midas_header,
4814  "REGR", -1),
4815  "Error reading polynomial 'REGR' from '%s'",
4816  *linetable_filename);
4817  }
4818  }
4819 
4820 
4821  check( absolute_order_local =
4822  uves_polynomial_convert_from_plist_midas(midas_header, "RORD",-1),
4823  "Error reading polynomial 'RORD' from '%s'", *linetable_filename);
4824 
4825  /* For FLAMES data, it seems that the polynomial is half an order shifted
4826  (for unknown reasons) */
4827  if (flames)
4828  {
4829  check_nomsg( uves_polynomial_shift(absolute_order_local, 0, 0.5) );
4830  }
4831  }
4832  else
4833  /* CPL format */
4834  {
4835  /* physmod + wavecal recipes use different naming conventions,
4836  workaround for this:
4837  */
4838  if (cpl_table_has_column(*linetable, "YNEW"))
4839  {
4840  cpl_table_name_column(*linetable, "YNEW", "Ynew");
4841  }
4842 
4843  if (dispersion_relation != NULL)
4844  {
4845  check( *dispersion_relation = load_polynomial(
4846  *linetable_filename,
4847  base_extension + UVES_LINE_TABLE_EXTENSION_DISPERSION),
4848  "Could not read polynomial from extension %d of file '%s'",
4849  base_extension + UVES_LINE_TABLE_EXTENSION_DISPERSION,
4850  *linetable_filename);
4851  }
4852 
4853  check( absolute_order_local =
4854  load_polynomial(*linetable_filename,
4855  base_extension + UVES_LINE_TABLE_EXTENSION_ABSORDER),
4856  "Could not read polynomial from extension %d of file '%s'",
4857  base_extension + UVES_LINE_TABLE_EXTENSION_ABSORDER, *linetable_filename);
4858  }
4859 
4860  if (absolute_order != NULL)
4861  {
4862  *absolute_order = uves_polynomial_duplicate(absolute_order_local);
4863  }
4864 
4865 
4866  check( align_order_line_table(
4867  *linetable, absolute_order_local, linetable_header,
4868  order_locations, minorder, maxorder),
4869  "Error while aligning line/order tables");
4870 
4871 
4872  /* Remove all other columns than 'Ident', 'Order', 'X', 'Pixelsize' */
4873  {
4874  const char *colname;
4875 
4876  /* Loop through all columns */
4877 
4878  /* It is undefined behaviour (for a reason!) to loop through
4879  columns while deleting some of them. Therefore, copy the
4880  structure of the linetable to another (empty) table */
4881 
4882  uves_free_table(&temp);
4883  check(( temp = cpl_table_new(0),
4884  cpl_table_copy_structure(temp, *linetable)),
4885  "Error duplicating line table column structure");
4886 
4887  colname = cpl_table_get_column_name(temp);
4888  while (colname != NULL)
4889  {
4890  if (!(strcmp(colname, "X" ) == 0 ||
4891  strcmp(colname, "Order" ) == 0 ||
4892  strcmp(colname, "Ident" ) == 0 ||
4893  strcmp(colname, "FIBRE" ) == 0 ||
4894  strcmp(colname, "Fibre" ) == 0 ||
4895  strcmp(colname, LINETAB_PIXELSIZE) == 0))
4896  {
4897  cpl_table_erase_column(*linetable, colname);
4898  uves_msg_debug("Removing unused column '%s'", colname);
4899  }
4900 
4901  /* Call with NULL argument to get the next column name */
4902  colname = cpl_table_get_column_name(NULL);
4903  }
4904  }
4905 
4906  /* support MIDAS
4907  * Calculate 'Pixel' column (lower case) for MIDAS tables
4908  */
4909  if ( !cpl_table_has_column(*linetable, LINETAB_PIXELSIZE) )
4910  {
4911  check( create_column_pixelsize(*linetable),
4912  "Error adding 'Pixelsize' column");
4913  }
4914 
4915  /* Remove un-identified lines (where Ident = invalid or Ident = zero) ... */
4916  check( uves_erase_invalid_table_rows(*linetable, "Ident"),
4917  "Error deleting rows with illegal 'Ident' value");
4918 
4919  check( uves_erase_table_rows(*linetable, "Ident", CPL_LESS_THAN, 0.01),
4920  "Error deleting rows with illegal 'Ident' value");
4921 
4922  /* Check for any other invalid value */
4923  assure( uves_erase_invalid_table_rows(*linetable, NULL) == 0, CPL_ERROR_ILLEGAL_INPUT,
4924  "After deleting rows with invalid 'Ident' values, "
4925  "the table in extension %d of file '%s' still contains invalid rows",
4926  base_extension + UVES_LINE_TABLE_EXTENSION, *linetable_filename);
4927 
4928  /* Sort line table by 'Order' (ascending), then 'X' (ascending) */
4929  check( uves_sort_table_2(*linetable, "Order", "X", false, false), "Error sorting line table");
4930 
4931  cleanup:
4932  uves_free_propertylist(&primary_header);
4933  uves_free_propertylist(&header);
4934  uves_free_propertylist(&midas_header);
4935  uves_free_table(&temp);
4936  uves_polynomial_delete(&absolute_order_local);
4937  cpl_free(absorders);
4938  if (cpl_error_get_code() != CPL_ERROR_NONE) {
4939  *linetable_filename = NULL;
4940  uves_free_table(linetable);
4941  if (dispersion_relation != NULL) uves_polynomial_delete(dispersion_relation);
4942  if (absolute_order != NULL) uves_polynomial_delete(absolute_order);
4943  }
4944  return;
4945 }
4946 
4947 /*----------------------------------------------------------------------------*/
4951 /*----------------------------------------------------------------------------*/
4952 void
4953 uves_load_linetable_const(const cpl_frameset *frames,
4954  bool flames,
4955  const char *chip_name,
4956  const polynomial *order_locations, int minorder, int maxorder,
4957  const char **linetable_filename,
4958  const cpl_table **linetable,
4959  const uves_propertylist **linetable_header,
4960  const polynomial **dispersion_relation,
4961  polynomial **absolute_order,
4962  enum uves_chip chip, int trace_id, int window)
4963 {
4964  uves_load_linetable(frames, flames, chip_name, order_locations,
4965  minorder, maxorder,
4966  linetable_filename,
4967  (cpl_table **)linetable,
4968  (uves_propertylist **)linetable_header,
4969  (polynomial **)dispersion_relation,
4970  absolute_order,
4971  chip, trace_id, window);
4972 }
4973 
4974 
4975 
4976 /*----------------------------------------------------------------------------*/
4991 /*----------------------------------------------------------------------------*/
4992 
4993 cpl_error_code
4994 uves_load_response_curve(const cpl_frameset *frames, const char *chip_name,
4995  const char **response_filename,
4996  cpl_image **response_curve,
4997  cpl_table **master_response,
4998  uves_propertylist **response_header, enum uves_chip chip)
4999 {
5000  const char *tags[2];
5001  int number_of_tags = sizeof(tags) / sizeof(char *);
5002  int extension;
5003  int indx;
5004 
5005  *response_curve = NULL;
5006  *response_header = NULL;
5007  *master_response = NULL;
5008 
5009  tags[0] = UVES_INSTR_RESPONSE (chip);
5010  tags[1] = UVES_MASTER_RESPONSE(chip);
5011 
5012  check( *response_filename = uves_find_frame(frames, tags, number_of_tags, &indx,
5013  NULL),
5014  "Could not find '%s' in frame set", tags[0]);
5015 
5016 
5017  if (indx == 0)
5018  {
5019  extension = UVES_INSTR_RESPONSE_EXTENSION(chip);
5020 
5021  /* Load the response image
5022 
5023  Note: Even if the response curve was saved as
5024  a FITS file with NAXIS=1, cpl_image_load() will
5025  create an image of size nx1, which is just
5026  what we want
5027  */
5028  check( *response_curve = uves_load_image_file(*response_filename,
5029  /* CPL_TYPE_DOUBLE, Convert to this type */
5030  0, /* plane number */
5031  extension, /* Extension number */
5032 
5033 response_header
5034  ),
5035  "Could not load response curve from extension %d of file '%s'",
5036  extension, *response_filename);
5037 
5038  /* Load the header */
5039 /*
5040  check( *response_header = uves_propertylist_load(*response_filename,
5041  extension),
5042  "Could not load header from extension %d of file '%s'",
5043  extension, *response_filename);
5044 */
5045  check_nomsg( uves_warn_if_chip_names_dont_match(*response_header, chip_name, chip) );
5046  }
5047  else
5048  /* Master response */
5049  {
5050  extension = UVES_MASTER_RESPONSE_EXTENSION(chip);
5051 
5052  check( *master_response = cpl_table_load(*response_filename,
5053  UVES_LINE_INTMON_TABLE_EXTENSION,
5054  1), /* Mark identified
5055  invalid values? (1=yes) */
5056  "Error master response curve from extension %d of file '%s'",
5057  extension, *response_filename);
5058 
5059  /* Convert columns to double */
5060  check(( cpl_table_cast_column(*master_response, "LAMBDA", "LAMBDA_double",
5061  CPL_TYPE_DOUBLE),
5062  cpl_table_erase_column(*master_response, "LAMBDA"),
5063  cpl_table_name_column(*master_response, "LAMBDA_double", "LAMBDA")),
5064  "Could not cast column 'LAMBDA'");
5065 
5066  check(( cpl_table_cast_column(*master_response, "FLUX_CONV", "FLUX_CONV_double",
5067  CPL_TYPE_DOUBLE),
5068  cpl_table_erase_column(*master_response, "FLUX_CONV"),
5069  cpl_table_name_column(*master_response, "FLUX_CONV_double", "FLUX_CONV")),
5070  "Could not cast column 'FLUX_CONV'");
5071 
5072  /* Do not need the header, which also does not contain
5073  keywords needed for uves_warn_if_chip_names_dont_match() */
5074  }
5075 
5076  cleanup:
5077  if (cpl_error_get_code() != CPL_ERROR_NONE)
5078  {
5079  *response_filename = NULL;
5080  uves_free_image(response_curve);
5081  uves_free_propertylist(response_header);
5082  }
5083  return cpl_error_get_code();
5084 }
5085 
5086 
5087 /*----------------------------------------------------------------------------*/
5097 /*----------------------------------------------------------------------------*/
5098 cpl_error_code uves_load_lineintmon(const cpl_frameset *frames,
5099  const char **line_intmon_filename,
5100  cpl_table **line_intmon)
5101 {
5102  const char *tags[1] = {UVES_LINE_INTMON_TABLE};
5103 
5104  int number_of_tags = sizeof(tags) / sizeof(char *);
5105  int indx;
5106 
5107  /* Get filename */
5108  check( *line_intmon_filename = uves_find_frame(frames, tags, number_of_tags,
5109  &indx, NULL),
5110  "No line intensity table (%s) found in SOF", tags[0]);
5111 
5112  /* Load table */
5113  check( *line_intmon = cpl_table_load(*line_intmon_filename,
5114  UVES_LINE_INTMON_TABLE_EXTENSION,
5115  1), /* Mark identified
5116  invalid values? (1=yes) */
5117  "Error loading line reference table from extension %d of file '%s'",
5118  UVES_LINE_INTMON_TABLE_EXTENSION, *line_intmon_filename);
5119 
5120  check(( cpl_table_cast_column(*line_intmon, "WAVE", "Wave", CPL_TYPE_DOUBLE),
5121  cpl_table_erase_column(*line_intmon, "WAVE")),
5122  "Could not cast and rename column");
5123 
5124  /* Sort table by 'Wave' (ascending) */
5125  check( uves_sort_table_1(*line_intmon, "Wave", false), "Error sorting table");
5126 
5127  cleanup:
5128  if (cpl_error_get_code() != CPL_ERROR_NONE)
5129  {
5130  *line_intmon_filename = NULL;
5131  uves_free_table(line_intmon);
5132  }
5133  return cpl_error_get_code();
5134 }
5135 
5136 
5137 /*----------------------------------------------------------------------------*/
5149 /*----------------------------------------------------------------------------*/
5150 void
5151 uves_load_corvel(const cpl_frameset *frames,
5152  cpl_table **corvel,
5153  uves_propertylist **corvel_header,
5154  const char **corvel_filename)
5155 {
5156  const char *tags[1];
5157  int number_of_tags = sizeof(tags) / sizeof(char *);
5158  int indx;
5159  int extension;
5160 
5161  tags[0] = FLAMES_CORVEL_MASK;
5162 
5163  assure_nomsg( corvel != NULL, CPL_ERROR_NULL_INPUT );
5164  assure_nomsg( corvel_filename != NULL, CPL_ERROR_NULL_INPUT );
5165 
5166  /* Get filename */
5167  check( *corvel_filename = uves_find_frame(frames, tags, number_of_tags,
5168  &indx, NULL),
5169  "No velocity correction table (%s) found in SOF", tags[0]);
5170 
5171  /* Load table */
5172  extension = 1;
5173  check( *corvel = cpl_table_load(*corvel_filename,
5174  extension,
5175  1), /* Mark identified
5176  invalid values? (1=yes) */
5177  "Error loading line reference table from extension %d of file '%s'",
5178  extension, *corvel_filename);
5179 
5180  /* Load header */
5181  if (corvel_header != NULL)
5182  {
5183  extension = 0;
5184  check( *corvel_header = uves_propertylist_load(*corvel_filename,
5185  extension),
5186  "Could not load header from extension %d of file %s",
5187  extension, *corvel_filename);
5188 
5189  }
5190 
5191  cleanup:
5192  if (cpl_error_get_code() != CPL_ERROR_NONE)
5193  {
5194  *corvel_filename = NULL;
5195  uves_free_table(corvel);
5196  }
5197  return;
5198 }
5199 
5200 /*----------------------------------------------------------------------------*/
5216 /*----------------------------------------------------------------------------*/
5217 cpl_error_code
5218 uves_load_linerefertable(const cpl_frameset *frames,
5219  const char **line_refer_filename,
5220  cpl_table **line_refer, uves_propertylist **line_refer_header)
5221 {
5222  const char *tags[1] = {UVES_LINE_REFER_TABLE};
5223 
5224  int number_of_tags = sizeof(tags) / sizeof(char *);
5225  int indx;
5226 
5227  /* Get filename */
5228  check( *line_refer_filename = uves_find_frame(frames, tags, number_of_tags,
5229  &indx, NULL),
5230  "No line reference table (%s) found in SOF", tags[0]);
5231 
5232  /* Load table */
5233  check( *line_refer = cpl_table_load(*line_refer_filename,
5234  UVES_LINE_REFER_TABLE_EXTENSION,
5235  1), /* Mark identified
5236  invalid values? (1=yes) */
5237  "Error loading line reference table from extension %d of file '%s'",
5238  UVES_LINE_REFER_TABLE_EXTENSION, *line_refer_filename);
5239 
5240  /* Load header if requested */
5241  if (line_refer_header != NULL)
5242  {
5243  check( *line_refer_header = uves_propertylist_load(*line_refer_filename, 0),
5244  "Could not load header of line_refer table in '%s'", *line_refer_filename);
5245  }
5246 
5247  assure( uves_erase_invalid_table_rows(*line_refer, NULL) == 0, CPL_ERROR_ILLEGAL_INPUT,
5248  "Table in extension %d of file '%s' contains invalid rows",
5249  UVES_LINE_REFER_TABLE_EXTENSION, *line_refer_filename);
5250 
5251  check(( cpl_table_cast_column(*line_refer, "WAVE", "Wave", CPL_TYPE_DOUBLE),
5252  cpl_table_erase_column(*line_refer, "WAVE")),
5253  "Could not cast and rename column");
5254 
5255  /* Write uncertainties of wavelengths.
5256  The value 0.002 is finetuned/retro-fitted to get a chi_sq ~ 1 when
5257  using the new catalogue from
5258 
5259  M. T. Murphy, P. Tzanavaris, J. K. Webb, C. Lovis
5260  "Selection of ThAr lines for wavelength calibration of echelle
5261  spectra and implications for variations in the fine-structure constant",
5262  Submitted to MNRAS
5263  */
5264 
5265 #if 0
5266  check(( cpl_table_duplicate_column(*line_refer, "dWave", *line_refer, "Wave"),
5267  cpl_table_divide_scalar (*line_refer, "dWave", 300000*10)),
5268  "Error writing wavelength uncertainties");
5269 #else
5270  /* we should do this */
5271  check(( cpl_table_new_column(*line_refer, "dWave", CPL_TYPE_DOUBLE),
5272  cpl_table_fill_column_window(*line_refer,
5273  "dWave",
5274  0,
5275  cpl_table_get_nrow(*line_refer), 0.002)),
5276  "Error writing wavelength uncertainties");
5277 #endif
5278 
5279  /* Sort table by 'Wave' (ascending) */
5280  check( uves_sort_table_1(*line_refer, "Wave", false), "Error sorting table");
5281 
5282  cleanup:
5283  if (cpl_error_get_code() != CPL_ERROR_NONE) {
5284  *line_refer_filename = NULL;
5285  uves_free_table (line_refer);
5286  if (line_refer_header != NULL) uves_free_propertylist(line_refer_header);
5287  }
5288  return cpl_error_get_code();
5289 }
5290 
5291 /*----------------------------------------------------------------------------*/
5305 /*----------------------------------------------------------------------------*/
5306 cpl_error_code
5307 uves_load_flux_table(const cpl_frameset *frames, const char **flux_table_filename,
5308  cpl_table **flux_table)
5309 {
5310  const char *tags[1] = {UVES_FLUX_STD_TABLE};
5311 
5312  int number_of_tags = sizeof(tags) / sizeof(char *);
5313  int indx;
5314 
5315  /* Get filename */
5316  check( *flux_table_filename = uves_find_frame(frames, tags, number_of_tags,
5317  &indx, NULL),
5318  "No standard star flux table (%s) in SOF", tags[0]);
5319 
5320  /* Load table */
5321  check( *flux_table = cpl_table_load(*flux_table_filename,
5322  UVES_FLUX_STD_TABLE_EXTENSION,
5323  1), /* Mark identified
5324  invalid values? (1=yes) */
5325  "Error loading flux table from extension %d of file '%s'",
5326  UVES_FLUX_STD_TABLE_EXTENSION, *flux_table_filename);
5327 
5328  if (false)
5329  /* Don't do this, it will remove one std (LTT2415) from the table which has TYPE = NULL.
5330  Instead, set type to "NULL" (this is only used for messages)
5331  */
5332  {
5333  if (uves_erase_invalid_table_rows(*flux_table, NULL) != 0)
5334  {
5335  uves_msg_warning("Table in extension %d of file '%s' contains null values",
5336  UVES_FLUX_STD_TABLE_EXTENSION, *flux_table_filename);
5337  }
5338  }
5339  else
5340  {
5341  int i;
5342  for (i = 0; i < cpl_table_get_nrow(*flux_table); i++)
5343  {
5344  if (cpl_table_get_string(*flux_table, "TYPE", i) == NULL)
5345  {
5346  cpl_table_set_string(*flux_table, "TYPE", i, "NULL");
5347  }
5348  }
5349  }
5350 
5351 
5352  cleanup:
5353  if (cpl_error_get_code() != CPL_ERROR_NONE)
5354  {
5355  *flux_table_filename = NULL;
5356  uves_free_table(flux_table);
5357  }
5358  return cpl_error_get_code();
5359 }
5360 
5361 
5362 /*----------------------------------------------------------------------------*/
5376 /*----------------------------------------------------------------------------*/
5377 cpl_error_code
5378 uves_load_atmo_ext(const cpl_frameset *frames, const char **atmext_table_filename,
5379  cpl_table **atmext_table)
5380 {
5381  const char *tags[1] = {UVES_EXTCOEFF_TABLE};
5382 
5383  int number_of_tags = sizeof(tags) / sizeof(char *);
5384  int indx;
5385 
5386  /* Get filename */
5387  check( *atmext_table_filename = uves_find_frame(frames, tags, number_of_tags,
5388  &indx, NULL),
5389  "No atmospheric extinction table (%s) found in SOF", tags[0]);
5390 
5391  /* Load table */
5392  check( *atmext_table = cpl_table_load(*atmext_table_filename,
5393  UVES_EXTCOEFF_TABLE_EXTENSION,
5394  1), /* Mark identified
5395  invalid values? (1=yes) */
5396  "Error loading atmospheric extinction table from extension %d of file '%s'",
5397  UVES_EXTCOEFF_TABLE_EXTENSION, *atmext_table_filename);
5398 
5399  assure( uves_erase_invalid_table_rows(*atmext_table, NULL) == 0, CPL_ERROR_ILLEGAL_INPUT,
5400  "Table in extension %d of file '%s' contains invalid rows",
5401  UVES_EXTCOEFF_TABLE_EXTENSION, *atmext_table_filename);
5402 
5403  check( uves_sort_table_1(*atmext_table, "LAMBDA", false),
5404  "Error sorting table");
5405 
5406  /* Convert columns to double */
5407  check(( cpl_table_cast_column(*atmext_table, "LAMBDA", "LAMBDA_double", CPL_TYPE_DOUBLE),
5408  cpl_table_erase_column(*atmext_table, "LAMBDA"),
5409  cpl_table_name_column(*atmext_table, "LAMBDA_double", "LAMBDA")),
5410  "Could not cast column 'LAMBDA'");
5411 
5412  check(( cpl_table_cast_column(*atmext_table, "LA_SILLA", "LA_SILLA_double", CPL_TYPE_DOUBLE),
5413  cpl_table_erase_column(*atmext_table, "LA_SILLA"),
5414  cpl_table_name_column(*atmext_table, "LA_SILLA_double", "LA_SILLA")),
5415  "Could not cast column 'LA_SILLA'");
5416 
5417  cleanup:
5418  if (cpl_error_get_code() != CPL_ERROR_NONE)
5419  {
5420  *atmext_table_filename = NULL;
5421  uves_free_table(atmext_table);
5422  }
5423  return cpl_error_get_code();
5424 }
5425 /*----------------------------------------------------------------------------*/
5433 /*----------------------------------------------------------------------------*/
5434 char *
5435 uves_guess_order_table_filename(enum uves_chip chip)
5436 {
5437  return uves_local_filename("orderguesstable", chip, -1, -1);
5438 }
5439 
5440 /*----------------------------------------------------------------------------*/
5448 /*----------------------------------------------------------------------------*/
5449 char *
5450 uves_order_table_filename(enum uves_chip chip)
5451 {
5452  return uves_local_filename("ordertable", chip, -1, -1);
5453 }
5454 
5455 /*----------------------------------------------------------------------------*/
5462 /*----------------------------------------------------------------------------*/
5463 char *uves_ordef_filename(enum uves_chip chip)
5464 {
5465  return uves_local_filename("order_def", chip, -1, -1);
5466 }
5467 
5468 /*----------------------------------------------------------------------------*/
5476 /*----------------------------------------------------------------------------*/
5477 char *
5478 uves_masterdark_filename(enum uves_chip chip)
5479 {
5480  return uves_local_filename("masterdark", chip, -1, -1);
5481 }
5482 
5483 
5484 /*----------------------------------------------------------------------------*/
5490 /*----------------------------------------------------------------------------*/
5491 char *
5492 uves_flat_ratio_filename(enum uves_chip chip)
5493 {
5494  return uves_local_filename("ratio", chip, -1, -1);
5495 }
5496 
5497 /*----------------------------------------------------------------------------*/
5504 /*----------------------------------------------------------------------------*/
5505 char *uves_cd_align_filename(enum uves_chip chip)
5506 {
5507  return uves_local_filename("cd_align", chip, -1, -1);
5508 }
5509 
5510 /*----------------------------------------------------------------------------*/
5518 /*----------------------------------------------------------------------------*/
5519 char *
5520 uves_masterflat_filename(enum uves_chip chip)
5521 {
5522  return uves_local_filename("masterflat", chip, -1, -1);
5523 }
5524 /*----------------------------------------------------------------------------*/
5532 /*----------------------------------------------------------------------------*/
5533 char *
5534 uves_masterflat_bkg_filename(enum uves_chip chip)
5535 {
5536  return uves_local_filename("masterflat_bkg", chip, -1, -1);
5537 }
5538 
5539 /*----------------------------------------------------------------------------*/
5547 /*----------------------------------------------------------------------------*/
5548 char *
5549 uves_masterbias_filename(enum uves_chip chip)
5550 {
5551  return uves_local_filename("masterbias", chip, -1, -1);
5552 }
5553 
5554 /*----------------------------------------------------------------------------*/
5562 /*----------------------------------------------------------------------------*/
5563 char *
5564 uves_guess_line_table_filename(enum uves_chip chip)
5565 {
5566  return uves_local_filename("lineguesstable", chip, -1, -1);
5567 }
5568 /*----------------------------------------------------------------------------*/
5576 /*----------------------------------------------------------------------------*/
5577 char *
5578 uves_line_table_filename(enum uves_chip chip)
5579 {
5580  return uves_local_filename("linetable", chip, -1, -1);
5581 }
5582 
5583 /*----------------------------------------------------------------------------*/
5591 /*----------------------------------------------------------------------------*/
5592 char *
5593 uves_line_table_filename_paf(enum uves_chip chip)
5594 {
5595  return uves_local_filename("linetable_paf", chip, -1, -1);
5596 }
5597 
5598 /*----------------------------------------------------------------------------*/
5606 /*----------------------------------------------------------------------------*/
5607 char *
5608 uves_response_curve_filename(enum uves_chip chip)
5609 {
5610  return uves_local_filename("response", chip, -1, -1);
5611 }
5612 
5613 /*----------------------------------------------------------------------------*/
5621 /*----------------------------------------------------------------------------*/
5622 char *
5623 uves_response_curve_2d_filename(enum uves_chip chip)
5624 {
5625  return uves_local_filename("response_2d", chip, -1, -1);
5626 }
5627 
5628 /*----------------------------------------------------------------------------*/
5636 /*----------------------------------------------------------------------------*/
5637 char *
5638 uves_response_red_standard_filename(enum uves_chip chip)
5639 {
5640  return uves_local_filename("red_std", chip, -1, -1);
5641 }
5642 
5643 
5644 /*----------------------------------------------------------------------------*/
5652 /*----------------------------------------------------------------------------*/
5653 char *
5654 uves_response_red_noappend_standard_filename(enum uves_chip chip)
5655 {
5656  return uves_local_filename("red_nonmerged", chip, -1, -1);
5657 }
5658 
5659 /*----------------------------------------------------------------------------*/
5667 /*----------------------------------------------------------------------------*/
5668 char *
5669 uves_response_bkg_standard_filename(enum uves_chip chip)
5670 {
5671  return uves_local_filename("bkg_std", chip, -1, -1);
5672 }
5673 
5674 
5675 /*----------------------------------------------------------------------------*/
5683 /*----------------------------------------------------------------------------*/
5684 char *
5685 uves_order_extract_qc_standard_filename(enum uves_chip chip)
5686 {
5687  return uves_local_filename("order_extract_qc", chip, -1, -1);
5688 }
5689 
5690 /*----------------------------------------------------------------------------*/
5698 /*----------------------------------------------------------------------------*/
5699 char *
5700 uves_response_efficiency_filename(enum uves_chip chip)
5701 {
5702  return uves_local_filename("efficiency", chip, -1, -1);
5703 }
5704 
5705 /*----------------------------------------------------------------------------*/
5713 /*----------------------------------------------------------------------------*/
5714 
5715 char *
5716 uves_scired_red_2d_science_filename(enum uves_chip chip)
5717 {
5718  return uves_local_filename("red_2d_science", chip, -1, -1);
5719 }
5720 
5728 /*----------------------------------------------------------------------------*/
5729 
5730 
5731 
5732 char *
5733 uves_scired_red_science_filename(enum uves_chip chip)
5734 {
5735  return uves_local_filename("red_science", chip, -1, -1);
5736 }
5744 /*----------------------------------------------------------------------------*/
5745 
5746 
5747 
5748 char *
5749 uves_scired_red_noappend_science_filename(enum uves_chip chip)
5750 {
5751  return uves_local_filename("red_nonmerged_science", chip, -1, -1);
5752 }
5753 /*----------------------------------------------------------------------------*/
5761 /*----------------------------------------------------------------------------*/
5762 char *
5763 uves_scired_red_error_filename(enum uves_chip chip)
5764 {
5765  return uves_local_filename("error_red_science", chip, -1, -1);
5766 }
5767 
5768 /*----------------------------------------------------------------------------*/
5776 /*----------------------------------------------------------------------------*/
5777 char *
5778 uves_scired_red_noappend_error_filename(enum uves_chip chip)
5779 {
5780  return uves_local_filename("error_red_nonmerged_science", chip, -1, -1);
5781 }
5782 
5783 /*----------------------------------------------------------------------------*/
5791 /*----------------------------------------------------------------------------*/
5792 char *
5793 uves_scired_red_2d_error_filename(enum uves_chip chip)
5794 {
5795  return uves_local_filename("error_2d_science", chip, -1, -1);
5796 }
5797 
5798 
5799 /*----------------------------------------------------------------------------*/
5807 /*----------------------------------------------------------------------------*/
5808 char *
5809 uves_scired_fluxcal_science_filename(enum uves_chip chip)
5810 {
5811  return uves_local_filename("fluxcal_science", chip, -1, -1);
5812 }
5813 
5814 
5815 /*----------------------------------------------------------------------------*/
5823 /*----------------------------------------------------------------------------*/
5824 char *
5825 uves_scired_fluxcal_science_noappend_filename(enum uves_chip chip)
5826 {
5827  return uves_local_filename("fluxcal_nonmerged_science", chip, -1, -1);
5828 }
5829 /*----------------------------------------------------------------------------*/
5837 /*----------------------------------------------------------------------------*/
5838 char *
5839 uves_scired_fluxcal_error_filename(enum uves_chip chip)
5840 {
5841  return uves_local_filename("fluxcal_error_science", chip, -1, -1);
5842 }
5843 
5844 
5845 /*----------------------------------------------------------------------------*/
5853 /*----------------------------------------------------------------------------*/
5854 char *
5855 uves_scired_fluxcal_error_noappend_filename(enum uves_chip chip)
5856 {
5857  return uves_local_filename("fluxcal_error_nonmerged_science", chip, -1, -1);
5858 }
5859 
5860 
5861 
5869 /*----------------------------------------------------------------------------*/
5870 char *
5871 uves_scired_fluxcal_science_2d_filename(enum uves_chip chip)
5872 {
5873  return uves_local_filename("fluxcal_2d_science", chip, -1, -1);
5874 }
5875 /*----------------------------------------------------------------------------*/
5883 /*----------------------------------------------------------------------------*/
5884 char *
5885 uves_scired_fluxcal_error_2d_filename(enum uves_chip chip)
5886 {
5887  return uves_local_filename("fluxcal_error_2d_science", chip, -1, -1);
5888 }
5889 /*----------------------------------------------------------------------------*/
5897 /*----------------------------------------------------------------------------*/
5898 char *
5899 uves_scired_ff_variance_filename(enum uves_chip chip)
5900 {
5901  return uves_local_filename("variance_ff_science", chip, -1, -1);
5902 }
5903 
5904 /*----------------------------------------------------------------------------*/
5912 /*----------------------------------------------------------------------------*/
5913 char *
5914 uves_scired_ff_variance_2d_filename(enum uves_chip chip)
5915 {
5916  return uves_local_filename("variance_ff_2d_science", chip, -1, -1);
5917 }
5918 
5919 /*----------------------------------------------------------------------------*/
5926 /*----------------------------------------------------------------------------*/
5927 char *
5928 uves_scired_merged_2d_science_filename(enum uves_chip chip)
5929 {
5930  return uves_local_filename("merged_2d_science", chip, -1, -1);
5931 }
5932 
5940 /*----------------------------------------------------------------------------*/
5941 char *
5942 uves_scired_merged_science_filename(enum uves_chip chip)
5943 {
5944  return uves_local_filename("merged_science", chip, -1, -1);
5945 }
5946 /*----------------------------------------------------------------------------*/
5954 /*----------------------------------------------------------------------------*/
5955 char *
5956 uves_scired_merged_sky_filename(enum uves_chip chip)
5957 {
5958  return uves_local_filename("merged_sky", chip, -1, -1);
5959 }
5960 
5961 /*----------------------------------------------------------------------------*/
5969 /*----------------------------------------------------------------------------*/
5970 char *
5971 uves_scired_background_filename(enum uves_chip chip)
5972 {
5973  return uves_local_filename("background", chip, -1, -1);
5974 }
5975 
5976 /*----------------------------------------------------------------------------*/
5984 /*----------------------------------------------------------------------------*/
5985 char *
5986 uves_scired_resampled_filename(enum uves_chip chip)
5987 {
5988  return uves_local_filename("resampled_science", chip, -1, -1);
5989 }
5990 
5991 
5992 
5993 /*----------------------------------------------------------------------------*/
6001 /*----------------------------------------------------------------------------*/
6002 char *
6003 uves_scired_resampled_2d_filename(enum uves_chip chip)
6004 {
6005  return uves_local_filename("resampled_2d_science", chip, -1, -1);
6006 }
6007 
6008 
6009 /*----------------------------------------------------------------------------*/
6017 /*----------------------------------------------------------------------------*/
6018 char *
6019 uves_scired_resampledmf_filename(enum uves_chip chip)
6020 {
6021  return uves_local_filename("resampled_mflat", chip, -1, -1);
6022 }
6023 
6024 /*----------------------------------------------------------------------------*/
6033 /*----------------------------------------------------------------------------*/
6034 char *
6035 uves_scired_rebinned_filename(enum uves_chip chip)
6036 {
6037  return uves_local_filename("resampled_ff_science", chip, -1, -1);
6038 }
6039 
6040 /*----------------------------------------------------------------------------*/
6049 /*----------------------------------------------------------------------------*/
6050 char *
6051 uves_scired_rebinned_error_filename(enum uves_chip chip)
6052 {
6053  return uves_local_filename("resampled_error_ff_science", chip, -1, -1);
6054 }
6055 
6056 
6065 /*----------------------------------------------------------------------------*/
6066 char *
6067 uves_scired_rebinned_2d_filename(enum uves_chip chip)
6068 {
6069  return uves_local_filename("resampled_ff_2d_science", chip, -1, -1);
6070 }
6071 
6080 /*----------------------------------------------------------------------------*/
6081 char *
6082 uves_scired_rebinned_2d_error_filename(enum uves_chip chip)
6083 {
6084  return uves_local_filename("resampled_error_ff_2d_science", chip, -1, -1);
6085 }
6086 /*----------------------------------------------------------------------------*/
6094 /*----------------------------------------------------------------------------*/
6095 char *
6096 uves_scired_ordertrace_filename(enum uves_chip chip)
6097 {
6098  return uves_local_filename("ordertrace", chip, -1, -1);
6099 }
6100 
6101 /*----------------------------------------------------------------------------*/
6109 /*----------------------------------------------------------------------------*/
6110 char *
6111 uves_scired_crmask_filename(enum uves_chip chip)
6112 {
6113  return uves_local_filename("cr_mask", chip, -1, -1);
6114 }
6115 
6116 /*----------------------------------------------------------------------------*/
6124 /*----------------------------------------------------------------------------*/
6125 char *
6126 uves_scired_wmap_filename(enum uves_chip chip)
6127 {
6128  return uves_local_filename("wave_map", chip, -1, -1);
6129 }
6130 
6131 /*----------------------------------------------------------------------------*/
6139 /*----------------------------------------------------------------------------*/
6140 char *uves_scired_ext2d_filename(enum uves_chip chip)
6141 {
6142  return uves_local_filename("ext_2d_science", chip, -1, -1);
6143 }
6144 
6145 /*----------------------------------------------------------------------------*/
6153 /*----------------------------------------------------------------------------*/
6154 char *uves_scired_ff2d_filename(enum uves_chip chip)
6155 {
6156  return uves_local_filename("ff_2d_science", chip, -1, -1);
6157 }
6158 
6159 /*----------------------------------------------------------------------------*/
6180 /*----------------------------------------------------------------------------*/
6181 char *
6182 uves_local_filename(const char *prefix, enum uves_chip chip, int trace, int window)
6183 {
6184  char *result = NULL;
6185  const char *chip_string;
6186  const char *suffix = ".fits"; /* Always */
6187  char *t = NULL;
6188  char *w = NULL;
6189 
6190  assure( (trace < 0 && window < 0) || /* Empty suffix */
6191  (trace < 0 && window > 0) || /* Window only suffix */
6192  (trace >= 0 && window > 0), /* Trace & window suffix */
6193  CPL_ERROR_ILLEGAL_INPUT, "Illegal trace and window numbers: (%d, %d)",
6194  trace, window);
6195 
6196  /* Chip */
6197  chip_string = uves_chip_tostring_lower(chip);
6198 
6199  /* Trace and window number (possibly empty string) */
6200  check(( t = int_to_string(trace),
6201  w = int_to_string(window)),
6202  "Error creating substrings");
6203 
6204 /* old code:
6205  result = cpl_calloc(strlen(prefix) + 1 +
6206  strlen(chip_string) + strlen(t) + strlen(w) + strlen(suffix) + 1,
6207  sizeof(char));
6208 
6209  assure_mem( result );
6210 
6211  strcpy(result, prefix);
6212  strcat(result, "_");
6213  strcat(result, chip_string);
6214  strcat(result, t);
6215  strcat(result, w);
6216  strcat(result, suffix);
6217 */
6218  result = uves_sprintf("%s_%s%s%s%s", prefix, chip_string, t, w, suffix);
6219  assure_mem( result );
6220 
6221  cleanup:
6222  cpl_free(t);
6223  cpl_free(w);
6224  if (cpl_error_get_code() != CPL_ERROR_NONE)
6225  {
6226  cpl_free(result); result = NULL;
6227  }
6228  return result;
6229 }
6230 
6231 /*----------------------------------------------------------------------------*/
6242 /*----------------------------------------------------------------------------*/
6243 static char *
6244 int_to_string(int i)
6245 {
6246  char *result = NULL;
6247 
6248  assure( -1 <= i, CPL_ERROR_ILLEGAL_INPUT, "Illegal number (%d)", i);
6249 
6250  if (i == -1)
6251  {
6252  /* Empty string */
6253  result = cpl_calloc(1, sizeof(char));
6254  assure_mem( result );
6255  }
6256  else
6257  {
6258  result = uves_sprintf("_%d", i);
6259  }
6260 
6261  cleanup:
6262  if (cpl_error_get_code() != CPL_ERROR_NONE){
6263  cpl_free(result); result = NULL;
6264  }
6265  return result;
6266 }
6267 
6268 
6269 /*----------------------------------------------------------------------------*/
6279 /*----------------------------------------------------------------------------*/
6280 
6281 cpl_image*
6282 uves_vector_to_image(const cpl_vector* vector,cpl_type type)
6283 {
6284  int i=0;
6285  cpl_image* image=NULL;
6286  int size=0;
6287  const double* pv=NULL;
6288  int* pi=NULL;
6289  float* pf=NULL;
6290  double* pd=NULL;
6291 
6292 
6293  size=cpl_vector_get_size(vector);
6294  image=cpl_image_new(size,1,type);
6295  pv=cpl_vector_get_data_const(vector);
6296  if(type == CPL_TYPE_INT) {
6297  pi=cpl_image_get_data_int(image);
6298  for(i=0;i<size;i++) {
6299  pi[i]=pv[i];
6300  }
6301  } else if (type == CPL_TYPE_FLOAT) {
6302  pf=cpl_image_get_data_float(image);
6303  for(i=0;i<size;i++) {
6304  pf[i]=pv[i];
6305  }
6306  } else if (type == CPL_TYPE_DOUBLE) {
6307  pd=cpl_image_get_data_double(image);
6308  for(i=0;i<size;i++) {
6309  pd[i]=pv[i];
6310  }
6311  } else {
6312  assure( false, CPL_ERROR_INVALID_TYPE,
6313  "No CPL type to represent BITPIX = %d", type);
6314  }
6315 
6316  cleanup:
6317  if (cpl_error_get_code() != CPL_ERROR_NONE){
6318  uves_free_image(&image);
6319  }
6320 
6321  return image;
6322 
6323 }
int uves_pfits_get_prescanx(const uves_propertylist *plist, enum uves_chip chip)
Find out the x-prescan.
Definition: uves_pfits.c:594
int uves_pfits_get_firstabsorder(const uves_propertylist *plist)
Get first absolute order number.
Definition: uves_pfits.c:1734
const cpl_property * uves_propertylist_get_const(const uves_propertylist *self, long position)
Access property list elements by index.
cpl_error_code uves_pfits_set_data_median(uves_propertylist *plist, double median)
Write the median pixel value.
Definition: uves_pfits.c:1816
#define uves_msg_error(...)
Print an error message.
Definition: uves_msg.h:64
void uves_polynomial_delete(polynomial **p)
Delete a polynomial.
char * uves_get_datetime_iso8601(void)
Returns the current date and time as a static string.
Definition: uves_time.c:118
#define uves_msg_warning(...)
Print an warning message.
Definition: uves_msg.h:87
cpl_error_code uves_pfits_set_data_stddev(uves_propertylist *plist, double stddev)
Write the RMS error of pixel values.
Definition: uves_pfits.c:1796
int uves_pfits_get_ovrscanx(const uves_propertylist *plist, enum uves_chip chip)
Find out the x-overscan.
Definition: uves_pfits.c:659
int uves_propertylist_erase(uves_propertylist *self, const char *name)
Erase the given property from a property list.
int uves_propertylist_is_empty(const uves_propertylist *self)
Check whether a property list is empty.
const char * uves_pfits_get_cunit1(const uves_propertylist *plist)
Find out the cunit1.
Definition: uves_pfits.c:2024
double uves_pfits_get_bscale(const uves_propertylist *plist)
Find out the bscale.
Definition: uves_pfits.c:2004
cpl_error_code uves_pfits_set_stoptime(uves_propertylist *plist, const char *stop_time)
Write the stop time.
Definition: uves_pfits.c:2642
int uves_pfits_get_lastabsorder(const uves_propertylist *plist)
Get last absolute order number.
Definition: uves_pfits.c:1764
const char * uves_pfits_get_cunit2(const uves_propertylist *plist)
Find out the cunit2.
Definition: uves_pfits.c:2043
int uves_pfits_get_windownumber(const uves_propertylist *plist)
Get the window number.
Definition: uves_pfits.c:1972
#define check_nomsg(CMD)
Definition: uves_error.h:204
polynomial * uves_polynomial_convert_from_table(cpl_table *t)
Convert a table to a polynomial.
cpl_table * uves_ordertable_traces_new(void)
Create the table that describes fibre traces.
Definition: uves_utils.c:3899
const char * uves_pfits_get_drs_id(const uves_propertylist *plist)
Find out the drs id.
Definition: uves_pfits.c:1017
double uves_pfits_get_cdelt2(const uves_propertylist *plist)
Find out the cdelt2.
Definition: uves_pfits.c:2483
#define passure(BOOL,...)
Definition: uves_error.h:207
const char * uves_tostring_cpl_frame_type(cpl_frame_type ft)
Convert a frame type to a string.
Definition: uves_dump.c:315
double uves_pfits_get_gratwlen(const uves_propertylist *plist, enum uves_chip chip)
find out the central wavelength
Definition: uves_pfits.c:1371
cpl_table * uves_polynomial_convert_to_table(const polynomial *p)
Convert a polynomial to a table.
int uves_pfits_get_slit3_x2encoder(const uves_propertylist *plist)
find out the value of UVES_ENCODER_REF2
Definition: uves_pfits.c:174
int uves_pfits_get_naxis(const uves_propertylist *plist)
Find out the NAXIS.
Definition: uves_pfits.c:2259
double uves_polynomial_derivative_2d(const polynomial *p, double x1, double x2, int varno)
Evaluate the partial derivative of a 2d polynomial.
uves_propertylist * uves_initialize_image_header(const char *ctype1, const char *ctype2, const char *cunit1, const char *cunit2, const char *bunit, const double bscale, double crval1, double crval2, double crpix1, double crpix2, double cdelt1, double cdelt2)
Initialize image header.
Definition: uves_utils.c:2174
double uves_pfits_get_crpix2(const uves_propertylist *plist)
Find out the crpix2.
Definition: uves_pfits.c:2447
uves_propertylist * uves_propertylist_new(void)
Create an empty property list.
long uves_propertylist_get_size(const uves_propertylist *self)
Get the current size of a property list.
#define uves_msg(...)
Print a message on 'info' or 'debug' level.
Definition: uves_msg.h:119
uves_propertylist * uves_propertylist_load(const char *name, int position)
Create a property list from a file.
const char * uves_pfits_get_bunit(const uves_propertylist *plist)
Find out the bunit.
Definition: uves_pfits.c:1985
polynomial * uves_polynomial_duplicate(const polynomial *p)
Copy a polynomial.
cpl_error_code uves_propertylist_set_string(uves_propertylist *self, const char *name, const char *value)
Set the value of the given string property list entry.
int uves_pfits_get_slit3_x1encoder(const uves_propertylist *plist)
find out the value of UVES_ENCODER_REF1
Definition: uves_pfits.c:156
cpl_error_code uves_pfits_set_data_max(uves_propertylist *plist, double max)
Write the max pixel value.
Definition: uves_pfits.c:1852
cpl_error_code uves_propertylist_copy_property_regexp(uves_propertylist *self, const uves_propertylist *other, const char *regexp, int invert)
Copy matching properties from another property list.
void uves_pfits_set_cd11(uves_propertylist *plist, double value)
Write the CD1_1 value.
Definition: uves_pfits.c:95
cpl_error_code uves_pfits_set_starttime(uves_propertylist *plist, const char *start_time)
Write the start time.
Definition: uves_pfits.c:2625
#define assure_mem(PTR)
Definition: uves_error.h:181
polynomial * uves_polynomial_new(const cpl_polynomial *pol)
Create a polynomial.
void uves_pfits_set_cd12(uves_propertylist *plist, double value)
Write the CD1_2 value.
Definition: uves_pfits.c:110
double uves_polynomial_evaluate_2d(const polynomial *p, double x1, double x2)
Evaluate a 2d polynomial.
int uves_chip_get_index(enum uves_chip chip)
Convert to integer.
Definition: uves_chip.c:124
double uves_polynomial_get_coeff_1d(const polynomial *p, int degree)
Get a coefficient of a 1D polynomial.
enum uves_chip uves_chip_get_first(bool blue)
Get first chip for blue or red arm.
Definition: uves_chip.c:92
void uves_pfits_set_ra(uves_propertylist *plist, double ra)
Write the right ascension.
Definition: uves_pfits.c:982
cpl_error_code uves_ordertable_traces_add(cpl_table *traces, int fibre_ID, double fibre_offset, int fibre_mask)
Add a trace.
Definition: uves_utils.c:3926
polynomial * uves_polynomial_regression_1d(cpl_table *t, const char *X, const char *Y, const char *sigmaY, int degree, const char *polynomial_fit, const char *residual_square, double *mean_squared_error, double kappa)
Fit a 1d polynomial to two table columns.
Definition: uves_utils.c:2591
cpl_error_code uves_pfits_set_data_average(uves_propertylist *plist, double average)
Write the average pixel value.
Definition: uves_pfits.c:1778
const char * uves_tostring_cpl_type(cpl_type t)
Convert a CPL type to a string.
Definition: uves_dump.c:378
#define uves_msg_low(...)
Print a message on a lower message level.
Definition: uves_msg.h:105
bool uves_format_is_new(const uves_propertylist *plist)
Find out FITS header format.
Definition: uves_pfits.c:573
const char * uves_chip_tostring_lower(enum uves_chip chip)
Convert to string.
Definition: uves_chip.c:139
cpl_error_code uves_polynomial_shift(polynomial *p, int varno, double shift)
Shift a polynomial.
int uves_propertylist_erase_regexp(uves_propertylist *self, const char *regexp, int invert)
Erase all properties with name matching a given regular expression.
void uves_pfits_set_lastabsorder(uves_propertylist *plist, int last_abs_order)
Write the last absolute order number.
Definition: uves_pfits.c:1750
enum uves_chip uves_chip_get_next(enum uves_chip chip)
Get next chip.
Definition: uves_chip.c:108
#define uves_msg_debug(...)
Print a debug message.
Definition: uves_msg.h:97
double uves_pfits_get_cdelt1(const uves_propertylist *plist)
Find out the cdelt1.
Definition: uves_pfits.c:2465
double uves_pfits_get_crval1(const uves_propertylist *plist)
Find out the crval1.
Definition: uves_pfits.c:2393
uves_propertylist * uves_propertylist_duplicate(const uves_propertylist *self)
Create a copy of the given property list.
#define assure_nomsg(BOOL, CODE)
Definition: uves_error.h:177
int uves_pfits_get_naxis1(const uves_propertylist *plist)
Find out the NAXIS1.
Definition: uves_pfits.c:2316
cpl_error_code uves_pfits_set_wlen1(uves_propertylist *plist, double wlen1)
Write the WLEN1 value.
Definition: uves_pfits.c:1873
int uves_propertylist_contains(const uves_propertylist *self, const char *name)
Check whether a property is present in a property list.
cpl_error_code uves_pfits_set_data_min(uves_propertylist *plist, double min)
Write the min pixel value.
Definition: uves_pfits.c:1834
int uves_pfits_get_traceid(const uves_propertylist *plist)
Get the trace ID number.
Definition: uves_pfits.c:1959
#define check(CMD,...)
Definition: uves_error.h:198
double uves_pfits_get_crval2(const uves_propertylist *plist)
Find out the crval2.
Definition: uves_pfits.c:2411
void uves_pfits_set_dec(uves_propertylist *plist, double dec)
Write the declination.
Definition: uves_pfits.c:964
int uves_pfits_get_bitpix(const uves_propertylist *plist)
Find out the BITPIX.
Definition: uves_pfits.c:2298
void uves_pfits_set_cd22(uves_propertylist *plist, double value)
Write the CD2_2 value.
Definition: uves_pfits.c:140
const char * uves_pfits_get_chipid(const uves_propertylist *plist, enum uves_chip chip)
Find out the chip ID.
Definition: uves_pfits.c:619
void uves_pfits_set_firstabsorder(uves_propertylist *plist, int first_abs_order)
Write the first absolute order number.
Definition: uves_pfits.c:1717
void uves_pfits_set_cd21(uves_propertylist *plist, double value)
Write the CD2_1 value.
Definition: uves_pfits.c:125
double uves_pfits_get_crpix1(const uves_propertylist *plist)
Find out the crpix1.
Definition: uves_pfits.c:2429
double uves_pfits_get_wlen1(const uves_propertylist *plist)
find out the WLEN1 wavelength value
Definition: uves_pfits.c:1350
const char * uves_pfits_get_ctype2(const uves_propertylist *plist)
Find out the ctype2.
Definition: uves_pfits.c:2081
int uves_propertylist_has(const uves_propertylist *self, const char *name)
Check whether a property is present in a property list.
int uves_pfits_put_qc(uves_propertylist *plist, const cpl_table *qclog)
Add QC-LOG to FITS header.
Definition: uves_qclog.c:735
const char * uves_pfits_get_ctype1(const uves_propertylist *plist)
Find out the ctype1.
Definition: uves_pfits.c:2062
cpl_error_code uves_propertylist_append(uves_propertylist *self, const uves_propertylist *other)
Append a property list..
cpl_error_code uves_propertylist_copy_property(uves_propertylist *self, const uves_propertylist *other, const char *name)
Copy a property from another property list.