GIRAFFE Pipeline Reference Manual

gifov.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 <math.h>
25
26#include <cxslist.h>
27#include <cxstrutils.h>
28#include <cxmemory.h>
29#include <cxmessages.h>
30
31#include <cpl_array.h>
32#include <cpl_propertylist.h>
33
34#include "gialias.h"
35#include "gimacros.h"
36#include "gierror.h"
37#include "gimessages.h"
38#include "gigrating.h"
39#include "gifov.h"
40#include "gifiberutils.h"
41#include "gisutils.h"
42#include "giutils.h"
43
44
54inline static cxint
55_giraffe_compare_int(cxcptr first, cxcptr second)
56{
57
58 cxint *_first = (cxint *)first;
59 cxint *_second = (cxint *)second;
60
61 return *_first - *_second;
62
63}
64
65
66inline static GiCube*
67_giraffe_fov_create_cube(const GiImage* spectra,
68 const cpl_table* fibers,
69 const GiRange* limits)
70{
71
72 cxint first = 0;
73 cxint last = 0;
74 cxint nx = 0;
75 cxint ny = 0;
76 cxint nz = 0;
77
78 cxdouble wmin = 0.;
79 cxdouble wmax = 0.;
80 cxdouble wstep = 0.;
81 /*cxdouble fstart = 1.;*/
82 /*cxdouble fend = 1.;*/
83
84 cpl_propertylist* properties = giraffe_image_get_properties(spectra);
85
86 cpl_image* _spectra = giraffe_image_get(spectra);
87
88 GiCube* cube = NULL;
89
90
91 if ((properties == NULL) || (_spectra == NULL)) {
92 return NULL;
93 }
94
95
96 /*
97 * Get the spectral range of the input spectra.
98 */
99
100 if (cpl_propertylist_has(properties, GIALIAS_BINWLMIN) == FALSE) {
101 return NULL;
102 }
103 else {
104 wmin = cpl_propertylist_get_double(properties, GIALIAS_BINWLMIN);
105 }
106
107 if (cpl_propertylist_has(properties, GIALIAS_BINWLMAX) == FALSE) {
108 return NULL;
109 }
110 else {
111 wmax = cpl_propertylist_get_double(properties, GIALIAS_BINWLMAX);
112 }
113
114 if (cpl_propertylist_has(properties, GIALIAS_BINSTEP) == FALSE) {
115 return NULL;
116 }
117 else {
118 wstep = cpl_propertylist_get_double(properties, GIALIAS_BINSTEP);
119 }
120
121
122 /*
123 * Determine the pixel limits corresponding to the spectral range.
124 */
125
126 first = 0;
127 last = cpl_image_get_size_y(_spectra) - 1;
128
129 if (limits != NULL) {
130
131 if (giraffe_range_get_min(limits) > wmin) {
132
133 cxdouble pixel = (giraffe_range_get_min(limits) - wmin) / wstep;
134
135
136 first = ceil(pixel);
137 /*fstart = pixel - first;*/
138
139 }
140
141 if (giraffe_range_get_max(limits) < wmax) {
142
143 cxdouble pixel = last - (wmax - giraffe_range_get_max(limits)) / wstep;
144
145
146 last = floor(pixel);
147 /*fend = pixel - last;*/
148
149 }
150
151 }
152
153
154 /*
155 * Determine the layout of the cube from the list of fibers.
156 */
157
158 giraffe_error_push();
159
160 nx = (cxint) cpl_table_get_column_max(fibers, "X");
161 ny = (cxint) cpl_table_get_column_max(fibers, "Y");
162
163 if (cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) {
164 return NULL;
165 }
166
167 giraffe_error_pop();
168
169
170 nz = last - first + 1;
171
172 if (nz <= 0) {
173 return NULL;
174 }
175
176
177 /*
178 * Create the data cube and fill it with the flux values.
179 */
180
181 cube = giraffe_cube_create(nx, ny, nz, NULL);
182
183 giraffe_cube_set_xaxis(cube, 1., 1.);
184 giraffe_cube_set_yaxis(cube, 1., 1.);
185 giraffe_cube_set_zaxis(cube, wmin, wstep);
186
187 if (cube != NULL) {
188
189 register cxint i = 0;
190 register cxint nf = cpl_table_get_nrow(fibers);
191
192 cxint ns = cpl_image_get_size_x(_spectra);
193
194 cxdouble* spixels = cpl_image_get_data_double(_spectra);
195 cxdouble* cpixels = giraffe_cube_get_data(cube);
196
197
198 cx_assert(spixels != NULL);
199 cx_assert(cpixels != NULL);
200 cx_assert(nf <= ns);
201
202 for (i = 0; i < nf; ++i) {
203
204 register cxint j = 0;
205
206 cxint idx = cpl_table_get_int(fibers, "INDEX", i, NULL) - 1;
207 cxint x = cpl_table_get_int(fibers, "X", i, NULL) - 1;
208 cxint y = cpl_table_get_int(fibers, "Y", i, NULL) - 1;
209
210
211 /*
212 * Fill image pixels skipping special fibers (CalSim or Sky)
213 * which have x = 0 and y = 0.
214 */
215
216 if ((x >= 0) && (y >= 0)) {
217
218 for (j = 0; j < nz; ++j) {
219 cpixels[(ny * j + y) * nx + x] =
220 spixels[(first + j) * ns + idx];
221 }
222
223 }
224
225 }
226
227 }
228
229 return cube;
230
231}
232
233
234/*
235 * Arrange the input images into an output image using a tabular layout.
236 */
237
238inline static cpl_image*
239_giraffe_fov_arrange_images(const cx_slist* subimages,
240 cxsize nrows, cxsize ncolumns, cxint offset)
241{
242
243 cxint x = 0;
244 cxint y = 0;
245 cxint nx = 0;
246 cxint ny = 0;
247 cxint sx = 0;
248 cxint sy = 0;
249 cxint xshift = offset;
250 cxint yshift = offset;
251
252 cxsize nslit = 0;
253 cxsize column = 0;
254
255 cx_slist_iterator pos;
256
257 cpl_image* image = NULL;
258
259
260 cx_assert(subimages != NULL);
261 cx_assert(nrows > 0);
262 cx_assert(ncolumns > 0);
263
264
265 /*
266 * Compute the size of the combined output image from the largest
267 * image in the list. The properties of the mosaic image are taken
268 * from the first (non-empty) image in the list.
269 */
270
271 pos = cx_slist_begin(subimages);
272
273 while (pos != cx_slist_end(subimages)) {
274
275 const cpl_image* simage = cx_slist_get(subimages, pos);
276
277 if (simage != NULL) {
278
279 cxint _nx = cpl_image_get_size_x(simage);
280 cxint _ny = cpl_image_get_size_y(simage);
281
282 sx = CX_MAX(nx, _nx);
283 sy = CX_MAX(ny, _ny);
284
285 }
286
287 pos = cx_slist_next(subimages, pos);
288
289 }
290
291
292 /*
293 * Adjust the number of rows to what is actually needed.
294 */
295
296 nslit = cx_slist_size(subimages);
297 nrows = CX_MAX(nslit / ncolumns, nrows);
298
299 if (nslit % ncolumns != 0) {
300 ++nrows;
301 }
302
303
304 /*
305 * Compute the size of the final "mosaic" image
306 */
307
308 nx = sx * ncolumns;
309 ny = sy * nrows;
310
311
312 if (offset < 0) {
313 xshift = nx / -offset + 1;
314 yshift = ny / -offset + 1;
315 }
316
317 nx += ncolumns * xshift - (xshift % 2);
318 ny += nrows * yshift - (yshift % 2);
319
320
321 /*
322 * Arrange subimages into a single image.
323 */
324
325 image = cpl_image_new(nx, ny, CPL_TYPE_DOUBLE);
326
327 y = yshift / 2;
328 x = xshift / 2;
329
330 pos = cx_slist_begin(subimages);
331
332 while (pos != cx_slist_end(subimages)) {
333
334 const cpl_image* simage = cx_slist_get(subimages, pos);
335
336 if (simage != NULL) {
337
338 cpl_error_code status = cpl_image_copy(image, simage,
339 x + 1, y + 1);
340
341 if (status != CPL_ERROR_NONE) {
342 cpl_image_delete(image);
343 return NULL;
344 }
345
346 }
347
348 ++column;
349
350 if (column < ncolumns) {
351 x += sx + xshift;
352 }
353 else {
354 column = 0;
355
356 x = xshift / 2;
357 y += sy + yshift;
358 }
359
360 pos = cx_slist_next(subimages, pos);
361
362 }
363
364 return image;
365
366}
367
368
369inline static cpl_image*
370_giraffe_fov_integrate_cube(const GiCube* cube, const GiRange* limits)
371{
372
373 cxsize depth = 0;
374
375 cxdouble wmin = 0.;
376 cxdouble wmax = 0.;
377 cxdouble wstep = 0.;
378 cxdouble start = 0.;
379 cxdouble end = 0.;
380
381 cpl_image* image = NULL;
382
383
384 cx_assert(cube != NULL);
385
386 depth = giraffe_cube_get_depth(cube);
387 giraffe_cube_get_zaxis(cube, &wmin, &wstep);
388
389 wmax = wmin + depth * wstep;
390 end = depth;
391
392 if (giraffe_range_get_min(limits) > wmin) {
393 start = (giraffe_range_get_min(limits) - wmin) / wstep;
394 }
395
396 if (giraffe_range_get_max(limits) < wmax) {
397 end = (giraffe_range_get_max(limits) - wmin) / wstep;
398 }
399
400 image = giraffe_cube_integrate(cube, start, end);
401
402 return image;
403
404}
405
406
428cxint
429giraffe_fov_build(GiFieldOfView* result, GiRebinning* rebinning,
430 GiTable* fibers, GiTable* wsolution,
431 GiTable* grating, GiTable* slitgeometry,
432 GiFieldOfViewConfig* config)
433{
434
435 const cxchar* const fctid = "giraffe_fov_build";
436
437 cxbool log_scale = FALSE;
438
439 cx_slist* simages = NULL;
440 cx_slist* eimages = NULL;
441 cx_slist* scubes = NULL;
442 cx_slist* ecubes = NULL;
443
444 cpl_propertylist* properties = NULL;
445
446 cpl_array* ssn = NULL;
447
448 cpl_image* fov = NULL;
449
450 cpl_table* _fibers = NULL;
451
452 GiInstrumentMode mode;
453
454 GiRange* limits = NULL;
455
456
457 if (result == NULL) {
458 cpl_error_set(fctid, CPL_ERROR_NULL_INPUT);
459 return -1;
460 }
461 else {
462
463 /*
464 * Make sure that the field of view object is empty
465 */
466
467 giraffe_fov_clear(result);
468
469 }
470
471 if (rebinning == NULL) {
472 cpl_error_set(fctid, CPL_ERROR_NULL_INPUT);
473 return -1;
474 }
475
476 if (rebinning->spectra == NULL || rebinning->errors == NULL) {
477 cpl_error_set(fctid, CPL_ERROR_ILLEGAL_INPUT);
478 return -1;
479 }
480
481 if (fibers == NULL) {
482 cpl_error_set(fctid, CPL_ERROR_NULL_INPUT);
483 return -1;
484 }
485
486 _fibers = giraffe_table_get(fibers);
487
488 if (_fibers == NULL) {
489 cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
490 return -1;
491 }
492
493 if (!cpl_table_has_column(_fibers, "X") ||
494 !cpl_table_has_column(_fibers, "Y")) {
495 cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
496 return -2;
497 }
498
499 if (config == NULL) {
500 cpl_error_set(fctid, CPL_ERROR_NULL_INPUT);
501 return -1;
502 }
503
504
505 /*
506 * Determine the instrument mode. Spectra taken in IFU mode must
507 * be processed on a per subslit basis, while ARGUS data can
508 * be processed ignoring the subslit information (simple
509 * reconstruction based on X and Y positions of fibers only)
510 */
511
512 properties = giraffe_image_get_properties(rebinning->spectra);
513
514 if (properties == NULL) {
515 cpl_error_set(fctid, CPL_ERROR_DATA_NOT_FOUND);
516 return -1;
517 }
518
519 mode = giraffe_get_mode(properties);
520
521
522 /*
523 * By default the cube and the fov-image will be reconstructed from
524 * the input spectra common wavelength range. If a wavelength range
525 * was specified by parameter settings these will be used, clamped
526 * to the input spectra common wavelength range.
527 */
528
529 limits = giraffe_rebin_get_wavelength_range(rebinning->spectra, wsolution,
530 grating, slitgeometry, TRUE);
531
532 if (limits == NULL) {
533 cpl_msg_error(fctid, "Computation of spectra common wavelength "
534 "range failed!");
535 return 1;
536 }
537
538 if (config->minimum > 0.) {
539 if (config->minimum < giraffe_range_get_min(limits)) {
540 cpl_msg_warning(fctid, "Ignoring invalid wavelength range "
541 "minimum %.3f nm", config->minimum);
542 }
543 else {
544 giraffe_range_set_min(limits, config->minimum);
545 }
546 }
547
548 if (config->maximum > 0.) {
549 if (config->maximum > giraffe_range_get_max(limits)) {
550 cpl_msg_warning(fctid, "Ignoring invalid wavelength range "
551 "maximum %.3f nm", config->maximum);
552 }
553 else {
554 giraffe_range_set_max(limits, config->maximum);
555 }
556 }
557
558 cpl_msg_info(fctid, "Building image for wavelength range [%.3f nm, "
559 "%.3f nm].", giraffe_range_get_min(limits),
560 giraffe_range_get_max(limits));
561
562
563 /*
564 * Convert limits if the spectrum wavelength scale is logarithmic
565 */
566
567 if (cpl_propertylist_has(properties, GIALIAS_BINSCALE)) {
568
569 const cxchar* s = cpl_propertylist_get_string(properties,
570 GIALIAS_BINSCALE);
571
572 if (cx_strncasecmp(s, "log", 3) == 0) {
573 giraffe_range_set_min(limits, log(giraffe_range_get_min(limits)));
574 giraffe_range_set_max(limits, log(giraffe_range_get_max(limits)));
575
576 log_scale = TRUE;
577 }
578 }
579 else {
580 cpl_msg_warning(fctid, "Could not determine spectrum wavelength "
581 "scaling method. Missing property `%s'. Assuming "
582 "scaling method `linear'!", GIALIAS_BINSCALE);
583 }
584
585
586 /*
587 * Create the containers to store the data cubes and the
588 * reconstructed images.
589 */
590
591 simages = cx_slist_new();
592 eimages = cx_slist_new();
593 scubes = cx_slist_new();
594 ecubes = cx_slist_new();
595
596
597 switch (mode) {
598 case GIMODE_IFU:
599 {
600
601 cxint i = 0;
602
603 cpl_array* _ssn = NULL;
604
605 cpl_image* smosaic = NULL;
606 cpl_image* emosaic = NULL;
607
608 GiImage* variance = NULL;
609
610
611 /*
612 * Determine the number and the list of used subslits.
613 */
614
615 ssn = giraffe_fiberlist_get_subslits(_fibers);
616
617 if (ssn == NULL) {
618 cx_slist_destroy(simages, (cx_free_func)cpl_image_delete);
619 simages = NULL;
620
621 cx_slist_destroy(eimages, (cx_free_func)cpl_image_delete);
622 eimages = NULL;
623
624 cx_slist_destroy(scubes, (cx_free_func)giraffe_cube_delete);
625 scubes = NULL;
626
627 cx_slist_destroy(ecubes, (cx_free_func)giraffe_cube_delete);
628 ecubes = NULL;
629
630 giraffe_range_delete(limits);
631 limits = NULL;
632
633 cpl_msg_error(fctid, "Sub-slit data missing in fiber table!");
634
635 return 1;
636 }
637
638
639 /*
640 * Compute the variances from the error map.
641 */
642
643 variance = giraffe_image_duplicate(rebinning->errors);
644
645 if (variance == NULL) {
646 cpl_array_delete(ssn);
647 ssn = NULL;
648
649 cx_slist_destroy(simages, (cx_free_func)cpl_image_delete);
650 simages = NULL;
651
652 cx_slist_destroy(eimages, (cx_free_func)cpl_image_delete);
653 eimages = NULL;
654
655 cx_slist_destroy(scubes, (cx_free_func)giraffe_cube_delete);
656 scubes = NULL;
657
658 cx_slist_destroy(ecubes, (cx_free_func)giraffe_cube_delete);
659 ecubes = NULL;
660
661 giraffe_range_delete(limits);
662 limits = NULL;
663
664 cpl_msg_error(fctid, "Failed to create variance map!");
665
666 return 1;
667 }
668
669 cpl_image_power(giraffe_image_get(variance), 2.);
670
671
672 /*
673 * Build the data cubes and images for each sub-slit
674 */
675
676 _ssn = cpl_array_duplicate(ssn);
677
678 for (i = 0; i < cpl_array_get_size(_ssn); ++i) {
679
680 cxbool failed = FALSE;
681
682 cxint nss = cpl_array_get_int(_ssn, i, NULL);
683
684 cpl_table* ssf = NULL;
685
686 cpl_table_unselect_all(_fibers);
687 cpl_table_or_selected_int(_fibers, "SSN", CPL_EQUAL_TO, nss);
688
689 /*
690 * Remove fibers without position information, i.e.
691 * simultaneous calibration fibers and sky fibers.
692 */
693
694 cpl_table_and_selected_int(_fibers, "X", CPL_GREATER_THAN, 0);
695 cpl_table_and_selected_int(_fibers, "Y", CPL_GREATER_THAN, 0);
696
697 ssf = cpl_table_extract_selected(_fibers);
698
699 if ((ssf != NULL) && (cpl_table_get_nrow(ssf) > 0)) {
700
701 cpl_matrix* transform = NULL;
702
703 cpl_propertylist* wcs = NULL;
704
705 cpl_image* _simage = NULL;
706 cpl_image* _eimage = NULL;
707
708 GiCube* _scube = NULL;
709 GiCube* _ecube = NULL;
710
711
712 _scube = _giraffe_fov_create_cube(rebinning->spectra,
713 ssf, NULL);
714
715 /*
716 * Build a world coordinate system for the cube
717 */
718
719 if (_scube != NULL) {
720
721 cxdouble xorigin = giraffe_cube_get_width(_scube) / 2.;
722 cxdouble yorigin = giraffe_cube_get_height(_scube) / 2.;
723
724 cxdouble xvalue =
725 cpl_table_get_double(ssf, "RA", 0, NULL);
726 cxdouble yvalue =
727 cpl_table_get_double(ssf, "DEC", 0, NULL);
728 cxdouble orientation =
729 cpl_table_get_double(ssf, "ORIENT", 0, NULL);
730
731 cxdouble zvalue = 0.;
732 cxdouble zstep = 0.;
733 cxdouble angle = GI_IFU_POSANG_OFFSET - orientation;
734 cxdouble pixscale = GI_IFU_PIXSCALE / 3600.;
735
736
737 transform = cpl_matrix_new(3, 3);
738
739 wcs = cpl_propertylist_new();
740
741 cpl_propertylist_update_double(wcs, "XORIGIN", xorigin);
742 cpl_propertylist_update_double(wcs, "YORIGIN", yorigin);
743 cpl_propertylist_update_double(wcs, "ZORIGIN", 1.);
744
745 giraffe_cube_get_zaxis(_scube, &zvalue, &zstep);
746
747 cpl_propertylist_update_double(wcs, "XPOINT", xvalue);
748 cpl_propertylist_update_double(wcs, "YPOINT", yvalue);
749 cpl_propertylist_update_double(wcs, "ZPOINT", zvalue);
750
751 cpl_propertylist_update_string(wcs, "XTYPE",
752 "RA---TAN");
753 cpl_propertylist_update_string(wcs, "YTYPE",
754 "DEC--TAN");
755
756 if (log_scale == TRUE) {
757 cpl_propertylist_update_string(wcs,
758 "ZTYPE", "AWAV-LOG");
759 }
760 else {
761 cpl_propertylist_update_string(wcs,
762 "ZTYPE", "AWAV");
763 }
764
765 cpl_propertylist_update_string(wcs, "XUNIT", "deg");
766 cpl_propertylist_update_string(wcs, "YUNIT", "deg");
767 cpl_propertylist_update_string(wcs, "ZUNIT", "nm");
768
769
770 /*
771 * Right ascension is counted eastward from the
772 * equinox, hence the negative sign on the upper
773 * left element of the scale matrix.
774 */
775
776 angle *= CX_PI / 180.;
777
778 cpl_matrix_set(transform, 0, 0, -pixscale * cos(angle));
779 cpl_matrix_set(transform, 0, 1, pixscale * -sin(angle));
780 cpl_matrix_set(transform, 1, 0, -pixscale * sin(angle));
781 cpl_matrix_set(transform, 1, 1, pixscale * cos(angle));
782 cpl_matrix_set(transform, 2, 2, zstep);
783
784 }
785
786 if (_scube != NULL) {
787 _simage = _giraffe_fov_integrate_cube(_scube, limits);
788 }
789
790 if ((_scube == NULL) || (_simage == NULL)) {
791
792 cpl_image_delete(_simage);
793 _simage = NULL;
794
795 giraffe_cube_delete(_scube);
796 _scube = NULL;
797
798 failed = TRUE;
799
800 cpl_msg_error(fctid, "Cannot create data cube for "
801 "sub-slit %d", nss);
802 }
803 else {
804 giraffe_cube_set_wcs(_scube, wcs, transform);
805
806 cx_slist_push_back(scubes, _scube);
807 cx_slist_push_back(simages, _simage);
808 }
809
810 if (!failed) {
811
812 _ecube = _giraffe_fov_create_cube(variance,
813 ssf, NULL);
814
815 if (_ecube != NULL) {
816 _eimage = _giraffe_fov_integrate_cube(_ecube,
817 limits);
818 }
819
820 if ((_ecube == NULL) || (_eimage == NULL)) {
821
822 cpl_image_delete(_eimage);
823 _eimage = NULL;
824
825 giraffe_cube_delete(_ecube);
826 _ecube = NULL;
827
828 failed = TRUE;
829
830 cpl_msg_error(fctid, "Cannot create error "
831 "cube for sub-slit %d", nss);
832 }
833 else {
834 giraffe_cube_sqrt(_ecube);
835 cpl_image_power(_eimage, 0.5);
836
837 giraffe_cube_set_wcs(_ecube, wcs, transform);
838
839 cx_slist_push_back(ecubes, _ecube);
840 cx_slist_push_back(eimages, _eimage);
841 }
842
843 }
844
845 cpl_propertylist_delete(wcs);
846 wcs = NULL;
847
848 cpl_matrix_delete(transform);
849 transform = NULL;
850
851 if (failed) {
852
853 cpl_table_delete(ssf);
854 ssf = NULL;
855
856 giraffe_image_delete(variance);
857 variance = NULL;
858
859 cpl_array_delete(_ssn);
860 _ssn = NULL;
861
862 cpl_array_delete(ssn);
863 ssn = NULL;
864
865 cx_slist_destroy(simages,
866 (cx_free_func)cpl_image_delete);
867 simages = NULL;
868
869 cx_slist_destroy(eimages,
870 (cx_free_func)cpl_image_delete);
871 eimages = NULL;
872
873 cx_slist_destroy(scubes,
874 (cx_free_func)giraffe_cube_delete);
875 scubes = NULL;
876
877 cx_slist_destroy(ecubes,
878 (cx_free_func)giraffe_cube_delete);
879 ecubes = NULL;
880
881 giraffe_range_delete(limits);
882 limits = NULL;
883
884 return 1;
885
886 }
887
888 }
889 else {
890
891 if (ssf != NULL) {
892 cpl_msg_debug(fctid, "Unused IFU button detected. "
893 "Skipping sub-slit %d", nss);
894
895 cpl_array_set_invalid(_ssn, i);
896
897 cx_slist_push_back(simages, NULL);
898 cx_slist_push_back(eimages, NULL);
899 }
900 }
901
902 cpl_table_delete(ssf);
903 ssf = NULL;
904
905 }
906
907
908 /*
909 * Extract valid subslit indices from the index array
910 */
911
912 if (cpl_array_count_invalid(_ssn) > 0) {
913
914 cxint j = 0;
915 cxint k = 0;
916
917 cpl_array_set_size(ssn, cpl_array_get_size(ssn) -
918 cpl_array_count_invalid(_ssn));
919
920 for (k = 0; k < cpl_array_get_size(_ssn); ++k) {
921
922 cxint invalid = 1;
923
924 register cxint idx = cpl_array_get_int(_ssn, k, &invalid);
925
926 if (!invalid) {
927 cpl_array_set_int(ssn, j, idx);
928 ++j;
929 }
930
931 }
932
933 }
934
935 cpl_array_delete(_ssn);
936 _ssn = NULL;
937
938 giraffe_image_delete(variance);
939 variance = NULL;
940
941
942 /*
943 * Put the images of the reconstructed field of view in an
944 * image using a tabular layout. This mosaic is stored as
945 * the first image in the image containers, to be consistent
946 * with the Argus mode, where only this image is provided.
947 */
948
949 smosaic = _giraffe_fov_arrange_images(simages, 5, 3, -4);
950 emosaic = _giraffe_fov_arrange_images(eimages, 5, 3, -4);
951
952 if ((smosaic == NULL) || (emosaic == NULL)) {
953
954 cpl_image_delete(smosaic);
955 smosaic = NULL;
956
957 cpl_image_delete(emosaic);
958 emosaic = NULL;
959
960 cx_slist_destroy(simages, (cx_free_func)cpl_image_delete);
961 simages = NULL;
962
963 cx_slist_destroy(eimages, (cx_free_func)cpl_image_delete);
964 eimages = NULL;
965
966 cx_slist_destroy(scubes, (cx_free_func)giraffe_cube_delete);
967 scubes = NULL;
968
969 cx_slist_destroy(ecubes, (cx_free_func)giraffe_cube_delete);
970 ecubes = NULL;
971
972 cpl_array_delete(ssn);
973 ssn = NULL;
974
975 giraffe_range_delete(limits);
976 limits = NULL;
977
978 return 1;
979
980 }
981
982 cx_slist_push_front(simages, smosaic);
983 cx_slist_push_front(eimages, emosaic);
984 break;
985
986 }
987
988 case GIMODE_ARGUS:
989 {
990 cxbool failed = FALSE;
991
992 cpl_image* simage = NULL;
993 cpl_image* eimage = NULL;
994
995 cpl_matrix* transform = NULL;
996
997 cpl_propertylist* wcs = NULL;
998
999 GiImage* variance = NULL;
1000
1001 GiCube* scube = NULL;
1002 GiCube* ecube = NULL;
1003
1004
1005 /*
1006 * Compute the variances from the error map.
1007 */
1008
1009 variance = giraffe_image_duplicate(rebinning->errors);
1010
1011 if (variance == NULL) {
1012
1013 cx_slist_destroy(simages, (cx_free_func)cpl_image_delete);
1014 simages = NULL;
1015
1016 cx_slist_destroy(eimages, (cx_free_func)cpl_image_delete);
1017 eimages = NULL;
1018
1019 cx_slist_destroy(scubes, (cx_free_func)giraffe_cube_delete);
1020 scubes = NULL;
1021
1022 cx_slist_destroy(ecubes, (cx_free_func)giraffe_cube_delete);
1023 ecubes = NULL;
1024
1025 giraffe_range_delete(limits);
1026 limits = NULL;
1027
1028 cpl_msg_error(fctid, "Failed to create variance map!");
1029 return 1;
1030
1031 }
1032
1033 cpl_image_power(giraffe_image_get(variance), 2.);
1034
1035
1036 /*
1037 * Build the data cubes and field of view images
1038 */
1039
1040 scube = _giraffe_fov_create_cube(rebinning->spectra,
1041 _fibers, NULL);
1042
1043 /*
1044 * Build a world coordinate system for the cube.
1045 */
1046
1047 /*
1048 * Argus has a +90 degrees offset with respect to the adaptor,
1049 * thus: PA_arg = PA_ada + 90.
1050 *
1051 * The Argus long axis is aligned with the North-South
1052 * direction, and North up for PA_arg = 0. Since in the
1053 * image the Argus long axis is the x-axis an extra 90.
1054 * degrees offset has to be applied to the WCS axes. And
1055 * finally, since the coordinate system is transformed
1056 * relative to the image, and PA_arg is counted positive
1057 * counter clockwise (from North through East), the agular
1058 * offsets must be counted negative.
1059 */
1060
1061 if (scube != NULL) {
1062
1063 cxdouble xorigin = giraffe_cube_get_width(scube) / 2.;
1064 cxdouble yorigin = giraffe_cube_get_height(scube) / 2.;
1065
1066 cxdouble xvalue = cpl_propertylist_get_double(properties,
1067 GIALIAS_RADEG);
1068 cxdouble yvalue = cpl_propertylist_get_double(properties,
1069 GIALIAS_DECDEG);
1070 cxdouble zvalue = 0.;
1071 cxdouble zstep = 0.;
1072 cxdouble angle = -90. -
1073 (cpl_propertylist_get_double(properties,
1074 GIALIAS_POSANG) +
1075 GI_ARGUS_POSANG_OFFSET);
1076
1077 cxdouble pixscale = GI_ARGUS_PIXSCALE_LOW;
1078
1079 const cxchar* scale =
1080 cpl_propertylist_get_string(properties,
1081 GIALIAS_ARGUS_SCALE);
1082
1083
1084 if ((scale != NULL) && (strcmp(scale, "POS_1_67") == 0)) {
1085 pixscale = GI_ARGUS_PIXSCALE_HIGH;
1086 }
1087
1088 /* Get pixel scale in degrees */
1089
1090 pixscale /= 3600.;
1091
1092
1093 transform = cpl_matrix_new(3, 3);
1094
1095 wcs = cpl_propertylist_new();
1096
1097 cpl_propertylist_update_double(wcs, "XORIGIN", xorigin);
1098 cpl_propertylist_update_double(wcs, "YORIGIN", yorigin);
1099 cpl_propertylist_update_double(wcs, "ZORIGIN", 1.);
1100
1101 giraffe_cube_get_zaxis(scube, &zvalue, &zstep);
1102
1103 cpl_propertylist_update_double(wcs, "XPOINT", xvalue);
1104 cpl_propertylist_update_double(wcs, "YPOINT", yvalue);
1105 cpl_propertylist_update_double(wcs, "ZPOINT", zvalue);
1106
1107 cpl_propertylist_update_string(wcs, "XTYPE", "RA---TAN");
1108 cpl_propertylist_update_string(wcs, "YTYPE", "DEC--TAN");
1109
1110 if (log_scale == TRUE) {
1111 cpl_propertylist_update_string(wcs,
1112 "ZTYPE", "AWAV-LOG");
1113 }
1114 else {
1115 cpl_propertylist_update_string(wcs,
1116 "ZTYPE", "AWAV");
1117 }
1118
1119 cpl_propertylist_update_string(wcs, "XUNIT", "deg");
1120 cpl_propertylist_update_string(wcs, "YUNIT", "deg");
1121 cpl_propertylist_update_string(wcs, "ZUNIT", "nm");
1122
1123
1124 /*
1125 * Right ascension is counted eastward from the equinox,
1126 * hence the negative sign on the upper left element of the
1127 * scale matrix.
1128 */
1129
1130 angle *= CX_PI / 180.;
1131
1132 cpl_matrix_set(transform, 0, 0, -pixscale * cos(angle));
1133 cpl_matrix_set(transform, 0, 1, pixscale * -sin(angle));
1134 cpl_matrix_set(transform, 1, 0, -pixscale * sin(angle));
1135 cpl_matrix_set(transform, 1, 1, pixscale * cos(angle));
1136 cpl_matrix_set(transform, 2, 2, zstep);
1137
1138 }
1139
1140
1141 if (scube != NULL) {
1142 simage = _giraffe_fov_integrate_cube(scube, limits);
1143 }
1144
1145 if ((scube == NULL) || (simage == NULL)) {
1146
1147 cpl_image_delete(simage);
1148 simage = NULL;
1149
1150 giraffe_cube_delete(scube);
1151 scube = NULL;
1152
1153 failed = TRUE;
1154
1155 cpl_msg_error(fctid, "Cannot create data cube!");
1156
1157 }
1158 else {
1159
1160 giraffe_cube_set_wcs(scube, wcs, transform);
1161
1162 cx_slist_push_back(scubes, scube);
1163 cx_slist_push_back(simages, simage);
1164
1165 }
1166
1167
1168 if (!failed) {
1169
1170 ecube = _giraffe_fov_create_cube(variance, _fibers, NULL);
1171 eimage = _giraffe_fov_integrate_cube(ecube, limits);
1172
1173 if ((ecube == NULL) || (eimage == NULL)) {
1174
1175 cpl_image_delete(eimage);
1176 eimage = NULL;
1177
1178 giraffe_cube_delete(ecube);
1179 ecube = NULL;
1180
1181 failed = TRUE;
1182
1183 cpl_msg_error(fctid, "Cannot create error cube!");
1184
1185 }
1186 else {
1187
1188 giraffe_cube_sqrt(ecube);
1189 cpl_image_power(eimage, 0.5);
1190
1191 giraffe_cube_set_wcs(ecube, wcs, transform);
1192
1193 cx_slist_push_back(ecubes, ecube);
1194 cx_slist_push_back(eimages, eimage);
1195
1196 }
1197
1198 }
1199
1200 cpl_propertylist_delete(wcs);
1201 wcs = NULL;
1202
1203 cpl_matrix_delete(transform);
1204 transform = NULL;
1205
1206 giraffe_image_delete(variance);
1207 variance = NULL;
1208
1209 if (failed) {
1210
1211 cx_slist_destroy(simages, (cx_free_func)cpl_image_delete);
1212 simages = NULL;
1213
1214 cx_slist_destroy(eimages, (cx_free_func)cpl_image_delete);
1215 eimages = NULL;
1216
1217 cx_slist_destroy(scubes, (cx_free_func)giraffe_cube_delete);
1218 scubes = NULL;
1219
1220 cx_slist_destroy(ecubes, (cx_free_func)giraffe_cube_delete);
1221 ecubes = NULL;
1222
1223 giraffe_range_delete(limits);
1224 limits = NULL;
1225
1226 return 1;
1227
1228 }
1229
1230 break;
1231 }
1232
1233 default:
1234 return 1;
1235 break;
1236 }
1237
1238
1239 /*
1240 * Fill the results container.
1241 */
1242
1243 result->mode = mode;
1244 result->ssn = ssn;
1245 ssn = NULL;
1246
1247 properties = giraffe_image_get_properties(rebinning->spectra);
1248 fov = cx_slist_pop_front(simages);
1249
1250 result->fov.spectra = giraffe_image_new(CPL_TYPE_DOUBLE);
1251 giraffe_image_set(result->fov.spectra, fov);
1252 giraffe_image_set_properties(result->fov.spectra, properties);
1253
1254 properties = giraffe_image_get_properties(result->fov.spectra);
1255
1256 /* Clear left over WCS keywords */
1257
1258 giraffe_propertylist_update_wcs(properties, 0, NULL, NULL, NULL,
1259 NULL, NULL);
1260
1261 cpl_propertylist_update_double(properties, GIALIAS_FOV_BANDMIN,
1262 giraffe_range_get_min(limits));
1263 cpl_propertylist_set_comment(properties, GIALIAS_FOV_BANDMIN,
1264 "Minimum wavelength of FOV band");
1265
1266 cpl_propertylist_update_double(properties, GIALIAS_FOV_BANDMAX,
1267 giraffe_range_get_max(limits));
1268 cpl_propertylist_set_comment(properties, GIALIAS_FOV_BANDMAX,
1269 "Maximum wavelength of FOV band");
1270
1271 cpl_image_delete(fov);
1272 fov = NULL;
1273
1274
1275 properties = giraffe_image_get_properties(rebinning->errors);
1276 fov = cx_slist_pop_front(eimages);
1277
1278 result->fov.errors = giraffe_image_new(CPL_TYPE_DOUBLE);
1279 giraffe_image_set(result->fov.errors, fov);
1280 giraffe_image_set_properties(result->fov.errors, properties);
1281
1282 properties = giraffe_image_get_properties(result->fov.errors);
1283
1284 /* Clear left over WCS keywords */
1285
1286 giraffe_propertylist_update_wcs(properties, 0, NULL, NULL, NULL,
1287 NULL, NULL);
1288 cpl_propertylist_update_double(properties, GIALIAS_FOV_BANDMIN,
1289 giraffe_range_get_min(limits));
1290 cpl_propertylist_set_comment(properties, GIALIAS_FOV_BANDMIN,
1291 "Minimum wavelength of FOV band");
1292
1293 cpl_propertylist_update_double(properties, GIALIAS_FOV_BANDMAX,
1294 giraffe_range_get_max(limits));
1295 cpl_propertylist_set_comment(properties, GIALIAS_FOV_BANDMAX,
1296 "Maximum wavelength of FOV band");
1297
1298 cpl_image_delete(fov);
1299 fov = NULL;
1300
1301 if (!cx_slist_empty(simages)) {
1302
1303 cx_slist_iterator pos = cx_slist_begin(simages);
1304
1305 result->images.spectra = cx_slist_new();
1306
1307 while (pos != cx_slist_end(simages)) {
1308
1309 GiImage* image = giraffe_image_new(CPL_TYPE_DOUBLE);
1310
1311 giraffe_image_set(image, cx_slist_get(simages, pos));
1312 cx_slist_push_back(result->images.spectra, image);
1313
1314 pos = cx_slist_next(simages, pos);
1315 }
1316
1317 }
1318
1319 if (!cx_slist_empty(eimages)) {
1320
1321 cx_slist_iterator pos = cx_slist_begin(eimages);
1322
1323 result->images.errors = cx_slist_new();
1324
1325 while (pos != cx_slist_end(eimages)) {
1326
1327 GiImage* image = giraffe_image_new(CPL_TYPE_DOUBLE);
1328
1329 giraffe_image_set(image, cx_slist_get(eimages, pos));
1330 cx_slist_push_back(result->images.errors, image);
1331
1332 pos = cx_slist_next(eimages, pos);
1333 }
1334
1335 }
1336
1337 if (config->cube == TRUE) {
1338
1339 if (!cx_slist_empty(scubes)) {
1340 result->cubes.spectra = scubes;
1341 scubes = NULL;
1342 }
1343
1344 if (!cx_slist_empty(ecubes)) {
1345 result->cubes.errors = ecubes;
1346 ecubes = NULL;
1347 }
1348
1349 }
1350
1351
1352 /*
1353 * Cleanup
1354 */
1355
1356 giraffe_range_delete(limits);
1357 limits = NULL;
1358
1359 cx_slist_destroy(simages, (cx_free_func)cpl_image_delete);
1360 simages = NULL;
1361
1362 cx_slist_destroy(eimages, (cx_free_func)cpl_image_delete);
1363 eimages = NULL;
1364
1365 if (scubes != NULL) {
1366 cx_slist_destroy(scubes, (cx_free_func)giraffe_cube_delete);
1367 scubes = NULL;
1368 }
1369
1370 if (ecubes != NULL) {
1371 cx_slist_destroy(ecubes, (cx_free_func)giraffe_cube_delete);
1372 ecubes = NULL;
1373 }
1374
1375 return 0;
1376
1377}
1378
1379
1393GiFieldOfView*
1395{
1396 GiFieldOfView* self = cx_malloc(sizeof *self);
1397
1398 self->mode = GIMODE_NONE;
1399 self->ssn = NULL;
1400
1401 self->fov.spectra = NULL;
1402 self->fov.errors = NULL;
1403
1404 self->images.spectra = NULL;
1405 self->images.errors = NULL;
1406
1407 self->cubes.spectra = NULL;
1408 self->cubes.errors = NULL;
1409
1410 return self;
1411
1412}
1413
1414
1427void
1428giraffe_fov_clear(GiFieldOfView* self)
1429{
1430
1431 if (self != NULL) {
1432
1433 if (self->cubes.errors != NULL) {
1434 cx_slist_destroy(self->cubes.errors,
1435 (cx_free_func)giraffe_cube_delete);
1436 self->cubes.errors = NULL;
1437 }
1438
1439 if (self->cubes.spectra != NULL) {
1440 cx_slist_destroy(self->cubes.spectra,
1441 (cx_free_func)giraffe_cube_delete);
1442 self->cubes.spectra = NULL;
1443 }
1444
1445 if (self->images.errors != NULL) {
1446 cx_slist_destroy(self->images.errors,
1447 (cx_free_func)giraffe_image_delete);
1448 self->images.errors = NULL;
1449 }
1450
1451 if (self->images.spectra != NULL) {
1452 cx_slist_destroy(self->images.spectra,
1453 (cx_free_func)giraffe_image_delete);
1454 self->images.spectra = NULL;
1455 }
1456
1457 if (self->fov.errors != NULL) {
1458 giraffe_image_delete(self->fov.errors);
1459 self->fov.errors = NULL;
1460 }
1461
1462 if (self->fov.spectra != NULL) {
1463 giraffe_image_delete(self->fov.spectra);
1464 self->fov.spectra = NULL;
1465 }
1466
1467 if (self->ssn != NULL) {
1468 cpl_array_delete(self->ssn);
1469 self->ssn = NULL;
1470 }
1471
1472 self->mode = GIMODE_NONE;
1473
1474 }
1475
1476 return;
1477
1478}
1479
1480
1494void
1495giraffe_fov_delete(GiFieldOfView* self)
1496{
1497
1498 if (self != NULL) {
1499 giraffe_fov_clear(self);
1500 cx_free(self);
1501 }
1502
1503 return;
1504
1505}
1506
1507
1530cxint
1531giraffe_fov_save_cubes(const GiFieldOfView* self,
1532 cpl_propertylist* properties,
1533 const cxchar* filename, cxptr data)
1534{
1535
1536
1537 cxint component = 0;
1538
1539 cx_slist* cubes = NULL;
1540
1541
1542 if ((self == NULL) || (properties == NULL) || (filename == NULL)) {
1543 return -1;
1544 }
1545
1546
1547 /*
1548 * Get the cube component that should be saved. Spectra or errors.
1549 */
1550
1551 if (data != NULL) {
1552 component = *((cxuint*)data);
1553 }
1554
1555 if (component == 0) {
1556 cubes = self->cubes.spectra;
1557 }
1558 else {
1559 cubes = self->cubes.errors;
1560 }
1561
1562 if (cubes == NULL) {
1563 return -2;
1564 }
1565
1566
1567 if (!cx_slist_empty(cubes)) {
1568
1569 if (self->mode == GIMODE_ARGUS) {
1570
1571 cxint status = 0;
1572 cxint iomode = CPL_IO_CREATE;
1573
1574 GiCube* cube = cx_slist_front(cubes);
1575
1576 status = giraffe_cube_save(cube, properties, filename, &iomode);
1577
1578 if (status != 0) {
1579 return 1;
1580 }
1581
1582 }
1583 else {
1584
1585 cxint nss = 0;
1586 cxint status = 0;
1587 cxint iomode = CPL_IO_CREATE;
1588
1589 cx_slist_const_iterator pos = cx_slist_begin(cubes);
1590
1591 cx_string* name = NULL;
1592
1593 cpl_propertylist* xproperties = NULL;
1594
1595
1596 status = giraffe_cube_save(NULL, properties, filename, &iomode);
1597
1598 if (status != 0) {
1599 return 1;
1600 }
1601
1602
1603 name = cx_string_new();
1604 xproperties = cpl_propertylist_new();
1605
1606 iomode = CPL_IO_EXTEND;
1607
1608 while (pos != cx_slist_end(cubes)) {
1609
1610 cxint ssn = cpl_array_get_int(self->ssn, nss, NULL);
1611
1612 GiCube* cube = cx_slist_get(cubes, pos);
1613
1614
1615 cx_string_sprintf(name, "SSN%-d", ssn);
1616 cpl_propertylist_update_string(xproperties, "EXTNAME",
1617 cx_string_get(name));
1618
1619 status = giraffe_cube_save(cube, xproperties, filename,
1620 &iomode);
1621
1622 if (status != 0) {
1623
1624 cpl_propertylist_delete(xproperties);
1625 xproperties = NULL;
1626
1627 cx_string_delete(name);
1628 name = NULL;
1629
1630 return 1;
1631
1632 }
1633
1634 pos = cx_slist_next(cubes, pos);
1635 ++nss;
1636
1637 }
1638
1639 cpl_propertylist_delete(xproperties);
1640 xproperties = NULL;
1641
1642 cx_string_delete(name);
1643 name = NULL;
1644
1645 }
1646
1647 }
1648
1649 return 0;
1650
1651}
1652
1653
1673cxint
1674giraffe_fov_save_cubes_eso3d(const GiFieldOfView* self,
1675 cpl_propertylist* properties,
1676 const cxchar* filename, cxptr data)
1677{
1678
1679 const cxchar* data_name = "SPECTRA";
1680 const cxchar* error_name = "ERRORS";
1681 const cxchar* link_names[2] = {"SCIDATA", "ERRDATA"};
1682
1683 cx_slist* scubes = NULL;
1684 cx_slist* ecubes = NULL;
1685
1686
1687 /* Currently not used. Set to avoid compiler warnings */
1688
1689 (void) data;
1690
1691
1692 if ((self == NULL) || (properties == NULL) || (filename == NULL)) {
1693 return -1;
1694 }
1695
1696 if (self->cubes.spectra == NULL) {
1697 return -2;
1698 }
1699
1700 if ((cpl_propertylist_has(properties, GIALIAS_EQUINOX) == FALSE) ||
1701 (cpl_propertylist_get_type(properties, GIALIAS_EQUINOX)
1702 != CPL_TYPE_DOUBLE)) {
1703 return -2;
1704 }
1705
1706
1707 /*
1708 * Get the cube components. If errors are present their number must
1709 * match the number of spectrum cubes!
1710 */
1711
1712 scubes = self->cubes.spectra;
1713
1714 if (cx_slist_empty(scubes)) {
1715 return -3;
1716 }
1717
1718 if (self->cubes.errors != NULL) {
1719
1720 ecubes = self->cubes.errors;
1721
1722 if (cx_slist_size(scubes) != cx_slist_size(ecubes)) {
1723 return -4;
1724 }
1725
1726 }
1727
1728
1729 if (self->mode == GIMODE_ARGUS) {
1730
1731 cxint status = 0;
1732 cxint iomode = CPL_IO_CREATE;
1733
1734 cxdouble equinox = cpl_propertylist_get_double(properties,
1735 GIALIAS_EQUINOX);
1736
1737 cpl_propertylist* xproperties = NULL;
1738
1739 GiCube* scube = cx_slist_front(scubes);
1740
1741
1742 status = giraffe_cube_save(NULL, properties, filename, &iomode);
1743
1744 if (status != 0) {
1745 return 1;
1746 }
1747
1748
1749 iomode = CPL_IO_EXTEND;
1750
1751 xproperties = cpl_propertylist_new();
1752
1753 cpl_propertylist_update_string(xproperties, GIALIAS_EXTNAME, data_name);
1754 cpl_propertylist_set_comment(xproperties, GIALIAS_EXTNAME,
1755 "FITS Extension name");
1756
1757 cpl_propertylist_update_string(xproperties, "HDUCLASS", "ESO");
1758 cpl_propertylist_set_comment(xproperties, "HDUCLASS",
1759 "Conforms to ESO data cube conventions");
1760
1761 cpl_propertylist_update_string(xproperties, "HDUDOC", "DICD");
1762 cpl_propertylist_set_comment(xproperties, "HDUDOC",
1763 "Data format specification document");
1764
1765 cpl_propertylist_update_string(xproperties, "HDUVERS",
1766 "DICD version 6");
1767 cpl_propertylist_set_comment(xproperties, "HDUVERS",
1768 "Specific version of the data format "
1769 "document");
1770
1771 cpl_propertylist_update_string(xproperties, "HDUCLAS1", "IMAGE");
1772 cpl_propertylist_set_comment(xproperties, "HDUCLAS1",
1773 "Image data format");
1774
1775 cpl_propertylist_update_string(xproperties, "HDUCLAS2", "DATA");
1776 cpl_propertylist_set_comment(xproperties, "HDUCLAS2",
1777 "Science data extension");
1778 cpl_propertylist_update_string(xproperties, link_names[1], error_name);
1779 cpl_propertylist_set_comment(xproperties, link_names[1],
1780 "Linked error data extension");
1781
1782 cpl_propertylist_update_double(xproperties, GIALIAS_EQUINOX,
1783 equinox);
1784
1785 status = giraffe_cube_save(scube, xproperties, filename,
1786 &iomode);
1787
1788 if (status != 0) {
1789
1790 cpl_propertylist_delete(xproperties);
1791 xproperties = NULL;
1792
1793 return 1;
1794
1795 }
1796
1797 cpl_propertylist_erase(xproperties, link_names[1]);
1798 cpl_propertylist_erase(xproperties, "BUNIT");
1799 cpl_propertylist_erase(xproperties, "DATAMIN");
1800 cpl_propertylist_erase(xproperties, "DATAMAX");
1801
1802
1803 if (ecubes != NULL) {
1804
1805 GiCube* ecube = cx_slist_front(ecubes);
1806
1807
1808 cpl_propertylist_update_string(xproperties, "EXTNAME", error_name);
1809
1810 cpl_propertylist_update_string(xproperties, "HDUCLAS2", "ERROR");
1811 cpl_propertylist_set_comment(xproperties, "HDUCLAS2",
1812 "Error data extension");
1813
1814 cpl_propertylist_update_string(xproperties, "HDUCLAS3", "RMSE");
1815 cpl_propertylist_set_comment(xproperties, "HDUCLAS3",
1816 "Type of error: root mean squared");
1817
1818 cpl_propertylist_update_string(xproperties, link_names[0],
1819 data_name);
1820 cpl_propertylist_set_comment(xproperties, link_names[0],
1821 "Linked science data extension");
1822
1823 status = giraffe_cube_save(ecube, xproperties, filename,
1824 &iomode);
1825
1826 if (status != 0) {
1827
1828 cpl_propertylist_delete(xproperties);
1829 xproperties = NULL;
1830
1831 return 1;
1832
1833 }
1834
1835 }
1836
1837 cpl_propertylist_delete(xproperties);
1838 xproperties = NULL;
1839
1840 }
1841 else {
1842
1843 cxint nss = 0;
1844 cxint status = 0;
1845 cxint iomode = CPL_IO_CREATE;
1846
1847 cxdouble equinox = cpl_propertylist_get_double(properties,
1848 GIALIAS_EQUINOX);
1849
1850 cx_slist_const_iterator spos = cx_slist_begin(scubes);
1851 cx_slist_const_iterator epos = cx_slist_begin(ecubes);
1852
1853 cx_string* name = NULL;
1854
1855 cpl_propertylist* xproperties = NULL;
1856
1857
1858 status = giraffe_cube_save(NULL, properties, filename, &iomode);
1859
1860 if (status != 0) {
1861 return 1;
1862 }
1863
1864
1865 name = cx_string_new();
1866 xproperties = cpl_propertylist_new();
1867
1868 iomode = CPL_IO_EXTEND;
1869
1870 while (spos != cx_slist_end(scubes)) {
1871
1872 cxint ssn = cpl_array_get_int(self->ssn, nss, NULL);
1873
1874 GiCube* scube = cx_slist_get(scubes, spos);
1875
1876
1877 cx_string_sprintf(name, "SSN%-d.%s", ssn, data_name);
1878
1879 cpl_propertylist_update_string(xproperties, GIALIAS_EXTNAME,
1880 cx_string_get(name));
1881 cpl_propertylist_set_comment(xproperties, GIALIAS_EXTNAME,
1882 "FITS Extension name");
1883
1884 cpl_propertylist_update_string(xproperties, "HDUCLASS", "ESO");
1885 cpl_propertylist_set_comment(xproperties, "HDUCLASS",
1886 "Conforms to ESO data cube "
1887 "conventions");
1888
1889 cpl_propertylist_update_string(xproperties, "HDUDOC", "DICD");
1890 cpl_propertylist_set_comment(xproperties, "HDUDOC",
1891 "Data format specification document");
1892
1893 cpl_propertylist_update_string(xproperties, "HDUVERS",
1894 "DICD version 6");
1895 cpl_propertylist_set_comment(xproperties, "HDUVERS",
1896 "Specific version of the data format "
1897 "document");
1898
1899 cpl_propertylist_update_string(xproperties, "HDUCLAS1", "IMAGE");
1900 cpl_propertylist_set_comment(xproperties, "HDUCLAS1",
1901 "Image data format");
1902
1903 cpl_propertylist_update_string(xproperties, "HDUCLAS2", "DATA");
1904 cpl_propertylist_set_comment(xproperties, "HDUCLAS2",
1905 "Science data extension");
1906
1907 cx_string_sprintf(name, "SSN%-d.%s", ssn, error_name);
1908
1909 cpl_propertylist_update_string(xproperties, link_names[1],
1910 cx_string_get(name));
1911 cpl_propertylist_set_comment(xproperties, link_names[1],
1912 "Linked error data extension");
1913
1914 cpl_propertylist_update_double(xproperties, GIALIAS_EQUINOX,
1915 equinox);
1916
1917 status = giraffe_cube_save(scube, xproperties, filename,
1918 &iomode);
1919
1920 if (status != 0) {
1921
1922 cpl_propertylist_delete(xproperties);
1923 xproperties = NULL;
1924
1925 cx_string_delete(name);
1926 name = NULL;
1927
1928 return 1;
1929
1930 }
1931
1932 cpl_propertylist_erase(xproperties, link_names[1]);
1933 cpl_propertylist_erase(xproperties, "BUNIT");
1934 cpl_propertylist_erase(xproperties, "DATAMIN");
1935 cpl_propertylist_erase(xproperties, "DATAMAX");
1936
1937
1938 if (ecubes != NULL) {
1939
1940 GiCube* ecube = cx_slist_get(ecubes, epos);
1941
1942
1943 cx_string_sprintf(name, "SSN%-d.%s", ssn, error_name);
1944
1945 cpl_propertylist_update_string(xproperties, "EXTNAME",
1946 cx_string_get(name));
1947
1948 cpl_propertylist_update_string(xproperties, "HDUCLAS2", "ERROR");
1949 cpl_propertylist_set_comment(xproperties, "HDUCLAS2",
1950 "Error data extension");
1951
1952 cpl_propertylist_update_string(xproperties, "HDUCLAS3", "RMSE");
1953 cpl_propertylist_set_comment(xproperties, "HDUCLAS3",
1954 "Type of error: root mean squared");
1955
1956 cx_string_sprintf(name, "SSN%-d.%s", ssn, data_name);
1957
1958 cpl_propertylist_update_string(xproperties, link_names[0],
1959 cx_string_get(name));
1960 cpl_propertylist_set_comment(xproperties, link_names[0],
1961 "Linked science data extension");
1962
1963 status = giraffe_cube_save(ecube, xproperties, filename,
1964 &iomode);
1965
1966
1967 if (status != 0) {
1968
1969 cpl_propertylist_delete(xproperties);
1970 xproperties = NULL;
1971
1972 cx_string_delete(name);
1973 name = NULL;
1974
1975 return 1;
1976
1977 }
1978
1979 epos = cx_slist_next(ecubes, epos);
1980
1981 }
1982
1983 spos = cx_slist_next(scubes, spos);
1984 ++nss;
1985
1986 }
1987
1988 cpl_propertylist_delete(xproperties);
1989 xproperties = NULL;
1990
1991 cx_string_delete(name);
1992 name = NULL;
1993
1994 }
1995
1996 return 0;
1997
1998}
1999
2000
2012GiFieldOfViewConfig*
2013giraffe_fov_config_create(cpl_parameterlist* list)
2014{
2015
2016 const cxchar* s = NULL;
2017
2018 cpl_parameter* p;
2019
2020 GiFieldOfViewConfig* config = NULL;
2021
2022
2023 if (list == NULL) {
2024 return NULL;
2025 }
2026
2027 config = cx_calloc(1, sizeof *config);
2028
2029
2030 p = cpl_parameterlist_find(list, "giraffe.fov.range.minimum");
2031 config->minimum = cpl_parameter_get_double(p);
2032
2033 p = cpl_parameterlist_find(list, "giraffe.fov.range.maximum");
2034 config->maximum = cpl_parameter_get_double(p);
2035
2036 p = cpl_parameterlist_find(list, "giraffe.fov.cube");
2037 config->cube = cpl_parameter_get_bool(p);
2038
2039 p = cpl_parameterlist_find(list, "giraffe.fov.cube.format");
2040 s = cpl_parameter_get_string(p);
2041
2042 if (strcmp(s, "single") == 0) {
2043 config->format = GIFOV_FORMAT_SINGLE;
2044 }
2045 else if (strcmp(s, "eso3d") == 0) {
2046 config->format = GIFOV_FORMAT_ESO3D;
2047 }
2048
2049 return config;
2050
2051}
2052
2053
2067void
2068giraffe_fov_config_destroy(GiFieldOfViewConfig* config)
2069{
2070
2071 if (config != NULL) {
2072 cx_free(config);
2073 }
2074
2075 return;
2076
2077}
2078
2079
2089void
2090giraffe_fov_config_add(cpl_parameterlist* list)
2091{
2092
2093 cpl_parameter* p;
2094
2095
2096 if (list == NULL) {
2097 return;
2098 }
2099
2100 p = cpl_parameter_new_value("giraffe.fov.range.minimum",
2101 CPL_TYPE_DOUBLE,
2102 "Minimum wavelength for image reconstruction",
2103 "giraffe.fov.range",
2104 0.);
2105 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "recon-min");
2106 cpl_parameterlist_append(list, p);
2107
2108
2109 p = cpl_parameter_new_value("giraffe.fov.range.maximum",
2110 CPL_TYPE_DOUBLE,
2111 "Maximum wavelength for image reconstruction",
2112 "giraffe.fov.range",
2113 0.);
2114 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "recon-max");
2115 cpl_parameterlist_append(list, p);
2116
2117
2118 p = cpl_parameter_new_value("giraffe.fov.cube",
2119 CPL_TYPE_BOOL,
2120 "Turns data cube creation on and off",
2121 "giraffe.fov.cube",
2122 TRUE);
2123 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "recon-cube");
2124 cpl_parameterlist_append(list, p);
2125
2126 p = cpl_parameter_new_enum("giraffe.fov.cube.format",
2127 CPL_TYPE_STRING,
2128 "Selects the file format for cubes",
2129 "giraffe.fov.cube",
2130 "single", 2, "single", "eso3d");
2131 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "recon-format");
2132 cpl_parameterlist_append(list, p);
2133
2134 return;
2135
2136}
cxsize giraffe_cube_get_width(const GiCube *self)
Get the width of the given data cube.
Definition: gicube.c:530
cxsize giraffe_cube_get_depth(const GiCube *self)
Get the depth of the given data cube.
Definition: gicube.c:576
cxint giraffe_cube_set_yaxis(GiCube *self, cxdouble start, cxdouble step)
Set the data cube's y-axis start value and step size.
Definition: gicube.c:942
cxint giraffe_cube_get_zaxis(const GiCube *self, cxdouble *start, cxdouble *step)
Get the data cube's z-axis start value and step size.
Definition: gicube.c:890
cxint giraffe_cube_set_wcs(GiCube *self, const cpl_propertylist *axes, const cpl_matrix *transformation)
Set the data cube's world coordinate system.
Definition: gicube.c:1032
cpl_image * giraffe_cube_integrate(const GiCube *self, cxdouble start, cxdouble end)
Integrate a cube along the z-axis.
Definition: gicube.c:1142
cxint giraffe_cube_set_zaxis(GiCube *self, cxdouble start, cxdouble step)
Set the data cube's z-axis start value and step size.
Definition: gicube.c:968
GiCube * giraffe_cube_create(cxsize width, cxsize height, cxsize depth, cxdouble *data)
Create a data cube with the given width, height and depth.
Definition: gicube.c:447
cxint giraffe_cube_set_xaxis(GiCube *self, cxdouble start, cxdouble step)
Set the data cube's x-axis start value and step size.
Definition: gicube.c:916
cxdouble * giraffe_cube_get_data(const GiCube *self)
Get a reference to the data cube's pixel buffer.
Definition: gicube.c:707
void giraffe_cube_delete(GiCube *self)
Destroys a cube object.
Definition: gicube.c:504
cxint giraffe_cube_save(const GiCube *self, cpl_propertylist *properties, const cxchar *filename, cxcptr data)
Save the given data cube to disk.
Definition: gicube.c:1236
cxsize giraffe_cube_get_height(const GiCube *self)
Get the height of the given data cube.
Definition: gicube.c:553
cxint giraffe_cube_sqrt(GiCube *self)
Compute the square root of the elements of a cube.
Definition: gicube.c:1091
cpl_array * giraffe_fiberlist_get_subslits(const cpl_table *fibers)
Get the list of subslit identifiers from a fiber setup.
GiFieldOfViewConfig * giraffe_fov_config_create(cpl_parameterlist *list)
Creates a setup structure for the field of view reconstruction.
Definition: gifov.c:2013
void giraffe_fov_clear(GiFieldOfView *self)
Delete the contents of a field of view object.
Definition: gifov.c:1428
void giraffe_fov_config_destroy(GiFieldOfViewConfig *config)
Destroys a field of view setup structure.
Definition: gifov.c:2068
GiFieldOfView * giraffe_fov_new(void)
Create an empty container for the results of the field of view reconstruction.
Definition: gifov.c:1394
cxint giraffe_fov_save_cubes_eso3d(const GiFieldOfView *self, cpl_propertylist *properties, const cxchar *filename, cxptr data)
Write the cube components of a field-of-view object to a file.
Definition: gifov.c:1674
void giraffe_fov_delete(GiFieldOfView *self)
Deallocate a field of view object and its contents.
Definition: gifov.c:1495
cxint giraffe_fov_build(GiFieldOfView *result, GiRebinning *rebinning, GiTable *fibers, GiTable *wsolution, GiTable *grating, GiTable *slitgeometry, GiFieldOfViewConfig *config)
Create and image and a data cube from extracted and rebinned spectra.
Definition: gifov.c:429
cxint giraffe_fov_save_cubes(const GiFieldOfView *self, cpl_propertylist *properties, const cxchar *filename, cxptr data)
Write the cube components of a field-of-view object to a file.
Definition: gifov.c:1531
void giraffe_fov_config_add(cpl_parameterlist *list)
Adds parameters for the image and data cube construction.
Definition: gifov.c:2090
cpl_image * giraffe_image_get(const GiImage *self)
Gets the image data.
Definition: giimage.c:218
cpl_propertylist * giraffe_image_get_properties(const GiImage *self)
Get the properties of an image.
Definition: giimage.c:282
void giraffe_image_delete(GiImage *self)
Destroys an image.
Definition: giimage.c:181
GiImage * giraffe_image_duplicate(const GiImage *self)
Creates a copy of an image.
Definition: giimage.c:139
cxint giraffe_image_set(GiImage *self, cpl_image *image)
Sets the image data.
Definition: giimage.c:244
GiImage * giraffe_image_new(cpl_type type)
Creates an empty image container.
Definition: giimage.c:65
cxint giraffe_image_set_properties(GiImage *self, cpl_propertylist *properties)
Attaches a property list to an image.
Definition: giimage.c:312
void giraffe_range_set_min(GiRange *self, cxdouble min)
Set the minimum of a range.
Definition: girange.c:144
void giraffe_range_delete(GiRange *self)
Destroys a range object.
Definition: girange.c:118
cxdouble giraffe_range_get_min(const GiRange *const self)
Get the minimum of a range.
Definition: girange.c:167
cxdouble giraffe_range_get_max(const GiRange *const self)
Get the maximum of a range.
Definition: girange.c:213
void giraffe_range_set_max(GiRange *self, cxdouble max)
Set the maximum of a range.
Definition: girange.c:190
GiRange * giraffe_rebin_get_wavelength_range(GiImage *spectra, GiTable *wlsolution, GiTable *grating, GiTable *slitgeometry, cxbool common)
Compute the wavelenght range of spectra.
Definition: girebinning.c:3914
cpl_table * giraffe_table_get(const GiTable *self)
Get the table data from a Giraffe table.
Definition: gitable.c:433
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