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

This file is part of the GIRAFFE Pipeline Reference Manual 2.16.12.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Fri Feb 21 2025 12:08:13 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2004