FORS Pipeline Reference Manual  4.12.5
fors_qc.c
1 /* $Id: fors_qc.c,v 1.10 2010-09-14 07:49:30 cizzo Exp $
2  *
3  * This file is part of the FORS Library
4  * Copyright (C) 2002-2010 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /*
22  * $Author: cizzo $
23  * $Date: 2010-09-14 07:49:30 $
24  * $Revision: 1.10 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <ctype.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <math.h>
38 
39 #include <cpl.h>
40 #include <fors_utils.h>
41 #include <fors_paf.h>
42 #include <fors_dfs.h>
43 #include <fors_qc.h>
44 
45 #define DICT_LINE_LENGTH (80)
46 #define MAX_PAF_NAME_LENGTH (80)
47 #define PAF_ROOT_NAME "qc"
48 
56 const char *const fors_qc_dic_version = "2.0";
57 
58 static ForsPAF *pafFile = NULL;
59 static int pafIndex = 0;
60 
61 
77 cpl_error_code fors_qc_start_group(cpl_propertylist *header,
78  const char *qcdic_version,
79  const char *instrument)
80 {
81  char pafName[MAX_PAF_NAME_LENGTH];
82 
83  if (pafFile)
84  return cpl_error_set("fors_qc_start_group", CPL_ERROR_FILE_ALREADY_OPEN);
85 
86  sprintf(pafName, "%s%.4d.paf", PAF_ROOT_NAME, pafIndex);
87 
88  if (!(pafFile = newForsPAF(pafName, "QC1 parameters", NULL, NULL)))
89  return cpl_error_set("fors_qc_start_group", CPL_ERROR_FILE_NOT_CREATED);
90 
92  "QC.DID", qcdic_version, "QC1 dictionary",
93  instrument);
94 
95  return CPL_ERROR_NONE;
96 
97 }
98 
99 #undef cleanup
100 #define cleanup \
101 do { \
102  cpl_propertylist_delete(header); \
103 } while(0)
104 
115 void fors_qc_write_group_heading(const cpl_frame *raw_frame,
116  const char *pro_catg,
117  const char *instrument)
118 {
119  cpl_propertylist *header = NULL;
120  assure( raw_frame != NULL, return, NULL );
121  assure( cpl_frame_get_filename(raw_frame) != NULL, return, NULL );
122 
123  header = cpl_propertylist_load(cpl_frame_get_filename(raw_frame), 0);
124  assure( !cpl_error_get_code(), return, "Could not load %s header",
125  cpl_frame_get_filename(raw_frame));
126 
127  fors_qc_write_string("PRO.CATG", pro_catg,
128  "Product category", instrument);
129  assure( !cpl_error_get_code(), return, "Cannot write product category to "
130  "QC log file");
131 
132  fors_qc_keyword_to_paf(header, "ESO DPR TYPE", NULL,
133  "DPR type", instrument);
134  assure( !cpl_error_get_code(), return, "Missing keyword DPR TYPE in raw "
135  "frame header");
136 
137  fors_qc_keyword_to_paf(header, "ESO TPL ID", NULL,
138  "Template", instrument);
139  assure( !cpl_error_get_code(), return, "Missing keyword TPL ID in raw "
140  "frame header");
141 
142  if (cpl_propertylist_has(header, "ESO INS FILT1 NAME")) {
143  fors_qc_keyword_to_paf(header, "ESO INS FILT1 NAME", NULL,
144  "Filter name", instrument);
145  assure( !cpl_error_get_code(), return, "Failed to write ESO INS FILT1 NAME");
146  }
147 
148  fors_qc_keyword_to_paf(header, "ESO INS COLL NAME", NULL,
149  "Collimator name", instrument);
150  assure( !cpl_error_get_code(), return, "Missing keyword INS COLL NAME in raw "
151  "frame header");
152 
153  fors_qc_keyword_to_paf(header, "ESO DET CHIP1 ID", NULL,
154  "Chip identifier", instrument);
155  assure( !cpl_error_get_code(), return, "Missing keyword DET CHIP1 ID in raw "
156  "frame header");
157 
158  fors_qc_keyword_to_paf(header, "ESO DET WIN1 BINX", NULL,
159  "Binning factor along X", instrument);
160  assure( !cpl_error_get_code(), return, "Missing keyword ESO DET WIN1 BINX "
161  "in raw frame header");
162 
163  fors_qc_keyword_to_paf(header, "ESO DET WIN1 BINY", NULL,
164  "Binning factor along Y", instrument);
165  assure( !cpl_error_get_code(), return, "Missing keyword ESO DET WIN1 BINY "
166  "in raw frame header");
167 
168  fors_qc_keyword_to_paf(header, "ARCFILE", NULL,
169  "Archive name of input data",
170  instrument);
171  assure( !cpl_error_get_code(), return, "Missing keyword ARCFILE in raw "
172  "frame header");
173 
174  {
175  char *pipefile = dfs_generate_filename(pro_catg);
176  fors_qc_write_string("PIPEFILE", pipefile,
177  "Pipeline product name", instrument);
178  cpl_free(pipefile); pipefile = NULL;
179  assure( !cpl_error_get_code(), return, "Cannot write PIPEFILE to QC log file");
180  }
181 
182  cleanup;
183  return;
184 }
185 
186 
187 
200 cpl_error_code fors_qc_end_group(void)
201 {
202 
203  if (!pafFile)
204  return cpl_error_set("fors_qc_end_group", CPL_ERROR_DATA_NOT_FOUND);
205 
206  if (!forsPAFIsEmpty(pafFile)) {
207  forsPAFWrite(pafFile);
208  pafIndex++;
209  }
210 
211  deleteForsPAF(pafFile);
212  pafFile = NULL;
213 
214  return CPL_ERROR_NONE;
215 
216 }
217 
218 
235 cpl_error_code fors_qc_write_string(const char *name, const char *value,
236  const char *comment, const char *instrument)
237 {
238 
239  int status;
240  int length = strlen(instrument) + 3;
241  char *allComment;
242 
243 
244  if (comment == NULL || name == NULL || instrument == NULL)
245  return cpl_error_set("fors_qc_write_string", CPL_ERROR_NULL_INPUT);
246 
247  length += strlen(comment) + 1;
248 
249  allComment = cpl_malloc(length * sizeof(char));
250 
251  sprintf(allComment, "%s [%s]", comment, instrument);
252 
253  status = forsPAFAppendString(pafFile, name, value, allComment);
254 
255  cpl_free(allComment);
256 
257  if (status)
258  cpl_msg_error("fors_qc_write_string",
259  "Cannot write parameter %s to QC1 PAF", name);
260 
261  cpl_msg_debug(cpl_func, "%s [%s] = '%s'", comment, name, value);
262 
263  return CPL_ERROR_NONE;
264 
265 }
266 
267 cpl_error_code fors_qc_write_string_chat(const char *name, const char *value,
268  const char *comment, const char *instrument)
269 {
270 
271  int status;
272  int length = strlen(instrument) + 3;
273  char *allComment;
274 
275 
276  if (comment == NULL || name == NULL || instrument == NULL)
277  return cpl_error_set("fors_qc_write_string_chat", CPL_ERROR_NULL_INPUT);
278 
279  length += strlen(comment) + 1;
280 
281  allComment = cpl_malloc(length * sizeof(char));
282 
283  sprintf(allComment, "%s [%s]", comment, instrument);
284 
285  status = forsPAFAppendString(pafFile, name, value, allComment);
286 
287  cpl_free(allComment);
288 
289  if (status)
290  cpl_msg_error("fors_qc_write_string_chat",
291  "Cannot write parameter %s to QC1 PAF", name);
292 
293  cpl_msg_info(cpl_func, "%s [%s] = '%s'", comment, name, value);
294 
295  return CPL_ERROR_NONE;
296 
297 }
298 
299 
321 cpl_error_code fors_qc_write_double(const char *name, double value,
322  const char *unit, const char *comment,
323  const char *instrument)
324 {
325 
326  cpl_error_code status;
327  int length = strlen(instrument) + 3;
328  char *allComment;
329 
330 
331  if (comment == NULL || name == NULL || instrument == NULL)
332  return cpl_error_set("fors_qc_write_double", CPL_ERROR_NULL_INPUT);
333 
334  length += strlen(comment) + 1;
335 
336  if (unit)
337  length += strlen(unit) + 3;
338 
339  allComment = cpl_malloc(length * sizeof(char));
340 
341  if (unit)
342  sprintf(allComment, "%s (%s) [%s]", comment, unit, instrument);
343  else
344  sprintf(allComment, "%s [%s]", comment, instrument);
345 
346  status = forsPAFAppendDouble(pafFile, name, value, allComment);
347 
348  cpl_free(allComment);
349 
350  if (status)
351  cpl_msg_error("fors_qc_write_double",
352  "Cannot write parameter %s to QC1 PAF", name);
353 
354  cpl_msg_info(cpl_func, "%s [%s] = %f %s",
355  comment, name, value, (unit != NULL) ? unit : "");
356 
357  return CPL_ERROR_NONE;
358 
359 }
360 
361 
362 cpl_error_code fors_qc_write_int(const char *name, int value, const char *unit,
363  const char *comment, const char *instrument)
364 {
365 
366  cpl_error_code status;
367  int length = strlen(instrument) + 3;
368  char *allComment;
369 
370 
371  if (comment == NULL || name == NULL || instrument == NULL)
372  return cpl_error_set("fors_qc_write_int", CPL_ERROR_NULL_INPUT);
373 
374  length += strlen(comment) + 1;
375 
376  if (unit)
377  length += strlen(unit) + 3;
378 
379  allComment = cpl_malloc(length * sizeof(char));
380 
381  if (unit)
382  sprintf(allComment, "%s (%s) [%s]", comment, unit, instrument);
383  else
384  sprintf(allComment, "%s [%s]", comment, instrument);
385 
386  status = forsPAFAppendInt(pafFile, name, value, allComment);
387 
388  cpl_free(allComment);
389 
390  if (status)
391  cpl_msg_error("fors_qc_write_int",
392  "Cannot write parameter %s to QC1 PAF", name);
393 
394  cpl_msg_info(cpl_func, "%s [%s] = %d %s",
395  comment, name, value, (unit != NULL) ? unit : "");
396 
397  return CPL_ERROR_NONE;
398 
399 }
400 
401 
425 cpl_error_code fors_qc_keyword_to_paf(cpl_propertylist *header,
426  const char *name, const char *unit,
427  const char *comment,
428  const char *instrument)
429 {
430 
431  const char func[] = "fors_qc_keyword_to_paf";
432 
433  char *keyName;
434  char *keep;
435  char *pos;
436  int ivalue;
437  float fvalue;
438  double dvalue;
439  char *svalue = NULL;
440  int status;
441  int i;
442 
443 
444  if (header == NULL) {
445  cpl_msg_error(func, "Empty header");
446  return cpl_error_set(func, CPL_ERROR_NULL_INPUT);
447  }
448 
449  if (!cpl_propertylist_has(header, name)) {
450  cpl_msg_error(func, "Keyword %s not found", name);
451  return cpl_error_set(func, CPL_ERROR_DATA_NOT_FOUND);
452  }
453 
454  switch (cpl_propertylist_get_type(header, name)) {
455  case CPL_TYPE_INT :
456  ivalue = cpl_propertylist_get_int(header, name);
457  break;
458  case CPL_TYPE_FLOAT :
459  fvalue = cpl_propertylist_get_float(header, name);
460  break;
461  case CPL_TYPE_DOUBLE :
462  dvalue = cpl_propertylist_get_double(header, name);
463  break;
464  case CPL_TYPE_STRING :
465  svalue = (char *)cpl_propertylist_get_string(header, name);
466  break;
467  default :
468  cpl_msg_error(func, "Unsupported keyword type");
469  return cpl_error_set(func, CPL_ERROR_INVALID_TYPE);
470  }
471 
472 
473  /*
474  * Construct entry name for PAF
475  */
476 
477  keep = keyName = cpl_strdup(name);
478 
479  pos = strstr(keyName, "ESO ");
480 
481  if (pos == keyName)
482  keyName += 4;
483 
484  for (i = 0; keyName[i] != '\0'; i++)
485  if (keyName[i] == ' ')
486  keyName[i] = '.';
487 
488  /*
489  * Now write entry to PAF object.
490  */
491 
492  switch (cpl_propertylist_get_type(header, name)) {
493  case CPL_TYPE_INT :
494  status = fors_qc_write_int(keyName, ivalue, unit, comment, instrument);
495  break;
496  case CPL_TYPE_FLOAT :
497  dvalue = fvalue;
498  case CPL_TYPE_DOUBLE :
499  status = fors_qc_write_double(keyName, dvalue, unit, comment, instrument);
500  break;
501  default : /* CPL_TYPE_STRING */
502  status = fors_qc_write_string(keyName, svalue, comment, instrument);
503  }
504 
505  if (status)
506  cpl_msg_error(func, "Could not copy keyword value to QC1 PAF!");
507 
508  cpl_free(keep);
509 
510  return status;
511 
512 }
513 
535 cpl_error_code fors_qc_write_qc_string(cpl_propertylist *header,
536  const char *name, const char *value,
537  const char *comment,
538  const char *instrument)
539 {
540  const char func[] = "fors_qc_write_qc_string";
541 
542  char *header_name;
543  int i;
544 
545  if (strcmp("QC.DID", name)) {
546  if (fors_qc_write_string_chat(name, value, comment, instrument)) {
547  cpl_error_set_where(func);
548  return cpl_error_get_code();
549  }
550  }
551  else {
552  if (fors_qc_write_string(name, value, comment, instrument)) {
553  cpl_error_set_where(func);
554  return cpl_error_get_code();
555  }
556  }
557 
558  header_name = cpl_malloc((strlen(name) + 6) * sizeof(char *));
559 
560  strcpy(header_name, "ESO ");
561  strcat(header_name, name);
562 
563  for (i = 0; header_name[i] != '\0'; i++)
564  if (header_name[i] == '.')
565  header_name[i] = ' ';
566 
567  if (cpl_propertylist_update_string(header, header_name, value)) {
568  cpl_free(header_name);
569  cpl_error_set_where(func);
570  return cpl_error_get_code();
571  }
572 
573  cpl_propertylist_set_comment(header, header_name, comment);
574 
575  cpl_free(header_name);
576 
577  return CPL_ERROR_NONE;
578 }
579 
604 cpl_error_code fors_qc_write_qc_double(cpl_propertylist *header, double value,
605  const char *name, const char *unit,
606  const char *comment,
607  const char *instrument)
608 {
609 
610  const char func[] = "fors_qc_write_qc_double";
611 
612  char *header_name;
613  int i;
614 
615 
616  if (fors_qc_write_double(name, value, unit, comment, instrument)) {
617  cpl_error_set_where(func);
618  return cpl_error_get_code();
619  }
620 
621  header_name = cpl_malloc((strlen(name) + 6) * sizeof(char *));
622 
623  strcpy(header_name, "ESO ");
624  strcat(header_name, name);
625 
626  for (i = 0; header_name[i] != '\0'; i++)
627  if (header_name[i] == '.')
628  header_name[i] = ' ';
629 
630  if (cpl_propertylist_update_double(header, header_name, value)) {
631  cpl_free(header_name);
632  cpl_error_set_where(func);
633  return cpl_error_get_code();
634  }
635 
636  cpl_propertylist_set_comment(header, header_name, comment);
637 
638  cpl_free(header_name);
639 
640  return CPL_ERROR_NONE;
641 
642 }
643 
644 
645 cpl_error_code fors_qc_write_qc_int(cpl_propertylist *header, int value,
646  const char *name, const char *unit,
647  const char *comment,
648  const char *instrument)
649 {
650 
651  const char func[] = "fors_qc_write_qc_int";
652 
653  char *header_name;
654  int i;
655 
656 
657  if (fors_qc_write_int(name, value, unit, comment, instrument)) {
658  cpl_error_set_where(func);
659  return cpl_error_get_code();
660  }
661 
662  header_name = cpl_malloc((strlen(name) + 6) * sizeof(char *));
663 
664  strcpy(header_name, "ESO ");
665  strcat(header_name, name);
666 
667  for (i = 0; header_name[i] != '\0'; i++)
668  if (header_name[i] == '.')
669  header_name[i] = ' ';
670 
671  if (cpl_propertylist_update_int(header, header_name, value)) {
672  cpl_free(header_name);
673  cpl_error_set_where(func);
674  return cpl_error_get_code();
675  }
676 
677  cpl_propertylist_set_comment(header, header_name, comment);
678 
679  cpl_free(header_name);
680 
681  return CPL_ERROR_NONE;
682 
683 }
684 
685 /*
686  * @brief
687  * Write an integer value to the active QC1 PAF object and to a header.
688  *
689  * @return @c CPL_ERROR_NONE on success
690  *
691  * @param filnam Name of existing FITS file.
692  * @param value Value to write.
693  * @param name QC1 PAF entry name.
694  * @param unit Optional unit to be associated to value.
695  * @param comment Optional comment to be associated to value.
696  *
697  * @doc
698  * This function writes the header entries directly to the header
699  * of the FITS file written to disk, using the qfits_replace_card() call.
700  * An entry with the specified @em name is written to the current QC1 PAF
701  * object. From the entry @em name, the name of the QC keyword that
702  * should be written to header is derived prepending the string "ESO "
703  * and replacing all '.' with a blank (e.g., "QC.BIAS.MASTER.MEAN"
704  * becomes "ESO QC BIAS MASTER MEAN"). Finally, the new keyword
705  * is written to the header. Note that before calling this funtion
706  * a QC1 PAF object must be created with a call to fors_qc_start_group().
707  */
708 
709 /*
710 cpl_error_code fors_qc_write_qc_int(char *filnam, int value, const char *name,
711  const char *unit, const char *comment,
712  const char *instrument)
713 {
714 
715  const char func[] = "fors_qc_write_qc_int";
716 
717  char line[81];
718  char val[81];
719  char *descName;
720  int i;
721 
722 
723  if (fors_qc_write_int(name, value, unit, comment, instrument)) {
724  cpl_msg_error(func, "Could not copy value to QC1 PAF!");
725  cpl_error_set_where(func);
726  return cpl_error_get_code();
727  }
728 
729  descName = cpl_malloc((strlen(name) + 15) * sizeof(char *));
730 
731  strcpy(descName, "HIERARCH ESO ");
732  strcat(descName, name);
733 
734  for (i = 0; descName[i] != '\0'; i++)
735  if (descName[i] == '.')
736  descName[i] = ' ';
737 
738  sprintf(val, "%d", value);
739  keytuple2str(line, descName, val, (char *)comment);
740  qfits_replace_card(filnam, descName, line);
741 
742  cpl_free(descName);
743 
744  return CPL_ERROR_NONE;
745 
746 }
747 
748 
749 cpl_error_code fors_qc_write_qc_double(char *filnam, double value,
750  const char *name, const char *unit,
751  const char *comment,
752  const char *instrument)
753 {
754 
755  const char func[] = "fors_qc_write_qc_double";
756 
757  char line[81];
758  char val[81];
759  char *descName;
760  int i;
761 
762 
763  if (fors_qc_write_double(name, value, unit, comment, instrument)) {
764  cpl_msg_error(func, "Could not copy value to QC1 PAF!");
765  cpl_error_set_where(func);
766  return cpl_error_get_code();
767  }
768 
769  descName = cpl_malloc((strlen(name) + 15) * sizeof(char *));
770 
771  strcpy(descName, "HIERARCH ESO ");
772  strcat(descName, name);
773 
774  for (i = 0; descName[i] != '\0'; i++)
775  if (descName[i] == '.')
776  descName[i] = ' ';
777 
778  sprintf(val, "%1.6e", value);
779  keytuple2str(line, descName, val, (char *)comment);
780  qfits_replace_card(filnam, descName, line);
781 
782  cpl_free(descName);
783 
784  return CPL_ERROR_NONE;
785 
786 }
787 
788 */
789 
int forsPAFAppendInt(ForsPAF *paf, const char *name, int value, const char *comment)
Append a integer value to a PAF object.
Definition: fors_paf.c:729
cpl_error_code fors_qc_write_qc_string(cpl_propertylist *header, const char *name, const char *value, const char *comment, const char *instrument)
Write a string value to the active QC1 PAF object and to a header.
Definition: fors_qc.c:535
cpl_error_code fors_qc_write_double(const char *name, double value, const char *unit, const char *comment, const char *instrument)
Add double parameter to current QC1 group.
Definition: fors_qc.c:321
int forsPAFIsEmpty(const ForsPAF *paf)
Check whether a PAF object is empty.
Definition: fors_paf.c:594
void deleteForsPAF(ForsPAF *paf)
Destroy a PAF object.
Definition: fors_paf.c:511
cpl_error_code fors_qc_write_qc_double(cpl_propertylist *header, double value, const char *name, const char *unit, const char *comment, const char *instrument)
Write an integer value to the active QC1 PAF object and to a header.
Definition: fors_qc.c:604
cpl_error_code fors_qc_keyword_to_paf(cpl_propertylist *header, const char *name, const char *unit, const char *comment, const char *instrument)
Copy a keyword value to the currently active QC1 PAF object.
Definition: fors_qc.c:425
cpl_error_code fors_qc_start_group(cpl_propertylist *header, const char *qcdic_version, const char *instrument)
Initiate a new QC1 group.
Definition: fors_qc.c:77
#define assure(EXPR)
Definition: list.c:101
cpl_error_code fors_qc_write_string(const char *name, const char *value, const char *comment, const char *instrument)
Add string parameter to current QC1 group.
Definition: fors_qc.c:235
int forsPAFAppendDouble(ForsPAF *paf, const char *name, double value, const char *comment)
Append a double value to a PAF object.
Definition: fors_paf.c:764
cpl_error_code fors_qc_end_group(void)
Close current QC1 PAF file.
Definition: fors_qc.c:200
int forsPAFWrite(ForsPAF *paf)
Write a PAF object to a disk file.
Definition: fors_paf.c:834
void fors_qc_write_group_heading(const cpl_frame *raw_frame, const char *pro_catg, const char *instrument)
Initiate a new QC1 group and log basic QC.
Definition: fors_qc.c:115
int forsPAFAppendString(ForsPAF *paf, const char *name, const char *value, const char *comment)
Append a string value to a PAF object.
Definition: fors_paf.c:800
ForsPAF * newForsPAF(const char *name, const char *type, const char *id, const char *desc)
Create a new PAF object.
Definition: fors_paf.c:550