GIRAFFE Pipeline Reference Manual

gifiberutils.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 <stdlib.h>
25
26#include <cxstring.h>
27#include <cxslist.h>
28#include <cxstrutils.h>
29#include <cxmemory.h>
30#include <cxmessages.h>
31
32#include <cpl_propertylist.h>
33#include <cpl_msg.h>
34#include <cpl_error.h>
35
36#include "gialias.h"
37#include "gierror.h"
38#include "giframe.h"
39#include "gitable.h"
40#include "gimessages.h"
41#include "giutils.h"
42#include "gifiberutils.h"
43
44
53inline static cxint
54_giraffe_compare_int(cxcptr first, cxcptr second)
55{
56
57 cxint *_first = (cxint *)first;
58 cxint *_second = (cxint *)second;
59
60 return *_first - *_second;
61
62}
63
64
85cpl_table *
86giraffe_fiberlist_create(const cxchar *filename, cxint nspec,
87 const cxint *spectra)
88{
89
90 const cxchar *const fctid = "giraffe_fiberlist_create";
91
92
93 cxbool calsim;
94
95 cxint i;
96 cxint status = 0;
97
98 cxint nfibers;
99 cxint nbuttons;
100
101 cxint fiberext = 0;
102
103 cx_string *slit_name = NULL;
104
105 cpl_table *fibers = NULL;
106 cpl_table *_slits;
107 cpl_table *_ozpoz = NULL;
108
109 cpl_propertylist *properties = NULL;
110 cpl_propertylist *ozproperties = NULL;
111 cpl_propertylist *sorting_order = NULL;
112
113 GiTable *slits = NULL;
114 GiTable *ozpoz = NULL;
115
116 GiInstrumentMode mode;
117
118
119
120 if (!filename) {
121 return NULL;
122 }
123
124
125 /*
126 * Check whether the input file is a calibration and retrieve the
127 * name of the slit in use.
128 */
129
130 properties = cpl_propertylist_load(filename, 0);
131
132 if (properties == NULL) {
133 cpl_msg_error(fctid, "Cannot load properties of data set 0 "
134 "from `%s'!", filename);
135 cpl_propertylist_delete(properties);
136 return NULL;
137 }
138 else {
139
140 if (!cpl_propertylist_has(properties, GIALIAS_STSCFF) &&
141 !cpl_propertylist_has(properties, GIALIAS_STSCTAL)) {
142 cpl_msg_warning(fctid, "%s: Properties (%s, %s) not found! "
143 "Simultaneous calibration lamps assumed to "
144 "be off!", filename, GIALIAS_STSCFF,
145 GIALIAS_STSCTAL);
146 calsim = FALSE;
147 }
148 else {
149
150 cxint scff = cpl_propertylist_get_bool(properties,
151 GIALIAS_STSCFF);
152 cxint sctal= cpl_propertylist_get_bool(properties,
153 GIALIAS_STSCTAL);
154
155
156 if (scff || sctal) {
157 cpl_msg_info(fctid, "Simultaneous calibration lamps "
158 "are on.");
159 calsim = TRUE;
160 }
161 else {
162 cpl_msg_info(fctid, "Simultaneous calibration lamps "
163 "are off.");
164 calsim = FALSE;
165 }
166
167 }
168
169
170 slit_name =
171 cx_string_create(cpl_propertylist_get_string(properties,
172 GIALIAS_SLITNAME));
173 if (!slit_name) {
174 cpl_msg_error(fctid, "%s: Property (%s) not found!", filename,
175 GIALIAS_SLITNAME);
176 cpl_propertylist_delete(properties);
177 return NULL;
178 }
179 else {
180 cx_string_strip(slit_name);
181 }
182
183 mode = giraffe_get_mode(properties);
184
185 if (mode == GIMODE_NONE) {
186 cpl_msg_error(fctid, "Invalid instrument mode!");
187
188 cx_string_delete(slit_name);
189 cpl_propertylist_delete(properties);
190
191 return NULL;
192 }
193
194 cpl_propertylist_delete(properties);
195 }
196
197 /*
198 * Check if OzPoz table is present in the input file.
199 * If it is, continue the normal processing.
200 * Otherwise, assume this is a CALSIM file and load the fiber table
201 * from the first extension, refered to as GIOZPOZ_EXTENSION.
202 */
203
204 ozproperties = cpl_propertylist_load(filename, GIOZPOZ_EXTENSION);
205
206 cxint ozstatus = 0;
207
208 if (ozproperties && cpl_propertylist_has(ozproperties, GIALIAS_EXTNAME)) {
209 const cxchar *magic;
210
211 magic = cpl_propertylist_get_string(ozproperties, GIALIAS_EXTNAME);
212
213 if (strcmp(GIOZPOZ_MAGIC, magic) == 0) {
214 ozstatus = 1;
215 fiberext = GIFIBER_EXTENSION;
216 }
217
218 if (strcmp(GIFIBER_MAGIC, magic) == 0) {
219 ozstatus = 2;
220 fiberext = GIOZPOZ_EXTENSION;
221 }
222 }
223
224 if (ozproperties) {
225 cpl_propertylist_delete(ozproperties);
226 }
227
228 /*
229 * Load OzPoz table from current frame
230 */
231
232 if (ozstatus == 1) {
233 ozpoz = giraffe_table_new();
234 cx_assert(ozpoz != NULL);
235
236 giraffe_error_push();
237
238 status = giraffe_table_load(ozpoz, filename, GIOZPOZ_EXTENSION,
239 GIOZPOZ_MAGIC);
240
241 if (status)
242 {
243 if (cpl_error_get_code() == CPL_ERROR_BAD_FILE_FORMAT)
244 {
245 cpl_msg_error(fctid, "Data set %d in `%s' is not an "
246 "OzPoz table!",
247 GIOZPOZ_EXTENSION, filename);
249 cpl_table_delete(fibers);
250
251 return NULL;
252 }
253 else
254 {
255 if (status != 2)
256 {
257 cpl_msg_error(fctid, "No OzPoz table found in `%s'!",
258 filename);
260 return NULL;
261 }
262
263 cpl_msg_warning(fctid, "Empty OzPoz table found in `%s'.",
264 filename);
265 }
266 }
267
268 giraffe_error_pop();
269
270 _ozpoz = giraffe_table_get(ozpoz);
271 }
272
273 /*
274 * Load fiber table from current frame.
275 */
276
277 slits = giraffe_table_new();
278 cx_assert(slits != NULL);
279
280 giraffe_error_push();
281
282 if (giraffe_table_load(slits, filename, fiberext,
283 GIFIBER_MAGIC)) {
284 if (cpl_error_get_code() == CPL_ERROR_BAD_FILE_FORMAT) {
285 cpl_msg_error(fctid, "Data set %d in `%s' is not a fiber table!",
286 GIFIBER_EXTENSION, filename);
288 return NULL;
289 }
290 else {
291 cpl_msg_error(fctid, "Cannot load data set %d (fiber table) "
292 "from `%s'!", GIFIBER_EXTENSION, filename);
294 return NULL;
295 }
296 }
297
298 giraffe_error_pop();
299
300 _slits = giraffe_table_get(slits);
301
302
303 /*
304 * Select all entries with the appropriate slit name from the table
305 */
306
307 cpl_table_select_all(_slits);
308 cpl_table_and_selected_string(_slits, "Slit", CPL_NOT_EQUAL_TO,
309 cx_string_get(slit_name));
310
311 giraffe_error_push();
312
313 cpl_table_erase_selected(_slits);
314
315 if (cpl_error_get_code() != CPL_ERROR_NONE) {
316 cpl_msg_error(fctid, "Invalid slit `%s' selected. No fibers found.",
317 cx_string_get(slit_name));
318
319 cx_string_delete(slit_name);
320 slit_name = NULL;
321
323 slits = NULL;
324
325 return NULL;
326 }
327
328 giraffe_error_pop();
329
330 cx_string_delete(slit_name);
331 slit_name = NULL;
332
333
334 /*
335 * Move the relevant columns from the fiber table to the
336 * final fibers list.
337 */
338
339 nfibers = cpl_table_get_nrow(_slits);
340 fibers = cpl_table_new(nfibers);
341
342 giraffe_error_push();
343
344 cpl_table_new_column(fibers, "INDEX", CPL_TYPE_INT);
345 cpl_table_new_column(fibers, "FPS", CPL_TYPE_INT);
346 cpl_table_new_column(fibers, "SSN", CPL_TYPE_INT);
347 cpl_table_new_column(fibers, "PSSN", CPL_TYPE_INT);
348 cpl_table_new_column(fibers, "RP", CPL_TYPE_INT);
349
350 for (i = 0; i < nfibers; i++) {
351
352 cxchar *s;
353
354 cxint fps = strtol(cpl_table_get_string(_slits, "FPS", i), NULL, 10);
355 cxint ssn = strtol(cpl_table_get_string(_slits, "SSN", i), NULL, 10);
356 cxint pssn = strtol(cpl_table_get_string(_slits, "PSSN", i),
357 NULL, 10);
358 cxint rp = -1;
359
360
361 s = (cxchar*) cpl_table_get_string(_slits, "RP", i);
362
363 if (s != NULL) {
364 rp = strtol(s, NULL, 10);
365 }
366 else {
367 if (mode == GIMODE_ARGUS) {
368
369 const cxchar *rpid = cpl_table_get_string(_slits,
370 "Retractor", i);
371
372 if (cx_strncasecmp(rpid, "Cal", 3) != 0) {
373 rp = 0;
374 }
375
376 }
377 }
378
379 cpl_table_set_int(fibers, "FPS", i, fps);
380 cpl_table_set_int(fibers, "SSN", i, ssn);
381 cpl_table_set_int(fibers, "PSSN", i, pssn);
382 cpl_table_set_int(fibers, "RP", i, rp);
383
384 }
385
386 if (mode == GIMODE_IFU || mode == GIMODE_ARGUS) {
387
388 if (cpl_table_has_column(_slits, "X") &&
389 cpl_table_has_column(_slits, "Y")) {
390
391 cpl_table_new_column(fibers, "X", CPL_TYPE_INT);
392 cpl_table_new_column(fibers, "Y", CPL_TYPE_INT);
393
394 for (i = 0; i < nfibers; i++) {
395 const cxchar *s;
396
397 cxint x = 0;
398 cxint y = 0;
399
400
401 s = cpl_table_get_string(_slits, "X", i);
402
403 if (s != NULL) {
404 x = strtol(s, NULL, 10);
405 }
406
407 s = cpl_table_get_string(_slits, "Y", i);
408
409 if (s != NULL) {
410 y = strtol(s, NULL, 10);
411 }
412
413 cpl_table_set_int(fibers, "X", i, x);
414 cpl_table_set_int(fibers, "Y", i, y);
415 }
416
417 }
418
419 }
420
421 cpl_table_move_column(fibers, "Retractor", _slits);
422
423 if (cpl_error_get_code() != CPL_ERROR_NONE) {
424 cpl_msg_error(fctid, "Data set %d in `%s' is not a valid "
425 "fiber table!", GIFIBER_EXTENSION, filename);
427 cpl_table_delete(fibers);
428
429 return NULL;
430 }
431
432 giraffe_error_pop();
433
435
436
437 /*
438 * For Argus the slit is mirrored compared to IFU and Medusa
439 * and we have to reverse the order of the slits table.
440 */
441
442 if (mode == GIMODE_ARGUS) {
443
444 sorting_order = cpl_propertylist_new();
445
446 cpl_propertylist_append_bool(sorting_order, "FPS", 1);
447 cpl_table_sort(fibers, sorting_order);
448
449 cpl_propertylist_delete(sorting_order);
450 sorting_order = NULL;
451
452 }
453
454
455 /*
456 * Postprocess initial fiber table
457 */
458
459 for (i = 0; i < nfibers; i++) {
460
461 const cxchar *s = cpl_table_get_string(fibers, "Retractor", i);
462
463
464 if (strstr(s, "Calibration")) {
465 cpl_table_set_int(fibers, "RP", i, -1);
466 }
467
468 cpl_table_set_int(fibers, "INDEX", i, i + 1);
469
470 }
471
472 if (!cpl_table_has_column(fibers, "FPD")) {
473 cpl_table_duplicate_column(fibers, "FPD", fibers, "INDEX");
474 }
475
476 cpl_table_new_column(fibers, "OBJECT", CPL_TYPE_STRING);
477 cpl_table_new_column(fibers, "R", CPL_TYPE_DOUBLE);
478 cpl_table_new_column(fibers, "THETA", CPL_TYPE_DOUBLE);
479 cpl_table_new_column(fibers, "ORIENT", CPL_TYPE_DOUBLE);
480 cpl_table_new_column(fibers, "TYPE", CPL_TYPE_STRING);
481
482 cpl_table_fill_column_window_double(fibers, "R", 0, nfibers, 0.);
483 cpl_table_fill_column_window_double(fibers, "THETA", 0, nfibers, 0.);
484 cpl_table_fill_column_window_double(fibers, "ORIENT", 0, nfibers, 0.);
485
486 if (_ozpoz != NULL) {
487 if (cpl_table_has_column(_ozpoz, "RA")) {
488 cpl_table_new_column(fibers, "RA", CPL_TYPE_DOUBLE);
489 cpl_table_fill_column_window_double(fibers, "RA", 0,
490 nfibers, 0.);
491 }
492
493 if (cpl_table_has_column(_ozpoz, "DEC")) {
494 cpl_table_new_column(fibers, "DEC", CPL_TYPE_DOUBLE);
495 cpl_table_fill_column_window_double(fibers, "DEC", 0,
496 nfibers, 0.);
497 }
498
499 if (cpl_table_has_column(_ozpoz, "MAGNITUDE")) {
500 cpl_table_new_column(fibers, "MAGNITUDE", CPL_TYPE_DOUBLE);
501 cpl_table_fill_column_window_double(fibers, "MAGNITUDE", 0,
502 nfibers, 0.);
503 }
504
505 if (cpl_table_has_column(_ozpoz, "B_V")) {
506 cpl_table_new_column(fibers, "B_V", CPL_TYPE_DOUBLE);
507 cpl_table_fill_column_window_double(fibers, "B_V", 0,
508 nfibers, 0.);
509 }
510 }
511
512
513 /*
514 * Select rows in the fiber table which have a corresponding entry
515 * in the OzPoz table. Both tables are associated using the
516 * `button number'. For matching entries the OzPoz data is copied
517 * to the fiber table. Also the simultaneous calibration fibers
518 * are copied.
519 */
520
521 nbuttons = _ozpoz == NULL ? 0 : cpl_table_get_nrow(_ozpoz);
522
523 cpl_table_select_all(fibers);
524
525 for (i = 0; i < nfibers; i++) {
526
527 cxbool missing = TRUE;
528
529 cxint fiber = cpl_table_get_int(fibers, "RP", i, NULL);
530
531
532 /*
533 * If fiber equals -1 it is a simultaneous calibration, which
534 * has no entry in the OzPoz table. Otherwise we try to find it
535 * in the OzPoz table and copy the data for this fiber.
536 */
537
538 if (fiber == -1 && calsim == TRUE) {
539 cpl_table_set_string(fibers, "OBJECT", i, "CALSIM");
540 cpl_table_unselect_row(fibers, i);
541 missing = FALSE;
542 }
543 else if (ozstatus==1 && fiber == 0 && mode == GIMODE_ARGUS) {
544 cpl_table_unselect_row(fibers, i);
545 missing = FALSE;
546 }
547 else {
548
549 register cxint j;
550
551
552 for (j = 0; j < nbuttons; j++) {
553
554 cxint button = cpl_table_get_int(_ozpoz, "BUTTON", j, NULL);
555
556
557 if (fiber == button) {
558 const cxchar *object;
559 const cxchar *otype;
560
561 cxdouble r, theta, orient;
562
563 cxdouble ra = 0.;
564 cxdouble dec = 0.;
565 cxdouble mag = 0.;
566 cxdouble b_v = 0.;
567
568
569 object = cpl_table_get_string(_ozpoz, "OBJECT", j);
570 otype = cpl_table_get_string(_ozpoz, "TYPE", j);
571
572 r = cpl_table_get_double(_ozpoz, "R", j, NULL);
573 theta = cpl_table_get_double(_ozpoz, "THETA", j, NULL);
574 orient = cpl_table_get_double(_ozpoz, "ORIENT", j, NULL);
575
576 if (cpl_table_has_column(_ozpoz, "RA")) {
577 ra = cpl_table_get_double(_ozpoz, "RA", j, NULL);
578 }
579
580 if (cpl_table_has_column(_ozpoz, "DEC")) {
581 dec = cpl_table_get_double(_ozpoz, "DEC", j, NULL);
582 }
583
584 if (cpl_table_has_column(_ozpoz, "MAGNITUDE")) {
585 mag = cpl_table_get_float(_ozpoz, "MAGNITUDE", j,
586 NULL);
587 }
588
589 if (cpl_table_has_column(_ozpoz, "B_V")) {
590 b_v = cpl_table_get_double(_ozpoz, "B_V", j, NULL);
591 b_v = CX_CLAMP(b_v, -5., 5.);
592 }
593
594 cpl_table_set_string(fibers, "OBJECT", i, object);
595 cpl_table_set_string(fibers, "TYPE", i, otype);
596
597 cpl_table_set_double(fibers, "R", i, r);
598 cpl_table_set_double(fibers, "THETA", i, theta);
599 cpl_table_set_double(fibers, "ORIENT", i, orient);
600
601 if (cpl_table_has_column(fibers, "RA")) {
602 cpl_table_set_double(fibers, "RA", i, ra);
603 }
604
605 if (cpl_table_has_column(fibers, "DEC")) {
606 cpl_table_set_double(fibers, "DEC", i, dec);
607 }
608
609 if (cpl_table_has_column(fibers, "MAGNITUDE")) {
610 cpl_table_set_double(fibers, "MAGNITUDE", i, mag);
611 }
612
613 if (cpl_table_has_column(fibers, "B_V")) {
614 cpl_table_set_double(fibers, "B_V", i, b_v);
615 }
616
617 cpl_table_unselect_row(fibers, i);
618 missing = FALSE;
619 break;
620 }
621 }
622 }
623
624 if (missing == TRUE) {
625
626 cxint _fps = cpl_table_get_int(fibers, "FPS", i, NULL);
627 cpl_msg_debug(fctid, "Fiber at FPS = %d and RP = %d is not used", _fps, fiber);
628
629 }
630
631 }
632
633
634 giraffe_error_push();
635
636 cpl_table_erase_selected(fibers);
637
638 if (cpl_error_get_code() != CPL_ERROR_NONE) {
639 cpl_table_delete(fibers);
640 return NULL;
641 }
642
643 giraffe_error_pop();
644
646 ozpoz = NULL;
647
648
649 /*
650 * Finalize the fiber list by applying the user specified fiber
651 * selection list. Fibers which do not have an entry in the
652 * OzPoz table or which are beyond the limits are ignored.
653 */
654
655 if (spectra && nspec > 0) {
656
657 register cxint rows = cpl_table_get_nrow(fibers);
658
659
660 cx_assert(cpl_table_get_column_type(fibers, "FPD") == CPL_TYPE_INT);
661
662 cpl_table_select_all(fibers);
663
664 for (i = 0; i < rows; i++) {
665
666 register cxint j;
667 register cxint selected = 0;
668 register cxint idx = cpl_table_get_int(fibers, "FPD", i, NULL);
669
670
671 for (j = 0; j < nspec; j++) {
672 if (idx == spectra[j]) {
673 selected = 1;
674 break;
675 }
676 }
677
678 if (selected) {
679 cpl_table_unselect_row(fibers, i);
680 }
681 else {
682 cpl_table_select_row(fibers, i);
683 }
684
685 }
686
687 giraffe_error_push();
688
689 cpl_table_erase_selected(fibers);
690
691 if (cpl_error_get_code() != CPL_ERROR_NONE) {
692 cpl_table_delete(fibers);
693 return NULL;
694 }
695
696 giraffe_error_pop();
697
698 }
699
700
701 /*
702 * Update index column
703 */
704
705 for (i = 0; i < cpl_table_get_nrow(fibers); i++) {
706 cpl_table_set_int(fibers, "INDEX", i, i + 1);
707 }
708
709
710 /*
711 * Sort the final table according to the INDEX column
712 */
713
714 cx_assert(sorting_order == NULL);
715
716 sorting_order = cpl_propertylist_new();
717 cpl_propertylist_append_bool(sorting_order, "INDEX", 0);
718
719 cpl_table_sort(fibers, sorting_order);
720
721 cpl_propertylist_delete(sorting_order);
722 sorting_order = NULL;
723
724
725 return fibers;
726
727}
728
729
753GiTable *
754giraffe_fiberlist_load(const cxchar *filename, cxint dataset,
755 const cxchar *tag)
756{
757
758 const cxchar *fctid = "giraffe_fiberlist_load";
759
760
761 GiTable *fibers = giraffe_table_new();
762
763
764 cx_assert(fibers != NULL);
765
766 giraffe_error_push();
767
768 if (giraffe_table_load(fibers, filename, dataset, tag)) {
769 if (cpl_error_get_code() == CPL_ERROR_BAD_FILE_FORMAT) {
770 cpl_msg_error(fctid, "Data set %d in `%s' is not a fiber table!",
771 dataset, filename);
772 giraffe_table_delete(fibers);
773 return NULL;
774 }
775 else {
776 cpl_msg_error(fctid, "Cannot load data set %d (fiber table) "
777 "from `%s'!", dataset, filename);
778 giraffe_table_delete(fibers);
779 return NULL;
780 }
781 }
782
783 giraffe_error_pop();
784
785 return fibers;
786
787}
788
789
806cxint
807giraffe_fiberlist_save(GiTable *fibers, const cxchar *filename)
808{
809
810 const cxchar *fctid = "giraffe_fiberlist_save";
811
812 cxbool created = FALSE;
813
814 cxint code;
815
816 cpl_propertylist *properties = NULL;
817 cpl_table *table = NULL;
818
819
820 if (fibers == NULL || filename == NULL) {
821 cpl_error_set(fctid, CPL_ERROR_NULL_INPUT);
822 return 1;
823 }
824
825 table = giraffe_table_get(fibers);
826
827 if (table == NULL) {
828 cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
829 return 1;
830 }
831
832 properties = giraffe_table_get_properties(fibers);
833
834 if (properties == NULL) {
835 properties = cpl_propertylist_new();
836
837 cpl_propertylist_append_string(properties, GIALIAS_EXTNAME,
838 GIFRAME_FIBER_SETUP);
839 created = TRUE;
840
841 giraffe_table_set_properties(fibers, properties);
842 }
843 else {
844 if (cpl_propertylist_has(properties, GIALIAS_EXTNAME)) {
845 cpl_propertylist_set_string(properties, GIALIAS_EXTNAME,
846 GIFRAME_FIBER_SETUP);
847 }
848 else {
849 cpl_propertylist_append_string(properties, GIALIAS_EXTNAME,
850 GIFRAME_FIBER_SETUP);
851 }
852 }
853 cpl_propertylist_set_comment(properties, GIALIAS_EXTNAME,
854 "FITS Extension name");
855
856 code = cpl_table_save(table, NULL, properties, filename, CPL_IO_EXTEND);
857
858 if (created == TRUE) {
859 cpl_propertylist_delete(properties);
860 }
861
862 return code == CPL_ERROR_NONE ? 0 : 1;
863
864}
865
866
883cxint
884giraffe_fiberlist_attach(cpl_frame *frame, GiTable *fibers)
885{
886
887 const cxchar *fctid = "giraffe_fiberlist_attach";
888
889
890 cxbool created = FALSE;
891
892 cxint status = 0;
893
894 cpl_propertylist *properties = NULL;
895
896 GiTable *_fibers = NULL;
897
898
899 if (frame == NULL || fibers == NULL) {
900 cpl_error_set(fctid, CPL_ERROR_NULL_INPUT);
901 return 1;
902 }
903
904 _fibers = giraffe_table_duplicate(fibers);
905
906 properties = giraffe_table_get_properties(_fibers);
907
908 if (properties == NULL) {
909 properties = cpl_propertylist_new();
910 giraffe_table_set_properties(_fibers, properties);
911 created = TRUE;
912 }
913
914 if (cpl_table_has_column(giraffe_table_get(_fibers), "RINDEX")) {
915 cpl_table_erase_column(giraffe_table_get(_fibers), "RINDEX");
916 }
917
918 status = giraffe_frame_attach_table(frame, _fibers, GIFRAME_FIBER_SETUP,
919 TRUE);
920
921 if (created == TRUE) {
922 cpl_propertylist_delete(properties);
923 }
924
925 properties = NULL;
926
927 giraffe_table_delete(_fibers);
928 _fibers = NULL;
929
930 return status;
931
932}
933
934
952cxint giraffe_fiberlist_compare(const GiTable *fibers,
953 const GiTable *reference)
954{
955
956 register cxint i;
957 cxint equal = 1;
958
959 cpl_table *_fibers = giraffe_table_get(fibers);
960 cpl_table *_reference = giraffe_table_get(reference);
961
962
963 if (_fibers == NULL || _reference == NULL) {
964 return -1;
965 }
966
967 if (!cpl_table_has_column(_fibers, "FPS") ||
968 !cpl_table_has_column(_reference, "FPS")) {
969 return -2;
970 }
971
972
973 for (i = 0; i < cpl_table_get_nrow(_reference); i++) {
974
975 cxbool found = FALSE;
976
977 cxint j;
978 cxint fps = cpl_table_get_int(_reference, "FPS", i, NULL);
979
980 for (j = 0; j < cpl_table_get_nrow(_fibers); j++) {
981 cxint _fps = cpl_table_get_int(_fibers, "FPS", j, NULL);
982
983 if (fps == _fps) {
984 found = TRUE;
985 break;
986 }
987 }
988
989 if (found == FALSE) {
990 equal = 0;
991 break;
992 }
993
994 }
995
996 return equal;
997
998}
999
1000
1021cxint
1022giraffe_fiberlist_associate(GiTable *fibers, const GiTable *reference)
1023{
1024
1025 const cxchar *fctid = "giraffe_fiberlist_associate";
1026
1027 register cxint i;
1028
1029 cxint nf = 0;
1030 cxint nr = 0;
1031
1032 cpl_table *_fibers = NULL;
1033 cpl_table *_reference = NULL;
1034
1035
1036 if (fibers == NULL) {
1037 cpl_error_set(fctid, CPL_ERROR_NULL_INPUT);
1038 return 1;
1039 }
1040
1041 if (reference == NULL) {
1042 cpl_error_set(fctid, CPL_ERROR_NULL_INPUT);
1043 return 1;
1044 }
1045
1046 _fibers = giraffe_table_get(fibers);
1047 _reference = giraffe_table_get(reference);
1048
1049 if (!cpl_table_has_column(_fibers, "FPS")) {
1050 cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
1051 return 1;
1052 }
1053
1054 if (!cpl_table_has_column(_reference, "FPS")) {
1055 cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
1056 return 1;
1057 }
1058
1059
1060 /*
1061 * Create new column containing the fiber index of the calibration
1062 * spectrum in the reference table which is used to process the current
1063 * spectrum.
1064 */
1065
1066 if (!cpl_table_has_column(_fibers, "RINDEX")) {
1067
1068 cxint size = cpl_table_get_nrow(_fibers);
1069
1070 cxint status = cpl_table_duplicate_column(_fibers, "RINDEX",
1071 _fibers, "INDEX");
1072
1073 if (status != CPL_ERROR_NONE) {
1074 return 2;
1075 }
1076
1077 status = cpl_table_fill_column_window_int(_fibers, "RINDEX", 0,
1078 size, -1);
1079
1080 if (status != CPL_ERROR_NONE) {
1081 return 2;
1082 }
1083
1084 }
1085
1086
1087 /*
1088 * Write the reference fiber index of all fibers with a corresponding
1089 * entry in the reference fiber list to the input fiber list and select
1090 * it. Extract all selected fibers.
1091 */
1092
1093 nf = cpl_table_get_nrow(_fibers);
1094 nr = cpl_table_get_nrow(_reference);
1095
1096 cpl_table_unselect_all(_fibers);
1097
1098 for (i = 0; i < nf; i++) {
1099
1100 register cxint j;
1101
1102 cxint fps = cpl_table_get_int(_fibers, "FPS", i, NULL);
1103
1104
1105 for (j = 0; j < nr; j++) {
1106
1107 cxint _fps = cpl_table_get_int(_reference, "FPS", j, NULL);
1108
1109
1110 if (fps == _fps) {
1111
1112 cxint ridx = cpl_table_get_int(_reference, "INDEX", j, NULL);
1113
1114 cpl_table_set_int(_fibers, "RINDEX", i, ridx);
1115 cpl_table_select_row(_fibers, i);
1116
1117 break;
1118 }
1119 }
1120 }
1121
1122
1123 /*
1124 * From this point on, _fibers is not just a reference anymore, but
1125 * points to a newly allocated table object, which must be managed
1126 * properly.
1127 */
1128
1129 _fibers = cpl_table_extract_selected(_fibers);
1130
1131
1132 /*
1133 * Rewrite index column
1134 */
1135
1136 for (i = 0; i < cpl_table_get_nrow(_fibers); i++) {
1137 cpl_table_set_int(_fibers, "INDEX", i, i + 1);
1138 }
1139
1140
1141 giraffe_table_set(fibers, _fibers);
1142
1143 cpl_table_delete(_fibers);
1144
1145 return 0;
1146
1147}
1148
1149
1163cxint
1165{
1166
1167 cpl_table* _fibers = NULL;
1168
1169 if (fibers == NULL) {
1170 return -1;
1171 }
1172
1173 _fibers = giraffe_table_get(fibers);
1174
1175 if (_fibers == NULL) {
1176 return 1;
1177 }
1178
1179 giraffe_error_push();
1180
1181 if (cpl_table_has_column(_fibers, "RINDEX") == TRUE) {
1182 cpl_table_erase_column(_fibers, "RINDEX");
1183 }
1184
1185 if (cpl_error_get_code() != CPL_ERROR_NONE) {
1186 return 2;
1187 }
1188
1189 giraffe_error_pop();
1190
1191 return 0;
1192
1193}
1209const cxchar *
1210giraffe_fiberlist_query_index(const cpl_table *fibers)
1211{
1212
1213 const cxchar *names[] = {"RINDEX", "INDEX", NULL};
1214 const cxchar **idx = names;
1215
1216
1217 while (*idx != NULL) {
1218
1219 if (cpl_table_has_column((cpl_table *)fibers, *idx) != 0) {
1220 break;
1221 }
1222
1223 ++idx;
1224 }
1225
1226 return *idx;
1227
1228}
1229
1230
1246cpl_array*
1247giraffe_fiberlist_get_subslits(const cpl_table* fibers)
1248{
1249
1250 cxint nfibers = 0;
1251
1252 cpl_array* subslits = NULL;
1253
1254
1255 cx_assert(fibers != NULL);
1256
1257 nfibers = cpl_table_get_nrow(fibers);
1258
1259
1260 if (nfibers > 0) {
1261
1262 cxint i = 0;
1263 cxint nss = 0;
1264 cxint* ssn = NULL;
1265
1266
1267 subslits = cpl_array_new(nfibers, CPL_TYPE_INT);
1268 cpl_array_fill_window(subslits, 0, nfibers, 0);
1269
1270 ssn = cpl_array_get_data_int(subslits);
1271
1272
1273 /*
1274 * Create sorted list of subslit numbers
1275 */
1276
1277 for (i = 0; i < nfibers; ++i) {
1278 ssn[i] = cpl_table_get_int(fibers, "SSN", i, NULL);
1279 }
1280
1281 qsort(ssn, nfibers, sizeof(cxint), _giraffe_compare_int);
1282
1283
1284 /*
1285 * Remove duplicate subslit numbers from the list
1286 */
1287
1288 for (i = 1; i < nfibers; ++i) {
1289 if (ssn[i] != ssn[nss]) {
1290 ssn[++nss] = ssn[i];
1291 }
1292 }
1293
1294 ++nss;
1295 cpl_array_set_size(subslits, nss);
1296
1297 }
1298
1299 return subslits;
1300
1301}
1302
1303
1333cxint *
1334giraffe_parse_spectrum_selection(const cxchar *selection, cxint *nspec)
1335{
1336
1337 cxchar **lists = NULL;
1338 cxchar **ranges = NULL;
1339
1340 cxint i;
1341 cxint first = 0;
1342 cxint nfibers = 0;
1343 cxint *fibers = NULL;
1344 cxint *_fibers = NULL;
1345
1346 cx_slist *fl = NULL;
1347
1348 cx_slist_iterator pos;
1349
1350
1351 *nspec = 0;
1352
1353 lists = cx_strsplit(selection, ";", 2);
1354
1355 if (lists == NULL) {
1356 return NULL;
1357 }
1358
1359 if (lists[1] != NULL) {
1360 gi_warning("Usage of fiber exclusion lists is not supported! "
1361 "The given exclusion list is ignored!");
1362 }
1363
1364 ranges = cx_strsplit(lists[0], ",", -1);
1365
1366 if (ranges == NULL) {
1367 cx_strfreev(lists);
1368 return NULL;
1369 }
1370
1371 i = 0;
1372 while (ranges[i] != NULL) {
1373
1374 cxchar **bounds = cx_strsplit(ranges[i], "-", 2);
1375
1376 cxint j;
1377
1378
1379 if (bounds == NULL) {
1380 cx_strfreev(ranges);
1381 cx_strfreev(lists);
1382
1383 if (fibers) {
1384 cx_free(fibers);
1385 }
1386
1387 return NULL;
1388 }
1389 else {
1390
1391 cxchar *last;
1392
1393 cxlong lower = -1;
1394 cxlong upper = -1;
1395
1396
1397 lower = strtol(bounds[0], &last, 10);
1398
1399 if (*last != '\0') {
1400 cx_strfreev(bounds);
1401 cx_strfreev(ranges);
1402 cx_strfreev(lists);
1403
1404 if (fibers) {
1405 cx_free(fibers);
1406 }
1407
1408 return NULL;
1409 }
1410
1411 if (bounds[1] != NULL) {
1412
1413 upper = strtol(bounds[1], &last, 10);
1414
1415 if (*last != '\0') {
1416 cx_strfreev(bounds);
1417 cx_strfreev(ranges);
1418 cx_strfreev(lists);
1419
1420 if (fibers) {
1421 cx_free(fibers);
1422 }
1423
1424 return NULL;
1425 }
1426 }
1427
1428 upper = upper > 0 ? upper : lower;
1429
1430 if (lower <= 0 || upper <= 0 || upper < lower) {
1431 cx_strfreev(bounds);
1432 cx_strfreev(ranges);
1433 cx_strfreev(lists);
1434
1435 if (fibers) {
1436 cx_free(fibers);
1437 }
1438
1439 return NULL;
1440 }
1441
1442 ++nfibers;
1443
1444 if (upper > lower) {
1445 nfibers += upper - lower;
1446 }
1447
1448 fibers = cx_realloc(fibers, nfibers * sizeof(cxint));
1449
1450 for (j = first; j < nfibers; j++) {
1451 fibers[j] = lower + j - first;
1452 }
1453
1454 first = nfibers;
1455
1456 }
1457
1458 cx_strfreev(bounds);
1459 bounds = NULL;
1460
1461 ++i;
1462
1463 }
1464
1465 cx_strfreev(ranges);
1466 cx_strfreev(lists);
1467
1468 qsort(fibers, nfibers, sizeof(cxint), _giraffe_compare_int);
1469
1470
1471 /*
1472 * Remove duplicates from the fiber list
1473 */
1474
1475 fl = cx_slist_new();
1476
1477 for (i = 0; i < nfibers; i++) {
1478 cx_slist_push_back(fl, fibers + i);
1479 }
1480
1481 cx_slist_unique(fl, _giraffe_compare_int);
1482
1483 nfibers = cx_slist_size(fl);
1484 _fibers = cx_malloc(nfibers * sizeof(cxint));
1485
1486 i = 0;
1487
1488 pos = cx_slist_begin(fl);
1489 while (pos != cx_slist_end(fl)) {
1490
1491 cxint *fn = cx_slist_get(fl, pos);
1492
1493 cx_assert(fn != NULL);
1494 _fibers[i] = *fn;
1495
1496 pos = cx_slist_next(fl, pos);
1497 ++i;
1498 }
1499 cx_slist_delete(fl);
1500 cx_free(fibers);
1501
1502 *nspec = nfibers;
1503 return _fibers;
1504
1505}
1506
1507
1519cxint *
1521 const GiTable *reference, cxint *nspec)
1522{
1523
1524 cpl_table *fibers = giraffe_fiberlist_create(filename, 0, NULL);
1525 cpl_table *_reference = giraffe_table_get(reference);
1526
1527 cxint i = 0;
1528 cxint nspectra = 0;
1529 cxint nfibers = cpl_table_get_nrow(fibers);
1530 cxint nactive = cpl_table_get_nrow(_reference);
1531 cxint *spectra = NULL;
1532
1533
1534 if (fibers == NULL) {
1535 return NULL;
1536 }
1537
1538 if (!cpl_table_has_column(fibers, "FPS") ||
1539 !cpl_table_has_column(fibers, "FPD")) {
1540 cpl_table_delete(fibers);
1541 return NULL;
1542 }
1543
1544 if (!cpl_table_has_column(_reference, "FPS")) {
1545 cpl_table_delete(fibers);
1546 return NULL;
1547 }
1548
1549 if (nactive > nfibers) {
1550 cpl_table_delete(fibers);
1551 return NULL;
1552 }
1553
1554 *nspec = 0;
1555 spectra = cx_malloc(nactive * sizeof(cxint));
1556
1557 for (i = 0; i < nactive; ++i) {
1558
1559 cxint j = 0;
1560 cxint fps = cpl_table_get_int(_reference, "FPS", i, NULL);
1561
1562 for (j = 0; j < nfibers; ++j) {
1563
1564 cxint _fps = cpl_table_get_int(fibers, "FPS", j, NULL);
1565 cxint _fpd = cpl_table_get_int(fibers, "FPD", j, NULL);
1566
1567 if (_fps == fps) {
1568 spectra[nspectra] = _fpd;
1569 ++nspectra;
1570 break;
1571 }
1572
1573 }
1574
1575 }
1576
1577 cpl_table_delete(fibers);
1578
1579 if (nspectra < nactive) {
1580 spectra = cx_realloc(spectra, nspectra * sizeof(cxint));
1581 }
1582
1583 qsort(spectra, nspectra, sizeof(cxint), _giraffe_compare_int);
1584 *nspec = nspectra;
1585
1586 return spectra;
1587
1588}
GiTable * giraffe_fiberlist_load(const cxchar *filename, cxint dataset, const cxchar *tag)
Load a fiber table from a file.
Definition: gifiberutils.c:754
cpl_table * giraffe_fiberlist_create(const cxchar *filename, cxint nspec, const cxint *spectra)
Creates the fiber table.
Definition: gifiberutils.c:86
cxint giraffe_fiberlist_save(GiTable *fibers, const cxchar *filename)
Save a fiber table to a file.
Definition: gifiberutils.c:807
cxint giraffe_fiberlist_compare(const GiTable *fibers, const GiTable *reference)
Compare two fiber lists.
Definition: gifiberutils.c:952
cxint giraffe_fiberlist_attach(cpl_frame *frame, GiTable *fibers)
Attach a fiber table to a frame.
Definition: gifiberutils.c:884
cpl_array * giraffe_fiberlist_get_subslits(const cpl_table *fibers)
Get the list of subslit identifiers from a fiber setup.
const cxchar * giraffe_fiberlist_query_index(const cpl_table *fibers)
Query a fiber list for the name of the fiber reference index column.
cxint * giraffe_parse_spectrum_selection(const cxchar *selection, cxint *nspec)
Parses a spectrum selection string.
cxint * giraffe_create_spectrum_selection(const cxchar *filename, const GiTable *reference, cxint *nspec)
Create a spectrum selection from a reference table.
cxint giraffe_fiberlist_associate(GiTable *fibers, const GiTable *reference)
Associate a fiberlist with a reference list.
cxint giraffe_fiberlist_clear_index(GiTable *fibers)
Remove the reference index column from a fiber list.
cxint giraffe_frame_attach_table(cpl_frame *frame, GiTable *table, const cxchar *tag, cxbool update)
Attach a table to a product frame.
Definition: giframe.c:645
void gi_warning(const cxchar *format,...)
Log a warning.
Definition: gimessages.c:119
cxint giraffe_table_set(GiTable *self, cpl_table *table)
Sets the table data.
Definition: gitable.c:456
GiTable * giraffe_table_new(void)
Creates a new, empty Giraffe table.
Definition: gitable.c:85
GiTable * giraffe_table_duplicate(const GiTable *src)
Duplicate a Giraffe table.
Definition: gitable.c:176
cxint giraffe_table_load(GiTable *self, const cxchar *filename, cxint position, const cxchar *id)
Reads a data set from a file into a Giraffe table.
Definition: gitable.c:562
void giraffe_table_delete(GiTable *self)
Destroys a Giraffe table.
Definition: gitable.c:154
cpl_table * giraffe_table_get(const GiTable *self)
Get the table data from a Giraffe table.
Definition: gitable.c:433
cpl_propertylist * giraffe_table_get_properties(const GiTable *self)
Gets the table properties.
Definition: gitable.c:489
cxint giraffe_table_set_properties(GiTable *self, cpl_propertylist *properties)
Attaches a property list to an table.
Definition: gitable.c:516
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 13:47:22 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2004