GIRAFFE Pipeline Reference Manual

gilinedata.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#include <string.h>
25
26#include <cxtypes.h>
27#include <cxmemory.h>
28#include <cxmessages.h>
29#include <cxmap.h>
30#include <cxstrutils.h>
31
32#include <cpl_error.h>
33#include <cpl_image.h>
34
35#include "gialias.h"
36#include "gierror.h"
37#include "giutils.h"
38#include "gilinedata.h"
39
40
41
42/*
43 * @defgroup gilinedata Line Data Storage
44 *
45 * TBD
46 */
47
50struct GiLineData {
51
52 const cxchar* model;
53
54 cxint nfibers;
55 cxint nlines;
56 cxint* ignore;
57
58 cxdouble* wavelength;
59
60 cpl_image* status;
61
62 cx_map* values;
63
64};
65
66
67inline static cxbool
68_giraffe_linedata_compare(cxcptr s, cxcptr t)
69{
70
71 return strcmp(s, t) < 0 ? TRUE : FALSE;
72
73}
74
75inline static void
76_giraffe_linedata_clear(GiLineData* self)
77{
78
79 self->nfibers = 0;
80 self->nlines = 0;
81
82 if (self->model) {
83 cx_free((cxptr)self->model);
84 self->model = NULL;
85 }
86
87 if (self->ignore) {
88 cx_free(self->ignore);
89 self->ignore = NULL;
90 }
91
92 if (self->wavelength) {
93 cx_free(self->wavelength);
94 self->wavelength = NULL;
95 }
96
97 if (self->status) {
98 cpl_image_delete(self->status);
99 self->status = NULL;
100 }
101
102 if (self->values) {
103 cx_map_clear(self->values);
104 }
105
106 cx_assert(cx_map_empty(self->values));
107
108 return;
109}
110
111
112inline static cxint
113_giraffe_linedata_assign(GiLineData* self, cx_map* map, const cxchar* name,
114 const cpl_image* values)
115{
116
117 cx_map_iterator position = cx_map_find(map, name);
118
119
120 if (cpl_image_get_size_x(values) != self->nfibers) {
121 return 1;
122 }
123
124 if (cpl_image_get_size_y(values) != self->nlines) {
125 return 2;
126 }
127
128 if (position == cx_map_end(map)) {
129 cx_map_insert(map, cx_strdup(name), values);
130 }
131 else {
132
133 cpl_image* previous = cx_map_assign(map, position, values);
134
135 if (previous != NULL) {
136 cpl_image_delete(previous);
137 previous = NULL;
138 }
139
140 }
141
142 return 0;
143
144}
145
146
147inline static cxint
148_giraffe_linedata_set(GiLineData* self, cx_map* map, const cxchar* name,
149 cxint i, cxint j, cxdouble value)
150{
151
152 cxdouble* data = NULL;
153
154 cx_map_const_iterator position = cx_map_find(map, name);
155
156
157 if (position == cx_map_end(map)) {
158
159 cpl_image* buffer = cpl_image_new(self->nfibers, self->nlines,
160 CPL_TYPE_DOUBLE);
161 cx_map_insert(map, cx_strdup(name), buffer);
162 data = cpl_image_get_data(buffer);
163
164 }
165 else {
166
167 data = cpl_image_get_data(cx_map_get_value(map, position));
168
169 }
170
171 data[self->nfibers * j + i] = value;
172
173 return 0;
174
175}
176
177
178inline static cxint
179_giraffe_linedata_get(const GiLineData* self, const cx_map* map,
180 const cxchar* name, cxint i, cxint j, cxdouble* value)
181{
182
183 cxdouble* data = NULL;
184
185 cx_map_const_iterator position = cx_map_find(map, name);
186
187 if (position == cx_map_end(map)) {
188 return 1;
189 }
190
191 data = cpl_image_get_data(cx_map_get_value(map, position));
192 *value = data[self->nfibers * j + i];
193
194 return 0;
195
196}
197
198
199GiLineData*
200giraffe_linedata_new(void)
201{
202
203 GiLineData* self = cx_calloc(1, sizeof *self);
204
205 self->nfibers = 0;
206 self->nlines = 0;
207
208 self->model = NULL;
209 self->ignore = NULL;
210
211 self->wavelength = NULL;
212 self->status = NULL;
213
214 self->values = cx_map_new(_giraffe_linedata_compare, cx_free,
215 (cx_free_func)cpl_image_delete);
216 cx_assert(cx_map_empty(self->values));
217
218 return self;
219
220}
221
222
223GiLineData*
224giraffe_linedata_create(const cpl_table* lines, const cpl_table* fibers,
225 const cxchar* model)
226{
227 cxint i;
228
229 GiLineData* self = NULL;
230
231
232 if (lines == NULL) {
233 return NULL;
234 }
235
236 if (!cpl_table_has_column(lines, "WLEN")) {
237 return NULL;
238 }
239
240 if (fibers == NULL) {
241 return NULL;
242 }
243
244 if (model == NULL) {
245 return NULL;
246 }
247
248 self = cx_malloc(sizeof(GiLineData));
249 cx_assert(self);
250
251 self->nfibers = cpl_table_get_nrow(fibers);
252 self->nlines = cpl_table_get_nrow(lines);
253
254 self->model = cx_strdup(model);
255 self->ignore = cx_calloc(self->nlines, sizeof(cxint));
256
257 self->wavelength = cx_calloc(self->nlines, sizeof(cxdouble));
258
259 for (i = 0; i < self->nlines; i++) {
260 self->wavelength[i] = cpl_table_get(lines, "WLEN", i, NULL);
261 }
262
263 /* Lazy buffer creation! */
264 self->status = NULL;
265
266 self->values = cx_map_new(_giraffe_linedata_compare, cx_free,
267 (cx_free_func)cpl_image_delete);
268 cx_assert(cx_map_empty(self->values));
269
270 return self;
271
272}
273
274
275void
276giraffe_linedata_delete(GiLineData* self)
277{
278
279 if (self) {
280 _giraffe_linedata_clear(self);
281
282 if (self->values != NULL) {
283 cx_map_delete(self->values);
284 }
285
286 cx_free(self);
287 }
288
289 return;
290
291}
292
293
294cxint
295giraffe_linedata_reset(GiLineData* self, const cpl_table* lines,
296 const cpl_table* fibers, const cxchar* model)
297{
298
299 cxint i;
300
301
302 cx_assert(self != NULL);
303
304 if (lines == NULL) {
305 return 1;
306 }
307
308 if (!cpl_table_has_column(lines, "WLEN")) {
309 return 1;
310 }
311
312 if (fibers == NULL) {
313 return 1;
314 }
315
316 if (model == NULL) {
317 return 1;
318 }
319
320
321 self->nfibers = cpl_table_get_nrow(fibers);
322 self->nlines = cpl_table_get_nrow(lines);
323
324 if (self->model != NULL) {
325 cx_free((cxchar*)self->model);
326 }
327 self->model = cx_strdup(model);
328
329 if (self->ignore != NULL) {
330 cx_free(self->ignore);
331 }
332 self->ignore = cx_calloc(self->nlines, sizeof(cxint));
333
334 self->wavelength = cx_realloc(self->wavelength,
335 self->nlines * sizeof(cxdouble));
336
337 for (i = 0; i < self->nlines; i++) {
338
339 self->wavelength[i] = cpl_table_get(lines, "WLEN", i,
340 NULL);
341
342 }
343
344 if (self->status != NULL) {
345 cpl_image_delete(self->status);
346 self->status = NULL;
347 }
348
349 if (!cx_map_empty(self->values)) {
350 cx_map_clear(self->values);
351 }
352
353 return 0;
354
355}
356
357
358const cxchar*
359giraffe_linedata_model(const GiLineData* self)
360{
361
362 cx_assert(self != NULL);
363
364 return self->model;
365
366}
367
368
369cxsize
370giraffe_linedata_lines(const GiLineData* self)
371{
372
373 cx_assert(self != NULL);
374
375 return self->nlines;
376
377}
378
379
380cxsize
381giraffe_linedata_fibers(const GiLineData* self)
382{
383
384 cx_assert(self != NULL);
385
386 return self->nfibers;
387
388}
389
390
391cxbool
392giraffe_linedata_contains(GiLineData* self, const cxchar* name)
393{
394
395 cx_map_const_iterator position;
396
397
398 cx_assert(self != NULL);
399
400 if (name == NULL) {
401 return FALSE;
402 }
403
404 position = cx_map_find(self->values, name);
405
406 if (position == cx_map_end(self->values)) {
407 return FALSE;
408 }
409
410 return TRUE;
411
412}
413
414
415cxsize
416giraffe_linedata_rejected(const GiLineData* self)
417{
418
419 cxint i;
420 cxint* status;
421
422 cxsize count = 0;
423
424
425 cx_assert(self != NULL);
426
427 if (self->status != NULL) {
428
429 status = cpl_image_get_data(self->status);
430
431 for (i = 0; i < self->nfibers * self->nlines; i++) {
432 if (status[i] > 0) {
433 ++count;
434 }
435 }
436
437 }
438
439 return count;
440
441}
442
443
444cxsize
445giraffe_linedata_accepted(const GiLineData* self)
446{
447
448 cxsize count = 0;
449
450
451 cx_assert(self != NULL);
452
453 count = self->nfibers * self->nlines;
454
455 return count - giraffe_linedata_rejected(self);
456
457}
458
459
460cpl_image*
461giraffe_linedata_status(const GiLineData* self)
462{
463
464 cx_assert(self != NULL);
465
466 if (self->status == NULL) {
467 return cpl_image_new(self->nfibers, self->nlines, CPL_TYPE_INT);
468 }
469
470 return cpl_image_duplicate(self->status);
471
472}
473
474
475cxint
476giraffe_linedata_set_status(GiLineData* self, cxint fiber, cxint line,
477 cxint status)
478{
479
480 cxint* data = NULL;
481
482
483 cx_assert(self != NULL);
484
485 if (fiber >= self->nfibers) {
486 return 1;
487 }
488
489 if (line >= self->nlines) {
490 return 1;
491 }
492
493 if (self->status == NULL) {
494 self->status = cpl_image_new(self->nfibers, self->nlines,
495 CPL_TYPE_INT);
496 if (self->status == NULL) {
497 return -1;
498 }
499 }
500
501 data = cpl_image_get_data(self->status);
502
503 data[self->nfibers * line + fiber] = status;
504
505 if (status != 0) {
506 self->ignore[line] += 1;
507 }
508
509 return 0;
510
511}
512
513
514cxint
515giraffe_linedata_get_status(const GiLineData* self, cxint fiber, cxint line)
516{
517
518 cxint* data = NULL;
519
520
521 cx_assert(self != NULL);
522
523 if (fiber >= self->nfibers) {
524 return 1;
525 }
526
527 if (line >= self->nlines) {
528 return 1;
529 }
530
531 if (self->status == NULL) {
532 return 0;
533 }
534
535 data = cpl_image_get_data(self->status);
536
537 return data[self->nfibers * line + fiber];
538
539}
540
541
542cxint
543giraffe_linedata_set_wavelength(GiLineData* self, cxint line, cxdouble lambda)
544{
545
546 cx_assert(self != NULL);
547
548 if (line < 0 || line >= self->nlines) {
549 return 1;
550 }
551
552 self->wavelength[line] = lambda;
553
554 return 0;
555
556}
557
558
559cxdouble
560giraffe_linedata_get_wavelength(const GiLineData* self, cxint line)
561{
562
563 const cxchar* const fctid = "giraffe_linedata_get_wavelength";
564
565
566 cx_assert(self != NULL);
567
568 if (line < 0 || line >= self->nlines) {
569 cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
570 return 0.;
571 }
572
573 return self->wavelength[line];
574
575}
576
577
578cxint
579giraffe_linedata_set(GiLineData* self, const cxchar* name, cxint fiber,
580 cxint line, cxdouble value)
581{
582
583 cxint status = 0;
584
585 cx_assert(self != NULL);
586
587 if (name == NULL) {
588 return 1;
589 }
590
591 if (fiber >= self->nfibers) {
592 return 1;
593 }
594
595 if (line >= self->nlines) {
596 return 1;
597 }
598
599 status = _giraffe_linedata_set(self, self->values, name, fiber, line,
600 value);
601
602 if (status != 0) {
603 return 1;
604 }
605
606 return 0;
607
608}
609
610
611cxdouble
612giraffe_linedata_get(const GiLineData* self, const cxchar* name, cxint fiber,
613 cxint line)
614{
615
616 const cxchar* const fctid = "giraffe_linedata_get";
617
618 cxint status = 0;
619
620 cxdouble value = 0.;
621
622
623 cx_assert(self != NULL);
624
625 if (name == NULL) {
626 return 1;
627 }
628
629 if (fiber >= self->nfibers) {
630 return 1;
631 }
632
633 if (line >= self->nlines) {
634 return 1;
635 }
636
637 status = _giraffe_linedata_get(self, self->values, name, fiber, line,
638 &value);
639
640 if (status != 0) {
641 cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
642 return 0.;
643 }
644
645 return value;
646
647}
648
649
650cxint
651giraffe_linedata_set_data(GiLineData* self, const cxchar* name,
652 const cpl_image* data)
653{
654
655 cxint status = 0;
656
657
658 cx_assert(self != NULL);
659
660 if (name == NULL) {
661 return 1;
662 }
663
664 if (data == NULL) {
665 return 1;
666 }
667
668 status = _giraffe_linedata_assign(self, self->values, name, data);
669
670 if (status != 0) {
671 return 1;
672 }
673
674 return 0;
675
676}
677
678
679const cpl_image*
680giraffe_linedata_get_data(const GiLineData* self, const cxchar* name)
681{
682
683 cx_assert(self != NULL);
684
685 if (name == NULL) {
686 return NULL;
687 }
688
689 return cx_map_get(self->values, name);
690
691}
692
693
694cxint
695giraffe_linedata_load(GiLineData* self, const cxchar* filename)
696{
697
698 cxsize extension = 1;
699
700 cpl_table* lines = NULL;
701
702 cpl_propertylist* p = NULL;
703
704
705 if (self == NULL || filename == NULL) {
706 return -1;
707 }
708
709 _giraffe_linedata_clear(self);
710
711
712 giraffe_error_push();
713
714 p = cpl_propertylist_load(filename, 0);
715
716 if (p == NULL) {
717 return 1;
718 }
719
720 if (cpl_propertylist_has(p, GIALIAS_WSOL_LMNAME) == 0) {
721 return 1;
722 }
723 else {
724
725 self->model = cx_strdup(cpl_propertylist_get_string(p,
726 GIALIAS_WSOL_LMNAME));
727
728 }
729
730 if (cpl_error_get_code() != CPL_ERROR_NONE) {
731
732 if (p != NULL) {
733 cpl_propertylist_delete(p);
734 p = NULL;
735 }
736
737 return 1;
738
739 }
740
741 giraffe_error_pop();
742
743 cpl_propertylist_delete(p);
744 p = NULL;
745
746
747 /*
748 * Load line wavelength and line status flags
749 */
750
751 lines = cpl_table_load(filename, extension, 0);
752
753 if (lines == NULL) {
754 _giraffe_linedata_clear(self);
755 return 2;
756 }
757
758 if (cpl_table_has_column(lines, "WLEN") == FALSE) {
759 _giraffe_linedata_clear(self);
760 cpl_table_delete(lines);
761 return 2;
762 }
763 else {
764
765 const cxdouble* lambda = cpl_table_get_data_double(lines, "WLEN");
766
767 self->nlines = cpl_table_get_nrow(lines);
768
769 self->ignore = cx_calloc(self->nlines, sizeof(cxint));
770 self->wavelength = cx_malloc(self->nlines * sizeof(cxdouble));
771
772 memcpy(self->wavelength, lambda, self->nlines * sizeof(cxdouble));
773 }
774
775 cpl_table_delete(lines);
776
777 ++extension;
778
779 self->status = cpl_image_load(filename, CPL_TYPE_INT, 0, extension);
780
781 if (self->status == NULL) {
782 _giraffe_linedata_clear(self);
783 return 2;
784 }
785
786 self->nfibers = cpl_image_get_size_x(self->status);
787
788 ++extension;
789
790
791 /*
792 * Load the data buffers from the following extensions.
793 * The extension labels are used as names to as the names
794 * of the line parameters.
795 */
796
797 p = cpl_propertylist_load(filename, extension);
798
799 // FIXME: The condition extension < 22 is needed because of a problem
800 // in cpl_propertylist_load() of CPL 4.0. It must be removed if the
801 // patched version is available on Paranal/DFO machines.
802
803 while ((p != NULL) && (extension < 22)) {
804
805 const cxchar* name = cpl_propertylist_get_string(p, GIALIAS_EXTNAME);
806
807 if (name == NULL) {
808 cpl_propertylist_delete(p);
809 p = NULL;
810
811 _giraffe_linedata_clear(self);
812
813 return 3;
814 }
815 else {
816
817 cpl_image* buffer = cpl_image_load(filename, CPL_TYPE_DOUBLE,
818 0, extension);
819
820 if ((cpl_image_get_size_x(buffer) != self->nfibers) ||
821 (cpl_image_get_size_y(buffer) != self->nlines)) {
822
823 cpl_image_delete(buffer);
824 buffer = NULL;
825
826 cpl_propertylist_delete(p);
827 p = NULL;
828
829 _giraffe_linedata_clear(self);
830
831 return 3;
832
833 }
834
835 cx_map_insert(self->values, cx_strdup(name), buffer);
836
837 }
838
839 ++extension;
840
841 cpl_propertylist_delete(p);
842 p = cpl_propertylist_load(filename, extension);
843
844 }
845
846 cpl_propertylist_delete(p);
847 p = NULL;
848
849 return 0;
850
851}
852
853
854cxint
855giraffe_linedata_save(GiLineData* self, const cpl_propertylist* properties,
856 const cxchar* filename)
857{
858
859 cxint status = 0;
860
861 cpl_propertylist* p = NULL;
862
863
864 if (self == NULL || properties == NULL || filename == NULL) {
865 return -1;
866 }
867
868 p = cpl_propertylist_duplicate(properties);
869
870 status = giraffe_linedata_writer(self, p, filename, NULL);
871
872 cpl_propertylist_delete(p);
873 p = NULL;
874
875 return status;
876
877}
878
879
880cxint
881giraffe_linedata_writer(const GiLineData* self, cpl_propertylist* properties,
882 const cxchar* filename, cxcptr data)
883{
884
885 const cxchar* const fctid = "giraffe_linedata_writer";
886
887 cx_map_const_iterator position;
888
889 cpl_propertylist* p = NULL;
890
891 cpl_table* lines = NULL;
892
893
894 /* Unused */
895 (void) data;
896
897 if (self == NULL || properties == NULL || filename == NULL) {
898 return -1;
899 }
900
901 lines = cpl_table_new(self->nlines);
902
903 if (lines == NULL) {
904 return 1;
905 }
906
907 giraffe_error_push();
908
909 cpl_table_new_column(lines, "WLEN", CPL_TYPE_DOUBLE);
910 cpl_table_copy_data_double(lines, "WLEN", self->wavelength);
911
912 if (cpl_error_get_code() != CPL_ERROR_NONE) {
913 cpl_table_delete(lines);
914 lines = NULL;
915
916 return 1;
917 }
918
919 giraffe_error_pop();
920
921
922 cpl_propertylist_erase(properties, "BSCALE");
923 cpl_propertylist_erase(properties, "BZERO");
924 cpl_propertylist_erase(properties, "BUNIT");
925
926 /* FIXME: Workaround for CPL deficiency. World coordinate
927 * keywords are not removed from table headers.
928 */
929
930 cpl_propertylist_erase_regexp(properties, "^CRPIX[0-9]$", 0);
931 cpl_propertylist_erase_regexp(properties, "^CRVAL[0-9]$", 0);
932 cpl_propertylist_erase_regexp(properties, "^CDELT[0-9]$", 0);
933 cpl_propertylist_erase_regexp(properties, "^CTYPE[0-9]$", 0);
934
935 cpl_propertylist_erase_regexp(properties, "^DATA(MIN|MAX)", 0);
936
937 cpl_propertylist_erase(properties, "EXTNAME");
938
939
940 cpl_propertylist_update_string(properties, GIALIAS_WSOL_LMNAME,
941 self->model);
942 cpl_propertylist_set_comment(properties, GIALIAS_WSOL_LMNAME,
943 "Line profile model");
944
945 p = cpl_propertylist_new();
946 cpl_propertylist_append_string(p, GIALIAS_EXTNAME, "LINES");
947 cpl_propertylist_set_comment(p, GIALIAS_EXTNAME, "FITS Extension name");
948
949 giraffe_error_push();
950
951 cpl_table_save(lines, properties, p, filename, CPL_IO_CREATE);
952
953 if (cpl_error_get_code() != CPL_ERROR_NONE) {
954
955 cpl_propertylist_delete(p);
956 p = NULL;
957
958 cpl_table_delete(lines);
959 lines = NULL;
960
961 return 2;
962 }
963
964 cpl_table_delete(lines);
965 lines = NULL;
966
967 giraffe_error_pop();
968
969 cpl_propertylist_set_string(p, GIALIAS_EXTNAME, "LINE_FLAGS");
970
971 giraffe_error_push();
972
973 if (self->status == NULL) {
974
975 cpl_image* status = cpl_image_new(self->nfibers, self->nlines,
976 CPL_TYPE_INT);
977
978 cpl_image_save(status, filename, CPL_BPP_16_SIGNED, p,
979 CPL_IO_EXTEND);
980 cpl_image_delete(status);
981 status = NULL;
982
983 }
984 else {
985 cpl_image_save(self->status, filename, CPL_BPP_16_SIGNED, p,
986 CPL_IO_EXTEND);
987 }
988
989 if (cpl_error_get_code() != CPL_ERROR_NONE) {
990 cpl_propertylist_delete(p);
991 p = NULL;
992
993 return 2;
994 }
995
996 position = cx_map_begin(self->values);
997 while (position != cx_map_end(self->values)) {
998
999 cxint format = 0;
1000
1001 const cpl_image* ldata = cx_map_get_value(self->values, position);
1002
1003
1004 switch (cpl_image_get_type(ldata)) {
1005 case CPL_TYPE_INT:
1006 format = CPL_BPP_32_SIGNED;
1007 break;
1008
1009 case CPL_TYPE_FLOAT:
1010 format = CPL_BPP_IEEE_FLOAT;
1011 break;
1012
1013 case CPL_TYPE_DOUBLE:
1014 format = CPL_BPP_IEEE_FLOAT;
1015 break;
1016
1017 default:
1018 cpl_propertylist_delete(p);
1019 p = NULL;
1020
1021 cpl_error_set(fctid, CPL_ERROR_TYPE_MISMATCH);
1022 return 2;
1023
1024 break;
1025 }
1026
1027 cpl_propertylist_set_string(p, GIALIAS_EXTNAME,
1028 cx_map_get_key(self->values, position));
1029
1030 cpl_image_save(ldata, filename, format, p, CPL_IO_EXTEND);
1031
1032 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1033 cpl_propertylist_delete(p);
1034 p = NULL;
1035
1036 return 2;
1037 }
1038
1039 position = cx_map_next(self->values, position);
1040
1041 }
1042
1043 giraffe_error_pop();
1044
1045 cpl_propertylist_delete(p);
1046 p = NULL;
1047
1048 return 0;
1049
1050}

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 13:47:22 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2004