GIRAFFE Pipeline Reference Manual

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

This file is part of the GIRAFFE Pipeline Reference Manual 2.14.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Wed Mar 11 2015 13:19:41 by doxygen 1.8.9.1 written by Dimitri van Heesch, © 1997-2004