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