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 
53 inline 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 
65 inline 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 
237 inline 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 
368 inline 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 
427 cxint
428 giraffe_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 
1392 GiFieldOfView*
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 
1426 void
1427 giraffe_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 
1493 void
1494 giraffe_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 
1529 cxint
1530 giraffe_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 
1672 cxint
1673 giraffe_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 
2011 GiFieldOfViewConfig*
2012 giraffe_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 
2066 void
2067 giraffe_fov_config_destroy(GiFieldOfViewConfig* config)
2068 {
2069 
2070  if (config != NULL) {
2071  cx_free(config);
2072  }
2073 
2074  return;
2075 
2076 }
2077 
2078 
2088 void
2089 giraffe_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
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
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
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
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
cxsize giraffe_cube_get_height(const GiCube *self)
Get the height of the given data cube.
Definition: gicube.c:553
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_sqrt(GiCube *self)
Compute the square root of the elements of a cube.
Definition: gicube.c:1091
cxdouble * giraffe_cube_get_data(const GiCube *self)
Get a reference to the data cube's pixel buffer.
Definition: gicube.c:707
cpl_array * giraffe_fiberlist_get_subslits(const cpl_table *fibers)
Get the list of subslit identifiers from a fiber setup.
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
GiFieldOfViewConfig * giraffe_fov_config_create(cpl_parameterlist *list)
Creates a setup structure for the field of view reconstruction.
Definition: gifov.c:2012
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
void giraffe_image_delete(GiImage *self)
Destroys an image.
Definition: giimage.c:181
cpl_propertylist * giraffe_image_get_properties(const GiImage *self)
Get the properties of an image.
Definition: giimage.c:282
cpl_image * giraffe_image_get(const GiImage *self)
Gets the image data.
Definition: giimage.c:218
GiImage * giraffe_image_new(cpl_type type)
Creates an empty image container.
Definition: giimage.c:65
cxint giraffe_image_set(GiImage *self, cpl_image *image)
Sets the image data.
Definition: giimage.c:244
cxint giraffe_image_set_properties(GiImage *self, cpl_propertylist *properties)
Attaches a property list to an image.
Definition: giimage.c:312
GiImage * giraffe_image_duplicate(const GiImage *self)
Creates a copy of an image.
Definition: giimage.c:139
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.10.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Thu Dec 15 2022 21:18:51 by doxygen 1.9.1 written by Dimitri van Heesch, © 1997-2004