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