GIRAFFE Pipeline Reference Manual

giutils.c
1/*
2 * This file is part of the GIRAFFE Pipeline
3 * Copyright (C) 2002-2019 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, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif
23
24#ifdef HAVE_SYS_TYPES_H
25# include <sys/types.h>
26#endif
27#include <time.h>
28#include <string.h>
29#include <regex.h>
30
31#include <cxmemory.h>
32#include <cxmessages.h>
33#include <cxstring.h>
34#include <cxstrutils.h>
35
36#include <cpl_msg.h>
37#include <cpl_error.h>
38#include <cpl_errorstate.h>
39#include <cpl_matrix.h>
40#include <cpl_version.h>
41
42#include "gialias.h"
43#include "gitable.h"
44#include "gimessages.h"
45#include "gierror.h"
46#include "giutils.h"
47
48
57/*
58 * Giraffe version and license
59 */
60
61static const cxchar *_giraffe_license =
62 " This file is part of the GIRAFFE Instrument Pipeline\n"
63 " Copyright (C) 2002-2014 European Southern Observatory\n"
64 "\n"
65 " This program is free software; you can redistribute it and/or modify\n"
66 " it under the terms of the GNU General Public License as published by\n"
67 " the Free Software Foundation; either version 2 of the License, or\n"
68 " (at your option) any later version.\n"
69 "\n"
70 " This program is distributed in the hope that it will be useful,\n"
71 " but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
72 " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
73 " GNU General Public License for more details.\n"
74 "\n"
75 " You should have received a copy of the GNU General Public License\n"
76 " along with this program; if not, write to the Free Software\n"
77 " Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301"
78 " USA";
79
80
81inline static cxint
82_giraffe_plist_append(cpl_propertylist *self, cpl_property *p)
83{
84
85 const cxchar *name = cpl_property_get_name(p);
86 const cxchar *comment = cpl_property_get_comment(p);
87
88
89 switch (cpl_property_get_type(p)) {
90 case CPL_TYPE_BOOL:
91 {
92 cxbool value = cpl_property_get_bool(p);
93
94 cpl_propertylist_append_bool(self, name, value);
95 break;
96 }
97
98 case CPL_TYPE_CHAR:
99 {
100 cxchar value = cpl_property_get_char(p);
101
102 cpl_propertylist_append_char(self, name, value);
103 break;
104 }
105
106 case CPL_TYPE_INT:
107 {
108 cxint value = cpl_property_get_int(p);
109
110 cpl_propertylist_append_int(self, name, value);
111 break;
112 }
113
114 case CPL_TYPE_LONG:
115 {
116 cxlong value = cpl_property_get_long(p);
117
118 cpl_propertylist_append_long(self, name, value);
119 break;
120 }
121
122 case CPL_TYPE_FLOAT:
123 {
124 cxfloat value = cpl_property_get_float(p);
125
126 cpl_propertylist_append_float(self, name, value);
127 break;
128 }
129
130 case CPL_TYPE_DOUBLE:
131 {
132 cxdouble value = cpl_property_get_double(p);
133
134 cpl_propertylist_append_double(self, name, value);
135 break;
136 }
137
138 case CPL_TYPE_STRING:
139 {
140 const cxchar *value = cpl_property_get_string(p);
141
142 cpl_propertylist_append_string(self, name, value);
143 break;
144 }
145
146 default:
147
148 /*
149 * We should never reach this point! Since the property
150 * was a valid property it has a valid type. But this
151 * protects against addition of new types.
152 */
153
154 return 1;
155 break;
156 }
157
158 if (comment != NULL) {
159 cpl_propertylist_set_comment(self, name, comment);
160 }
161
162 return 0;
163
164}
165
166
167inline static cxint
168_giraffe_add_frame_info(cpl_propertylist *plist, const cxchar *name,
169 const cxchar *tag, cxint sequence, cxint frame_index,
170 cxint mode)
171{
172
173 const cxchar *id = NULL;
174 const cxchar *group = NULL;
175
176 cxint status = 0;
177
178 cx_string *key = NULL;
179 cx_string *comment = NULL;
180
181
182 if (plist == NULL) {
183 return 1;
184 }
185
186 switch (mode) {
187 case 0:
188 id = "RAW";
189 group = "raw";
190 break;
191
192 case 1:
193 id = "CAL";
194 group = "calibration";
195 break;
196
197 default:
198 return 2;
199 break;
200 }
201
202 key = cx_string_new();
203 comment = cx_string_new();
204
205
206 /*
207 * Frame name
208 */
209
210 cx_string_sprintf(key, "%s%-d %s%-d %s", "ESO PRO REC", sequence, id,
211 frame_index, "NAME");
212 cx_string_sprintf(comment, "%s %s %s", "File name of", group, "frame");
213
214 status = cpl_propertylist_update_string(plist, cx_string_get(key), name);
215
216 if (status != CPL_ERROR_NONE) {
217 cx_string_delete(key);
218 cx_string_delete(comment);
219
220 return 3;
221 }
222
223 status = cpl_propertylist_set_comment(plist, cx_string_get(key),
224 cx_string_get(comment));
225
226 if (status != 0) {
227 cx_string_delete(key);
228 cx_string_delete(comment);
229
230 return 3;
231 }
232
233
234 /*
235 * Frame category
236 */
237
238 cx_string_sprintf(key, "%s%-d %s%-d %s", "ESO PRO REC", sequence, id,
239 frame_index, "CATG");
240 cx_string_sprintf(comment, "%s %s %s", "Frame category of", group,
241 "frame");
242
243 status = cpl_propertylist_update_string(plist, cx_string_get(key), tag);
244
245 if (status != CPL_ERROR_NONE) {
246 cx_string_delete(key);
247 cx_string_delete(comment);
248
249 return 4;
250 }
251
252 status = cpl_propertylist_set_comment(plist, cx_string_get(key),
253 cx_string_get(comment));
254
255 if (status != 0) {
256 cx_string_delete(key);
257 cx_string_delete(comment);
258
259 return 4;
260 }
261
262 cx_string_delete(key);
263 cx_string_delete(comment);
264
265 return 0;
266
267}
268
269
270inline static cxint
271_giraffe_add_option_info(cpl_propertylist *plist,
272 const cpl_parameterlist *options, cxint sequence)
273{
274 cx_assert(plist != NULL);
275 cx_assert(options != NULL);
276 cx_assert(sequence >= 1);
277
278 cx_string *key = cx_string_new();
279 cx_string *comment = cx_string_new();
280
281 cxint pcount = 0;
282 const cpl_parameter *p = cpl_parameterlist_get_first_const(options);
283
284 if (p == NULL) {
285 cx_string_delete(key);
286 cx_string_delete(comment);
287 return 1;
288 }
289
290 while (p != NULL) {
291
292 cxint status = 0;
293 const cxchar *alias = cpl_parameter_get_alias(p, CPL_PARAMETER_MODE_CLI);
294 cx_string *value = cx_string_new();
295 cx_string *preset = cx_string_new();
296
297 switch (cpl_parameter_get_type(p)) {
298 case CPL_TYPE_BOOL:
299 {
300 int bval = cpl_parameter_get_bool(p);
301 cx_string_sprintf(value, "%s", (bval == 1) ? "true" : "false");
302
303 bval = cpl_parameter_get_default_bool(p);
304 cx_string_sprintf(preset, "%s", (bval == 1) ? "true" : "false");
305 break;
306 }
307 case CPL_TYPE_INT:
308 {
309 cx_string_sprintf(value, "%d", cpl_parameter_get_int(p));
310 cx_string_sprintf(preset, "%d", cpl_parameter_get_default_int(p));
311 break;
312 }
313 case CPL_TYPE_DOUBLE:
314 {
315 cx_string_sprintf(value, "%g", cpl_parameter_get_double(p));
316 cx_string_sprintf(preset, "%g", cpl_parameter_get_default_double(p));
317 break;
318 }
319 case CPL_TYPE_STRING:
320 {
321 cx_string_sprintf(value, "%s", cpl_parameter_get_string(p));
322 cx_string_sprintf(preset, "%s", cpl_parameter_get_default_string(p));
323 break;
324 }
325 default:
326 {
327 /* Unsupported parameter type */
328 status = -1;
329 break;
330 }
331 }
332
333 if (status != 0) {
334 cx_string_delete(key);
335 cx_string_delete(comment);
336 cx_string_delete(value);
337 cx_string_delete(preset);
338
339 return -1;
340 }
341
342 ++pcount;
343 cx_string_sprintf(key, "%s%-d %s%-d %s", "ESO PRO REC", sequence,
344 "PARAM", pcount, "NAME");
345 status = cpl_propertylist_update_string(plist, cx_string_get(key), alias);
346
347 if (status != 0) {
348 cx_string_delete(key);
349 cx_string_delete(comment);
350 cx_string_delete(value);
351 cx_string_delete(preset);
352
353 return 2;
354 }
355
356 status = cpl_propertylist_set_comment(plist, cx_string_get(key),
357 cpl_parameter_get_help(p));
358
359 if (status != 0) {
360 cx_string_delete(key);
361 cx_string_delete(comment);
362 cx_string_delete(value);
363 cx_string_delete(preset);
364
365 return 2;
366 }
367
368
369 cx_string_sprintf(key, "%s%-d %s%-d %s", "ESO PRO REC", sequence,
370 "PARAM", pcount, "VALUE");
371 cx_string_sprintf(comment, "Default: %s", cx_string_get(preset));
372
373 status = cpl_propertylist_update_string(plist, cx_string_get(key),
374 cx_string_get(value));
375
376 if (status != 0) {
377 cx_string_delete(key);
378 cx_string_delete(comment);
379 cx_string_delete(value);
380 cx_string_delete(preset);
381
382 return 3;
383 }
384
385 status = cpl_propertylist_set_comment(plist, cx_string_get(key),
386 cx_string_get(comment));
387
388 if (status != 0) {
389 cx_string_delete(key);
390 cx_string_delete(comment);
391 cx_string_delete(value);
392 cx_string_delete(preset);
393
394 return 3;
395 }
396
397 cx_string_delete(value);
398 cx_string_delete(preset);
399
400 p = cpl_parameterlist_get_next_const(options);
401
402 }
403
404 cx_string_delete(key);
405 cx_string_delete(comment);
406
407 return 0;
408}
409
410
421const cxchar *
423{
424
425 return _giraffe_license;
426
427}
428
429
443GiInstrumentMode
444giraffe_get_mode(cpl_propertylist *properties)
445{
446
447 const cxchar *fctid = "giraffe_get_mode";
448 const cxchar *mode;
449
450 cx_string *s = NULL;
451
452 GiInstrumentMode insmode;
453
454
455 if (!properties) {
456 cpl_error_set(fctid, CPL_ERROR_NULL_INPUT);
457 return GIMODE_NONE;
458 }
459
460
461 if (!cpl_propertylist_has(properties, GIALIAS_INSMODE)) {
462 gi_warning("%s: Property (%s) not found\n", fctid, GIALIAS_INSMODE);
463
464 if (!cpl_propertylist_has(properties, GIALIAS_SLITNAME)) {
465 cx_warning("%s: Property (%s) not found\n", fctid,
466 GIALIAS_SLITNAME);
467 return GIMODE_NONE;
468 }
469 else {
470 mode = cpl_propertylist_get_string(properties, GIALIAS_SLITNAME);
471 }
472 }
473 else {
474 mode = cpl_propertylist_get_string(properties, GIALIAS_SLITNAME);
475 }
476
477 if (!mode || strlen(mode) == 0) {
478 cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
479 return GIMODE_NONE;
480 }
481
482
483 s = cx_string_create(mode);
484 cx_string_lower(s);
485
486 if (strncmp(cx_string_get(s), "med", 3) == 0) {
487 insmode = GIMODE_MEDUSA;
488 }
489 else if (strncmp(cx_string_get(s), "ifu", 3) == 0) {
490 insmode = GIMODE_IFU;
491 }
492 else if (strncmp(cx_string_get(s), "arg", 3) == 0) {
493 insmode = GIMODE_ARGUS;
494 }
495 else {
496 cpl_error_set(fctid, CPL_ERROR_UNSUPPORTED_MODE);
497 insmode = GIMODE_NONE;
498 }
499
500 cx_string_delete(s);
501
502 return insmode;
503
504}
505
521cxchar *
522giraffe_path_get_basename(const cxchar *path)
523{
524
525 register cxssize base;
526 register cxssize last_nonslash;
527
528 cxsize len;
529
530 cxchar *result;
531
532
533 if (path == NULL) {
534 return NULL;
535 }
536
537 if (path[0] == '\0') {
538 return cx_strdup(".");
539 }
540
541 last_nonslash = strlen(path) - 1;
542
543 while (last_nonslash >= 0 && path[last_nonslash] == '/') {
544 --last_nonslash;
545 }
546
547
548 /* String only containing slashes */
549
550 if (last_nonslash == -1) {
551 return cx_strdup("/");
552 }
553
554 base = last_nonslash;
555
556 while (base >=0 && path[base] != '/') {
557 --base;
558 }
559
560 len = last_nonslash - base;
561
562 result = cx_malloc(len + 1);
563 memcpy(result, path + base + 1, len);
564 result[len] = '\0';
565
566 return result;
567
568}
569
570
583cxchar *
585{
586
587 struct tm *ts;
588
589 time_t seconds = time(NULL);
590
591 cxchar *sdate = NULL;
592
593 cxulong milliseconds = 0;
594
595 cx_string *self = cx_string_new();
596
597
598 cx_assert(self != NULL);
599
600 ts = localtime(&seconds);
601
602 cx_string_sprintf(self, "%4d-%02d-%02dT%02d:%02d:%02d.%03ld",
603 ts->tm_year + 1900,
604 ts->tm_mon + 1,
605 ts->tm_mday,
606 ts->tm_hour,
607 ts->tm_min,
608 ts->tm_sec,
609 milliseconds);
610
611 sdate = cx_strdup(cx_string_get(self));
612 cx_string_delete(self);
613
614 return sdate;
615
616}
617
618
626cxint
627giraffe_add_recipe_info(cpl_propertylist *plist, const GiRecipeInfo *info)
628{
629
630 if (plist == NULL) {
631 return -1;
632 }
633
634 if (info != NULL) {
635
636 cxint status = 0;
637
638 cx_string *name = cx_string_new();
639 cx_string *value = cx_string_new();
640
641
642 cx_string_sprintf(name, "%s%-d %s", "ESO PRO REC", info->sequence,
643 "ID");
644 cx_string_sprintf(value, "%s", info->recipe);
645
646 status = cpl_propertylist_update_string(plist, cx_string_get(name),
647 cx_string_get(value));
648
649
650 if (status != CPL_ERROR_NONE) {
651 cx_string_delete(name);
652 cx_string_delete(value);
653
654 return 1;
655 }
656
657 status = cpl_propertylist_set_comment(plist, cx_string_get(name),
658 "Pipeline recipe (unique) identifier");
659
660 if (status != 0) {
661 cx_string_delete(name);
662 cx_string_delete(value);
663
664 return 1;
665 }
666
667 cx_string_sprintf(name, "%s%-d %s", "ESO PRO REC", info->sequence,
668 "PIPE ID");
669 cx_string_sprintf(value, "%s/%s", PACKAGE, VERSION);
670
671 status = cpl_propertylist_update_string(plist, cx_string_get(name),
672 cx_string_get(value));
673
674
675 if (status != CPL_ERROR_NONE) {
676 cx_string_delete(name);
677 cx_string_delete(value);
678
679 return 1;
680 }
681
682 status = cpl_propertylist_set_comment(plist, cx_string_get(name),
683 "Pipeline (unique) identifier");
684
685 if (status != 0) {
686 cx_string_delete(name);
687 cx_string_delete(value);
688
689 return 1;
690 }
691
692 cx_string_sprintf(name, "%s%-d %s", "ESO PRO REC", info->sequence,
693 "DRS ID");
694 cx_string_sprintf(value, "cpl-%s", cpl_version_get_version());
695
696 status = cpl_propertylist_update_string(plist, cx_string_get(name),
697 cx_string_get(value));
698
699
700 if (status != CPL_ERROR_NONE) {
701 cx_string_delete(name);
702 cx_string_delete(value);
703
704 return 1;
705 }
706
707 status = cpl_propertylist_set_comment(plist, cx_string_get(name),
708 "Data Reduction System identifier");
709
710 if (status != 0) {
711 cx_string_delete(name);
712 cx_string_delete(value);
713
714 return 1;
715 }
716
717 if (info->start != NULL) {
718 cx_string_sprintf(name, "%s%-d %s", "ESO PRO REC",
719 info->sequence, "START");
720 status = cpl_propertylist_update_string(plist,
721 cx_string_get(name),
722 info->start);
723
724 if (status != CPL_ERROR_NONE) {
725 cx_string_delete(name);
726 cx_string_delete(value);
727
728 return 1;
729 }
730
731 status = cpl_propertylist_set_comment(plist, cx_string_get(name),
732 "Date when recipe execution "
733 "started.");
734
735 if (status != 0) {
736 cx_string_delete(name);
737 cx_string_delete(value);
738
739 return 1;
740 }
741 }
742
743 cx_string_delete(name);
744 cx_string_delete(value);
745
746
747 /*
748 * Add recipe options
749 */
750
751 status = _giraffe_add_option_info(plist, info->options, info->sequence);
752
753 if (status != 0) {
754 return 1;
755 }
756
757 }
758
759 return 0;
760
761}
762
763
785cxint
786giraffe_add_frameset_info(cpl_propertylist *plist, const cpl_frameset *set,
787 cxint sequence)
788{
789
790 if (plist == NULL) {
791 return -1;
792 }
793
794 if (set != NULL) {
795
796 cxsize nraw = 0;
797 cxsize ncalib = 0;
798
799 cx_string *key = cx_string_new();
800
801 const cpl_frame *frame = NULL;
802
803 cpl_frameset_iterator *it = cpl_frameset_iterator_new(set);
804
805
806 while ((frame = cpl_frameset_iterator_get_const(it)) != NULL) {
807
808 cpl_frame_group group = cpl_frame_get_group(frame);
809
810 const cxchar *name = cpl_frame_get_filename(frame);
811 const cxchar *tag = cpl_frame_get_tag(frame);
812 const cxchar *base = giraffe_path_get_basename(name);
813
814
815 cx_assert(base != NULL);
816
817 switch (group) {
818 case CPL_FRAME_GROUP_RAW:
819 {
820
821 cxint status = 0;
822
823 ++nraw;
824
825
826 /*
827 * Get the product's ancestor as the archive name of the
828 * first raw file in the reference set
829 */
830
831 if (!cpl_propertylist_has(plist, GIALIAS_ANCESTOR)) {
832
833 if (nraw == 1) {
834
835 cpl_propertylist *_plist = cpl_propertylist_load(name, 0);
836
837 if (_plist == NULL) {
838
839 if (base != NULL) {
840 cx_free((cxchar *)base);
841 }
842
843 cpl_frameset_iterator_delete(it);
844 cx_string_delete(key);
845
846 return -2;
847
848 }
849
850 if (cpl_propertylist_has(_plist, GIALIAS_ANCESTOR)) {
851 cpl_propertylist_copy_property(plist, _plist,
852 GIALIAS_ANCESTOR);
853 }
854 else {
855
856 const cxchar *s =
857 cpl_propertylist_get_string(_plist,
858 GIALIAS_ARCFILE);
859 const cxchar *c = "Inherited archive file name "
860 "of the first raw data frame";
861
862 if (s != NULL) {
863 cpl_propertylist_append_string(plist,
864 GIALIAS_ANCESTOR, s);
865 cpl_propertylist_set_comment(plist,
866 GIALIAS_ANCESTOR, c);
867 }
868
869 }
870
871 cpl_propertylist_delete(_plist);
872
873 }
874
875 }
876
877
878 status = _giraffe_add_frame_info(plist, base, tag,
879 sequence, nraw, 0);
880
881 if (status != 0) {
882 if (base != NULL) {
883 cx_free((cxchar *)base);
884 }
885
886 cpl_frameset_iterator_delete(it);
887 cx_string_delete(key);
888
889 return -2;
890 }
891
892
893 break;
894 }
895
896 case CPL_FRAME_GROUP_CALIB:
897 {
898
899 cpl_propertylist *_plist = NULL;
900
901
902 ++ncalib;
903 cxint status = _giraffe_add_frame_info(plist, base, tag,
904 sequence, ncalib, 1);
905
906 if (status != 0) {
907 if (base != NULL) {
908 cx_free((cxchar *)base);
909 }
910
911 cpl_frameset_iterator_delete(it);
912 cx_string_delete(key);
913
914 return -3;
915 }
916
917 _plist = cpl_propertylist_load(name, 0);
918
919 if (_plist == NULL) {
920 if (base != NULL) {
921 cx_free((cxchar *)base);
922 }
923
924 cpl_frameset_iterator_delete(it);
925 cx_string_delete(key);
926
927 return -3;
928 }
929
930
931 if (cpl_propertylist_has(_plist, GIALIAS_DATAMD5)) {
932
933 const cxchar *s =
934 cpl_propertylist_get_string(_plist, GIALIAS_DATAMD5);
935
936 if (strcmp(s, "Not computed") != 0) {
937
938 cx_string* md5 = cx_string_new();
939
940 cx_string_sprintf(md5, "%s%d %s%"
941 CX_PRINTF_FORMAT_SIZE_TYPE "%s",
942 "ESO PRO REC", sequence, "CAL",
943 ncalib, " DATAMD5");
944
945 status =
946 cpl_propertylist_update_string(plist,
947 cx_string_get(md5),
948 s);
949
950 if (status != CPL_ERROR_NONE) {
951 cx_string_delete(md5);
952 cpl_propertylist_delete(_plist);
953
954 if (base != NULL) {
955 cx_free((cxchar *)base);
956 }
957
958 cpl_frameset_iterator_delete(it);
959 cx_string_delete(key);
960
961 return -3;
962 }
963
964 cx_string_delete(md5);
965 }
966
967 }
968
969 cpl_propertylist_delete(_plist);
970 break;
971 }
972
973 default:
974 break;
975 }
976
977
978 if (base != NULL) {
979 cx_free((cxchar *)base);
980 }
981
982 cpl_frameset_iterator_advance(it, 1);
983
984 }
985
986 cpl_frameset_iterator_delete(it);
987 cx_string_delete(key);
988
989 }
990
991 return 0;
992
993}
994
995
1016cxint
1017giraffe_propertylist_update(cpl_propertylist *self,
1018 cpl_propertylist *properties,
1019 const cxchar *regexp)
1020{
1021
1022 const cxchar *fctid = "giraffe_propertylist_update";
1023
1024 cxlong i;
1025 cxlong sz = 0;
1026
1027
1028 cx_assert(self != NULL);
1029
1030 if (properties == NULL) {
1031 cpl_error_set(fctid, CPL_ERROR_NULL_INPUT);
1032 return -1;
1033 }
1034
1035 sz = cpl_propertylist_get_size(properties);
1036
1037 if (regexp == NULL || regexp[0] == '\0') {
1038
1039 for (i = 0; i < sz; i++) {
1040
1041 cpl_property *p = cpl_propertylist_get(properties, i);
1042 const cxchar *name = cpl_property_get_name(p);
1043
1044
1045 if (!cpl_propertylist_has(self, name)) {
1046
1047 cxint status = _giraffe_plist_append(self, p);
1048
1049 if (status) {
1050 cpl_error_set(fctid, CPL_ERROR_INVALID_TYPE);
1051 return 1;
1052 }
1053 }
1054 }
1055 }
1056 else {
1057
1058 cxint status = 0;
1059
1060 regex_t re;
1061
1062
1063 status = regcomp(&re, regexp, REG_EXTENDED | REG_NOSUB);
1064
1065 if (status) {
1066 cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
1067 return 1;
1068 }
1069
1070 for (i = 0; i < sz; i++) {
1071
1072 cpl_property *p = cpl_propertylist_get(properties, i);
1073 const cxchar *name = cpl_property_get_name(p);
1074
1075
1076 if (regexec(&re, name, (size_t)0, NULL, 0) == REG_NOMATCH) {
1077 continue;
1078 }
1079
1080 if (!cpl_propertylist_has(self, name)) {
1081
1082 status = _giraffe_plist_append(self, p);
1083
1084 if (status) {
1085 cpl_error_set(fctid, CPL_ERROR_INVALID_TYPE);
1086 return 1;
1087 }
1088 }
1089 }
1090
1091 regfree(&re);
1092
1093 }
1094
1095 return 0;
1096
1097}
1098
1099
1107cxint
1108giraffe_propertylist_copy(cpl_propertylist *self,
1109 const cxchar *name,
1110 const cpl_propertylist *other,
1111 const cxchar *othername)
1112{
1113
1114 const cxchar *fctid = "giraffe_propertylist_copy";
1115
1116
1117 const cxchar *s;
1118 const cxchar *comment;
1119
1120 cpl_type type;
1121
1122
1123
1124 cx_assert(self != NULL);
1125
1126 if (other == NULL) {
1127 return -1;
1128 }
1129
1130 if (othername == NULL) {
1131 return -2;
1132 }
1133
1134 if (!cpl_propertylist_has(other, othername)) {
1135 return 1;
1136 }
1137
1138 type = cpl_propertylist_get_type(other, othername);
1139
1140
1141 /*
1142 * Determine the name the new property should have in self.
1143 */
1144
1145 s = name == NULL ? othername : name;
1146
1147
1148 /*
1149 * Add the property to the destination list.
1150 */
1151
1152 switch (type) {
1153 case CPL_TYPE_CHAR:
1154 {
1155 cxchar value = cpl_propertylist_get_char(other, othername);
1156
1157 if (cpl_propertylist_has(self, s)) {
1158 cpl_propertylist_set_char(self, s, value);
1159 }
1160 else {
1161 cpl_propertylist_append_char(self, s, value);
1162 }
1163 }
1164 break;
1165
1166 case CPL_TYPE_BOOL:
1167 {
1168 cxbool value = cpl_propertylist_get_bool(other, othername);
1169
1170 if (cpl_propertylist_has(self, s)) {
1171 cpl_propertylist_set_bool(self, s, value);
1172 }
1173 else {
1174 cpl_propertylist_append_bool(self, s, value);
1175 }
1176 }
1177 break;
1178
1179 case CPL_TYPE_INT:
1180 {
1181 cxint value = cpl_propertylist_get_int(other, othername);
1182
1183 if (cpl_propertylist_has(self, s)) {
1184 cpl_propertylist_set_int(self, s, value);
1185 }
1186 else {
1187 cpl_propertylist_append_int(self, s, value);
1188 }
1189 }
1190 break;
1191
1192 case CPL_TYPE_LONG:
1193 {
1194 cxlong value = cpl_propertylist_get_long(other, othername);
1195
1196 if (cpl_propertylist_has(self, s)) {
1197 cpl_propertylist_set_long(self, s, value);
1198 }
1199 else {
1200 cpl_propertylist_append_long(self, s, value);
1201 }
1202 }
1203 break;
1204
1205 case CPL_TYPE_FLOAT:
1206 {
1207 cxfloat value = cpl_propertylist_get_float(other, othername);
1208
1209 if (cpl_propertylist_has(self, s)) {
1210 cpl_propertylist_set_float(self, s, value);
1211 }
1212 else {
1213 cpl_propertylist_append_float(self, s, value);
1214 }
1215 }
1216 break;
1217
1218 case CPL_TYPE_DOUBLE:
1219 {
1220 cxdouble value = cpl_propertylist_get_double(other, othername);
1221
1222 if (cpl_propertylist_has(self, s)) {
1223 cpl_propertylist_set_double(self, s, value);
1224 }
1225 else {
1226 cpl_propertylist_append_double(self, s, value);
1227 }
1228 }
1229 break;
1230
1231 case CPL_TYPE_STRING:
1232 {
1233 const cxchar *value = cpl_propertylist_get_string(other,
1234 othername);
1235
1236 if (cpl_propertylist_has(self, s)) {
1237 cpl_propertylist_set_string(self, s, value);
1238 }
1239 else {
1240 cpl_propertylist_append_string(self, s, value);
1241 }
1242 }
1243 break;
1244
1245 default:
1246 cpl_error_set(fctid, CPL_ERROR_INVALID_TYPE);
1247 return 2;
1248 break;
1249 }
1250
1251 comment = cpl_propertylist_get_comment(other, othername);
1252
1253 if (comment != NULL) {
1254 cpl_propertylist_set_comment(self, s, comment);
1255 }
1256
1257 return 0;
1258
1259}
1260
1261
1262cxint
1263giraffe_propertylist_update_wcs(cpl_propertylist* properties, cxsize naxis,
1264 const cxdouble* crpix, const cxdouble* crval,
1265 const cxchar** ctype, const cxchar** cunit,
1266 const cpl_matrix* cd)
1267{
1268
1269 if (properties == NULL) {
1270 return 0;
1271 }
1272
1273 cpl_propertylist_erase_regexp(properties, "^CRPIX[0-9]", 0);
1274 cpl_propertylist_erase_regexp(properties, "^CRVAL[0-9]", 0);
1275 cpl_propertylist_erase_regexp(properties, "^CDELT[0-9]", 0);
1276 cpl_propertylist_erase_regexp(properties, "^CTYPE[0-9]", 0);
1277 cpl_propertylist_erase_regexp(properties, "^CUNIT[0-9]", 0);
1278 cpl_propertylist_erase_regexp(properties, "^CROTA[0-9]", 0);
1279 cpl_propertylist_erase_regexp(properties, "^CD[0-9]*_[0-9]", 0);
1280 cpl_propertylist_erase_regexp(properties, "^PC[0-9]*_[0-9]", 0);
1281
1282
1283 if (naxis > 0) {
1284
1285
1286 register cxsize i = 0;
1287
1288 cx_string* keyword = cx_string_new();
1289 cx_string* comment = cx_string_new();
1290
1291
1292 cx_assert(cpl_matrix_get_nrow(cd) == cpl_matrix_get_ncol(cd));
1293
1294 for (i = 0; i < naxis; i++) {
1295
1296 cx_string_sprintf(keyword, "CTYPE%-" CX_PRINTF_FORMAT_SIZE_TYPE,
1297 i + 1);
1298 cx_string_sprintf(comment, "Coordinate system of axis %"
1299 CX_PRINTF_FORMAT_SIZE_TYPE, i + 1);
1300 cpl_propertylist_append_string(properties,
1301 cx_string_get(keyword), ctype[i]);
1302 cpl_propertylist_set_comment(properties, cx_string_get(keyword),
1303 cx_string_get(comment));
1304
1305 }
1306
1307 for (i = 0; i < naxis; i++) {
1308
1309 cx_string_sprintf(keyword, "CRPIX%-" CX_PRINTF_FORMAT_SIZE_TYPE,
1310 i + 1);
1311 cx_string_sprintf(comment, "Reference pixel of axis %"
1312 CX_PRINTF_FORMAT_SIZE_TYPE, i + 1);
1313 cpl_propertylist_append_double(properties,
1314 cx_string_get(keyword), crpix[i]);
1315 cpl_propertylist_set_comment(properties, cx_string_get(keyword),
1316 cx_string_get(comment));
1317
1318 }
1319
1320 for (i = 0; i < naxis; i++) {
1321
1322 cx_string_sprintf(keyword, "CRVAL%-" CX_PRINTF_FORMAT_SIZE_TYPE,
1323 i + 1);
1324 cx_string_sprintf(comment, "Coordinate of axis %"
1325 CX_PRINTF_FORMAT_SIZE_TYPE " at reference "
1326 "pixel", i + 1);
1327 cpl_propertylist_append_double(properties,
1328 cx_string_get(keyword), crval[i]);
1329 cpl_propertylist_set_comment(properties, cx_string_get(keyword),
1330 cx_string_get(comment));
1331
1332 }
1333
1334 for (i = 0; i < naxis; i++) {
1335
1336 if (cunit[i] != NULL) {
1337 cx_string_sprintf(keyword, "CUNIT%-"
1338 CX_PRINTF_FORMAT_SIZE_TYPE, i + 1);
1339 cx_string_sprintf(comment, "Unit of coordinate axis %"
1340 CX_PRINTF_FORMAT_SIZE_TYPE, i + 1);
1341 cpl_propertylist_append_string(properties,
1342 cx_string_get(keyword),
1343 cunit[i]);
1344 cpl_propertylist_set_comment(properties,
1345 cx_string_get(keyword),
1346 cx_string_get(comment));
1347 }
1348
1349 }
1350
1351
1352 /*
1353 * CD matrix
1354 */
1355
1356 for (i = 0; i < naxis; i++) {
1357
1358 register cxsize j = 0;
1359
1360
1361 for (j = 0; j < naxis; j++) {
1362
1363 cx_string_sprintf(keyword, "CD%-" CX_PRINTF_FORMAT_SIZE_TYPE
1364 "_%-" CX_PRINTF_FORMAT_SIZE_TYPE, i + 1,
1365 j + 1);
1366 cx_string_sprintf(comment, "Coordinate transformation matrix "
1367 "element");
1368 cpl_propertylist_append_double(properties,
1369 cx_string_get(keyword),
1370 cpl_matrix_get(cd, i, j));
1371 cpl_propertylist_set_comment(properties,
1372 cx_string_get(keyword),
1373 cx_string_get(comment));
1374 }
1375
1376 }
1377
1378 cx_string_delete(keyword);
1379 keyword = NULL;
1380
1381 cx_string_delete(comment);
1382 comment = NULL;
1383
1384 }
1385
1386 return 0;
1387
1388}
1389
1390
1391cxint
1392giraffe_frameset_set_groups(cpl_frameset* set, GiGroupInfo *groups)
1393{
1394
1395 cpl_frame* frame = NULL;
1396
1397 cpl_frameset_iterator *it = NULL;
1398
1399
1400 if (set == NULL) {
1401 return -1;
1402 }
1403
1404 if (groups == NULL || groups->tag == NULL) {
1405 return 0;
1406 }
1407
1408 it = cpl_frameset_iterator_new(set);
1409
1410 while ((frame = cpl_frameset_iterator_get(it)) != NULL) {
1411
1412 const cxchar* tag = cpl_frame_get_tag(frame);
1413
1414 if (tag != NULL &&
1415 cpl_frame_get_group(frame) == CPL_FRAME_GROUP_NONE) {
1416
1417 const GiGroupInfo* g = groups;
1418
1419 while (g->tag != NULL) {
1420 if (strcmp(tag, g->tag) == 0) {
1421 cpl_frame_set_group(frame, g->group);
1422 break;
1423 }
1424 ++g;
1425 }
1426
1427 }
1428
1429 cpl_frameset_iterator_advance(it, 1);
1430
1431 }
1432
1433 cpl_frameset_iterator_delete(it);
1434
1435 return 0;
1436
1437}
1438
1439
1473cxdouble giraffe_propertylist_get_conad(const cpl_propertylist* properties)
1474{
1475
1476 const cxchar* const fctid = "giraffe_propertylist_get_conad";
1477
1478 const cxchar *names[2] = {GIALIAS_CONAD, GIALIAS_CONAD_LEGACY};
1479 const cxchar *name = NULL;
1480
1481 cxdouble conad = 1.;
1482
1483
1484 cx_assert(properties != NULL);
1485
1486
1487 if (!cpl_propertylist_has(properties, GIALIAS_CONAD)) {
1488
1489 if (!cpl_propertylist_has(properties, GIALIAS_CONAD_LEGACY)) {
1490
1491 cpl_msg_error(fctid, "Missing detector gain property (%s, %s)! ",
1492 GIALIAS_CONAD, GIALIAS_CONAD_LEGACY);
1493 cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
1494
1495 return 0.;
1496
1497 }
1498 else {
1499 name = names[1];
1500 }
1501
1502
1503 }
1504 else {
1505 name = names[0];
1506 }
1507
1508 conad = cpl_propertylist_get_double(properties, name);
1509
1510 if (conad < 0.) {
1511
1512 cpl_msg_error(fctid, "Invalid conversion factor (%s) %.3g "
1513 "[e-/ADU]", name, conad);
1514 cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
1515
1516 return 0.;
1517
1518 }
1519
1520 return conad;
1521
1522}
1523
1524
1556cxdouble
1557giraffe_propertylist_get_ron(const cpl_propertylist* properties)
1558{
1559
1560 const cxchar* const fctid = "giraffe_propertylist_get_ron";
1561
1562
1563 cxdouble ron = 0.;
1564
1565
1566 cx_assert(properties != NULL);
1567
1568 if (!cpl_propertylist_has(properties, GIALIAS_BIASSIGMA)) {
1569 if (!cpl_propertylist_has(properties, GIALIAS_RON)) {
1570 cpl_msg_error(fctid, "Missing detector read-out noise "
1571 "property (%s)!", GIALIAS_RON);
1572 cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
1573
1574 return 0.;
1575 }
1576 else {
1577
1578 /*
1579 * Get default detector read-out noise. Note that this value
1580 * is already given in electrons. No conversion needed.
1581 */
1582
1583 cpl_msg_warning(fctid, "Missing bias RMS property (%s)! "
1584 "Using detector read-out noise property (%s).",
1585 GIALIAS_BIASSIGMA, GIALIAS_RON);
1586 ron = cpl_propertylist_get_double(properties, GIALIAS_RON);
1587 }
1588 }
1589 else {
1590
1591 cxdouble conad = 0.;
1592
1593
1594 /*
1595 * Get measured detector read-out noise. This is given in ADU and
1596 * has to be converted into electrons.
1597 */
1598
1599 giraffe_error_push();
1600
1601 conad = giraffe_propertylist_get_conad(properties);
1602
1603 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1604 return 0.;
1605 }
1606
1607 giraffe_error_pop();
1608
1609 ron = cpl_propertylist_get_double(properties, GIALIAS_BIASSIGMA) *
1610 conad;
1611
1612 }
1613
1614 return ron;
1615
1616}
1617/*
1618* The pipeline itself has no concept of treating different FLAT types differently.
1619* For QC parameters this function just reproduces the logic from giraf.oca.
1620*/
1621const char * giraffe_get_flat_type(cpl_propertylist* plist) {
1622 cpl_error_code error_code;
1623 cpl_errorstate prev_state = cpl_errorstate_get();
1624
1625 const char* CATG = cpl_propertylist_get_string(plist, "ESO DPR CATG");
1626 if (CATG == NULL) {
1627 error_code = cpl_error_get_code();
1628 cpl_msg_warning("getDO_CATG", "Failed to get ESO DPR CATG: %d", error_code);
1629 cpl_errorstate_set(prev_state);
1630 return NULL;
1631 }
1632
1633 const char* TYPE = cpl_propertylist_get_string(plist, "ESO DPR TYPE");
1634 if (TYPE == NULL) {
1635 error_code = cpl_error_get_code();
1636 cpl_msg_warning("getDO_CATG", "Failed to get ESO DPR TYPE: %d", error_code);
1637 cpl_errorstate_set(prev_state);
1638 return NULL;
1639 }
1640
1641 const char* TECH = cpl_propertylist_get_string(plist, "ESO DPR TECH");
1642 if (TECH == NULL) {
1643 error_code = cpl_error_get_code();
1644 cpl_msg_warning("getDO_CATG", "Failed to get ESO DPR TECH: %d", error_code);
1645 cpl_errorstate_set(prev_state);
1646 return NULL;
1647 }
1648
1649 if (strstr(CATG, "CALIB") != NULL) {
1650 if (strstr(TYPE, "FLAT") != NULL && strstr(TYPE, "LAMP") != NULL) {
1651 if (strstr(TYPE, "NASMYTH") != NULL) {
1652 if (strstr(TECH, "MOS") != NULL || strstr(TECH, "IFU") != NULL) {
1653 return "NAS"; // NASMYTH
1654 }
1655 }
1656 else if (strstr(TECH, "MOS") != NULL || strstr(TECH, "IFU") != NULL) {
1657 return "ROB"; // ROBOTIC
1658 }
1659 }
1660 else if (strstr(TYPE, "SKY") != NULL) {
1661 if (strstr(TECH, "MOS") != NULL || strstr(TECH, "IFU") != NULL) {
1662 return "SKY";
1663 }
1664 }
1665 }
1666
1667 return NULL;
1668}
1669
1670
1671int
1672giraffe_qc_airm_see_avg(cpl_propertylist *properties)
1673{
1674 double airmass = 0.0;
1675 double seeing = 0.0;
1676
1677 const cxchar *const fctid = "giraffe_qc_airm_see_avg";
1678
1679 const char *qcairm = GIALIAS_QCAIRMAVG;
1680 const char *qcsee = GIALIAS_QCSEEAVG;
1681
1682 cpl_errorstate tempes = cpl_errorstate_get();
1683
1684 if (cpl_propertylist_has(properties, GIALIAS_PROSCIENCE)) {
1685 if (cpl_propertylist_get_bool(properties, GIALIAS_PROSCIENCE)) {
1686 qcairm = GIALIAS_QCAIR;
1687 qcsee = GIALIAS_QCFWHM;
1688 }
1689 }
1690
1691 cxbool start = cpl_propertylist_has(properties, GIALIAS_AIRMASS_START);
1692 cxbool end = cpl_propertylist_has(properties, GIALIAS_AIRMASS_END);
1693
1694 if ((start == FALSE) || (end == FALSE)) {
1695 cpl_msg_debug(fctid, "Unable to compute airmass of the "
1696 "observation!");
1697
1698 return -1;
1699 }
1700 else {
1701 airmass =
1702 0.5 *
1703 (cpl_propertylist_get_double(properties, GIALIAS_AIRMASS_START) +
1704 cpl_propertylist_get_double(properties, GIALIAS_AIRMASS_END));
1705
1706
1707 cpl_propertylist_update_double(properties, qcairm, airmass);
1708 cpl_propertylist_set_comment(properties, qcairm,
1709 "Average airmass"
1710 " in the first raw frame");
1711 }
1712 start = cpl_propertylist_has(properties, GIALIAS_FWHM_START);
1713 end = cpl_propertylist_has(properties, GIALIAS_FWHM_END);
1714
1715 if ((start == FALSE) || (end == FALSE)) {
1716 cpl_msg_warning(fctid, "Unable to compute seeing of the "
1717 "observation!");
1718
1719 return -1;
1720 }
1721 else {
1722 seeing =
1723 0.5 * (cpl_propertylist_get_double(properties, GIALIAS_FWHM_START) +
1724 cpl_propertylist_get_double(properties, GIALIAS_FWHM_END));
1725
1726
1727 cpl_propertylist_update_double(properties, qcsee, seeing);
1728 cpl_propertylist_set_comment(properties, qcsee,
1729 "Average seeing"
1730 " in the first raw frame");
1731 }
1732
1733 cpl_errorstate_set(tempes);
1734
1735 return 0;
1736}
1737
1738int giraffe_qc_update_sci_props(cpl_propertylist* properties, GiTable* fibers) {
1739
1740 cpl_errorstate tempes = cpl_errorstate_get();
1741
1742 giraffe_qc_airm_see_avg(properties);
1743 giraffe_propertylist_copy(properties, GIALIAS_QCNFIB, properties,
1744 GIALIAS_NFIBERS);
1745
1746 cpl_table * fibtab = giraffe_table_get(fibers);
1747
1748 int nsci = 0;
1749 int nsky = 0;
1750
1751 nsci = cpl_table_and_selected_string(fibtab, "TYPE", CPL_EQUAL_TO, "M");
1752 cpl_table_select_all(fibtab);
1753 nsky = cpl_table_and_selected_string(fibtab, "TYPE", CPL_EQUAL_TO, "S");
1754 cpl_table_select_all(fibtab);
1755
1756 cpl_propertylist_append_int(properties, GIALIAS_QCNFIBSCI, nsci);
1757 cpl_propertylist_append_int(properties, GIALIAS_QCNFIBSKY, nsky);
1758
1759 cpl_errorstate_set(tempes);
1760
1761 return 0;
1762
1763}
1764
void gi_warning(const cxchar *format,...)
Log a warning.
Definition: gimessages.c:119
cpl_table * giraffe_table_get(const GiTable *self)
Get the table data from a Giraffe table.
Definition: gitable.c:433
cxint giraffe_add_recipe_info(cpl_propertylist *plist, const GiRecipeInfo *info)
Add recipe specific information to a property list.
Definition: giutils.c:627
cxchar * giraffe_localtime_iso8601(void)
Get the current date and time in ISO 8601 format.
Definition: giutils.c:584
cxint giraffe_add_frameset_info(cpl_propertylist *plist, const cpl_frameset *set, cxint sequence)
Add frameset specific information to a property list.
Definition: giutils.c:786
cxchar * giraffe_path_get_basename(const cxchar *path)
Gets the name of a file without any leading directory components.
Definition: giutils.c:522
cxint giraffe_propertylist_copy(cpl_propertylist *self, const cxchar *name, const cpl_propertylist *other, const cxchar *othername)
Copy a property from one list to another.
Definition: giutils.c:1108
cxdouble giraffe_propertylist_get_conad(const cpl_propertylist *properties)
Retrieve the ADU to electrons conversion factor from the given properties.
Definition: giutils.c:1473
const cxchar * giraffe_get_license(void)
Get the pipeline copyright and license.
Definition: giutils.c:422
cxint giraffe_propertylist_update(cpl_propertylist *self, cpl_propertylist *properties, const cxchar *regexp)
Update a property list.
Definition: giutils.c:1017
cxdouble giraffe_propertylist_get_ron(const cpl_propertylist *properties)
Retrieve the read-out noise from the given properties.
Definition: giutils.c:1557
GiInstrumentMode giraffe_get_mode(cpl_propertylist *properties)
Determines the instrument mode from a property list.
Definition: giutils.c:444

This file is part of the GIRAFFE Pipeline Reference Manual 2.19.4.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Fri Feb 6 2026 11:30:08 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2004