UVES Pipeline Reference Manual  5.5.5b2
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 
204 
205 
206 
207 
208  int nsof=0;
209  int i=0;
210  nsof = cpl_frameset_get_size(sof);
211  for (i=0 ; i<nsof ; i++) {
212  cpl_frame* frame = cpl_frameset_get_frame(sof,i);
213  char* 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  char* 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  cpl_frame* 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  }
1119  }
1120  }
1121 
1122  UVES_TIME_START("save product");
1123 
1124  /* Now save with the correct header */
1125  if (type == CPL_FRAME_TYPE_IMAGE)
1126  {
1127  bool use_bitpix16_for_int = (strcmp(recipe, make_str(FLAMES_CAL_ORDERPOS)) == 0);
1128 
1129  check( uves_save_image((cpl_image *) object, filename, pl,
1130  use_bitpix16_for_int, true),
1131  "Error saving image to file %s", filename);
1132  }
1133  else if (type == CPL_FRAME_TYPE_TABLE) /* Table */
1134  {
1135  check( uves_table_save((cpl_table *) object,
1136  pl, /* Primary header */
1137  table_header, /* Table header */
1138  filename,
1139  CPL_IO_DEFAULT), /* Create new file */
1140  "Error saving table to file '%s'", filename);
1141  }
1142  else
1143  {
1144  assure(false, CPL_ERROR_UNSUPPORTED_MODE, "Unsupported frame type");
1145  }
1146 
1147  UVES_TIME_END;
1148 
1149  cleanup:
1150  uves_free_propertylist(&pl);
1151 
1152  return cpl_error_get_code();
1153 }
1154 
1155 
1156 /*----------------------------------------------------------------------------*/
1165 /*----------------------------------------------------------------------------*/
1166 void
1167 uves_dfs_write_statistics(const cpl_image *image, uves_propertylist *header,
1168  unsigned stats_mask)
1169 {
1170  cpl_stats *stats = NULL;
1171 
1172  /* Only these bits are supported, all others must be zero */
1173  assure( (stats_mask & (CPL_STATS_MEAN | CPL_STATS_STDEV | CPL_STATS_MEDIAN |
1174  CPL_STATS_MIN | CPL_STATS_MAX)) == stats_mask,
1175  CPL_ERROR_UNSUPPORTED_MODE, "Cannot compute mask %d",
1176  stats_mask );
1177 
1178  UVES_TIME_START("calculate stats");
1179 
1180  check( stats = cpl_stats_new_from_image(
1181  image, stats_mask),
1182  "Error reading image statistics");
1183 
1184  UVES_TIME_END;
1185 
1186  if (stats_mask & CPL_STATS_MEDIAN)
1187  {
1188  check( uves_pfits_set_data_median (header, cpl_stats_get_median(stats) ),
1189  "Could not write median flux");
1190  }
1191  if (stats_mask & CPL_STATS_MEAN)
1192  {
1193  check( uves_pfits_set_data_average(header, cpl_stats_get_mean (stats) ),
1194  "Could not write average flux");
1195  }
1196  if (stats_mask & CPL_STATS_STDEV)
1197  {
1198  check( uves_pfits_set_data_stddev (header, cpl_stats_get_stdev (stats) ),
1199  "Could not write flux stdev");
1200  }
1201  if (stats_mask & CPL_STATS_MIN)
1202  {
1203  check( uves_pfits_set_data_min (header, cpl_stats_get_min (stats) ),
1204  "Could not write min flux");
1205  }
1206  if (stats_mask & CPL_STATS_MIN)
1207  {
1208  check( uves_pfits_set_data_max (header, cpl_stats_get_max (stats) ),
1209  "Could not write max flux");
1210  }
1211 
1212  cleanup:
1213  uves_free_stats(&stats);
1214  return;
1215 }
1216 
1217 
1218 /*----------------------------------------------------------------------------*/
1253 /*----------------------------------------------------------------------------*/
1254 void *
1255 uves_read_midas_array(const uves_propertylist *plist, const char *name,
1256  int *length, cpl_type *type, int *ncards)
1257 {
1258  void *result = NULL;
1259  unsigned result_size;
1260  int N = strlen(name);
1261  bool found = false;
1262  const char *value;
1263  int size;
1264  int i;
1265  const long int plist_size = uves_propertylist_get_size(plist);
1266 
1267  assure_nomsg( length != NULL, CPL_ERROR_NULL_INPUT );
1268  assure_nomsg( type != NULL, CPL_ERROR_NULL_INPUT );
1269  for (i = 0; !found && i < plist_size; i++)
1270  {
1271  const cpl_property *p = uves_propertylist_get_const(plist, i);
1272  value = cpl_property_get_name(p);
1273 
1274  if (strcmp(value, "HISTORY") == 0)
1275  {
1276 
1277  check( value = cpl_property_get_string(p),
1278  "Error reading property value");
1279 
1280  /* match the string "'<name>','t" */
1281 
1282  if ((int)strlen(value) >= 1+N+4 &&
1283  value[0] == '\'' &&
1284  value[N+1] == '\'' &&
1285  value[N+2] == ',' &&
1286  value[N+3] == '\'' &&
1287  strncmp(value+1, name, N) == 0
1288  )
1289  {
1290  switch(value[N+4]) {
1291  case 'R':
1292  /* Distinguish between
1293  "'<name>','R*4'" and
1294  "'<name>','R*8'"
1295  */
1296  *type = CPL_TYPE_DOUBLE;
1297 
1298  if ((int)strlen(value) >= 1+N+4+2 && value[N+4+1] == '*')
1299  {
1300  switch(value[N+4+2]) {
1301  case '4': *type = CPL_TYPE_FLOAT; break;
1302  case '8': *type = CPL_TYPE_DOUBLE; break;
1303  default:
1304  assure( false, CPL_ERROR_ILLEGAL_INPUT,
1305  "Unrecognized MIDAS type: 'R*%c'",
1306  value[N+4+2]);
1307  break;
1308  }
1309  }
1310  break;
1311  case 'I': *type = CPL_TYPE_INT ; size = sizeof(int); break;
1312  case 'C': *type = CPL_TYPE_STRING; size = sizeof(char); break;
1313  default:
1314  assure( false, CPL_ERROR_UNSUPPORTED_MODE,
1315  "Unrecognized type '%c'", value[N+4]);
1316  break;
1317  }
1318  found = true;
1319  }
1320  }
1321  }
1322 
1323  assure( found, CPL_ERROR_ILLEGAL_INPUT, "Could not find '%s' in property list", name);
1324 
1325  /* 'i' is now the row immediately after first occurence of 'HISTORY '<name>... */
1326  result_size = sizeof(double) * 100; /* realloc when/if out of memory */
1327  result = cpl_malloc(result_size);
1328 
1329  *length = 0;
1330  if (ncards != NULL) *ncards = 2; /* First HISTORY entry + termination HISTORY entry */
1331  do {
1332  const cpl_property *p;
1333 
1334  if (ncards != NULL) *ncards += 1;
1335 
1336  assure(i < plist_size,
1337  CPL_ERROR_ILLEGAL_INPUT, "Missing header data");
1338  p = uves_propertylist_get_const(plist, i);
1339  assure( cpl_property_get_type(p) == CPL_TYPE_STRING &&
1340  strcmp(cpl_property_get_name(p), "HISTORY") == 0,
1341  CPL_ERROR_ILLEGAL_INPUT, "Error parsing array");
1342  value = cpl_property_get_string(uves_propertylist_get_const(plist, i));
1343 
1344  uves_msg_debug("Parsing '%s'", value);
1345 
1346  if (*type == CPL_TYPE_STRING)
1347  {
1348  assure( strlen(value) < 100, CPL_ERROR_UNSUPPORTED_MODE,
1349  "String too long. Max size is 100");
1350 
1351  /* Remove any blanks from the string
1352  (e.g. convert "0 1 2" to "012")
1353  */
1354  {
1355  int len = strlen(value);
1356  int j = 0;
1357  int k;
1358  for (k = 0; k <= len; k++) /* including final '\0' */
1359  {
1360  //if (value[k] != ' '){
1361  ((char*)result)[j] = value[k];
1362  j++;
1363  // }
1364  }
1365  *length = j-1;
1366  }
1367 
1368  uves_msg_debug("Converted '%s' to '%s'",
1369  value, (char*)result);
1370 
1371  /* done parsing */
1372  value = "";
1373  }
1374 
1375  else { /* numerical types */
1376  if (strcmp(value, "") != 0) {
1377  double numberd = -1; /* suppres warning */
1378  int numberi = -1;
1379  float numberf = -1;
1380  const int base = 10;
1381  char *next = (char *) value;
1382 
1383  do {
1384  /* ignore OUTPUTI(1)- N,no.of data, */
1385  switch(*type) {
1386  case CPL_TYPE_DOUBLE:
1387  numberd = strtod(value, &next);
1388  uves_msg_debug("Got %g, remaining: '%s'", numberd, next);
1389  break;
1390  case CPL_TYPE_FLOAT:
1391  numberf = strtod(value, &next); // C99: strtof(value, &next);
1392  uves_msg_debug("Got %g, remaining: '%s'", numberf, next);
1393  break;
1394  case CPL_TYPE_INT:
1395  numberi = strtol(value, &next, base);
1396  uves_msg_debug("Got %d, remaining: '%s'", numberi, next);
1397  break;
1398  default:
1399  passure(false, " ");
1400  }
1401 
1402  if (next != value)
1403  {
1404  /* A prefix of the string could be converted */
1405  (*length)++;
1406  if (*length * sizeof(double) > result_size)
1407  {
1408  result_size *= 2;
1409  result = cpl_realloc(result, result_size);
1410  }
1411 
1412  switch(*type) {
1413  case CPL_TYPE_DOUBLE:
1414  ((double *)result)[*length-1] = numberd;
1415  break;
1416  case CPL_TYPE_FLOAT:
1417  ((float *)result)[*length-1] = numberf;
1418  break;
1419  case CPL_TYPE_INT:
1420  ((int *)result)[*length-1] = numberi;
1421  break;
1422  default:
1423  passure(false, " ");
1424  }
1425 
1426  value = next;
1427 
1428  switch(*type) {
1429  case CPL_TYPE_DOUBLE:
1430  numberd = strtod(value, &next);
1431  uves_msg_debug("Got %g, remaining: '%s'", numberd, next);
1432  break;
1433  case CPL_TYPE_FLOAT:
1434  numberf = strtod(value, &next); // C99: strtof(value, &next);
1435  uves_msg_debug("Got %g, remaining: '%s'", numberf, next);
1436  break;
1437  case CPL_TYPE_INT:
1438  numberi = strtol(value, &next, base);
1439  uves_msg_debug("Got %d, remaining: '%s'", numberi, next);
1440  break;
1441  default:
1442  passure(false, " ");
1443  }
1444  }
1445  } while (next != value);
1446  }
1447  }/* if numerical type */
1448 
1449  i++;
1450 
1451  assure( strcmp(value, "") == 0, CPL_ERROR_ILLEGAL_INPUT,
1452  "Cannot parse %s descriptor %s, remaining string: '%s'",
1453  uves_tostring_cpl_type(*type), name, value);
1454 
1455  /* Find out if we can continue parsing the next HISTORY keyword */
1456  if (i < plist_size)
1457  {
1458  p = uves_propertylist_get_const(plist, i);
1459  if (cpl_property_get_type(p) == CPL_TYPE_STRING &&
1460  strcmp(cpl_property_get_name(p), "HISTORY") == 0)
1461  {
1462  value = cpl_property_get_string(
1463  uves_propertylist_get_const(plist, i));
1464 
1465  if (*type == CPL_TYPE_STRING)
1466  {
1467  if (strcmp(value, "") != 0) {
1468  uves_msg_debug("String array %s with length > 1 found. Ignoring remaining values", name);
1469  while (strcmp(value, "") != 0 && i+1 < plist_size) {
1470  i++;
1471  p = uves_propertylist_get_const(plist, i);
1472  value = cpl_property_get_string(
1473  uves_propertylist_get_const(plist, i));
1474  if (ncards != NULL) *ncards += 1;
1475  }
1476  }
1477  }
1478  }
1479  }
1480 
1481  } while (strcmp(value, "") != 0);
1482 
1483  cleanup:
1484  if (cpl_error_get_code() != CPL_ERROR_NONE)
1485  {
1486  cpl_free(result); result = NULL;
1487  }
1488  return result;
1489 }
1490 
1491 
1492 /*----------------------------------------------------------------------------*/
1510 /*----------------------------------------------------------------------------*/
1511 cpl_error_code
1512 uves_save_table_local(const char *description, const char *filename_prefix,
1513  const cpl_table *table,
1514  enum uves_chip chip, int trace, int window,
1515  const uves_propertylist *pheader, const uves_propertylist *eheader)
1516 {
1517  char *filename = NULL;
1518 
1519  check( filename = uves_local_filename(filename_prefix, chip, trace, window),
1520  "Error getting filename");
1521 
1522  check( uves_table_save(table, pheader, eheader, filename, CPL_IO_DEFAULT),
1523  "Error saving table to file '%s'", filename);
1524 
1525  if (description != NULL) uves_msg("%s saved to '%s'", description, filename);
1526 
1527  cleanup:
1528  cpl_free(filename);
1529  return cpl_error_get_code();
1530 }
1531 
1532 /*----------------------------------------------------------------------------*/
1553 /*----------------------------------------------------------------------------*/
1554 cpl_error_code
1555 uves_save_image_local(const char *description, const char *filename_prefix,
1556  const cpl_image *image,
1557  enum uves_chip chip, int trace, int window,
1558  const uves_propertylist *plist,
1559  bool use_bitpix16_for_int)
1560 {
1561  char *filename = NULL;
1562 
1563  check( filename = uves_local_filename(filename_prefix, chip, trace, window),
1564  "Error getting filename");
1565 
1566  check( uves_save_image(image, filename, plist, use_bitpix16_for_int, true),
1567  "Error saving image to file '%s'", filename);
1568  if (description != NULL) uves_msg("%s saved to '%s'", description, filename);
1569 
1570  cleanup:
1571  cpl_free(filename);
1572  return cpl_error_get_code();
1573 }
1574 
1575 
1576 /*----------------------------------------------------------------------------*/
1586 /*----------------------------------------------------------------------------*/
1587 cpl_image *uves_load_image(const cpl_frame *f,
1588  int plane,
1589  int extension,
1590  uves_propertylist **header)
1591 {
1592  cpl_image *image = NULL;
1593  uves_propertylist *plist = NULL;
1594  const char *filename;
1595  int bitpix;
1596  cpl_type type;
1597  int naxis=0;
1598  cpl_vector * vector=NULL;
1599 
1600 
1601  assure_nomsg( f != NULL, CPL_ERROR_NULL_INPUT );
1602 
1603  assure( cpl_frame_get_type(f) == CPL_FRAME_TYPE_IMAGE,
1604  CPL_ERROR_TYPE_MISMATCH, "Wrong type: %s",
1605  uves_tostring_cpl_frame_type(cpl_frame_get_type(f)));
1606 
1607  filename = cpl_frame_get_filename(f);
1608 
1609  check( plist = uves_propertylist_load(filename, extension),
1610  "Could not load header from %s extension %d",
1611  filename, extension);
1612 
1613  check( bitpix = uves_pfits_get_bitpix(plist),
1614  "Could not read BITPIX from %s extension %d",
1615  filename, extension);
1616 
1617  if (bitpix == -32) type = CPL_TYPE_FLOAT;
1618  else if (bitpix == -64) type = CPL_TYPE_DOUBLE;
1619  else if (bitpix == 32) type = CPL_TYPE_INT;
1620  else if (bitpix == 16) type = CPL_TYPE_INT;
1621  else
1622  {
1623  assure( false, CPL_ERROR_UNSUPPORTED_MODE,
1624  "No CPL type to represent BITPIX = %d", bitpix);
1625  }
1626 
1627  check( naxis = uves_pfits_get_naxis(plist),
1628  "could not get NAXIS" );
1629 
1630  if( naxis == 1) {
1631 
1632  check( vector = cpl_vector_load(filename,extension),
1633  "Could not load vector from extension %d of file '%s' ",
1634  extension, filename);
1635  cknull(image=uves_vector_to_image(vector,type),
1636  "could not convert vector to image");
1637  } else {
1638 
1639 
1640  check( image = cpl_image_load(filename,
1641  type,
1642  plane,
1643  extension),
1644  "Could not load image from extension %d of file '%s' ",
1645  extension, filename);
1646 
1647  }
1648 
1649  if (header != NULL)
1650  {
1651  *header = uves_propertylist_duplicate(plist);
1652  }
1653 
1654  cleanup:
1655  uves_free_vector(&vector);
1656  uves_free_propertylist(&plist);
1657  return image;
1658 }
1659 /*----------------------------------------------------------------------------*/
1663 /*----------------------------------------------------------------------------*/
1664 
1665 cpl_image *uves_load_image_file(const char *filename,
1666  int plane,
1667  int extension,
1668  uves_propertylist **header)
1669 {
1670  cpl_image *i;
1671  cpl_frame *f = cpl_frame_new();
1672  cpl_frame_set_filename(f, filename);
1673  cpl_frame_set_type(f, CPL_FRAME_TYPE_IMAGE);
1674 
1675  i = uves_load_image(f, plane, extension, header);
1676 
1677  uves_free_frame(&f);
1678 
1679  return i;
1680 }
1681 
1682 /*----------------------------------------------------------------------------*/
1707 /*----------------------------------------------------------------------------*/
1708 void
1709 uves_save_image(const cpl_image *image, const char *filename, const uves_propertylist *plist,
1710  bool use_bitpix16_for_int, bool save1d)
1711 {
1712  cpl_type_bpp bpp;
1713  cpl_type t;
1714  const cpl_vector *image_1d = NULL;
1715  uves_propertylist *header = NULL;
1716  cpl_image *thresholded = NULL;
1717  cpl_image *thresholded_double = NULL;
1718 
1719  if (image == NULL) {
1720  check( uves_image_save(image, filename, CPL_BPP_IEEE_FLOAT, plist, CPL_IO_DEFAULT),
1721  "Error saving NULL image to file '%s'", filename);
1722  }
1723  else {
1724  check( t = cpl_image_get_type(image), "Error reading image type");
1725  if (t == CPL_TYPE_FLOAT ) bpp = CPL_BPP_IEEE_FLOAT;
1726  else if (t == CPL_TYPE_DOUBLE) bpp = CPL_BPP_IEEE_FLOAT;
1727  /* Internal computations in double precision,
1728  save as single precision */
1729 
1730  /* Some FLAMES images are BITPIX=16 (ORDEF),
1731  some are 32 SLIT_FF_COM_REDL
1732  */
1733  else if (t == CPL_TYPE_INT ) {
1734  if (use_bitpix16_for_int) bpp = CPL_BPP_16_UNSIGNED;
1735  else bpp = CPL_BPP_32_SIGNED;
1736  }
1737  else assure(false, CPL_ERROR_UNSUPPORTED_MODE,
1738  "Unsupported image type '%s'", uves_tostring_cpl_type(t));
1739 
1740 
1741  thresholded = cpl_image_duplicate(image);
1742  assure_mem( thresholded );
1743 
1744  if (t == CPL_TYPE_DOUBLE)
1745  {
1746  passure( bpp == CPL_BPP_IEEE_FLOAT, "%d", bpp);
1747 
1748  /* Avoid infinities that would happen when casting
1749  double -> float
1750  by thresholding the image to +-FLT_MAX (or, better
1751  a little less than FLT_MAX just to be sure).
1752 
1753  (This is not a really nice solution because it solves the
1754  problem (too large/small values) after it is introduced
1755  (rather than avoiding it), but a general solution of the
1756  problem would probably mean guarding every arithmetic
1757  operation with range checks.)
1758  */
1759 
1760  check_nomsg( cpl_image_threshold(thresholded,
1761  -FLT_MAX, FLT_MAX,
1762  -FLT_MAX, FLT_MAX) );
1763 
1764  /* Also get rid of NaN, set to zero (what else?) */
1765  {
1766  double *data = cpl_image_get_data_double(thresholded);
1767  int nx = cpl_image_get_size_x(thresholded);
1768  int ny = cpl_image_get_size_y(thresholded);
1769  int x, y;
1770 
1771  for (y = 0; y < ny; y++)
1772  for (x = 0; x < nx; x++)
1773  {
1774  if (irplib_isnan(data[x + y*nx]))
1775  {
1776  data[x + y*nx] = 0;
1777  }
1778  }
1779  }
1780  }
1781 
1782  if (save1d &&
1783  cpl_image_get_size_y(thresholded) == 1 &&
1784  (t == CPL_TYPE_DOUBLE ||
1785  t == CPL_TYPE_FLOAT)) {
1786 
1787  bool invert = false;
1788  if (plist != NULL)
1789  {
1790  header = uves_propertylist_duplicate(plist);
1791 
1792  uves_propertylist_erase_regexp(header, "^CDELT2$", invert);
1793  uves_propertylist_erase_regexp(header, "^CRPIX2$", invert);
1794  uves_propertylist_erase_regexp(header, "^CRVAL2$", invert);
1795  uves_propertylist_erase_regexp(header, "^CTYPE2$", invert);
1796  if(uves_propertylist_has(plist,"CDELT1")) {
1797  double cdelt1=uves_pfits_get_cdelt1(header);
1798  uves_pfits_set_cd11(header,cdelt1);
1799  }
1800  }
1801  else
1802  {
1803  header = NULL;
1804  }
1805 
1806  /* Image type must be double, before wrapping it
1807  in a vector */
1808  if (t == CPL_TYPE_FLOAT) {
1809  thresholded_double = cpl_image_cast(thresholded, CPL_TYPE_DOUBLE);
1810  }
1811  else {
1812  thresholded_double = cpl_image_duplicate(thresholded);
1813  }
1814 
1815  passure( cpl_image_get_type(thresholded_double) == CPL_TYPE_DOUBLE, "%d",
1816  cpl_image_get_type(thresholded_double));
1817 
1818  image_1d = cpl_vector_wrap(
1819  cpl_image_get_size_x(thresholded_double),
1820  cpl_image_get_data_double(thresholded_double));
1821 
1822  check( uves_vector_save(image_1d, filename, bpp, header, CPL_IO_DEFAULT),
1823  "Error saving vector to file '%s'", filename );
1824  }
1825  else
1826  {
1827 
1828  if (plist != NULL) {
1829  if(uves_propertylist_has(plist,"CDELT1")) {
1830  double cdelt1=uves_pfits_get_cdelt1(plist);
1831  uves_pfits_set_cd11(plist,cdelt1);
1832  uves_pfits_set_cd12(plist,0);
1833  }
1834  if(uves_propertylist_has(plist,"CDELT2")) {
1835  double cdelt2=uves_pfits_get_cdelt2(plist);
1836  uves_pfits_set_cd21(plist,0);
1837  uves_pfits_set_cd22(plist,cdelt2);
1838  }
1839  }
1840 
1841 
1842  check( uves_image_save(thresholded, filename, bpp, plist, CPL_IO_DEFAULT),
1843  "Error saving image to file '%s'", filename);
1844  }
1845  }
1846 
1847  cleanup:
1848  uves_unwrap_vector_const(&image_1d);
1849  uves_free_propertylist(&header);
1850  uves_free_image(&thresholded);
1851  uves_free_image(&thresholded_double);
1852 
1853  return;
1854 }
1855 
1856 
1857 /*----------------------------------------------------------------------------*/
1877 /*----------------------------------------------------------------------------*/
1878 void
1879 uves_save_imagelist(const cpl_imagelist *iml, const char *filename, const uves_propertylist *plist)
1880 {
1881  const cpl_image* img=NULL;
1882  cpl_type_bpp bpp;
1883  cpl_type t;
1884  const cpl_vector *image_1d = NULL;
1885  uves_propertylist *header = NULL;
1886  cpl_imagelist *thresholded = NULL;
1887 
1888  int nx = 0;
1889  int ny = 0;
1890  int nz = 0;
1891 
1892 
1893  cknull(iml,"Null input image");
1894  check(img=cpl_imagelist_get_const(iml,0),"error reading image");
1895 
1896  check_nomsg( nx = cpl_image_get_size_x(img));
1897  check_nomsg( ny = cpl_image_get_size_y(img));
1898  check_nomsg( nz = cpl_imagelist_get_size(iml));
1899 
1900  check( t = cpl_image_get_type(img), "Error reading image type");
1901  if (t == CPL_TYPE_FLOAT ) bpp = CPL_BPP_IEEE_FLOAT;
1902  else if (t == CPL_TYPE_DOUBLE) bpp = CPL_BPP_IEEE_FLOAT;
1903  /* Internal computations in double precision,
1904  save as single precision */
1905  else if (t == CPL_TYPE_INT ) bpp = CPL_BPP_16_UNSIGNED;
1906  else assure(false, CPL_ERROR_UNSUPPORTED_MODE,
1907  "Unsupported image type '%s'", uves_tostring_cpl_type(t));
1908 
1909 
1910  thresholded = cpl_imagelist_duplicate(iml);
1911  assure_mem( thresholded );
1912 
1913  if (t == CPL_TYPE_DOUBLE)
1914  {
1915  passure( bpp == CPL_BPP_IEEE_FLOAT, "%d", bpp);
1916 
1917  /* Avoid infinities that would happen when casting
1918  double -> float
1919  by thresholding the image to +-FLT_MAX (or, better
1920  a little less than FLT_MAX just to be sure).
1921 
1922  (This is not a really nice solution because it solves the
1923  problem (too large/small values) after it is introduced
1924  (rather than avoiding it), but a general solution of the
1925  problem would probably mean guarding every arithmetic
1926  operation with range checks.)
1927  */
1928 
1929  check_nomsg( cpl_imagelist_threshold(thresholded,
1930  -FLT_MAX, FLT_MAX,
1931  -FLT_MAX, FLT_MAX) );
1932 
1933 
1934 
1935  /* Also get rid of NaN, set to zero (what else?) */
1936  {
1937  int x, y, z;
1938 
1939 
1940  for (z = 0; z < nz; z++) {
1941  cpl_image* ima=cpl_imagelist_get(thresholded,z);
1942  double* data = cpl_image_get_data_double(ima);
1943 
1944  for (y = 0; y < ny; y++) {
1945  for (x = 0; x < nx; x++) {
1946  if (irplib_isnan(data[x + y*nx])) {
1947  data[x + y*nx] = 0;
1948  }
1949  }
1950  }
1951  }
1952  }
1953  }
1954  if (nz == 1 && t == CPL_TYPE_DOUBLE)
1955  /* To support other types (float, int) we would
1956  need to convert to double first */
1957  {
1958 
1959  if (plist != NULL)
1960  {
1961  header = uves_propertylist_duplicate(plist);
1962  bool invert = false;
1963  uves_propertylist_erase_regexp(header, "^CDELT3$", invert);
1964  uves_propertylist_erase_regexp(header, "^CRPIX3$", invert);
1965  uves_propertylist_erase_regexp(header, "^CRVAL3$", invert);
1966  uves_propertylist_erase_regexp(header, "^CTYPE3$", invert);
1967  }
1968  else
1969  {
1970  header = NULL;
1971  }
1972  /*
1973  image_1d = cpl_vector_wrap(nx,
1974  cpl_image_get_data_double_const(thresholded));
1975 
1976  check( uves_vector_save(image_1d, filename, bpp, header, CPL_IO_DEFAULT),
1977  "Error saving vector to file '%s'", filename );
1978  */
1979 
1980  }
1981  else
1982  {
1983  check( uves_imagelist_save(thresholded, filename, bpp, plist, CPL_IO_DEFAULT),
1984  "Error saving image to file '%s'", filename);
1985  }
1986 
1987  cleanup:
1988  uves_unwrap_vector_const(&image_1d);
1989  uves_free_propertylist(&header);
1990  uves_free_imagelist(&thresholded);
1991 
1992  return;
1993 }
1994 
1995 /*----------------------------------------------------------------------------*/
2009 /*----------------------------------------------------------------------------*/
2010 cpl_error_code
2011 uves_save_polynomial(polynomial *p, const char *filename, const uves_propertylist *header)
2012 {
2013  cpl_table *t = NULL;
2014 
2015  check( t = uves_polynomial_convert_to_table(p), "Error converting polynomial to table");
2016 
2017  check( uves_table_save(t,
2018  NULL, /* Primary header, ignored when
2019  mode = CPL_IO_EXTEND */
2020  header, /* Table header */
2021  filename,
2022  CPL_IO_EXTEND), /* Append to existing file */
2023  "Error saving table to file '%s'", filename);
2024 
2025  cleanup:
2026  uves_free_table(&t);
2027  return cpl_error_get_code();
2028 }
2029 
2030 
2031 /*----------------------------------------------------------------------------*/
2039 /*----------------------------------------------------------------------------*/
2040 static polynomial *
2041 load_polynomial(const char* filename, int extension)
2042 {
2043  polynomial *p = NULL; /* Result */
2044  cpl_table *t = NULL;
2045 
2046  check(t = cpl_table_load(filename,
2047  extension,
2048  1), /* Mark identified
2049  invalid null values (1=yes) */
2050  "Error loading polynomial from extension %d of file '%s'", extension, filename);
2051 
2052  assure( uves_erase_invalid_table_rows(t, NULL) == 0,
2053  CPL_ERROR_ILLEGAL_INPUT, "Table contains invalid rows");
2054 
2055  check(p = uves_polynomial_convert_from_table(t), "Error converting table to polynomial");
2056 
2057  cleanup:
2058  uves_free_table(&t);
2059  if (cpl_error_get_code() != CPL_ERROR_NONE)
2061  return p;
2062 }
2063 /*----------------------------------------------------------------------------*/
2078 /*----------------------------------------------------------------------------*/
2079 static const char *
2080 identify_arm(const cpl_frameset *frames, const char *blue_tag, const char *red_tag,
2081  bool *blue)
2082 {
2083  const char *tag = NULL; /* Result */
2084 
2085  const cpl_frame *frame = NULL;
2086 
2087  passure( frames != NULL, "");
2088  assure (!cpl_frameset_is_empty(frames), CPL_ERROR_ILLEGAL_INPUT, "No input frames");
2089 
2090  /* Identify blue/red arm */
2091  frame = cpl_frameset_find_const(frames, blue_tag);
2092  *blue = (frame != NULL);
2093 
2094  if (frame == NULL)
2095  {
2096  frame = cpl_frameset_find_const(frames, red_tag);
2097  }
2098 
2099  assure( frame != NULL, CPL_ERROR_ILLEGAL_INPUT,
2100  "No valid input frames "
2101  "('%s' or '%s') in frame set",
2102  blue_tag, red_tag);
2103 
2104  assure( cpl_frameset_find_const(frames, blue_tag) == NULL ||
2105  cpl_frameset_find_const(frames, red_tag) == NULL,
2106  CPL_ERROR_INCOMPATIBLE_INPUT,
2107  "Multiple types of input frames ('%s' and '%s') in frame set",
2108  blue_tag, red_tag);
2109 
2110  tag = cpl_frame_get_tag(frame);
2111 
2112  uves_msg("Input frames are '%s'", tag);
2113 
2114 
2115  cleanup:
2116  return tag;
2117 }
2118 
2119 /*----------------------------------------------------------------------------*/
2137 /*----------------------------------------------------------------------------*/
2138 cpl_image *
2139 uves_crop_and_rotate(const cpl_image *image, const uves_propertylist *header,
2140  enum uves_chip chip,
2141  const uves_propertylist *redl_header,
2142  bool new_format, uves_propertylist **out_header)
2143 {
2144  cpl_image *result = NULL;
2145  int prescanx, ovrscanx;
2146  cpl_size nx, ny;
2147  int x_0, y_0, x_1, y_1; /* Extracted area (inclusive) in
2148  FITS convention (i.e. counting from 1) */
2149 
2150  const char *ctype1, *ctype2; /* Geometry */
2151  const char *cunit1, *cunit2; /* Units */
2152  const char *bunit;
2153  double bscale=0;
2154  double crval1, crval2;
2155  double crpix1, crpix2;
2156  double cdelt1, cdelt2;
2157 
2158 
2159  passure( image != NULL, " ");
2160  passure( header != NULL, " ");
2161  passure( out_header != NULL, " ");
2162 
2163  nx = cpl_image_get_size_x(image);
2164  ny = cpl_image_get_size_y(image);
2165 
2166 
2167  /* Determine pre- and overscan areas */
2168  check( prescanx = uves_pfits_get_prescanx(header, chip), "Could not read x-prescan info" );
2169  check( ovrscanx = uves_pfits_get_ovrscanx(header, chip), "Could not read x-overscan info");
2170 
2171  /* Don't try to read the y pre- and overscan regions, which should be zero for UVES.
2172  The keywords are not present in older UVES data. */
2173 
2174  /* Read geometry */
2175  check( ctype1 = uves_pfits_get_ctype1(header), "Error reading keyword");
2176  check( ctype2 = uves_pfits_get_ctype2(header), "Error reading keyword");
2177  check( crval1 = uves_pfits_get_crval1(header), "Error reading keyword");
2178  check( crval2 = uves_pfits_get_crval2(header), "Error reading keyword");
2179  check( crpix1 = uves_pfits_get_crpix1(header), "Error reading keyword");
2180  check( crpix2 = uves_pfits_get_crpix2(header), "Error reading keyword");
2181  check( cdelt1 = uves_pfits_get_cdelt1(header), "Error reading keyword");
2182  check( cdelt2 = uves_pfits_get_cdelt2(header), "Error reading keyword");
2183  if (uves_propertylist_contains(header, UVES_BUNIT))
2184  {
2185  bunit = uves_pfits_get_bunit(header);
2186  }
2187  else
2188  {
2189  bunit = " ";
2190  }
2191  if (uves_propertylist_contains(header, UVES_BSCALE))
2192  {
2193  bscale = uves_pfits_get_bscale(header);
2194  }
2195  else
2196  {
2197  bscale = 0;
2198  }
2199 
2200  if (uves_propertylist_contains(header, UVES_CUNIT1))
2201  {
2202  cunit1 = uves_pfits_get_cunit1(header);
2203  }
2204  else
2205  {
2206  cunit1 = " ";
2207  }
2208  if (uves_propertylist_contains(header, UVES_CUNIT2))
2209  {
2210  cunit2 = uves_pfits_get_cunit2(header);
2211  }
2212  else
2213  {
2214  cunit2 = " ";
2215  }
2216 
2217 
2218  /* Crop the image */
2219  {
2220  y_0 = 1;
2221  y_1 = ny;
2222  if (new_format || chip == UVES_CHIP_BLUE)
2223  {
2224  x_0 = prescanx + 1;
2225  x_1 = nx - ovrscanx;
2226  }
2227  else /* red, old format */
2228  {
2229  if (chip == UVES_CHIP_REDU)
2230  {
2231  x_0 = prescanx + 1;
2232  x_1 = nx/2 - ovrscanx;
2233  }
2234  else
2235  { /* lower */
2236  x_0 = nx/2 + prescanx + 1;
2237  x_1 = nx - ovrscanx;
2238  }
2239  }
2240  check( result = cpl_image_extract(image, x_0, y_0, x_1, y_1), "Could not crop image");
2241  crpix1 = crpix1 - (x_0 - 1);
2242  crpix2 = crpix2 - (y_0 - 1);
2243  nx = (x_1 - x_0) + 1;
2244  ny = (y_1 - y_0) + 1;
2245  }
2246 
2247  UVES_TIME_START("Rotation");
2248  /* ... is a bit slow, and there's probably nothing to
2249  do about as it involves moving data between remote
2250  places in memory.
2251  */
2252 
2253  /* Rotate the image into standard orientation */
2254  {
2255  int crpix1_old = crpix1;
2256  int crpix2_old = crpix2;
2257  int crval1_old = crval1;
2258  int crval2_old = crval2;
2259  int cdelt1_old = cdelt1;
2260  int cdelt2_old = cdelt2;
2261  const char *ctype1_old = ctype1;
2262  const char *ctype2_old = ctype2;
2263 
2264  if (chip == UVES_CHIP_BLUE)
2265  {
2266  /* 90 deg counterclockwise rotation */
2267  check( cpl_image_turn(result, -1), "Could not turn image");
2268 
2269  crpix1 = ny - (crpix2_old - 1); /* Note: old value of ny */
2270  crpix2 = crpix1_old;
2271  crval1 = crval2_old;
2272  crval2 = crval1_old;
2273  }
2274  else
2275  {
2276  /* Red */
2277  /* Flip image around y=-x */
2278  check( cpl_image_flip(result, 3), "Could not flip image");
2279 
2280  crpix1 = ny - (crpix2_old - 1); /* Note: old value of nx, ny */
2281  crpix2 = nx - (crpix1_old - 1);
2282  crval1 = crval2_old;
2283  crval2 = crval1_old;
2284  }
2285 
2286 
2287  /* Always swap these ones */
2288  ctype1 = ctype2_old;
2289  ctype2 = ctype1_old;
2290  cdelt1 = cdelt2_old;
2291  cdelt2 = cdelt1_old;
2292  }
2293 
2294  UVES_TIME_END;
2295 
2296  /* Here we should use the CROTAi keywords to
2297  properly describe the new rotation */
2298 
2299  /* Instead, redefine CRVAL as in the following, on request from DFO */
2300 
2301  crpix1 = 1;
2302  crpix2 = 1;
2303  if (chip == UVES_CHIP_BLUE || chip == UVES_CHIP_REDL)
2304  {
2305  crval1 = 1;
2306  crval2 = 1;
2307  }
2308  else
2309  {
2310  int physical_gap_between_chips = 64; /* Pixels. Unbinned. Hardcoded. */
2311 
2312 
2313  passure( chip == UVES_CHIP_REDU , "%d", chip );
2314 
2315  crval1 = 1;
2316 
2317  /* Set CRVAL2 = REDL_height - REDL_overscan - REDL_prescan + gap. */
2318  if (new_format)
2319  {
2320 
2321  check( crval2 = 1 +
2322  (uves_pfits_get_naxis1(redl_header) -
2323  uves_pfits_get_ovrscanx(redl_header, UVES_CHIP_REDL) -
2324  uves_pfits_get_prescanx(redl_header, UVES_CHIP_REDL)) *
2325  uves_pfits_get_cdelt1(redl_header) +
2326  physical_gap_between_chips,
2327  "Error reading REDL chip geometry");
2328 
2329  uves_msg_debug("Setting CRVAL2 = 1 + (%d - %d - %d) * %f + %d = %f",
2330  uves_pfits_get_naxis1(redl_header),
2331  uves_pfits_get_ovrscanx(redl_header, UVES_CHIP_REDL),
2332  uves_pfits_get_prescanx(redl_header, UVES_CHIP_REDL),
2333  uves_pfits_get_cdelt1(redl_header),
2334  physical_gap_between_chips, crval2);
2335  }
2336  else
2337  {
2338 
2339  /* old format */
2340  check( crval2 = 1 +
2341  (uves_pfits_get_naxis1(header)/2 -
2342  uves_pfits_get_ovrscanx(redl_header, UVES_CHIP_REDL) -
2343  uves_pfits_get_prescanx(redl_header, UVES_CHIP_REDL)) *
2344  uves_pfits_get_cdelt1(redl_header) +
2345  physical_gap_between_chips,
2346  "Error reading REDL chip geometry");
2347 
2348  uves_msg_debug("Setting CRVAL2 = 1 + (%d - %d - %d) * %f + %d = %f",
2349  uves_pfits_get_naxis1(header)/2,
2350  uves_pfits_get_ovrscanx(redl_header, UVES_CHIP_REDL),
2351  uves_pfits_get_prescanx(redl_header, UVES_CHIP_REDL),
2352  uves_pfits_get_cdelt1(redl_header),
2353  physical_gap_between_chips, crval2);
2354  }
2355 
2356  }
2357 
2358 
2359  /* Update header with new geometry */
2360  check( *out_header = uves_initialize_image_header(ctype1, ctype2,
2361  cunit1, cunit2,
2362  bunit,bscale,
2363  crval1, crval2,
2364  crpix1, crpix2,
2365  cdelt1, cdelt2),
2366  "Error initializing header");
2367 
2368  //check(uves_propertylist_copy_property_regexp(*out_header, header,
2369  // "^ESO ", 0),
2370  // "Error copying hieararch keys");
2371 
2372 
2373  uves_msg("Raw image cropped and rotated from %" CPL_SIZE_FORMAT "x%" CPL_SIZE_FORMAT " to %" CPL_SIZE_FORMAT "x%" CPL_SIZE_FORMAT "",
2374  nx, ny,
2375  cpl_image_get_size_x(result),
2376  cpl_image_get_size_y(result));
2377 
2378  cleanup:
2379  if (cpl_error_get_code() != CPL_ERROR_NONE)
2380  {
2381  uves_free_image(&result);
2382  if (out_header != NULL)
2383  {
2384  uves_free_propertylist(out_header);
2385  }
2386  }
2387 
2388  return result;
2389 }
2390 
2391 /*----------------------------------------------------------------------------*/
2405 /*----------------------------------------------------------------------------*/
2406 void
2407 uves_warn_if_chip_names_dont_match(const uves_propertylist *calib_header,
2408  const char *raw_chip_name, enum uves_chip chip)
2409 {
2410  const char *calib_chip_name;
2411  bool mismatch = false;
2412 
2413  check( calib_chip_name = uves_pfits_get_chipid(calib_header, chip),
2414  "Could not read chip name of calibration data");
2415 
2416 
2417  /* Ignore leading/trailing blanks when comparing name strings.
2418  * (The following is O(n^2) where n is the string length,
2419  * but that's ok because the strings stored in a FITS card are short).
2420  */
2421  {
2422  unsigned int calib_first, calib_last; /* inclusive */
2423  unsigned int raw_first, raw_last;
2424 
2425  calib_first = 0;
2426  raw_first = 0;
2427  while (calib_first < strlen(calib_chip_name) - 1 && calib_chip_name[calib_first] == ' ' )
2428  {
2429  calib_first++;
2430  }
2431  while (raw_first < strlen(raw_chip_name) - 1 && raw_chip_name[raw_first] == ' ' )
2432  {
2433  raw_first++;
2434  }
2435 
2436  calib_last = strlen(calib_chip_name) - 1;
2437  raw_last = strlen(raw_chip_name) - 1;
2438  while (calib_chip_name[calib_last] == ' ' && calib_last > 0)
2439  {
2440  calib_last--;
2441  }
2442  while (raw_chip_name[raw_last] == ' ' && raw_last > 0)
2443  {
2444  raw_last--;
2445  }
2446 
2447  /* Compare substrings */
2448  if (calib_last - calib_first != raw_last - raw_first)
2449  {
2450  mismatch = true;
2451  }
2452  else
2453  {
2454  unsigned int i;
2455 
2456  for (i = 0; i <= (calib_last - calib_first); i++)
2457  {
2458  if (raw_chip_name[raw_first + i] !=
2459  calib_chip_name[calib_first + i])
2460  {
2461  mismatch = true;
2462  }
2463  }
2464  }
2465  }
2466 
2467 
2468  if (mismatch)
2469  {
2470  uves_msg_warning("Calibration frame chip ID '%s' does "
2471  "not match raw frame chip ID '%s'",
2472  calib_chip_name, raw_chip_name);
2473  }
2474 
2475  cleanup:
2476  return;
2477 }
2478 
2479 
2480 /*----------------------------------------------------------------------------*/
2502 /*----------------------------------------------------------------------------*/
2503 
2504 static cpl_error_code
2505 load_raw_image(const char *filename,
2506  cpl_type type,
2507  bool flames,
2508  bool blue,
2509  cpl_image *raw_image[2],
2510  uves_propertylist *raw_header[2],
2511  uves_propertylist *rotated_header[2])
2512 {
2513 
2514 
2515  cpl_image *image = NULL;
2516  uves_propertylist *primary_header = NULL;
2517  uves_propertylist *ext_header = NULL;
2518  int extension, nextensions;
2519  bool new_format;
2520  int plane = 0; /* Only one plane in FLAMES/UVES raw files */
2521 
2522  cpl_image* image1=NULL;
2523  cpl_image* image2=NULL;
2524  int sx=0;
2525  int sy=0;
2526 
2527 
2528  /* Initialize parameters */
2529  raw_image[0] = NULL;
2530  raw_image[1] = NULL;
2531  raw_header[0] = NULL;
2532  raw_header[1] = NULL;
2533  rotated_header[0] = NULL;
2534  rotated_header[1] = NULL;
2535 
2536  check( nextensions = uves_get_nextensions(filename),
2537  "Error reading number of extensions of file '%s'", filename);
2538 
2539  /* Find out if new/old format */
2540  extension = 0;
2541  check( primary_header = uves_propertylist_load(filename,
2542  extension),
2543  "Could not load header from extension %d of file '%s'",
2544  extension, filename);
2545 
2546  check( new_format = uves_format_is_new(primary_header),
2547  "Error determining new/old format of file %s", filename);
2548 
2549  uves_msg_low("Raw frame is %s, %s format, file '%s' has %d extensions",
2550  (blue) ? "blue" : "red", (new_format) ? "new" : "old",
2551  filename, nextensions);
2552 
2553  /* If the raw frame is blue, or if it's an old format red frame */
2554  if (blue || !new_format)
2555  {
2556  enum uves_chip chip;
2557 
2558  uves_msg_debug("Frame is blue or old format");
2559 
2560  assure( nextensions == 0 ||
2561  (blue && nextensions == 2) ||
2562  (flames && nextensions == 2),
2563  CPL_ERROR_ILLEGAL_INPUT,
2564  "Unrecognized format of file '%s'. %d extensions expected. %d found.",
2565  filename,
2566  ((flames||blue) && (nextensions ==2)) ? 2 : 0, nextensions);
2567 
2568  /* FLAMES: the 2 extensions contain OzPoz table and FLAMES FIBRE table */
2569 
2570  /* Load the header */
2571  check( raw_header[0] = uves_propertylist_load(filename,
2572  extension),
2573  "Could not load header from extension %d of file '%s'",
2574  extension, filename);
2575 
2576 
2577  extension = 0;
2578  if(blue && nextensions == 2) {
2579  extension = 1;
2580  check( raw_header[1] = uves_propertylist_load(filename,
2581  extension),
2582  "Could not load header from extension %d of file '%s'",
2583  extension, filename);
2584  check( uves_propertylist_append(raw_header[0],raw_header[1]),
2585  "Could not collate header from extension 1 to 0 of file '%s'",filename);
2586  uves_free_propertylist(&raw_header[1]);
2587 
2588  check( image1 = cpl_image_load(filename,
2589  type,
2590  plane,
2591  extension
2592  ), "Could not load image from extension %d of file '%s' ",
2593  extension, filename);
2594  cpl_image_save(image1, "ima1.fits", CPL_BPP_IEEE_FLOAT,
2595  NULL,CPL_IO_DEFAULT);
2596 
2597  extension = 2;
2598  check( image2 = cpl_image_load(filename,
2599  type,
2600  plane,
2601  extension
2602  ), "Could not load image from extension %d of file '%s' ",
2603  extension, filename);
2604  check_nomsg(sx=cpl_image_get_size_x(image1));
2605  check_nomsg(sy=cpl_image_get_size_y(image1));
2606 
2607  check_nomsg(image=cpl_image_new(2*sx,sy,type));
2608  check_nomsg(cpl_image_copy(image,image1,1,1));
2609  check_nomsg(cpl_image_copy(image,image2,1+sx,1));
2610 
2611 
2612  uves_free_image(&image1);
2613  uves_free_image(&image2);
2614 
2615  extension = 1;
2616 
2617 
2618 
2619  } else {
2620 
2621 
2622  check( image = cpl_image_load(filename,
2623  type,
2624  plane,
2625  extension
2626  ), "Could not load image from extension %d of file '%s' ",
2627  extension, filename);
2628  }
2629 
2630  /* Get blue (or lower red) chip */
2631  chip = (blue) ? UVES_CHIP_BLUE : UVES_CHIP_REDL;
2632  check( raw_image[0] = uves_crop_and_rotate(image, raw_header[0],
2633  chip, raw_header[0],
2634  new_format,
2635  &rotated_header[0]),
2636  "Error splitting image");
2637 
2638  if (!blue)
2639  {
2640  const uves_propertylist *redl_header;
2641 
2642  /* Upper red chip, use again the primary header */
2643  check( raw_header[1] = uves_propertylist_duplicate(raw_header[0]),
2644  "Error duplicating FITS header");
2645 
2646  /* Get upper red chip */
2647  chip = UVES_CHIP_REDU;
2648  redl_header = raw_header[0];
2649  check( raw_image[1] = uves_crop_and_rotate(image, raw_header[1],
2650  chip, redl_header,
2651  new_format,
2652  &rotated_header[1]),
2653  "Error splitting red image");
2654  }
2655  else
2656  {
2657  raw_image[1] = NULL;
2658  raw_header[1] = NULL;
2659  rotated_header[1] = NULL;
2660  }
2661  }
2662  else
2663  /* New red format. UVES must have 2 extensions,
2664  * FLAMES must have 2 or more extensions
2665  */
2666  {
2667  uves_msg_debug("Frame is red, new format");
2668 
2669  assure( nextensions >= 2, CPL_ERROR_UNSUPPORTED_MODE,
2670  "File '%s' (red frame) has %d extensions. 2+ extensions expected "
2671  "for new format",
2672  filename, nextensions);
2673 
2674  uves_msg_debug("New red format, %s frame",
2675  (nextensions > 2) ? "FLAMES" : "FLAMES/UVES");
2676 
2677 
2678  /* Images always in extension 1 and 2. First load just the headers */
2679  for (extension = 1; extension <= 2; extension++)
2680  {
2681  /* In the FITS file, REDU is stored
2682  in extension 1, and REDL is stored in
2683  extension 2 */
2684  enum uves_chip chip = (extension == 1) ? UVES_CHIP_REDU : UVES_CHIP_REDL;
2685  int indx = uves_chip_get_index(chip);
2686 
2687  /* Load the extension header */
2688  uves_free_propertylist(&ext_header);
2689  check( ext_header = uves_propertylist_load(filename,
2690  extension),
2691  "Could not load header from extension %d of file '%s'",
2692  extension, filename);
2693 
2694  /* Merge with primary header */
2695  check( raw_header[indx] = uves_propertylist_duplicate(primary_header),
2696  "Error cloning primary header");
2697 
2698  if (!uves_propertylist_is_empty(ext_header))
2699  {
2700  if(cpl_propertylist_has(ext_header,"TM-START") &&
2701  cpl_propertylist_has(primary_header,"TM-START") ) {
2702  uves_propertylist_erase(ext_header,"TM-START");
2703  }
2704  if(cpl_propertylist_has(ext_header,"DATE-OBS") &&
2705  cpl_propertylist_has(primary_header,"DATE-OBS") ) {
2706  uves_propertylist_erase(ext_header,"DATE-OBS");
2707  }
2708  if(cpl_propertylist_has(ext_header,"EXPTIME") &&
2709  cpl_propertylist_has(ext_header,"EXPTIME")) {
2710  uves_propertylist_erase(ext_header,"EXPTIME");
2711  }
2713  ext_header, ".*", 0),
2714  "Error merging primary header with extension %d header",
2715  extension);
2716  }
2717  }
2718 
2719 
2720  /* Remove pre-, overscan areas (we needed to load both image headers for this) */
2721  for (extension = 1; extension <= 2; extension++)
2722  {
2723  enum uves_chip chip = (extension == 1) ? UVES_CHIP_REDU : UVES_CHIP_REDL;
2724  int indx = uves_chip_get_index(chip);
2725  int indx_redl = uves_chip_get_index(UVES_CHIP_REDL);
2726 
2727  const uves_propertylist *redl_header = raw_header[indx_redl];
2728 
2729  uves_free_image(&image);
2730  check( image = cpl_image_load(filename,
2731  type,
2732  plane,
2733  extension),
2734  "Could not load image from extension %d of file '%s' ",
2735  extension, filename);
2736 
2737  check( raw_image[indx] = uves_crop_and_rotate(image,
2738  raw_header[indx],
2739  chip, redl_header,
2740  new_format,
2741  &rotated_header[indx]),
2742  "Error splitting red image");
2743  }
2744 
2745 
2746  }/* if new format */
2747 
2748 
2749  cleanup:
2750  uves_free_image(&image);
2751  uves_free_image(&image1);
2752  uves_free_image(&image2);
2753 
2754  uves_free_propertylist(&primary_header);
2755  uves_free_propertylist(&ext_header);
2756 
2757  if (cpl_error_get_code() != CPL_ERROR_NONE)
2758  {
2759  uves_free_image (&raw_image[0]);
2760  uves_free_image (&raw_image[1]);
2761  uves_free_propertylist(&raw_header[0]);
2762  uves_free_propertylist(&raw_header[1]);
2763  uves_free_propertylist(&rotated_header[0]);
2764  uves_free_propertylist(&rotated_header[1]);
2765  }
2766 
2767  return cpl_error_get_code();
2768 }
2769 
2770 
2771 /*----------------------------------------------------------------------------*/
2799 /*----------------------------------------------------------------------------*/
2800 cpl_error_code
2801 uves_load_raw_imagelist(const cpl_frameset *frames,
2802  bool flames,
2803  const char *blue_tag, const char *red_tag, cpl_type type,
2804  cpl_imagelist *images[2],
2805  uves_propertylist **raw_headers[2], uves_propertylist *rotated_header[2],
2806  bool *blue)
2807 {
2808  const char *tag = NULL;
2809  const cpl_frame *frame = NULL;
2810  cpl_image *temp_image[2] = {NULL, NULL};
2811  uves_propertylist *temp_header[2] = {NULL, NULL};
2812  cpl_size number_of_frames = 0;
2813  int frameset_size = 0; /* Keeps track of number of raw_header pointers allocated */
2814  int nchips;
2815  int chip;
2816 
2817  raw_headers[0] = NULL;
2818  raw_headers[1] = NULL;
2819 
2820  check( frameset_size = cpl_frameset_get_size(frames),
2821  "Error reading frameset size");
2822 
2823  check( tag = identify_arm(frames, blue_tag, red_tag, blue),
2824  "Could not identify chip type");
2825 
2826  nchips = (*blue) ? 1 : 2;
2827  for(chip = 0; chip < nchips; chip++)
2828  {
2829  images[chip] = NULL;
2830  rotated_header[chip] = NULL;
2831 
2832  images[chip] = cpl_imagelist_new();
2833  raw_headers[chip] = cpl_calloc(frameset_size, sizeof(uves_propertylist *));
2834  }
2835 
2836  /* Load all input images with correct tag,
2837  split,
2838  insert into image list(s) */
2839 
2840  number_of_frames = 0;
2841  int i=0;
2842  int nfrm;
2843  nfrm=cpl_frameset_get_size(frames);
2844  for(i=0;i<nfrm;i++)
2845  {
2846  frame=cpl_frameset_get_frame_const(frames,i);
2847  /* If match */
2848  if ( strcmp(cpl_frame_get_tag(frame), tag) == 0)
2849  {
2850  const char *filename = cpl_frame_get_filename(frame);
2851 
2852  /* Load image + header */
2853  uves_free_propertylist(&rotated_header[0]);
2854  uves_free_propertylist(&rotated_header[1]);
2855 
2856  check( load_raw_image(filename,
2857  type,
2858  flames,
2859  *blue,
2860  temp_image,
2861  temp_header,
2862  rotated_header),
2863  "Could not load image from file '%s'", filename);
2864 
2865  /* Append to image lists */
2866  for(chip = 0; chip < nchips; chip++)
2867  {
2868  raw_headers[chip][number_of_frames] = temp_header[chip];
2869  temp_header[chip] = NULL;
2870 
2871  check( cpl_imagelist_set(images[chip],
2872  temp_image[chip],
2873  /* Position */
2874  cpl_imagelist_get_size(images[chip])
2875  ),
2876  "Could not insert image into image list");
2877 
2878  /* Don't deallocate image or header */
2879  temp_image[chip] = NULL;
2880  }
2881 
2882  number_of_frames += 1;
2883  }
2884  }
2885 
2886  /* Check that image sizes are identical */
2887 
2888  for(chip = 0; chip < nchips; chip++)
2889  {
2890  /* This function returns zero iff the list is uniform */
2891  assure (cpl_imagelist_is_uniform(images[chip]) == 0,
2892  CPL_ERROR_INCOMPATIBLE_INPUT,
2893  "Input images are not of same size and type");
2894 
2895  passure( cpl_imagelist_get_size(images[chip]) == number_of_frames,
2896  "%" CPL_SIZE_FORMAT " %" CPL_SIZE_FORMAT"", cpl_imagelist_get_size(images[0]), number_of_frames);
2897 
2898  }
2899 
2900 
2901  /* Check central wavelengths (not bias/dark) */
2902  if ( strcmp(UVES_BIAS (*blue), tag) != 0 &&
2903  strcmp(UVES_DARK (*blue), tag) != 0 &&
2904  strcmp(UVES_PDARK(*blue), tag) != 0) {
2905  enum uves_chip chip_id;
2906  int i;
2907  double wlen = 0;
2908 
2909  for (chip_id = uves_chip_get_first(*blue);
2910  chip_id != UVES_CHIP_INVALID;
2911  chip_id = uves_chip_get_next(chip_id)) {
2912  for (i = 0; i < number_of_frames; i++) {
2913  if (i == 0) {
2915  raw_headers[uves_chip_get_index(chip_id)][i], chip_id),
2916  "Error reading central wavelength of input frame number %d", i+1);
2917  }
2918  else {
2919  double w;
2920 
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  assure( fabs((w-wlen)/wlen) < 0.01, CPL_ERROR_INCOMPATIBLE_INPUT,
2926  "Mis-matching input frame central wavelengths: "
2927  "%e (frame 1) != %e (frame %d)", wlen, w, i+1);
2928  }
2929  }
2930  }
2931  }
2932 
2933  cleanup:
2934  uves_free_image(&temp_image[0]);
2935  uves_free_image(&temp_image[1]);
2936  uves_free_propertylist(&temp_header[0]);
2937  uves_free_propertylist(&temp_header[1]);
2938 
2939  if (cpl_error_get_code() != CPL_ERROR_NONE) {
2940  if (raw_headers[0] != NULL) {
2941  int i;
2942  for (i = 0; i < frameset_size; i++) {
2943  if (raw_headers[0] != NULL) uves_free_propertylist(&raw_headers[0][i]);
2944  if (raw_headers[1] != NULL) uves_free_propertylist(&raw_headers[1][i]);
2945  }
2946  }
2947  cpl_free(raw_headers[0]); raw_headers[0] = NULL;
2948  cpl_free(raw_headers[1]); raw_headers[1] = NULL;
2949 
2950  uves_free_imagelist(&images[0]);
2951  uves_free_imagelist(&images[1]);
2952 
2953  uves_free_propertylist(&rotated_header[0]);
2954  uves_free_propertylist(&rotated_header[1]);
2955  }
2956 
2957  return cpl_error_get_code();
2958 }
2959 
2960 
2961 /*----------------------------------------------------------------------------*/
2978 /*----------------------------------------------------------------------------*/
2979 cpl_error_code
2980 uves_load_orderpos(const cpl_frameset *frames,
2981  bool flames,
2982  const char **raw_filename,
2983  cpl_image *raw_image[2],
2984  uves_propertylist *raw_header[2],
2985  uves_propertylist *rotated_header[2], bool *blue)
2986 {
2987  const char *tags[4];
2988 
2989  int number_of_tags = sizeof(tags) / sizeof(char *);
2990  int indx;
2991 
2992  /* Warning: Duplicate logic. The number of tags must match the size of the
2993  tags array defined above */
2994  tags[0] = UVES_ORDER_FLAT(flames, false); /* red */
2995  tags[1] = UVES_ORDER_FLAT(flames, true); /* blue */
2996  tags[2] = UVES_STD_STAR(false);
2997  tags[3] = UVES_STD_STAR(true);
2998 
2999  if (flames)
3000  {
3001  *blue = false;
3002  number_of_tags = 1;
3003 
3004  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx,
3005  NULL),
3006  "Could not find raw frame (%s) in SOF",
3007  tags[0]);
3008 
3009  }
3010  else
3011  {
3012  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx,
3013  NULL),
3014  "Could not find raw frame (%s, %s, %s, or %s) in SOF",
3015  tags[0], tags[1], tags[2], tags[3]);
3016 
3017  *blue = (indx == 1) || (indx == 3);
3018  }
3019 
3020  /* Load the image */
3021  check( load_raw_image(*raw_filename,
3022  CPL_TYPE_DOUBLE,
3023  flames,
3024  *blue,
3025  raw_image,
3026  raw_header,
3027  rotated_header),
3028  "Error loading image from file '%s'", *raw_filename);
3029 
3030  passure( !flames || !(*blue), "%d %d",
3031  flames, *blue );
3032 
3033  cleanup:
3034  if (cpl_error_get_code() != CPL_ERROR_NONE)
3035  {
3036  *raw_filename = NULL;
3037  }
3038 
3039  return cpl_error_get_code();
3040 }
3041 
3042 /*----------------------------------------------------------------------------*/
3058 /*----------------------------------------------------------------------------*/
3059 cpl_error_code
3060 uves_load_formatcheck(const cpl_frameset *frames,
3061  bool flames,
3062  const char **raw_filename,
3063  cpl_image *raw_image[2],
3064  uves_propertylist *raw_header[2],
3065  uves_propertylist *rotated_header[2], bool *blue)
3066 {
3067  const char *tags[2];
3068  int number_of_tags = sizeof(tags) / sizeof(char *);
3069  int indx;
3070 
3071  tags[0] = UVES_FORMATCHECK(flames, false); /* red */
3072  tags[1] = UVES_FORMATCHECK(flames, true); /* blue */
3073  if (flames)
3074  {
3075  *blue = false;
3076  number_of_tags = 1;
3077 
3078  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3079  "Could not find raw frame (%s) in SOF",
3080  tags[0]);
3081  }
3082  else
3083  {
3084  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3085  "Could not find raw frame (%s or %s) in SOF",
3086  tags[0], tags[1]);
3087 
3088  *blue = (indx == 1);
3089  }
3090 
3091  /* Load the image */
3092  check( load_raw_image(*raw_filename,
3093  CPL_TYPE_DOUBLE,
3094  flames,
3095  *blue,
3096  raw_image,
3097  raw_header,
3098  rotated_header),
3099  "Error loading image from file '%s'", *raw_filename);
3100 
3101  cleanup:
3102  if (cpl_error_get_code() != CPL_ERROR_NONE)
3103  {
3104  *raw_filename = NULL;
3105  }
3106  return cpl_error_get_code();
3107 }
3108 
3109 /*----------------------------------------------------------------------------*/
3128 /*----------------------------------------------------------------------------*/
3129 void uves_load_cd_align(const cpl_frameset *frames,
3130  const char **raw_filename1,
3131  const char **raw_filename2,
3132  cpl_image *raw_image1[2],
3133  cpl_image *raw_image2[2],
3134  uves_propertylist *raw_header1[2],
3135  uves_propertylist *raw_header2[2],
3136  uves_propertylist *rotated_header1[2],
3137  uves_propertylist *rotated_header2[2],
3138  bool *blue)
3139 {
3140  const char *tags[2];
3141  int number_of_tags = sizeof(tags) / sizeof(char *);
3142  int indx;
3143  bool flames = false;
3144  const cpl_frame *frame;
3145 
3146  tags[0] = UVES_CD_ALIGN(false); /* red */
3147  tags[1] = UVES_CD_ALIGN(true); /* blue */
3148 
3149  check( *raw_filename1 = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3150  "Could not find raw frame (%s or %s) in SOF",
3151  tags[0], tags[1]);
3152 
3153  *blue = (indx == 1);
3154 
3155  assure( cpl_frameset_count_tags(frames, tags[indx]) == 2,
3156  CPL_ERROR_ILLEGAL_INPUT,
3157  "%d %s frames found. Exactly 2 required",
3158  cpl_frameset_count_tags(frames, tags[indx]), tags[indx] );
3159 
3160  /* Load the two frames */
3161  {
3162  int n = 1;
3163  int i=0;
3164  int nfrm=cpl_frameset_get_size(frames);
3165  for (i = 0;i < nfrm;i++)
3166  {
3167  frame=cpl_frameset_get_frame_const(frames,i);
3168  if (strcmp(cpl_frame_get_tag(frame), tags[indx]) == 0)
3169  {
3170  if (n == 1)
3171  {
3172  *raw_filename1 = cpl_frame_get_filename(frame);
3173  }
3174  else
3175  {
3176  *raw_filename2 = cpl_frame_get_filename(frame);
3177  }
3178 
3179  check( load_raw_image(n == 1 ?
3180  *raw_filename1 :
3181  *raw_filename2,
3182  CPL_TYPE_DOUBLE,
3183  flames,
3184  *blue,
3185  n == 1 ?
3186  raw_image1 :
3187  raw_image2,
3188  n == 1 ?
3189  raw_header1 :
3190  raw_header2,
3191  n == 1 ?
3192  rotated_header1 :
3193  rotated_header2),
3194  "Error loading image from file '%s'",
3195  n == 1 ? *raw_filename1 : *raw_filename2);
3196 
3197  n++;
3198  }
3199  }
3200  }
3201 
3202  cleanup:
3203  if (cpl_error_get_code() != CPL_ERROR_NONE)
3204  {
3205  *raw_filename1 = NULL;
3206  *raw_filename2 = NULL;
3207  }
3208 
3209  return;
3210 }
3211 
3212 
3213 /*----------------------------------------------------------------------------*/
3234 /*----------------------------------------------------------------------------*/
3235 void
3236 uves_load_arclamp(const cpl_frameset *frames,
3237  bool flames,
3238  const char **raw_filename,
3239  cpl_image *raw_image[2], uves_propertylist *raw_header[2],
3240  uves_propertylist *rotated_header[2], bool *blue,
3241  bool *sim_cal)
3242 {
3243  const char *tags[4];
3244 
3245  int number_of_tags = sizeof(tags) / sizeof(char *);
3246  int indx;
3247 
3248  /* Warning: duplicate logic. Array size above must match */
3249  if (flames)
3250  {
3251  assure_nomsg( sim_cal != NULL, CPL_ERROR_NULL_INPUT );
3252 
3253  tags[0] = UVES_ARC_LAMP(flames, true); /* blue flag not used */
3254  tags[1] = FLAMES_FIB_SCI_SIM;
3255 
3256  number_of_tags = 2;
3257  *blue = false;
3258 
3259  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3260  "Could not find raw frame (%s or %s) in SOF",
3261  tags[0], tags[1]);
3262 
3263  *sim_cal = (indx == 1);
3264  }
3265  else
3266  {
3267  tags[0] = UVES_ARC_LAMP(flames, true);
3268  tags[1] = UVES_ARC_LAMP(flames, false);
3269  tags[2] = UVES_ECH_ARC_LAMP(true);
3270  tags[3] = UVES_ECH_ARC_LAMP(false);
3271 
3272  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3273  "Could not find raw frame (%s, %s, %s or %s) in SOF",
3274  tags[0], tags[1], tags[2], tags[3]);
3275 
3276  *blue = (indx == 0 || indx == 2);
3277  }
3278 
3279  /* Load the image */
3280  check( load_raw_image(*raw_filename,
3281  CPL_TYPE_DOUBLE,
3282  flames,
3283  *blue,
3284  raw_image,
3285  raw_header,
3286  rotated_header),
3287  "Error loading image from file '%s'", *raw_filename);
3288 
3289  cleanup:
3290  if (cpl_error_get_code() != CPL_ERROR_NONE) {
3291  *raw_filename = NULL;
3292  uves_free_image (raw_image);
3293  uves_free_propertylist(raw_header);
3294  }
3295  return;
3296 }
3297 
3298 /*----------------------------------------------------------------------------*/
3313 /*----------------------------------------------------------------------------*/
3314 cpl_error_code
3315 uves_load_science(const cpl_frameset *frames, const char **raw_filename,
3316  cpl_image *raw_image[2],
3317  uves_propertylist *raw_header[2],
3318  uves_propertylist *rotated_header[2],
3319  bool *blue,
3320  const char **sci_type)
3321 {
3322  /* Note: the two following arrays must match */
3323  const char *tags[] =
3324  {
3325  UVES_SCIENCE(true), UVES_SCIENCE(false),
3326  UVES_SCI_EXTND(true), UVES_SCI_EXTND(false),
3327  UVES_SCI_POINT(true), UVES_SCI_POINT(false),
3328  UVES_SCI_SLICER(true), UVES_SCI_SLICER(false),
3329  UVES_TFLAT(true), UVES_TFLAT(false)
3330  };
3331 
3332  const char *type[] =
3333  {
3334  "SCIENCE", "SCIENCE",
3335  "SCI_EXTND", "SCI_EXTND",
3336  "SCI_POINT", "SCI_POINT",
3337  "SCI_SLICER", "SCI_SLICER",
3338  "TFLAT", "TFLAT",
3339  };
3340 
3341  int number_of_tags = sizeof(tags) / sizeof(char *);
3342  int indx;
3343  bool flames = false;
3344 
3345  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3346  "No science frame (%s, %s, %s, %s, %s, %s, %s, %s, %s or %s) in SOF",
3347  tags[0], tags[1], tags[2], tags[3],
3348  tags[4], tags[5], tags[6], tags[7], tags[7], tags[8]);
3349 
3350  *blue = (indx % 2 == 0);
3351  *sci_type = type[indx];
3352 
3353  /* Load the image */
3354  check( load_raw_image(*raw_filename,
3355  CPL_TYPE_DOUBLE,
3356  flames,
3357  *blue,
3358  raw_image,
3359  raw_header,
3360  rotated_header),
3361  "Error loading image from file '%s'", *raw_filename);
3362  cleanup:
3363  if (cpl_error_get_code() != CPL_ERROR_NONE)
3364  {
3365  *raw_filename = NULL;
3366  uves_free_image (raw_image);
3367  uves_free_propertylist(raw_header);
3368  }
3369  return cpl_error_get_code();
3370 }
3371 
3372 /*----------------------------------------------------------------------------*/
3389 /*----------------------------------------------------------------------------*/
3390 cpl_error_code
3391 uves_load_standard(const cpl_frameset *frames, const char **raw_filename,
3392  cpl_image *raw_image[2],
3393  uves_propertylist *raw_header[2],
3394  uves_propertylist *rotated_header[2], bool *blue)
3395 {
3396  const char *tags[] = { UVES_STD_STAR(true), UVES_STD_STAR(false) };
3397  int number_of_tags = sizeof(tags) / sizeof(char *);
3398  int indx;
3399  bool flames = false;
3400 
3401  check( *raw_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3402  "Could not identify raw frame (%s or %s) in SOF", tags[0], tags[1]);
3403 
3404  *blue = (indx == 0);
3405 
3406  /* Load the image */
3407  check( load_raw_image(*raw_filename,
3408  CPL_TYPE_DOUBLE,
3409  flames,
3410  *blue,
3411  raw_image,
3412  raw_header,
3413  rotated_header),
3414  "Error loading image from file '%s'", *raw_filename);
3415 
3416  cleanup:
3417  if (cpl_error_get_code() != CPL_ERROR_NONE)
3418  {
3419  *raw_filename = NULL;
3420  uves_free_image (raw_image);
3421  uves_free_propertylist(raw_header);
3422  }
3423  return cpl_error_get_code();
3424 }
3425 
3426 /*----------------------------------------------------------------------------*/
3442 /*----------------------------------------------------------------------------*/
3443 
3444 cpl_error_code
3445 uves_load_drs(const cpl_frameset *frames,
3446  bool flames,
3447  const char *chip_name,
3448  const char **drs_filename,
3449  uves_propertylist **drs_header,
3450  enum uves_chip chip)
3451 {
3452  const char *tags[1];
3453  int number_of_tags = sizeof(tags) / sizeof(char *);
3454  int extension;
3455  int indx;
3456 
3457  *drs_header = NULL;
3458  tags[0] = UVES_DRS_SETUP(flames, chip);
3459  extension = UVES_DRS_SETUP_EXTENSION(chip);
3460 
3461  check( *drs_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3462  "Could not find DRS table (%s) in SOF", tags[0]);
3463 
3464  /* Load the header */
3465  check( *drs_header = uves_propertylist_load(*drs_filename,
3466  extension),
3467  "Could not load header from extension %d of file '%s'", extension, *drs_filename);
3468 
3469  check_nomsg( uves_warn_if_chip_names_dont_match(*drs_header, chip_name, chip) );
3470 
3471  cleanup:
3472  if (cpl_error_get_code() != CPL_ERROR_NONE) {
3473  *drs_filename = NULL;
3474  uves_free_propertylist(drs_header);
3475  }
3476  return cpl_error_get_code();
3477 }
3478 
3479 /*----------------------------------------------------------------------------*/
3487 /*----------------------------------------------------------------------------*/
3488 cpl_image *
3489 uves_load_weights(const cpl_frameset *frames, const char **weights_filename,
3490  enum uves_chip chip)
3491 {
3492  cpl_image *weights = NULL;
3493  const char *tags[1];
3494  int number_of_tags = sizeof(tags) / sizeof(char *);
3495  int extension = 0;
3496  int indx;
3497 
3498  assure( weights_filename != NULL, CPL_ERROR_NULL_INPUT, "Null filename");
3499 
3500  tags[0] = UVES_WEIGHTS(chip);
3501 
3502  check( *weights_filename = uves_find_frame(frames,
3503  tags, number_of_tags, &indx, NULL),
3504  "Could not find '%s' in frame set", tags[0]);
3505 
3506  check( weights = cpl_image_load(*weights_filename,
3507  CPL_TYPE_DOUBLE, /* Convert to this type */
3508  0, /* plane number */
3509  extension /* Extension number */
3510  ),
3511  "Could not load master bias from extension %d of file '%s'",
3512  extension, *weights_filename);
3513 
3514  cleanup:
3515  return weights;
3516 }
3517 
3518 
3519 /*----------------------------------------------------------------------------*/
3535 /*----------------------------------------------------------------------------*/
3536 
3537 cpl_error_code
3538 uves_load_mbias(const cpl_frameset *frames, const char *chip_name,
3539  const char **mbias_filename,
3540  cpl_image **mbias, uves_propertylist **mbias_header, enum uves_chip chip)
3541 {
3542  const char *tags[1];
3543  int number_of_tags = sizeof(tags) / sizeof(char *);
3544  int extension;
3545  int indx;
3546 
3547  *mbias = NULL;
3548  *mbias_header = NULL;
3549 
3550  tags[0] = UVES_MASTER_BIAS (chip);
3551  extension = UVES_MASTER_BIAS_EXTENSION(chip);
3552 
3553  check( *mbias_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3554  "Could not find '%s' in frame set", tags[0]);
3555 
3556  /* Load the mbias image */
3557  check( *mbias = cpl_image_load(*mbias_filename,
3558  CPL_TYPE_DOUBLE, /* Convert to this type */
3559  0, /* plane number */
3560  extension /* Extension number */
3561  ),
3562  "Could not load master bias from extension %d of file '%s'",
3563  extension, *mbias_filename);
3564 
3565  /* Load the header */
3566  check( *mbias_header = uves_propertylist_load(*mbias_filename,
3567  extension),
3568  "Could not load header from extension %d of file '%s'",
3569  extension, *mbias_filename);
3570 
3571  check_nomsg( uves_warn_if_chip_names_dont_match(*mbias_header, chip_name, chip) );
3572 
3573  cleanup:
3574  if (cpl_error_get_code() != CPL_ERROR_NONE)
3575  {
3576  *mbias_filename = NULL;
3577  uves_free_image(mbias);
3578  uves_free_propertylist(mbias_header);
3579  }
3580  return cpl_error_get_code();
3581 }
3582 
3583 
3584 /*----------------------------------------------------------------------------*/
3600 /*----------------------------------------------------------------------------*/
3601 
3602 cpl_error_code
3603 uves_load_master_formatcheck(const cpl_frameset *frames, const char *chip_name,
3604  const char **mform_filename,
3605  cpl_image **mform, uves_propertylist **mform_header, enum uves_chip chip)
3606 {
3607  const char *tags[1];
3608  int number_of_tags = sizeof(tags) / sizeof(char *);
3609  int extension;
3610  int indx;
3611 
3612  *mform = NULL;
3613  *mform_header = NULL;
3614 
3615  tags[0] = UVES_MASTER_ARC_FORM (chip);
3616  extension = UVES_MASTER_ARC_FORM_EXTENSION(chip);
3617 
3618  check( *mform_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3619  "Could not find '%s' in frame set", tags[0]);
3620 
3621  /* Load the mbias image */
3622  check( *mform = cpl_image_load(*mform_filename,
3623  CPL_TYPE_DOUBLE, /* Convert to this type */
3624  0, /* plane number */
3625  extension /* Extension number */
3626  ),
3627  "Could not load master formatcheck from extension %d of file '%s'",
3628  extension, *mform_filename);
3629 
3630  /* Load the header */
3631 
3632  check( *mform_header = uves_propertylist_load(*mform_filename,
3633  extension),
3634  "Could not load header from extension %d of file '%s'",
3635  extension, *mform_filename);
3636 
3637  check_nomsg( uves_warn_if_chip_names_dont_match(*mform_header, chip_name, chip) );
3638 
3639  cleanup:
3640  if (cpl_error_get_code() != CPL_ERROR_NONE)
3641  {
3642  *mform_filename = NULL;
3643  uves_free_image(mform);
3644  uves_free_propertylist(mform_header);
3645  }
3646  return cpl_error_get_code();
3647 }
3648 
3649 /*----------------------------------------------------------------------------*/
3665 /*----------------------------------------------------------------------------*/
3666 
3667 cpl_error_code
3668 uves_load_mdark(const cpl_frameset *frames, const char *chip_name,
3669  const char **mdark_filename, cpl_image **mdark,
3670  uves_propertylist **mdark_header, enum uves_chip chip)
3671 {
3672  const char *tags[2];
3673  int number_of_tags = sizeof(tags) / sizeof(char *);
3674  int extension;
3675  int indx;
3676 
3677  *mdark = NULL;
3678  *mdark_header = NULL;
3679 
3680  tags[0] = UVES_MASTER_DARK (chip);
3681  tags[1] = UVES_MASTER_PDARK (chip);
3682  extension = UVES_MASTER_DARK_EXTENSION(chip);
3683 
3684  check( *mdark_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3685  "Could not find %s or %s in frame set", tags[0], tags[1]);
3686 
3687  /* Load the mdark image */
3688  check( *mdark = cpl_image_load(*mdark_filename,
3689  CPL_TYPE_DOUBLE, /* Convert to this type */
3690  0, /* plane number */
3691  extension /* Extension number */
3692  ),
3693  "Could not load master dark from extension %d of file '%s'",
3694  extension, *mdark_filename);
3695 
3696  /* Load the header */
3697  check( *mdark_header = uves_propertylist_load(*mdark_filename,
3698  extension),
3699  "Could not load header from extension %d of file '%s'",
3700  extension, *mdark_filename);
3701 
3702  check_nomsg( uves_warn_if_chip_names_dont_match(*mdark_header, chip_name, chip) );
3703 
3704  cleanup:
3705  if (cpl_error_get_code() != CPL_ERROR_NONE)
3706  {
3707  *mdark_filename = NULL;
3708  uves_free_image(mdark);
3709  uves_free_propertylist(mdark_header);
3710  }
3711  return cpl_error_get_code();
3712 }
3713 /*----------------------------------------------------------------------------*/
3729 /*----------------------------------------------------------------------------*/
3730 void
3731 uves_load_ref_flat(const cpl_frameset *frames, const char *chip_name,
3732  const char **filename, cpl_image **rflat,
3733  uves_propertylist **rflat_header, enum uves_chip chip)
3734 {
3735  const char *tags[1];
3736  int number_of_tags = sizeof(tags) / sizeof(char *);
3737  int extension;
3738  int indx;
3739 
3740  *rflat = NULL;
3741  *rflat_header = NULL;
3742 
3743  tags[0] = UVES_REF_TFLAT(chip);
3744  extension = UVES_MASTER_FLAT_EXTENSION(chip);
3745 
3746  check( *filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3747  "Could not find %s in frame set", tags[0]);
3748 
3749  check( *rflat = cpl_image_load(*filename,
3750  CPL_TYPE_DOUBLE, /* Convert to this type */
3751  0, /* plane number */
3752  extension /* Extension number */
3753  ),
3754  "Could not load reference dark from extension %d of file '%s'",
3755  extension, *filename);
3756 
3757  check( *rflat_header = uves_propertylist_load(*filename,
3758  extension),
3759  "Could not load header from extension %d of file '%s'",
3760  extension, *filename);
3761 
3762  check_nomsg( uves_warn_if_chip_names_dont_match(*rflat_header, chip_name, chip) );
3763 
3764  cleanup:
3765  if (cpl_error_get_code() != CPL_ERROR_NONE)
3766  {
3767  *filename = NULL;
3768  uves_free_image(rflat);
3769  uves_free_propertylist(rflat_header);
3770  }
3771 
3772  return;
3773 }
3774 
3775 /*----------------------------------------------------------------------------*/
3791 /*----------------------------------------------------------------------------*/
3792 
3793 cpl_error_code
3794 uves_load_mflat_const(const cpl_frameset *frames, const char *chip_name,
3795  const char **mflat_filename,
3796  cpl_image **mflat, uves_propertylist **mflat_header,
3797  enum uves_chip chip,
3798  const cpl_frame **mflat_frame)
3799 {
3800  const char *tags[6];
3801  int number_of_tags = sizeof(tags) / sizeof(char *);
3802  int extension;
3803  int indx;
3804 
3805  *mflat = NULL;
3806  *mflat_header = NULL;
3807 
3808  tags[0] = UVES_REF_TFLAT (chip); /* Use REF TFLAT, rather than MASTER_TFLAT */
3809  tags[1] = UVES_MASTER_FLAT (chip);
3810  tags[2] = UVES_MASTER_DFLAT (chip);
3811  tags[3] = UVES_MASTER_IFLAT (chip);
3812  tags[4] = UVES_MASTER_TFLAT (chip);
3813  tags[5] = UVES_MASTER_SCREEN_FLAT (chip);
3814  extension = UVES_MASTER_FLAT_EXTENSION(chip);
3815 
3816  check( *mflat_filename = uves_find_frame(frames, tags, number_of_tags, &indx,
3817  mflat_frame),
3818  "Could not find '%s', '%s', '%s', '%s' or '%s' in frame set",
3819  tags[0], tags[1], tags[2], tags[3], tags[4]);
3820 
3821  /* Load the mflat image */
3822  check( *mflat = cpl_image_load(*mflat_filename,
3823  CPL_TYPE_DOUBLE, /* Convert to this type */
3824  0, /* plane number */
3825  extension /* Extension number */
3826  ),
3827  "Could not load master flat from extension %d of file '%s'",
3828  extension, *mflat_filename);
3829 
3830  /* Load the header */
3831  check( *mflat_header = uves_propertylist_load(*mflat_filename,
3832  extension),
3833  "Could not load header from extension %d of file '%s'",
3834  extension, *mflat_filename);
3835 
3836  check_nomsg( uves_warn_if_chip_names_dont_match(*mflat_header, chip_name, chip) );
3837 
3838  cleanup:
3839  if (cpl_error_get_code() != CPL_ERROR_NONE)
3840  {
3841  *mflat_filename = NULL;
3842  uves_free_image(mflat);
3843  uves_free_propertylist(mflat_header);
3844  }
3845  return cpl_error_get_code();
3846 }
3847 
3848 /*----------------------------------------------------------------------------*/
3863 /*----------------------------------------------------------------------------*/
3864 cpl_error_code
3865 uves_load_mflat(cpl_frameset *frames, const char *chip_name,
3866  const char **mflat_filename,
3867  cpl_image **mflat, uves_propertylist **mflat_header, enum uves_chip chip,
3868  cpl_frame **mflat_frame)
3869 {
3870  return uves_load_mflat_const((const cpl_frameset *)frames,
3871  chip_name,
3872  mflat_filename,
3873  mflat, mflat_header, chip,
3874  (const cpl_frame **) mflat_frame);
3875 }
3876 
3877 /*----------------------------------------------------------------------------*/
3909 /*----------------------------------------------------------------------------*/
3910 cpl_error_code
3911 uves_load_ordertable(const cpl_frameset *frames,
3912  bool flames,
3913  const char *chip_name,
3914  const char **ordertable_filename,
3915  cpl_table **ordertable,
3916  uves_propertylist **ordertable_header,
3917  uves_propertylist **ordertable_xheader,
3918  polynomial **order_locations,
3919  cpl_table **traces,
3920  int *tab_in_out_oshift,
3921  double *tab_in_out_yshift,
3922  int ** fib_msk,
3923  double ** fib_pos,
3924  enum uves_chip chip,
3925  bool guess_table)
3926 {
3927  uves_propertylist *midas_header = NULL; /* Table header if midas format */
3928  uves_propertylist *prime_header = NULL; /* Prime header if flames */
3929  const char *tags[1];
3930  int number_of_tags = sizeof(tags) / sizeof(char *);
3931  bool format_is_midas;
3932  int *tioo = NULL;
3933  double *tioy = NULL;
3934  int indx;
3935 
3936  double *fibre_pos = NULL;
3937  int *fibre_mask = NULL;
3938 
3939  if (guess_table)
3940  {
3941  tags[0] = UVES_GUESS_ORDER_TABLE(flames, chip);
3942  }
3943  else
3944  {
3945  tags[0] = UVES_ORDER_TABLE(flames, chip);
3946  }
3947 
3948  check( *ordertable_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
3949  "No order table (%s) found in SOF", tags[0]);
3950 
3951  check( *ordertable = cpl_table_load(*ordertable_filename,
3952  UVES_ORDER_TABLE_EXTENSION,
3953  1), /* Mark identified
3954  invalid values? (1=yes) */
3955  "Error loading order table from extension %d of file '%s'",
3956  UVES_ORDER_TABLE_EXTENSION, *ordertable_filename);
3957 
3958  assure(ordertable_header != NULL,CPL_ERROR_NULL_INPUT,
3959  "NULL primary header uves_propertylist variable header");
3960  check( *ordertable_header = uves_propertylist_load(*ordertable_filename, 0),
3961  "Could not load header from extension 0 of '%s'", *ordertable_filename);
3962 
3963  if(ordertable_xheader != NULL) {
3964 
3965  check( *ordertable_xheader = uves_propertylist_load(*ordertable_filename, 1),
3966  "Could not load header from extension 1 of '%s'", *ordertable_filename);
3967 
3968 
3969 
3970  }
3971  check_nomsg( uves_warn_if_chip_names_dont_match(*ordertable_header, chip_name, chip) );
3972 
3973  check(uves_check_if_format_is_midas(*ordertable_header,&format_is_midas),
3974  "Error getting FITS format");
3975 
3976 
3977  if (!format_is_midas && !flames)
3978  {
3979  /* The format check and order position recipes create order tables
3980  with different column names. Rename if necessary.
3981 
3982  This is a workaround for the problem that different recipes
3983  create the same products (order tables and line tables).
3984  The true solution would be to remove the format check recipe from
3985  the recution cascade, and use the theoretical physical model to
3986  bootstrap the order definition and wavelength calibration.
3987  */
3988  if (cpl_table_has_column(*ordertable, "ORDER"))
3989  {
3990  cpl_table_name_column(*ordertable, "ORDER", "Order");
3991  }
3992  if (cpl_table_has_column(*ordertable, "YFIT"))
3993  {
3994  cpl_table_name_column(*ordertable, "YFIT", "Yfit");
3995  }
3996 
3997  if (order_locations != NULL)
3998  {
3999  check( *order_locations =
4000  load_polynomial(*ordertable_filename, UVES_ORDER_TABLE_EXTENSION_POLY),
4001  "Could not read polynomial from extension %d of file '%s'",
4002  UVES_ORDER_TABLE_EXTENSION_POLY, *ordertable_filename);
4003  }
4004 
4005  if (traces != NULL)
4006  {
4007  check( *traces = cpl_table_load(*ordertable_filename,
4008  UVES_ORDER_TABLE_EXTENSION_FIBRE,
4009  1), /* Mark identified
4010  invalid values? (1=yes) */
4011  "Error loading fibre table from extension %d of file '%s'",
4012  UVES_ORDER_TABLE_EXTENSION_FIBRE, *ordertable_filename);
4013  }
4014  }
4015  else
4016  /* MIDAS format, or FLAMES */
4017  {
4018  /* Rename */
4019  check(( cpl_table_cast_column (*ordertable, "ORDER", "Order", CPL_TYPE_INT),
4020  cpl_table_erase_column(*ordertable, "ORDER")),
4021  "Error casting and renaming column 'ORDER'");
4022 
4023  check( cpl_table_name_column(*ordertable, "YFIT", "Yfit"),
4024  "Error renaming column 'YFIT'");
4025 
4026  //check( midas_header = uves_propertylist_load(*ordertable_filename, 1),
4027  // "Could not load header from extension 1 of '%s'",
4028  // *ordertable_filename);
4029  check(midas_header = uves_propertylist_load(*ordertable_filename, 1),
4030  "Could not load header from extension 1 of '%s'",
4031  *ordertable_filename);
4032 
4033  if(flames) {
4034  check(prime_header = uves_propertylist_load(*ordertable_filename, 0),
4035  "Could not load header from extension 0 of '%s'",
4036  *ordertable_filename);
4037  check_nomsg(uves_propertylist_append(midas_header,prime_header));
4038  }
4039 
4040  /* Load polynomial named 'COEFF' from descriptors in extension 1 */
4041  if (order_locations != NULL)
4042  {
4043  check( *order_locations =
4044  uves_polynomial_convert_from_plist_midas(midas_header, "COEFF",-1),
4045  "Error reading polynomial from %s", *ordertable_filename);
4046  }
4047 
4048 
4049  if (flames && tab_in_out_oshift != NULL )
4050  {
4051  /* Get tab_in_out_oshift */
4052  int tioo_length;
4053  cpl_type tioo_type;
4054 
4055  check( tioo = uves_read_midas_array(
4056  midas_header, "TAB_IN_OUT_OSHIFT", &tioo_length,
4057  &tioo_type, NULL),
4058  "Error reading TAB_IN_OUT_OSHIFT from MIDAS header");
4059 
4060  assure( tioo_type == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
4061  "Type of TAB_IN_OUT_OSHIFT is %s, double expected",
4062  uves_tostring_cpl_type(tioo_type));
4063 
4064  if (tioo_length != 1)
4065  {
4066  uves_msg_warning("Length of TAB_IN_OUT_OSHIFT array is %d; "
4067  "%d expected", tioo_length, 1);
4068  }
4069 
4070  *tab_in_out_oshift = tioo[0];
4071 
4072  uves_msg_debug("TAB_IN_OUT_OSHIFT = %d", *tab_in_out_oshift);
4073 
4074  }
4075 
4076  if (flames && tab_in_out_yshift != NULL)
4077  {
4078  /* Get tab_in_out_yshift */
4079  int tioy_length;
4080  cpl_type tioy_type;
4081 
4082  check( tioy = uves_read_midas_array(
4083  midas_header, "TAB_IN_OUT_YSHIFT", &tioy_length,
4084  &tioy_type, NULL),
4085  "Error reading TAB_IN_OUT_YSHIFT from MIDAS header");
4086 
4087  assure( tioy_type == CPL_TYPE_DOUBLE, CPL_ERROR_TYPE_MISMATCH,
4088  "Type of TAB_IN_OUT_YSHIFT is %s, double expected",
4089  uves_tostring_cpl_type(tioy_type));
4090 
4091  if (tioy_length != 1)
4092  {
4093  uves_msg_warning("Length of TAB_IN_OUT_YSHIFT array is %d; "
4094  "%d expected", tioy_length, 1);
4095  }
4096 
4097  *tab_in_out_yshift = tioy[0];
4098 
4099  uves_msg_debug("TAB_IN_OUT_YSHIFT = %f", *tab_in_out_yshift);
4100  }
4101 
4102  if (traces != NULL)
4103  {
4104  *traces = uves_ordertable_traces_new();
4105 
4106  if (!flames)
4107  /* UVES: one trace with zero offset */
4108  {
4109  int fibre_ID = 0;
4110  double fibre_offset = 0.0;
4111  int fibre_msk = 1;
4112  uves_ordertable_traces_add(*traces,
4113  fibre_ID,
4114  fibre_offset,
4115  fibre_msk);
4116  }
4117  else
4118  /* FLAMES */
4119  {
4120 
4121  int fibre_pos_length;
4122  int fibre_mask_length;
4123  cpl_type fibre_pos_type;
4124  cpl_type fibre_mask_type;
4125  int fibre_ID;
4126 
4127  check( fibre_pos = uves_read_midas_array(
4128  midas_header, "FIBREPOS", &fibre_pos_length,
4129  &fibre_pos_type, NULL),
4130  "Error reading FIBREPOS from MIDAS header");
4131 
4132  assure( fibre_pos_type == CPL_TYPE_DOUBLE, CPL_ERROR_TYPE_MISMATCH,
4133  "Type of FIBREPOS is %s, double expected",
4134  uves_tostring_cpl_type(fibre_pos_type));
4135 
4136  check( fibre_mask = uves_read_midas_array(
4137  midas_header, "FIBREMASK", &fibre_mask_length,
4138  &fibre_mask_type, NULL),
4139  "Error reading FIBREMASK from MIDAS header");
4140 
4141  assure( fibre_mask_type == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
4142  "Type of FIBREMASK is %s, double expected",
4143  uves_tostring_cpl_type(fibre_mask_type));
4144 
4145  assure( fibre_pos_length == fibre_mask_length,
4146  CPL_ERROR_INCOMPATIBLE_INPUT,
4147  "FIBREMASK has length %d, but "
4148  "FIBREPOS has length %d",
4149  fibre_mask_length, fibre_pos_length );
4150 
4151  *fib_pos= cpl_malloc(sizeof(double) * fibre_pos_length);
4152  *fib_msk= cpl_malloc(sizeof(int) * fibre_mask_length);
4153 
4154  for (fibre_ID = 0; fibre_ID < fibre_mask_length; fibre_ID++)
4155  {
4156  uves_msg_debug("Found trace %d, position %f (%s)",
4157  fibre_ID, fibre_pos[fibre_ID],
4158  fibre_mask[fibre_ID] ?
4159  "enabled" : "disabled");
4160  uves_ordertable_traces_add(*traces,
4161  fibre_ID,
4162  fibre_pos[fibre_ID],
4163  fibre_mask[fibre_ID]);
4164  (*fib_pos)[fibre_ID]=fibre_pos[fibre_ID];
4165  (*fib_msk)[fibre_ID]=fibre_mask[fibre_ID];
4166  }
4167  }
4168  }
4169  }
4170 
4171  cleanup:
4172  uves_free_propertylist(&midas_header);
4173  uves_free_double(&fibre_pos);
4174  uves_free_int(&fibre_mask);
4175  uves_free_int(&tioo);
4176  uves_free_double(&tioy);
4177  uves_free_propertylist(&prime_header);
4178 
4179  if (cpl_error_get_code() != CPL_ERROR_NONE)
4180  {
4181  *ordertable_filename = NULL;
4182  uves_free_table (ordertable);
4183  uves_free_propertylist(ordertable_header);
4184  if (order_locations != NULL) uves_polynomial_delete(order_locations);
4185  if (traces != NULL) uves_free_table (traces);
4186  }
4187  return cpl_error_get_code();
4188 }
4189 
4190 
4191 
4192 /*--------------------------------------------------------------------------*/
4201 /*--------------------------------------------------------------------------*/
4202 
4203 
4204 cpl_error_code
4205 uves_check_if_format_is_midas(uves_propertylist* header, bool* format_is_midas)
4206 {
4207 
4208  /* Determine format of order table and read the polynomial */
4209  if (uves_propertylist_contains(header, UVES_DRS_ID)) {
4210 
4211 
4212  const char* drs_id=NULL;
4213 
4214  check( drs_id = uves_pfits_get_drs_id(header), "Error reading DRS ID");
4215  if (strstr(drs_id, "CPL") != NULL ||
4216  strstr(drs_id, "cpl") != NULL) {
4217  *format_is_midas = false;
4218  uves_msg_debug("Order table was written by CPL");
4219  } else if (strstr(drs_id, "MIDAS") != NULL ||
4220  strstr(drs_id, "midas") != NULL) {
4221  *format_is_midas = true;
4222  uves_msg_low("Order table was written by MIDAS");
4223  } else {
4224  assure ( false, CPL_ERROR_ILLEGAL_INPUT,
4225  "Unrecognized order table format, DRS_ID = '%s'", drs_id);
4226  }
4227  } else {
4228 
4229  *format_is_midas = true;
4230  uves_msg_debug("No '%s' keyword found. Assuming MIDAS format", UVES_DRS_ID);
4231  }
4232 
4233  cleanup:
4234  return cpl_error_get_code();
4235 
4236 }
4237 
4238 /*--------------------------------------------------------------------------*/
4248 /*--------------------------------------------------------------------------*/
4249 
4250 static cpl_error_code
4251 create_column_pixelsize(cpl_table *linetable)
4252 {
4253  polynomial *p = NULL;
4254  cpl_table *t = NULL;
4255  double d1, d2;
4256  int i;
4257  int degree = 3;
4258 
4259  /* Remove rows with Ident = 0 (unidentified lines) */
4260  check( t = uves_extract_table_rows(linetable, "Ident", CPL_GREATER_THAN, 0.1),
4261  "Error deleting rows with Ident=0");
4262 
4263  /* Create column Aux := Ident * Order */
4264  check(( cpl_table_duplicate_column(t, "Aux", t, "Ident"),
4265  cpl_table_multiply_columns(t, "Aux", "Order")),
4266  "Error creating 'Aux' column");
4267 
4269  "X", "Aux", NULL,
4270  degree,
4271  NULL, NULL,
4272  NULL,
4273  -1),
4274  "Regression failed");
4275 
4276  check( d1 = uves_polynomial_get_coeff_1d(p, 1),
4277  "Error reading polynomial coefficient");
4278 
4279  check( d2 = uves_polynomial_get_coeff_1d(p, 2),
4280  "Error reading polynomial coefficient");
4281 
4282  cpl_table_new_column(linetable, LINETAB_PIXELSIZE, CPL_TYPE_DOUBLE);
4283 
4284  for (i = 0; i < cpl_table_get_nrow(linetable); i++)
4285  {
4286  int x;
4287  int order;
4288  double pixelsize;
4289  double ident;
4290 
4291  check(( x = cpl_table_get_double(linetable, "X", i, NULL),
4292  order = cpl_table_get_int (linetable, "Order", i, NULL),
4293  ident = cpl_table_get_double(linetable, "Ident", i, NULL)),
4294  "Error reading line table");
4295 
4296  assure( order != 0, CPL_ERROR_ILLEGAL_INPUT, "Illegal order number: %d", order);
4297 
4298  /*
4299  * MIDAS approximates
4300  * d(lambda m)/dx (x,m) = d1 + 2*d2*x
4301  *
4302  * where the polynomial itself is ... + d1*x + d2*x^2 + ...
4303  */
4304  pixelsize = (d1 + 2*d2* x) / order;
4305 // pixelsize = uves_polynomial_derivative_2d(dispersion_relation, x, order, 1)/order;
4306 
4307  if (ident > 0.01)
4308  {
4309  cpl_table_set_double(linetable, LINETAB_PIXELSIZE, i, pixelsize);
4310  }
4311  else
4312  {
4313  cpl_table_set_invalid(linetable, LINETAB_PIXELSIZE, i);
4314  }
4315  }
4316 
4317  cleanup:
4318  uves_free_table(&t);
4320  return cpl_error_get_code();
4321 }
4322 
4323 
4324 
4325 /*----------------------------------------------------------------------------*/
4352 /*----------------------------------------------------------------------------*/
4353 static void
4354 align_order_line_table(cpl_table *linetable, const polynomial *absolute_order,
4355  uves_propertylist **linetable_header,
4356  const polynomial *order_locations, int minorder, int maxorder)
4357 {
4358  polynomial *absord = NULL;
4359 
4360  assure ( order_locations != NULL, CPL_ERROR_NULL_INPUT,
4361  "Null order locations polynomial!");
4362 
4363  assure ( absolute_order != NULL, CPL_ERROR_NULL_INPUT,
4364  "Null absolute order pllynomial!");
4365  assure( cpl_table_has_column(linetable, "X" ), CPL_ERROR_DATA_NOT_FOUND,
4366  "Missing line table column 'X'");
4367  assure( cpl_table_has_column(linetable, "Ynew"), CPL_ERROR_DATA_NOT_FOUND,
4368  "Missing line table column 'Ynew'");
4369  assure( cpl_table_has_column(linetable, "Order"), CPL_ERROR_DATA_NOT_FOUND,
4370  "Missing line table column 'Order'");
4371 
4372  assure( cpl_table_get_column_type(linetable, "X") == CPL_TYPE_DOUBLE,
4373  CPL_ERROR_TYPE_MISMATCH, "Line table column 'X' has type %s (double expected))",
4374  uves_tostring_cpl_type(cpl_table_get_column_type(linetable, "X")) );
4375 
4376  assure( cpl_table_get_column_type(linetable, "Ynew") == CPL_TYPE_DOUBLE,
4377  CPL_ERROR_TYPE_MISMATCH, "Line table column 'Ynew' has type %s (double expected))",
4378  uves_tostring_cpl_type(cpl_table_get_column_type(linetable, "Ynew")) );
4379 
4380  assure( cpl_table_get_column_type(linetable, "Y") == CPL_TYPE_INT,
4381  CPL_ERROR_TYPE_MISMATCH, "Line table column 'Y' has type %s (integer expected))",
4382  uves_tostring_cpl_type(cpl_table_get_column_type(linetable, "Y")) );
4383 
4384 
4385  if (linetable_header != NULL)
4386  /* then correct first/abs order keywords */
4387  {
4388  int line_first, line_last;
4389  int ord_first, ord_last;
4390  {
4391 
4392  int maxx;
4393  int minx;
4394  int x, y, order, absorder; /* At chip center */
4395  int coeff;
4396 
4397 
4398  maxx = uves_round_double(cpl_table_get_column_max(linetable, "X"));
4399 
4400  minx = uves_round_double(cpl_table_get_column_min(linetable, "X"));
4401 
4402  assure( 1 <= minx && minx <= maxx, CPL_ERROR_ILLEGAL_INPUT,
4403  "Illegal min/max line x positions: %d/%d, must be > 1",
4404  minx, maxx);
4405 
4406  /* Center of chip */
4407  x = (minx + maxx) / 2;
4408  order = (minorder + maxorder) / 2;
4409 
4410  y = uves_polynomial_evaluate_2d(order_locations, x, order);
4411  if (uves_polynomial_derivative_2d(absolute_order, x, y, 2) > 0) {
4412  coeff = +1;
4413  }
4414  else {
4415  coeff = -1;
4416  }
4417 
4418  assure ( order_locations != NULL, CPL_ERROR_NULL_INPUT,
4419  "Null order locations polynomial!");
4420 
4421 
4422  absorder = uves_round_double(uves_polynomial_evaluate_2d(absolute_order, x, y));
4423 
4424 
4425  uves_msg_debug("Absolute order polynomial at (%d, %d) = %f, "
4426  "rounding to %d", x, y,
4427  uves_polynomial_evaluate_2d(absolute_order, x, y), absorder);
4428 
4429  ord_first = absorder + (minorder - order) * coeff;
4430  ord_last = absorder + (maxorder - order) * coeff;
4431  }
4432 
4433  check( line_first =
4434  uves_pfits_get_firstabsorder(*linetable_header),
4435  "Could not read order number from line table header");
4436 
4437  check( line_last =
4438  uves_pfits_get_lastabsorder (*linetable_header),
4439  "Could not read order number from line table header");
4440 
4441  uves_msg_debug("Order table range: %d - %d. Line table range: %d - %d",
4442  ord_first, ord_last, line_first, line_last);
4443 
4444  if (line_first != ord_first ||
4445  line_last != ord_last)
4446  {
4447  uves_msg_warning("Provided line and order tables are incompatible. "
4448  "Line table contains orders %d - %d. "
4449  "Order table contains orders %d - %d. "
4450  "Correcting on the fly",
4451  line_first, line_last, ord_first, ord_last);
4452 
4453  check( uves_pfits_set_firstabsorder(*linetable_header,
4454  ord_first),
4455  "Could not write corrected first absolute order number");
4456  check( uves_pfits_set_lastabsorder(*linetable_header,
4457  ord_last),
4458  "Could not write corrected first absolute order number");
4459 
4460  uves_msg_debug("Setting line table order range = %d - %d",
4461  ord_first, ord_last);
4462  }
4463  }
4464  /* This 'Y' column is the relative order number in linetables
4465  but the absolute order number (and therefore equal to
4466  the 'order' column) in line guess tables (!!)
4467  */
4468 
4469  {
4470  double epsilon = 0.01; /* Must be larger than machine precision but
4471  less than the typical difference between
4472  absolute/relative numbering (~100)
4473  */
4474 
4475  if (fabs(cpl_table_get_column_median(linetable, "Y") -
4476  cpl_table_get_column_median(linetable, "Order")) > epsilon)
4477 
4478  /* If column 'Y' is different from 'Order',
4479  then 'Y' is the relative order number and
4480  should be corrected (if there is an inconsistency).
4481 
4482  For now, simply delete the 'Y' column because it is
4483  not used later. If the 'Y' column will be used later,
4484  it must be corrected at this place.
4485  */
4486  {
4487  uves_msg_debug("Removing line table column 'Y'");
4488  cpl_table_erase_column(linetable, "Y");
4489  }
4490  }
4491 
4492  cleanup:
4493  uves_polynomial_delete(&absord);
4494 }
4495 
4496 
4497 /*----------------------------------------------------------------------------*/
4536 /*----------------------------------------------------------------------------*/
4537 void
4538 uves_load_linetable(const cpl_frameset *frames,
4539  bool flames,
4540  const char *chip_name,
4541  const polynomial *order_locations, int minorder, int maxorder,
4542  const char **linetable_filename,
4543  cpl_table **linetable,
4544  uves_propertylist **linetable_header,
4545  polynomial **dispersion_relation,
4546  polynomial **absolute_order,
4547  enum uves_chip chip, int trace_id, int window)
4548 {
4549  uves_propertylist *primary_header = NULL;
4550  uves_propertylist *header = NULL;
4551  uves_propertylist *midas_header = NULL; /* MIDAS extension header */
4552  int *absorders = NULL; /* Absolute order numbers */
4553  cpl_table *temp = NULL;
4554  polynomial *absolute_order_local = NULL;
4555  const char *tags[3];
4556  int number_of_tags = sizeof(tags) / sizeof(char *);
4557  const char *drs_id;
4558  bool format_is_midas; /* Was file written by CPL or MIDAS? */
4559  int base_extension; /* Last extension (e.g. 0) before
4560  extension with line table */
4561  int indx;
4562 
4563  if (flames)
4564  {
4565  tags[0] = UVES_GUESS_LINE_TABLE(flames, chip);
4566  tags[1] = UVES_LINE_TABLE(flames, chip);
4567  tags[2] = UVES_LINE_TABLE(flames, chip);
4568  number_of_tags = 3;
4569 
4570  check( *linetable_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
4571  "No line table (%s, %s or %s) found in SOF", tags[0], tags[1], tags[2]);
4572  }
4573  else
4574  {
4575  tags[0] = UVES_LINE_TABLE(flames, chip);
4576  tags[1] = UVES_LINE_TABLE(flames, chip);
4577  tags[2] = UVES_GUESS_LINE_TABLE(flames, chip);
4578 
4579  /* For backwards compatibility with MIDAS,
4580  also look for LINE_TABLE_chip%d */
4581  if (cpl_frameset_find_const(frames, tags[0]) == NULL &&
4582  cpl_frameset_find_const(frames, tags[1]) == NULL &&
4583  cpl_frameset_find_const(frames, tags[2]) == NULL)
4584  {
4585  uves_msg_debug("No %s", tags[0]);
4586 
4587  if (window >= 1)
4588  {
4589  /* Look for LINE_TABLE_BLUEwindow */
4590 
4591  tags[0] = UVES_LINE_TABLE_MIDAS(chip, window);
4592  tags[1] = UVES_LINE_TABLE_MIDAS(chip, window);
4593  tags[2] = UVES_LINE_TABLE_MIDAS(chip, window);
4594 
4595  uves_msg_debug("Trying %s", tags[0]);
4596  }
4597  if (window <= 0)
4598  {
4599  /* Look for any LINE_TABLE_BLUEi */
4600  tags[0] = UVES_LINE_TABLE_MIDAS(chip, 1);
4601  tags[1] = UVES_LINE_TABLE_MIDAS(chip, 2);
4602  tags[2] = UVES_LINE_TABLE_MIDAS(chip, 3);
4603 
4604  uves_msg_debug("Trying %s, %s or %s", tags[0], tags[1], tags[2]);
4605  }
4606  }
4607 
4608  check( *linetable_filename = uves_find_frame(frames, tags, number_of_tags, &indx, NULL),
4609  "No line table (%s, %s or %s) found in SOF", tags[0], tags[1], tags[2]);
4610  }
4611 
4612  /* Read primary header */
4613  check( primary_header = uves_propertylist_load(*linetable_filename, 0),
4614  "Could not load primary header of '%s'", *linetable_filename);
4615 
4616  check_nomsg( uves_warn_if_chip_names_dont_match(primary_header, chip_name, chip) );
4617 
4618  /* Determine format of line table */
4619  if (uves_propertylist_contains(primary_header, UVES_DRS_ID))
4620  {
4621  check( drs_id = uves_pfits_get_drs_id(primary_header), "Error reading DRS ID");
4622  if (strstr(drs_id, "CPL") != NULL || strstr(drs_id, "cpl") != NULL)
4623  {
4624  format_is_midas = false;
4625  uves_msg_debug("Line table was written by CPL");
4626  }
4627  else if (strstr(drs_id, "MIDAS") != NULL || strstr(drs_id, "midas") != NULL)
4628  {
4629  format_is_midas = true;
4630  uves_msg_debug("Line table was written by MIDAS");
4631  }
4632  else
4633  {
4634  assure ( false,
4635  CPL_ERROR_ILLEGAL_INPUT,
4636  "Unrecognized line table format, DRS_ID = '%s'", drs_id);
4637  }
4638  }
4639  else
4640  {
4641  format_is_midas = true;
4642  uves_msg_debug("No '%s' keyword found. Assuming MIDAS format", UVES_DRS_ID);
4643  }
4644 
4645  if (format_is_midas || flames)
4646  {
4647  if (!flames)
4648  {
4649  assure( trace_id == 0 && (window == -1 || (1 <= window && window <= 3)),
4650  CPL_ERROR_UNSUPPORTED_MODE,
4651  "Cannot read (fibre, window) = (%d, %d) from MIDAS line table",
4652  trace_id, window);
4653 
4654  base_extension = 0;
4655  }
4656  else
4657  {
4658 
4659  if(trace_id > 0) {
4660 
4661  assure( ((1<= trace_id && trace_id <= 9) && (window == -1)),
4662  CPL_ERROR_UNSUPPORTED_MODE,
4663  "Cannot read (fibre, window) = (%d, %d) from MIDAS line table",
4664  trace_id, window);
4665 
4666  base_extension = 0;
4667 
4668 
4669  } else {
4670 
4671  uves_msg_warning("Assuming line table is guess table");
4672  base_extension = 0;
4673  }
4674  }
4675  }
4676  else
4677  /* Find table extension containing the line table for the specified trace and window */
4678  {
4679  int nextensions;
4680  bool found;
4681 
4682  check( nextensions = uves_get_nextensions(*linetable_filename),
4683  "Error reading number of extensions of file '%s'", *linetable_filename);
4684  header = NULL;
4685  found = false;
4686 
4687  uves_msg_debug("Number of extensions = %d", nextensions);
4688 
4689  for (base_extension = 1; base_extension < nextensions && !found; base_extension++)
4690  {
4691  int header_trace;
4692  int header_window;
4693 
4694  /* Read header trace & window info */
4695  check(( uves_free_propertylist(&header),
4696  header = uves_propertylist_load(*linetable_filename, base_extension)),
4697  "Could not header of extension %d of '%s'",
4698  base_extension, *linetable_filename);
4699 
4700  check( header_trace = uves_pfits_get_traceid (header),
4701  "Error reading trace ID from header of extension %d of '%s'",
4702  base_extension, *linetable_filename);
4703 
4704  check( header_window = uves_pfits_get_windownumber(header),
4705  "Error reading window number from header of extension %d of '%s'",
4706  base_extension, *linetable_filename);
4707 
4708  uves_msg_debug("Found (trace, window) = (%d, %d), need (%d, %d)",
4709  header_trace, header_window,
4710  trace_id, window);
4711 
4712  found = ( (trace_id == header_trace) &&
4713  (window == -1 || window == header_window) );
4714  }
4715 
4716  assure( found,
4717  CPL_ERROR_ILLEGAL_INPUT,
4718  "Line table (trace, window) = (%d, %d) is not present in file '%s'",
4719  trace_id, window, *linetable_filename);
4720 
4721  /* Let 'base_extension' be the first extension before
4722  the proper extension was found (0, 3, 6, ...) */
4723  base_extension -= 2;
4724  /* ...and incremented in for-loop */
4725  }
4726 
4727  check( *linetable = cpl_table_load(*linetable_filename,
4728  base_extension + UVES_LINE_TABLE_EXTENSION,
4729  1), /* Mark identified
4730  invalid values? (1=yes) */
4731  "Error loading line table from extension %d of file '%s'",
4732  base_extension + UVES_LINE_TABLE_EXTENSION, *linetable_filename);
4733 
4734  /* Read header of table extension if requested */
4735  if (linetable_header != NULL)
4736  {
4737  check( *linetable_header =
4738  uves_propertylist_load(*linetable_filename,
4739  base_extension + UVES_LINE_TABLE_EXTENSION),
4740  "Could not load header of extension %d of '%s'",
4741  base_extension + UVES_LINE_TABLE_EXTENSION, *linetable_filename);
4742 
4743  if (format_is_midas)
4744  {
4745  int size = 0;
4746  cpl_type type;
4747  absorders = uves_read_midas_array(*linetable_header, "ORDER", &size,
4748  &type, NULL);
4749 
4750  assure( type == CPL_TYPE_INT, CPL_ERROR_TYPE_MISMATCH,
4751  "Type of ORDER is %s, int expected",
4752  uves_tostring_cpl_type(type));
4753 
4754  assure( size == 2,
4755  CPL_ERROR_ILLEGAL_INPUT,
4756  "'ORDER' array has size %d. Size 2 expected.", size);
4757  check(( uves_pfits_set_firstabsorder(*linetable_header, absorders[0]),
4758  uves_pfits_set_lastabsorder(*linetable_header, absorders[1])),
4759  "Error updating table header");
4760  }
4761  }
4762 
4763  /* Read the polynomials if requested */
4764  if (format_is_midas)
4765  {
4766  /* Rename & cast order/ident/X columns */
4767  check(( cpl_table_cast_column(*linetable, "X", "xxxx", CPL_TYPE_DOUBLE),
4768  cpl_table_erase_column(*linetable, "X"),
4769  cpl_table_name_column(*linetable, "xxxx", "X")),
4770  "Error casting and renaming column 'X'");
4771 
4772  check(( cpl_table_cast_column(*linetable, "YNEW", "xxxx", CPL_TYPE_DOUBLE),
4773  cpl_table_erase_column(*linetable, "YNEW"),
4774  cpl_table_name_column(*linetable, "xxxx", "Ynew")),
4775  "Error casting and renaming column 'YNEW'");
4776 
4777  check(( cpl_table_cast_column(*linetable, "Y", "xxxx", CPL_TYPE_INT),
4778  cpl_table_erase_column(*linetable, "Y"),
4779  cpl_table_name_column(*linetable, "xxxx", "Y")),
4780  "Error casting and renaming column 'Y'");
4781 
4782  check(( cpl_table_cast_column(*linetable, "ORDER", "Order", CPL_TYPE_INT),
4783  cpl_table_erase_column(*linetable, "ORDER")),
4784  "Error casting and renaming column 'ORDER'");
4785 
4786  check( cpl_table_name_column(*linetable, "IDENT", "Ident"),
4787  "Error renaming column 'IDENT'");
4788 
4789  check( midas_header = uves_propertylist_load(
4790  *linetable_filename,
4791  base_extension + UVES_LINE_TABLE_EXTENSION),
4792  "Could not load header of extension %d of '%s'",
4793  base_extension + UVES_LINE_TABLE_EXTENSION, *linetable_filename);
4794 
4795  if (dispersion_relation != NULL) {
4796  if (trace_id > 0) {
4797  check( *dispersion_relation =
4798  uves_polynomial_convert_from_plist_midas(midas_header,
4799  "REGR", trace_id),
4800  "Error reading polynomial 'REGR%d' from '%s'",
4801  trace_id,
4802  *linetable_filename);
4803  }
4804  else {
4805  check( *dispersion_relation =
4806  uves_polynomial_convert_from_plist_midas(midas_header,
4807  "REGR", -1),
4808  "Error reading polynomial 'REGR' from '%s'",
4809  *linetable_filename);
4810  }
4811  }
4812 
4813 
4814  check( absolute_order_local =
4815  uves_polynomial_convert_from_plist_midas(midas_header, "RORD",-1),
4816  "Error reading polynomial 'RORD' from '%s'", *linetable_filename);
4817 
4818  /* For FLAMES data, it seems that the polynomial is half an order shifted
4819  (for unknown reasons) */
4820  if (flames)
4821  {
4822  check_nomsg( uves_polynomial_shift(absolute_order_local, 0, 0.5) );
4823  }
4824  }
4825  else
4826  /* CPL format */
4827  {
4828  /* physmod + wavecal recipes use different naming conventions,
4829  workaround for this:
4830  */
4831  if (cpl_table_has_column(*linetable, "YNEW"))
4832  {
4833  cpl_table_name_column(*linetable, "YNEW", "Ynew");
4834  }
4835 
4836  if (dispersion_relation != NULL)
4837  {
4838  check( *dispersion_relation = load_polynomial(
4839  *linetable_filename,
4840  base_extension + UVES_LINE_TABLE_EXTENSION_DISPERSION),
4841  "Could not read polynomial from extension %d of file '%s'",
4842  base_extension + UVES_LINE_TABLE_EXTENSION_DISPERSION,
4843  *linetable_filename);
4844  }
4845 
4846  check( absolute_order_local =
4847  load_polynomial(*linetable_filename,
4848  base_extension + UVES_LINE_TABLE_EXTENSION_ABSORDER),
4849  "Could not read polynomial from extension %d of file '%s'",
4850  base_extension + UVES_LINE_TABLE_EXTENSION_ABSORDER, *linetable_filename);
4851  }
4852 
4853  if (absolute_order != NULL)
4854  {
4855  *absolute_order = uves_polynomial_duplicate(absolute_order_local);
4856  }
4857 
4858 
4859  check( align_order_line_table(
4860  *linetable, absolute_order_local, linetable_header,
4861  order_locations, minorder, maxorder),
4862  "Error while aligning line/order tables");
4863 
4864 
4865  /* Remove all other columns than 'Ident', 'Order', 'X', 'Pixelsize' */
4866  {
4867  const char *colname;
4868 
4869  /* Loop through all columns */
4870 
4871  /* It is undefined behaviour (for a reason!) to loop through
4872  columns while deleting some of them. Therefore, copy the
4873  structure of the linetable to another (empty) table */
4874 
4875  uves_free_table(&temp);
4876  check(( temp = cpl_table_new(0),
4877  cpl_table_copy_structure(temp, *linetable)),
4878  "Error duplicating line table column structure");
4879 
4880  colname = cpl_table_get_column_name(temp);
4881  while (colname != NULL)
4882  {
4883  if (!(strcmp(colname, "X" ) == 0 ||
4884  strcmp(colname, "Order" ) == 0 ||
4885  strcmp(colname, "Ident" ) == 0 ||
4886  strcmp(colname, "FIBRE" ) == 0 ||
4887  strcmp(colname, "Fibre" ) == 0 ||
4888  strcmp(colname, LINETAB_PIXELSIZE) == 0))
4889  {
4890  cpl_table_erase_column(*linetable, colname);
4891  uves_msg_debug("Removing unused column '%s'", colname);
4892  }
4893 
4894  /* Call with NULL argument to get the next column name */
4895  colname = cpl_table_get_column_name(NULL);
4896  }
4897  }
4898 
4899  /* support MIDAS
4900  * Calculate 'Pixel' column (lower case) for MIDAS tables
4901  */
4902  if ( !cpl_table_has_column(*linetable, LINETAB_PIXELSIZE) )
4903  {
4904  check( create_column_pixelsize(*linetable),
4905  "Error adding 'Pixelsize' column");
4906  }
4907 
4908  /* Remove un-identified lines (where Ident = invalid or Ident = zero) ... */
4909  check( uves_erase_invalid_table_rows(*linetable, "Ident"),
4910  "Error deleting rows with illegal 'Ident' value");
4911 
4912  check( uves_erase_table_rows(*linetable, "Ident", CPL_LESS_THAN, 0.01),
4913  "Error deleting rows with illegal 'Ident' value");
4914 
4915  /* Check for any other invalid value */
4916  assure( uves_erase_invalid_table_rows(*linetable, NULL) == 0, CPL_ERROR_ILLEGAL_INPUT,
4917  "After deleting rows with invalid 'Ident' values, "
4918  "the table in extension %d of file '%s' still contains invalid rows",
4919  base_extension + UVES_LINE_TABLE_EXTENSION, *linetable_filename);
4920 
4921  /* Sort line table by 'Order' (ascending), then 'X' (ascending) */
4922  check( uves_sort_table_2(*linetable, "Order", "X", false, false), "Error sorting line table");
4923 
4924  cleanup:
4925  uves_free_propertylist(&primary_header);
4926  uves_free_propertylist(&header);
4927  uves_free_propertylist(&midas_header);
4928  uves_free_table(&temp);
4929  uves_polynomial_delete(&absolute_order_local);
4930  cpl_free(absorders);
4931  if (cpl_error_get_code() != CPL_ERROR_NONE) {
4932  *linetable_filename = NULL;
4933  uves_free_table(linetable);
4934  if (dispersion_relation != NULL) uves_polynomial_delete(dispersion_relation);
4935  if (absolute_order != NULL) uves_polynomial_delete(absolute_order);
4936  }
4937  return;
4938 }
4939 
4940 /*----------------------------------------------------------------------------*/
4944 /*----------------------------------------------------------------------------*/
4945 void
4946 uves_load_linetable_const(const cpl_frameset *frames,
4947  bool flames,
4948  const char *chip_name,
4949  const polynomial *order_locations, int minorder, int maxorder,
4950  const char **linetable_filename,
4951  const cpl_table **linetable,
4952  const uves_propertylist **linetable_header,
4953  const polynomial **dispersion_relation,
4954  polynomial **absolute_order,
4955  enum uves_chip chip, int trace_id, int window)
4956 {
4957  uves_load_linetable(frames, flames, chip_name, order_locations,
4958  minorder, maxorder,
4959  linetable_filename,
4960  (cpl_table **)linetable,
4961  (uves_propertylist **)linetable_header,
4962  (polynomial **)dispersion_relation,
4963  absolute_order,
4964  chip, trace_id, window);
4965 }
4966 
4967 
4968 
4969 /*----------------------------------------------------------------------------*/
4984 /*----------------------------------------------------------------------------*/
4985 
4986 cpl_error_code
4987 uves_load_response_curve(const cpl_frameset *frames, const char *chip_name,
4988  const char **response_filename,
4989  cpl_image **response_curve,
4990  cpl_table **master_response,
4991  uves_propertylist **response_header, enum uves_chip chip)
4992 {
4993  const char *tags[2];
4994  int number_of_tags = sizeof(tags) / sizeof(char *);
4995  int extension;
4996  int indx;
4997 
4998  *response_curve = NULL;
4999  *response_header = NULL;
5000  *master_response = NULL;
5001 
5002  tags[0] = UVES_INSTR_RESPONSE (chip);
5003  tags[1] = UVES_MASTER_RESPONSE(chip);
5004 
5005  check( *response_filename = uves_find_frame(frames, tags, number_of_tags, &indx,
5006  NULL),
5007  "Could not find '%s' in frame set", tags[0]);
5008 
5009 
5010  if (indx == 0)
5011  {
5012  extension = UVES_INSTR_RESPONSE_EXTENSION(chip);
5013 
5014  /* Load the response image
5015 
5016  Note: Even if the response curve was saved as
5017  a FITS file with NAXIS=1, cpl_image_load() will
5018  create an image of size nx1, which is just
5019  what we want
5020  */
5021  check( *response_curve = uves_load_image_file(*response_filename,
5022  /* CPL_TYPE_DOUBLE, Convert to this type */
5023  0, /* plane number */
5024  extension, /* Extension number */
5025 
5026 response_header
5027  ),
5028  "Could not load response curve from extension %d of file '%s'",
5029  extension, *response_filename);
5030 
5031  /* Load the header */
5032 /*
5033  check( *response_header = uves_propertylist_load(*response_filename,
5034  extension),
5035  "Could not load header from extension %d of file '%s'",
5036  extension, *response_filename);
5037 */
5038  check_nomsg( uves_warn_if_chip_names_dont_match(*response_header, chip_name, chip) );
5039  }
5040  else
5041  /* Master response */
5042  {
5043  extension = UVES_MASTER_RESPONSE_EXTENSION(chip);
5044 
5045  check( *master_response = cpl_table_load(*response_filename,
5046  UVES_LINE_INTMON_TABLE_EXTENSION,
5047  1), /* Mark identified
5048  invalid values? (1=yes) */
5049  "Error master response curve from extension %d of file '%s'",
5050  extension, *response_filename);
5051 
5052  /* Convert columns to double */
5053  check(( cpl_table_cast_column(*master_response, "LAMBDA", "LAMBDA_double",
5054  CPL_TYPE_DOUBLE),
5055  cpl_table_erase_column(*master_response, "LAMBDA"),
5056  cpl_table_name_column(*master_response, "LAMBDA_double", "LAMBDA")),
5057  "Could not cast column 'LAMBDA'");
5058 
5059  check(( cpl_table_cast_column(*master_response, "FLUX_CONV", "FLUX_CONV_double",
5060  CPL_TYPE_DOUBLE),
5061  cpl_table_erase_column(*master_response, "FLUX_CONV"),
5062  cpl_table_name_column(*master_response, "FLUX_CONV_double", "FLUX_CONV")),
5063  "Could not cast column 'FLUX_CONV'");
5064 
5065  /* Do not need the header, which also does not contain
5066  keywords needed for uves_warn_if_chip_names_dont_match() */
5067  }
5068 
5069  cleanup:
5070  if (cpl_error_get_code() != CPL_ERROR_NONE)
5071  {
5072  *response_filename = NULL;
5073  uves_free_image(response_curve);
5074  uves_free_propertylist(response_header);
5075  }
5076  return cpl_error_get_code();
5077 }
5078 
5079 
5080 /*----------------------------------------------------------------------------*/
5090 /*----------------------------------------------------------------------------*/
5091 cpl_error_code uves_load_lineintmon(const cpl_frameset *frames,
5092  const char **line_intmon_filename,
5093  cpl_table **line_intmon)
5094 {
5095  const char *tags[1] = {UVES_LINE_INTMON_TABLE};
5096 
5097  int number_of_tags = sizeof(tags) / sizeof(char *);
5098  int indx;
5099 
5100  /* Get filename */
5101  check( *line_intmon_filename = uves_find_frame(frames, tags, number_of_tags,
5102  &indx, NULL),
5103  "No line intensity table (%s) found in SOF", tags[0]);
5104 
5105  /* Load table */
5106  check( *line_intmon = cpl_table_load(*line_intmon_filename,
5107  UVES_LINE_INTMON_TABLE_EXTENSION,
5108  1), /* Mark identified
5109  invalid values? (1=yes) */
5110  "Error loading line reference table from extension %d of file '%s'",
5111  UVES_LINE_INTMON_TABLE_EXTENSION, *line_intmon_filename);
5112 
5113  check(( cpl_table_cast_column(*line_intmon, "WAVE", "Wave", CPL_TYPE_DOUBLE),
5114  cpl_table_erase_column(*line_intmon, "WAVE")),
5115  "Could not cast and rename column");
5116 
5117  /* Sort table by 'Wave' (ascending) */
5118  check( uves_sort_table_1(*line_intmon, "Wave", false), "Error sorting table");
5119 
5120  cleanup:
5121  if (cpl_error_get_code() != CPL_ERROR_NONE)
5122  {
5123  *line_intmon_filename = NULL;
5124  uves_free_table(line_intmon);
5125  }
5126  return cpl_error_get_code();
5127 }
5128 
5129 
5130 /*----------------------------------------------------------------------------*/
5142 /*----------------------------------------------------------------------------*/
5143 void
5144 uves_load_corvel(const cpl_frameset *frames,
5145  cpl_table **corvel,
5146  uves_propertylist **corvel_header,
5147  const char **corvel_filename)
5148 {
5149  const char *tags[1];
5150  int number_of_tags = sizeof(tags) / sizeof(char *);
5151  int indx;
5152  int extension;
5153 
5154  tags[0] = FLAMES_CORVEL_MASK;
5155 
5156  assure_nomsg( corvel != NULL, CPL_ERROR_NULL_INPUT );
5157  assure_nomsg( corvel_filename != NULL, CPL_ERROR_NULL_INPUT );
5158 
5159  /* Get filename */
5160  check( *corvel_filename = uves_find_frame(frames, tags, number_of_tags,
5161  &indx, NULL),
5162  "No velocity correction table (%s) found in SOF", tags[0]);
5163 
5164  /* Load table */
5165  extension = 1;
5166  check( *corvel = cpl_table_load(*corvel_filename,
5167  extension,
5168  1), /* Mark identified
5169  invalid values? (1=yes) */
5170  "Error loading line reference table from extension %d of file '%s'",
5171  extension, *corvel_filename);
5172 
5173  /* Load header */
5174  if (corvel_header != NULL)
5175  {
5176  extension = 0;
5177  check( *corvel_header = uves_propertylist_load(*corvel_filename,
5178  extension),
5179  "Could not load header from extension %d of file %s",
5180  extension, *corvel_filename);
5181 
5182  }
5183 
5184  cleanup:
5185  if (cpl_error_get_code() != CPL_ERROR_NONE)
5186  {
5187  *corvel_filename = NULL;
5188  uves_free_table(corvel);
5189  }
5190  return;
5191 }
5192 
5193 /*----------------------------------------------------------------------------*/
5209 /*----------------------------------------------------------------------------*/
5210 cpl_error_code
5211 uves_load_linerefertable(const cpl_frameset *frames,
5212  const char **line_refer_filename,
5213  cpl_table **line_refer, uves_propertylist **line_refer_header)
5214 {
5215  const char *tags[1] = {UVES_LINE_REFER_TABLE};
5216 
5217  int number_of_tags = sizeof(tags) / sizeof(char *);
5218  int indx;
5219 
5220  /* Get filename */
5221  check( *line_refer_filename = uves_find_frame(frames, tags, number_of_tags,
5222  &indx, NULL),
5223  "No line reference table (%s) found in SOF", tags[0]);
5224 
5225  /* Load table */
5226  check( *line_refer = cpl_table_load(*line_refer_filename,
5227  UVES_LINE_REFER_TABLE_EXTENSION,
5228  1), /* Mark identified
5229  invalid values? (1=yes) */
5230  "Error loading line reference table from extension %d of file '%s'",
5231  UVES_LINE_REFER_TABLE_EXTENSION, *line_refer_filename);
5232 
5233  /* Load header if requested */
5234  if (line_refer_header != NULL)
5235  {
5236  check( *line_refer_header = uves_propertylist_load(*line_refer_filename, 0),
5237  "Could not load header of line_refer table in '%s'", *line_refer_filename);
5238  }
5239 
5240  assure( uves_erase_invalid_table_rows(*line_refer, NULL) == 0, CPL_ERROR_ILLEGAL_INPUT,
5241  "Table in extension %d of file '%s' contains invalid rows",
5242  UVES_LINE_REFER_TABLE_EXTENSION, *line_refer_filename);
5243 
5244  check(( cpl_table_cast_column(*line_refer, "WAVE", "Wave", CPL_TYPE_DOUBLE),
5245  cpl_table_erase_column(*line_refer, "WAVE")),
5246  "Could not cast and rename column");
5247 
5248  /* Write uncertainties of wavelengths.
5249  The value 0.002 is finetuned/retro-fitted to get a chi_sq ~ 1 when
5250  using the new catalogue from
5251 
5252  M. T. Murphy, P. Tzanavaris, J. K. Webb, C. Lovis
5253  "Selection of ThAr lines for wavelength calibration of echelle
5254  spectra and implications for variations in the fine-structure constant",
5255  Submitted to MNRAS
5256  */
5257 
5258 #if 0
5259  check(( cpl_table_duplicate_column(*line_refer, "dWave", *line_refer, "Wave"),
5260  cpl_table_divide_scalar (*line_refer, "dWave", 300000*10)),
5261  "Error writing wavelength uncertainties");
5262 #else
5263  /* we should do this */
5264  check(( cpl_table_new_column(*line_refer, "dWave", CPL_TYPE_DOUBLE),
5265  cpl_table_fill_column_window(*line_refer,
5266  "dWave",
5267  0,
5268  cpl_table_get_nrow(*line_refer), 0.002)),
5269  "Error writing wavelength uncertainties");
5270 #endif
5271 
5272  /* Sort table by 'Wave' (ascending) */
5273  check( uves_sort_table_1(*line_refer, "Wave", false), "Error sorting table");
5274 
5275  cleanup:
5276  if (cpl_error_get_code() != CPL_ERROR_NONE) {
5277  *line_refer_filename = NULL;
5278  uves_free_table (line_refer);
5279  if (line_refer_header != NULL) uves_free_propertylist(line_refer_header);
5280  }
5281  return cpl_error_get_code();
5282 }
5283 
5284 /*----------------------------------------------------------------------------*/
5298 /*----------------------------------------------------------------------------*/
5299 cpl_error_code
5300 uves_load_flux_table(const cpl_frameset *frames, const char **flux_table_filename,
5301  cpl_table **flux_table)
5302 {
5303  const char *tags[1] = {UVES_FLUX_STD_TABLE};
5304 
5305  int number_of_tags = sizeof(tags) / sizeof(char *);
5306  int indx;
5307 
5308  /* Get filename */
5309  check( *flux_table_filename = uves_find_frame(frames, tags, number_of_tags,
5310  &indx, NULL),
5311  "No standard star flux table (%s) in SOF", tags[0]);
5312 
5313  /* Load table */
5314  check( *flux_table = cpl_table_load(*flux_table_filename,
5315  UVES_FLUX_STD_TABLE_EXTENSION,
5316  1), /* Mark identified
5317  invalid values? (1=yes) */
5318  "Error loading flux table from extension %d of file '%s'",
5319  UVES_FLUX_STD_TABLE_EXTENSION, *flux_table_filename);
5320 
5321  if (false)
5322  /* Don't do this, it will remove one std (LTT2415) from the table which has TYPE = NULL.
5323  Instead, set type to "NULL" (this is only used for messages)
5324  */
5325  {
5326  if (uves_erase_invalid_table_rows(*flux_table, NULL) != 0)
5327  {
5328  uves_msg_warning("Table in extension %d of file '%s' contains null values",
5329  UVES_FLUX_STD_TABLE_EXTENSION, *flux_table_filename);
5330  }
5331  }
5332  else
5333  {
5334  int i;
5335  for (i = 0; i < cpl_table_get_nrow(*flux_table); i++)
5336  {
5337  if (cpl_table_get_string(*flux_table, "TYPE", i) == NULL)
5338  {
5339  cpl_table_set_string(*flux_table, "TYPE", i, "NULL");
5340  }
5341  }
5342  }
5343 
5344 
5345  cleanup:
5346  if (cpl_error_get_code() != CPL_ERROR_NONE)
5347  {
5348  *flux_table_filename = NULL;
5349  uves_free_table(flux_table);
5350  }
5351  return cpl_error_get_code();
5352 }
5353 
5354 
5355 /*----------------------------------------------------------------------------*/
5369 /*----------------------------------------------------------------------------*/
5370 cpl_error_code
5371 uves_load_atmo_ext(const cpl_frameset *frames, const char **atmext_table_filename,
5372  cpl_table **atmext_table)
5373 {
5374  const char *tags[1] = {UVES_EXTCOEFF_TABLE};
5375 
5376  int number_of_tags = sizeof(tags) / sizeof(char *);
5377  int indx;
5378 
5379  /* Get filename */
5380  check( *atmext_table_filename = uves_find_frame(frames, tags, number_of_tags,
5381  &indx, NULL),
5382  "No atmospheric extinction table (%s) found in SOF", tags[0]);
5383 
5384  /* Load table */
5385  check( *atmext_table = cpl_table_load(*atmext_table_filename,
5386  UVES_EXTCOEFF_TABLE_EXTENSION,
5387  1), /* Mark identified
5388  invalid values? (1=yes) */
5389  "Error loading atmospheric extinction table from extension %d of file '%s'",
5390  UVES_EXTCOEFF_TABLE_EXTENSION, *atmext_table_filename);
5391 
5392  assure( uves_erase_invalid_table_rows(*atmext_table, NULL) == 0, CPL_ERROR_ILLEGAL_INPUT,
5393  "Table in extension %d of file '%s' contains invalid rows",
5394  UVES_EXTCOEFF_TABLE_EXTENSION, *atmext_table_filename);
5395 
5396  check( uves_sort_table_1(*atmext_table, "LAMBDA", false),
5397  "Error sorting table");
5398 
5399  /* Convert columns to double */
5400  check(( cpl_table_cast_column(*atmext_table, "LAMBDA", "LAMBDA_double", CPL_TYPE_DOUBLE),
5401  cpl_table_erase_column(*atmext_table, "LAMBDA"),
5402  cpl_table_name_column(*atmext_table, "LAMBDA_double", "LAMBDA")),
5403  "Could not cast column 'LAMBDA'");
5404 
5405  check(( cpl_table_cast_column(*atmext_table, "LA_SILLA", "LA_SILLA_double", CPL_TYPE_DOUBLE),
5406  cpl_table_erase_column(*atmext_table, "LA_SILLA"),
5407  cpl_table_name_column(*atmext_table, "LA_SILLA_double", "LA_SILLA")),
5408  "Could not cast column 'LA_SILLA'");
5409 
5410  cleanup:
5411  if (cpl_error_get_code() != CPL_ERROR_NONE)
5412  {
5413  *atmext_table_filename = NULL;
5414  uves_free_table(atmext_table);
5415  }
5416  return cpl_error_get_code();
5417 }
5418 /*----------------------------------------------------------------------------*/
5426 /*----------------------------------------------------------------------------*/
5427 char *
5428 uves_guess_order_table_filename(enum uves_chip chip)
5429 {
5430  return uves_local_filename("orderguesstable", chip, -1, -1);
5431 }
5432 
5433 /*----------------------------------------------------------------------------*/
5441 /*----------------------------------------------------------------------------*/
5442 char *
5443 uves_order_table_filename(enum uves_chip chip)
5444 {
5445  return uves_local_filename("ordertable", chip, -1, -1);
5446 }
5447 
5448 /*----------------------------------------------------------------------------*/
5455 /*----------------------------------------------------------------------------*/
5456 char *uves_ordef_filename(enum uves_chip chip)
5457 {
5458  return uves_local_filename("order_def", chip, -1, -1);
5459 }
5460 
5461 /*----------------------------------------------------------------------------*/
5469 /*----------------------------------------------------------------------------*/
5470 char *
5471 uves_masterdark_filename(enum uves_chip chip)
5472 {
5473  return uves_local_filename("masterdark", chip, -1, -1);
5474 }
5475 
5476 
5477 /*----------------------------------------------------------------------------*/
5483 /*----------------------------------------------------------------------------*/
5484 char *
5485 uves_flat_ratio_filename(enum uves_chip chip)
5486 {
5487  return uves_local_filename("ratio", chip, -1, -1);
5488 }
5489 
5490 /*----------------------------------------------------------------------------*/
5497 /*----------------------------------------------------------------------------*/
5498 char *uves_cd_align_filename(enum uves_chip chip)
5499 {
5500  return uves_local_filename("cd_align", chip, -1, -1);
5501 }
5502 
5503 /*----------------------------------------------------------------------------*/
5511 /*----------------------------------------------------------------------------*/
5512 char *
5513 uves_masterflat_filename(enum uves_chip chip)
5514 {
5515  return uves_local_filename("masterflat", chip, -1, -1);
5516 }
5517 /*----------------------------------------------------------------------------*/
5525 /*----------------------------------------------------------------------------*/
5526 char *
5527 uves_masterflat_bkg_filename(enum uves_chip chip)
5528 {
5529  return uves_local_filename("masterflat_bkg", chip, -1, -1);
5530 }
5531 
5532 /*----------------------------------------------------------------------------*/
5540 /*----------------------------------------------------------------------------*/
5541 char *
5542 uves_masterbias_filename(enum uves_chip chip)
5543 {
5544  return uves_local_filename("masterbias", chip, -1, -1);
5545 }
5546 
5547 /*----------------------------------------------------------------------------*/
5555 /*----------------------------------------------------------------------------*/
5556 char *
5557 uves_guess_line_table_filename(enum uves_chip chip)
5558 {
5559  return uves_local_filename("lineguesstable", chip, -1, -1);
5560 }
5561 /*----------------------------------------------------------------------------*/
5569 /*----------------------------------------------------------------------------*/
5570 char *
5571 uves_line_table_filename(enum uves_chip chip)
5572 {
5573  return uves_local_filename("linetable", chip, -1, -1);
5574 }
5575 
5576 /*----------------------------------------------------------------------------*/
5584 /*----------------------------------------------------------------------------*/
5585 char *
5586 uves_line_table_filename_paf(enum uves_chip chip)
5587 {
5588  return uves_local_filename("linetable_paf", chip, -1, -1);
5589 }
5590 
5591 /*----------------------------------------------------------------------------*/
5599 /*----------------------------------------------------------------------------*/
5600 char *
5601 uves_response_curve_filename(enum uves_chip chip)
5602 {
5603  return uves_local_filename("response", chip, -1, -1);
5604 }
5605 
5606 /*----------------------------------------------------------------------------*/
5614 /*----------------------------------------------------------------------------*/
5615 char *
5616 uves_response_curve_2d_filename(enum uves_chip chip)
5617 {
5618  return uves_local_filename("response_2d", chip, -1, -1);
5619 }
5620 
5621 /*----------------------------------------------------------------------------*/
5629 /*----------------------------------------------------------------------------*/
5630 char *
5631 uves_response_red_standard_filename(enum uves_chip chip)
5632 {
5633  return uves_local_filename("red_std", chip, -1, -1);
5634 }
5635 
5636 
5637 /*----------------------------------------------------------------------------*/
5645 /*----------------------------------------------------------------------------*/
5646 char *
5647 uves_response_red_noappend_standard_filename(enum uves_chip chip)
5648 {
5649  return uves_local_filename("red_nonmerged", chip, -1, -1);
5650 }
5651 
5652 /*----------------------------------------------------------------------------*/
5660 /*----------------------------------------------------------------------------*/
5661 char *
5662 uves_response_bkg_standard_filename(enum uves_chip chip)
5663 {
5664  return uves_local_filename("bkg_std", chip, -1, -1);
5665 }
5666 
5667 
5668 /*----------------------------------------------------------------------------*/
5676 /*----------------------------------------------------------------------------*/
5677 char *
5678 uves_order_extract_qc_standard_filename(enum uves_chip chip)
5679 {
5680  return uves_local_filename("order_extract_qc", chip, -1, -1);
5681 }
5682 
5683 /*----------------------------------------------------------------------------*/
5691 /*----------------------------------------------------------------------------*/
5692 char *
5693 uves_response_efficiency_filename(enum uves_chip chip)
5694 {
5695  return uves_local_filename("efficiency", chip, -1, -1);
5696 }
5697 
5698 /*----------------------------------------------------------------------------*/
5706 /*----------------------------------------------------------------------------*/
5707 
5708 char *
5709 uves_scired_red_2d_science_filename(enum uves_chip chip)
5710 {
5711  return uves_local_filename("red_2d_science", chip, -1, -1);
5712 }
5713 
5721 /*----------------------------------------------------------------------------*/
5722 
5723 
5724 
5725 char *
5726 uves_scired_red_science_filename(enum uves_chip chip)
5727 {
5728  return uves_local_filename("red_science", chip, -1, -1);
5729 }
5737 /*----------------------------------------------------------------------------*/
5738 
5739 
5740 
5741 char *
5742 uves_scired_red_noappend_science_filename(enum uves_chip chip)
5743 {
5744  return uves_local_filename("red_nonmerged_science", chip, -1, -1);
5745 }
5746 /*----------------------------------------------------------------------------*/
5754 /*----------------------------------------------------------------------------*/
5755 char *
5756 uves_scired_red_error_filename(enum uves_chip chip)
5757 {
5758  return uves_local_filename("error_red_science", chip, -1, -1);
5759 }
5760 
5761 /*----------------------------------------------------------------------------*/
5769 /*----------------------------------------------------------------------------*/
5770 char *
5771 uves_scired_red_noappend_error_filename(enum uves_chip chip)
5772 {
5773  return uves_local_filename("error_red_nonmerged_science", chip, -1, -1);
5774 }
5775 
5776 /*----------------------------------------------------------------------------*/
5784 /*----------------------------------------------------------------------------*/
5785 char *
5786 uves_scired_red_2d_error_filename(enum uves_chip chip)
5787 {
5788  return uves_local_filename("error_2d_science", chip, -1, -1);
5789 }
5790 
5791 
5792 /*----------------------------------------------------------------------------*/
5800 /*----------------------------------------------------------------------------*/
5801 char *
5802 uves_scired_fluxcal_science_filename(enum uves_chip chip)
5803 {
5804  return uves_local_filename("fluxcal_science", chip, -1, -1);
5805 }
5806 
5807 
5808 /*----------------------------------------------------------------------------*/
5816 /*----------------------------------------------------------------------------*/
5817 char *
5818 uves_scired_fluxcal_science_noappend_filename(enum uves_chip chip)
5819 {
5820  return uves_local_filename("fluxcal_nonmerged_science", chip, -1, -1);
5821 }
5822 /*----------------------------------------------------------------------------*/
5830 /*----------------------------------------------------------------------------*/
5831 char *
5832 uves_scired_fluxcal_error_filename(enum uves_chip chip)
5833 {
5834  return uves_local_filename("fluxcal_error_science", chip, -1, -1);
5835 }
5836 
5837 
5838 /*----------------------------------------------------------------------------*/
5846 /*----------------------------------------------------------------------------*/
5847 char *
5848 uves_scired_fluxcal_error_noappend_filename(enum uves_chip chip)
5849 {
5850  return uves_local_filename("fluxcal_error_nonmerged_science", chip, -1, -1);
5851 }
5852 
5853 
5854 
5862 /*----------------------------------------------------------------------------*/
5863 char *
5864 uves_scired_fluxcal_science_2d_filename(enum uves_chip chip)
5865 {
5866  return uves_local_filename("fluxcal_2d_science", chip, -1, -1);
5867 }
5868 /*----------------------------------------------------------------------------*/
5876 /*----------------------------------------------------------------------------*/
5877 char *
5878 uves_scired_fluxcal_error_2d_filename(enum uves_chip chip)
5879 {
5880  return uves_local_filename("fluxcal_error_2d_science", chip, -1, -1);
5881 }
5882 /*----------------------------------------------------------------------------*/
5890 /*----------------------------------------------------------------------------*/
5891 char *
5892 uves_scired_ff_variance_filename(enum uves_chip chip)
5893 {
5894  return uves_local_filename("variance_ff_science", chip, -1, -1);
5895 }
5896 
5897 /*----------------------------------------------------------------------------*/
5905 /*----------------------------------------------------------------------------*/
5906 char *
5907 uves_scired_ff_variance_2d_filename(enum uves_chip chip)
5908 {
5909  return uves_local_filename("variance_ff_2d_science", chip, -1, -1);
5910 }
5911 
5912 /*----------------------------------------------------------------------------*/
5919 /*----------------------------------------------------------------------------*/
5920 char *
5921 uves_scired_merged_2d_science_filename(enum uves_chip chip)
5922 {
5923  return uves_local_filename("merged_2d_science", chip, -1, -1);
5924 }
5925 
5933 /*----------------------------------------------------------------------------*/
5934 char *
5935 uves_scired_merged_science_filename(enum uves_chip chip)
5936 {
5937  return uves_local_filename("merged_science", chip, -1, -1);
5938 }
5939 /*----------------------------------------------------------------------------*/
5947 /*----------------------------------------------------------------------------*/
5948 char *
5949 uves_scired_merged_sky_filename(enum uves_chip chip)
5950 {
5951  return uves_local_filename("merged_sky", chip, -1, -1);
5952 }
5953 
5954 /*----------------------------------------------------------------------------*/
5962 /*----------------------------------------------------------------------------*/
5963 char *
5964 uves_scired_background_filename(enum uves_chip chip)
5965 {
5966  return uves_local_filename("background", chip, -1, -1);
5967 }
5968 
5969 /*----------------------------------------------------------------------------*/
5977 /*----------------------------------------------------------------------------*/
5978 char *
5979 uves_scired_resampled_filename(enum uves_chip chip)
5980 {
5981  return uves_local_filename("resampled_science", chip, -1, -1);
5982 }
5983 
5984 
5985 
5986 /*----------------------------------------------------------------------------*/
5994 /*----------------------------------------------------------------------------*/
5995 char *
5996 uves_scired_resampled_2d_filename(enum uves_chip chip)
5997 {
5998  return uves_local_filename("resampled_2d_science", chip, -1, -1);
5999 }
6000 
6001 
6002 /*----------------------------------------------------------------------------*/
6010 /*----------------------------------------------------------------------------*/
6011 char *
6012 uves_scired_resampledmf_filename(enum uves_chip chip)
6013 {
6014  return uves_local_filename("resampled_mflat", chip, -1, -1);
6015 }
6016 
6017 /*----------------------------------------------------------------------------*/
6026 /*----------------------------------------------------------------------------*/
6027 char *
6028 uves_scired_rebinned_filename(enum uves_chip chip)
6029 {
6030  return uves_local_filename("resampled_ff_science", chip, -1, -1);
6031 }
6032 
6033 /*----------------------------------------------------------------------------*/
6042 /*----------------------------------------------------------------------------*/
6043 char *
6044 uves_scired_rebinned_error_filename(enum uves_chip chip)
6045 {
6046  return uves_local_filename("resampled_error_ff_science", chip, -1, -1);
6047 }
6048 
6049 
6058 /*----------------------------------------------------------------------------*/
6059 char *
6060 uves_scired_rebinned_2d_filename(enum uves_chip chip)
6061 {
6062  return uves_local_filename("resampled_ff_2d_science", chip, -1, -1);
6063 }
6064 
6073 /*----------------------------------------------------------------------------*/
6074 char *
6075 uves_scired_rebinned_2d_error_filename(enum uves_chip chip)
6076 {
6077  return uves_local_filename("resampled_error_ff_2d_science", chip, -1, -1);
6078 }
6079 /*----------------------------------------------------------------------------*/
6087 /*----------------------------------------------------------------------------*/
6088 char *
6089 uves_scired_ordertrace_filename(enum uves_chip chip)
6090 {
6091  return uves_local_filename("ordertrace", chip, -1, -1);
6092 }
6093 
6094 /*----------------------------------------------------------------------------*/
6102 /*----------------------------------------------------------------------------*/
6103 char *
6104 uves_scired_crmask_filename(enum uves_chip chip)
6105 {
6106  return uves_local_filename("cr_mask", chip, -1, -1);
6107 }
6108 
6109 /*----------------------------------------------------------------------------*/
6117 /*----------------------------------------------------------------------------*/
6118 char *
6119 uves_scired_wmap_filename(enum uves_chip chip)
6120 {
6121  return uves_local_filename("wave_map", chip, -1, -1);
6122 }
6123 
6124 /*----------------------------------------------------------------------------*/
6132 /*----------------------------------------------------------------------------*/
6133 char *uves_scired_ext2d_filename(enum uves_chip chip)
6134 {
6135  return uves_local_filename("ext_2d_science", chip, -1, -1);
6136 }
6137 
6138 /*----------------------------------------------------------------------------*/
6146 /*----------------------------------------------------------------------------*/
6147 char *uves_scired_ff2d_filename(enum uves_chip chip)
6148 {
6149  return uves_local_filename("ff_2d_science", chip, -1, -1);
6150 }
6151 
6152 /*----------------------------------------------------------------------------*/
6173 /*----------------------------------------------------------------------------*/
6174 char *
6175 uves_local_filename(const char *prefix, enum uves_chip chip, int trace, int window)
6176 {
6177  char *result = NULL;
6178  const char *chip_string;
6179  const char *suffix = ".fits"; /* Always */
6180  char *t = NULL;
6181  char *w = NULL;
6182 
6183  assure( (trace < 0 && window < 0) || /* Empty suffix */
6184  (trace < 0 && window > 0) || /* Window only suffix */
6185  (trace >= 0 && window > 0), /* Trace & window suffix */
6186  CPL_ERROR_ILLEGAL_INPUT, "Illegal trace and window numbers: (%d, %d)",
6187  trace, window);
6188 
6189  /* Chip */
6190  chip_string = uves_chip_tostring_lower(chip);
6191 
6192  /* Trace and window number (possibly empty string) */
6193  check(( t = int_to_string(trace),
6194  w = int_to_string(window)),
6195  "Error creating substrings");
6196 
6197 /* old code:
6198  result = cpl_calloc(strlen(prefix) + 1 +
6199  strlen(chip_string) + strlen(t) + strlen(w) + strlen(suffix) + 1,
6200  sizeof(char));
6201 
6202  assure_mem( result );
6203 
6204  strcpy(result, prefix);
6205  strcat(result, "_");
6206  strcat(result, chip_string);
6207  strcat(result, t);
6208  strcat(result, w);
6209  strcat(result, suffix);
6210 */
6211  result = uves_sprintf("%s_%s%s%s%s", prefix, chip_string, t, w, suffix);
6212  assure_mem( result );
6213 
6214  cleanup:
6215  cpl_free(t);
6216  cpl_free(w);
6217  if (cpl_error_get_code() != CPL_ERROR_NONE)
6218  {
6219  cpl_free(result); result = NULL;
6220  }
6221  return result;
6222 }
6223 
6224 /*----------------------------------------------------------------------------*/
6235 /*----------------------------------------------------------------------------*/
6236 static char *
6237 int_to_string(int i)
6238 {
6239  char *result = NULL;
6240 
6241  assure( -1 <= i, CPL_ERROR_ILLEGAL_INPUT, "Illegal number (%d)", i);
6242 
6243  if (i == -1)
6244  {
6245  /* Empty string */
6246  result = cpl_calloc(1, sizeof(char));
6247  assure_mem( result );
6248  }
6249  else
6250  {
6251  result = uves_sprintf("_%d", i);
6252  }
6253 
6254  cleanup:
6255  if (cpl_error_get_code() != CPL_ERROR_NONE){
6256  cpl_free(result); result = NULL;
6257  }
6258  return result;
6259 }
6260 
6261 
6262 /*----------------------------------------------------------------------------*/
6272 /*----------------------------------------------------------------------------*/
6273 
6274 cpl_image*
6275 uves_vector_to_image(const cpl_vector* vector,cpl_type type)
6276 {
6277  int i=0;
6278  cpl_image* image=NULL;
6279  int size=0;
6280  const double* pv=NULL;
6281  int* pi=NULL;
6282  float* pf=NULL;
6283  double* pd=NULL;
6284 
6285 
6286  size=cpl_vector_get_size(vector);
6287  image=cpl_image_new(size,1,type);
6288  pv=cpl_vector_get_data_const(vector);
6289  if(type == CPL_TYPE_INT) {
6290  pi=cpl_image_get_data_int(image);
6291  for(i=0;i<size;i++) {
6292  pi[i]=pv[i];
6293  }
6294  } else if (type == CPL_TYPE_FLOAT) {
6295  pf=cpl_image_get_data_float(image);
6296  for(i=0;i<size;i++) {
6297  pf[i]=pv[i];
6298  }
6299  } else if (type == CPL_TYPE_DOUBLE) {
6300  pd=cpl_image_get_data_double(image);
6301  for(i=0;i<size;i++) {
6302  pd[i]=pv[i];
6303  }
6304  } else {
6305  assure( false, CPL_ERROR_INVALID_TYPE,
6306  "No CPL type to represent BITPIX = %d", type);
6307  }
6308 
6309  cleanup:
6310  if (cpl_error_get_code() != CPL_ERROR_NONE){
6311  uves_free_image(&image);
6312  }
6313 
6314  return image;
6315 
6316 }
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.