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_propertylist_get_double(properties,
732  GIALIAS_RADEG);
733  cxdouble yvalue =
734  cpl_propertylist_get_double(properties,
735  GIALIAS_DECDEG);
736  cxdouble orientation =
737  cpl_table_get_double(ssf, "ORIENT", 0, NULL);
738 
739  cxdouble zvalue = 0.;
740  cxdouble zstep = 0.;
741  cxdouble angle = GI_IFU_POSANG_OFFSET - orientation;
742  cxdouble pixscale = GI_IFU_PIXSCALE / 3600.;
743 
744 
745  transform = cpl_matrix_new(3, 3);
746 
747  wcs = cpl_propertylist_new();
748 
749  cpl_propertylist_update_double(wcs, "XORIGIN", xorigin);
750  cpl_propertylist_update_double(wcs, "YORIGIN", yorigin);
751  cpl_propertylist_update_double(wcs, "ZORIGIN", 1.);
752 
753  giraffe_cube_get_zaxis(_scube, &zvalue, &zstep);
754 
755  cpl_propertylist_update_double(wcs, "XPOINT", xvalue);
756  cpl_propertylist_update_double(wcs, "YPOINT", yvalue);
757  cpl_propertylist_update_double(wcs, "ZPOINT", zvalue);
758 
759  cpl_propertylist_update_string(wcs, "XTYPE",
760  "RA---TAN");
761  cpl_propertylist_update_string(wcs, "YTYPE",
762  "DEC--TAN");
763 
764  if (log_scale == TRUE) {
765  cpl_propertylist_update_string(wcs,
766  "ZTYPE", "AWAV-LOG");
767  }
768  else {
769  cpl_propertylist_update_string(wcs,
770  "ZTYPE", "AWAV");
771  }
772 
773  cpl_propertylist_update_string(wcs, "XUNIT", "deg");
774  cpl_propertylist_update_string(wcs, "YUNIT", "deg");
775  cpl_propertylist_update_string(wcs, "ZUNIT", "nm");
776 
777 
778  /*
779  * Right ascension is counted eastward from the
780  * equinox, hence the negative sign on the upper
781  * left element of the scale matrix.
782  */
783 
784  angle *= CX_PI / 180.;
785 
786  cpl_matrix_set(transform, 0, 0, -pixscale * cos(angle));
787  cpl_matrix_set(transform, 0, 1, pixscale * -sin(angle));
788  cpl_matrix_set(transform, 1, 0, -pixscale * sin(angle));
789  cpl_matrix_set(transform, 1, 1, pixscale * cos(angle));
790  cpl_matrix_set(transform, 2, 2, zstep);
791 
792  }
793 
794  if (_scube != NULL) {
795  _simage = _giraffe_fov_integrate_cube(_scube, limits);
796  }
797 
798  if ((_scube == NULL) || (_simage == NULL)) {
799 
800  cpl_image_delete(_simage);
801  _simage = NULL;
802 
803  giraffe_cube_delete(_scube);
804  _scube = NULL;
805 
806  failed = TRUE;
807 
808  cpl_msg_error(fctid, "Cannot create data cube for "
809  "sub-slit %d", nss);
810  }
811  else {
812  giraffe_cube_set_wcs(_scube, wcs, transform);
813 
814  cx_slist_push_back(scubes, _scube);
815  cx_slist_push_back(simages, _simage);
816  }
817 
818  if (!failed) {
819 
820  _ecube = _giraffe_fov_create_cube(variance,
821  ssf, NULL);
822 
823  if (_ecube != NULL) {
824  _eimage = _giraffe_fov_integrate_cube(_ecube,
825  limits);
826  }
827 
828  if ((_ecube == NULL) || (_eimage == NULL)) {
829 
830  cpl_image_delete(_eimage);
831  _eimage = NULL;
832 
833  giraffe_cube_delete(_ecube);
834  _ecube = NULL;
835 
836  failed = TRUE;
837 
838  cpl_msg_error(fctid, "Cannot create error "
839  "cube for sub-slit %d", nss);
840  }
841  else {
842  giraffe_cube_sqrt(_ecube);
843  cpl_image_power(_eimage, 0.5);
844 
845  giraffe_cube_set_wcs(_ecube, wcs, transform);
846 
847  cx_slist_push_back(ecubes, _ecube);
848  cx_slist_push_back(eimages, _eimage);
849  }
850 
851  }
852 
853  cpl_propertylist_delete(wcs);
854  wcs = NULL;
855 
856  cpl_matrix_delete(transform);
857  transform = NULL;
858 
859  if (failed) {
860 
861  cpl_table_delete(ssf);
862  ssf = NULL;
863 
864  giraffe_image_delete(variance);
865  variance = NULL;
866 
867  cpl_array_delete(_ssn);
868  _ssn = NULL;
869 
870  cpl_array_delete(ssn);
871  ssn = NULL;
872 
873  cx_slist_destroy(simages,
874  (cx_free_func)cpl_image_delete);
875  simages = NULL;
876 
877  cx_slist_destroy(eimages,
878  (cx_free_func)cpl_image_delete);
879  eimages = NULL;
880 
881  cx_slist_destroy(scubes,
882  (cx_free_func)giraffe_cube_delete);
883  scubes = NULL;
884 
885  cx_slist_destroy(ecubes,
886  (cx_free_func)giraffe_cube_delete);
887  ecubes = NULL;
888 
889  giraffe_range_delete(limits);
890  limits = NULL;
891 
892  return 1;
893 
894  }
895 
896  }
897  else {
898 
899  if (ssf != NULL) {
900  cpl_msg_debug(fctid, "Unused IFU button detected. "
901  "Skipping sub-slit %d", nss);
902 
903  cpl_array_erase_window(ssn, i, 1);
904 
905  cx_slist_push_back(simages, NULL);
906  cx_slist_push_back(eimages, NULL);
907  }
908  }
909 
910  cpl_table_delete(ssf);
911  ssf = NULL;
912 
913  }
914 
915  cpl_array_delete(_ssn);
916  _ssn = NULL;
917 
918  giraffe_image_delete(variance);
919  variance = NULL;
920 
921 
922  /*
923  * Put the images of the reconstructed field of view in an
924  * image using a tabular layout. This mosaic is stored as
925  * the first image in the image containers, to be consistent
926  * with the Argus mode, where only this image is provided.
927  */
928 
929  smosaic = _giraffe_fov_arrange_images(simages, 5, 3, -4);
930  emosaic = _giraffe_fov_arrange_images(eimages, 5, 3, -4);
931 
932  if ((smosaic == NULL) || (emosaic == NULL)) {
933 
934  cpl_image_delete(smosaic);
935  smosaic = NULL;
936 
937  cpl_image_delete(emosaic);
938  emosaic = NULL;
939 
940  cx_slist_destroy(simages, (cx_free_func)cpl_image_delete);
941  simages = NULL;
942 
943  cx_slist_destroy(eimages, (cx_free_func)cpl_image_delete);
944  eimages = NULL;
945 
946  cx_slist_destroy(scubes, (cx_free_func)giraffe_cube_delete);
947  scubes = NULL;
948 
949  cx_slist_destroy(ecubes, (cx_free_func)giraffe_cube_delete);
950  ecubes = NULL;
951 
952  cpl_array_delete(ssn);
953  ssn = NULL;
954 
955  giraffe_range_delete(limits);
956  limits = NULL;
957 
958  return 1;
959 
960  }
961 
962  cx_slist_push_front(simages, smosaic);
963  cx_slist_push_front(eimages, emosaic);
964  break;
965 
966  }
967 
968  case GIMODE_ARGUS:
969  {
970  cxbool failed = FALSE;
971 
972  cpl_image* simage = NULL;
973  cpl_image* eimage = NULL;
974 
975  cpl_matrix* transform = NULL;
976 
977  cpl_propertylist* wcs = NULL;
978 
979  GiImage* variance = NULL;
980 
981  GiCube* scube = NULL;
982  GiCube* ecube = NULL;
983 
984 
985  /*
986  * Compute the variances from the error map.
987  */
988 
989  variance = giraffe_image_duplicate(rebinning->errors);
990 
991  if (variance == NULL) {
992 
993  cx_slist_destroy(simages, (cx_free_func)cpl_image_delete);
994  simages = NULL;
995 
996  cx_slist_destroy(eimages, (cx_free_func)cpl_image_delete);
997  eimages = NULL;
998 
999  cx_slist_destroy(scubes, (cx_free_func)giraffe_cube_delete);
1000  scubes = NULL;
1001 
1002  cx_slist_destroy(ecubes, (cx_free_func)giraffe_cube_delete);
1003  ecubes = NULL;
1004 
1005  giraffe_range_delete(limits);
1006  limits = NULL;
1007 
1008  cpl_msg_error(fctid, "Failed to create variance map!");
1009  return 1;
1010 
1011  }
1012 
1013  cpl_image_power(giraffe_image_get(variance), 2.);
1014 
1015 
1016  /*
1017  * Build the data cubes and field of view images
1018  */
1019 
1020  scube = _giraffe_fov_create_cube(rebinning->spectra,
1021  _fibers, NULL);
1022 
1023  /*
1024  * Build a world coordinate system for the cube.
1025  */
1026 
1027  /*
1028  * Argus has a +90 degrees offset with respect to the adaptor,
1029  * thus: PA_arg = PA_ada + 90.
1030  *
1031  * The Argus long axis is aligned with the North-South
1032  * direction, and North up for PA_arg = 0. Since in the
1033  * image the Argus long axis is the x-axis an extra 90.
1034  * degrees offset has to be applied to the WCS axes. And
1035  * finally, since the coordinate system is transformed
1036  * relative to the image, and PA_arg is counted positive
1037  * counter clockwise (from North through East), the agular
1038  * offsets must be counted negative.
1039  */
1040 
1041  if (scube != NULL) {
1042 
1043  cxdouble xorigin = giraffe_cube_get_width(scube) / 2.;
1044  cxdouble yorigin = giraffe_cube_get_height(scube) / 2.;
1045 
1046  cxdouble xvalue = cpl_propertylist_get_double(properties,
1047  GIALIAS_RADEG);
1048  cxdouble yvalue = cpl_propertylist_get_double(properties,
1049  GIALIAS_DECDEG);
1050  cxdouble zvalue = 0.;
1051  cxdouble zstep = 0.;
1052  cxdouble angle = -90. -
1053  (cpl_propertylist_get_double(properties,
1054  GIALIAS_POSANG) +
1055  GI_ARGUS_POSANG_OFFSET);
1056 
1057  cxdouble pixscale = GI_ARGUS_PIXSCALE_LOW;
1058 
1059  const cxchar* scale =
1060  cpl_propertylist_get_string(properties,
1061  GIALIAS_ARGUS_SCALE);
1062 
1063 
1064  if ((scale != NULL) && (strcmp(scale, "POS_1_67") == 0)) {
1065  pixscale = GI_ARGUS_PIXSCALE_HIGH;
1066  }
1067 
1068  /* Get pixel scale in degrees */
1069 
1070  pixscale /= 3600.;
1071 
1072 
1073  transform = cpl_matrix_new(3, 3);
1074 
1075  wcs = cpl_propertylist_new();
1076 
1077  cpl_propertylist_update_double(wcs, "XORIGIN", xorigin);
1078  cpl_propertylist_update_double(wcs, "YORIGIN", yorigin);
1079  cpl_propertylist_update_double(wcs, "ZORIGIN", 1.);
1080 
1081  giraffe_cube_get_zaxis(scube, &zvalue, &zstep);
1082 
1083  cpl_propertylist_update_double(wcs, "XPOINT", xvalue);
1084  cpl_propertylist_update_double(wcs, "YPOINT", yvalue);
1085  cpl_propertylist_update_double(wcs, "ZPOINT", zvalue);
1086 
1087  cpl_propertylist_update_string(wcs, "XTYPE", "RA---TAN");
1088  cpl_propertylist_update_string(wcs, "YTYPE", "DEC--TAN");
1089 
1090  if (log_scale == TRUE) {
1091  cpl_propertylist_update_string(wcs,
1092  "ZTYPE", "AWAV-LOG");
1093  }
1094  else {
1095  cpl_propertylist_update_string(wcs,
1096  "ZTYPE", "AWAV");
1097  }
1098 
1099  cpl_propertylist_update_string(wcs, "XUNIT", "deg");
1100  cpl_propertylist_update_string(wcs, "YUNIT", "deg");
1101  cpl_propertylist_update_string(wcs, "ZUNIT", "nm");
1102 
1103 
1104  /*
1105  * Right ascension is counted eastward from the equinox,
1106  * hence the negative sign on the upper left element of the
1107  * scale matrix.
1108  */
1109 
1110  angle *= CX_PI / 180.;
1111 
1112  cpl_matrix_set(transform, 0, 0, -pixscale * cos(angle));
1113  cpl_matrix_set(transform, 0, 1, pixscale * -sin(angle));
1114  cpl_matrix_set(transform, 1, 0, -pixscale * sin(angle));
1115  cpl_matrix_set(transform, 1, 1, pixscale * cos(angle));
1116  cpl_matrix_set(transform, 2, 2, zstep);
1117 
1118  }
1119 
1120 
1121  if (scube != NULL) {
1122  simage = _giraffe_fov_integrate_cube(scube, limits);
1123  }
1124 
1125  if ((scube == NULL) || (simage == NULL)) {
1126 
1127  cpl_image_delete(simage);
1128  simage = NULL;
1129 
1130  giraffe_cube_delete(scube);
1131  scube = NULL;
1132 
1133  failed = TRUE;
1134 
1135  cpl_msg_error(fctid, "Cannot create data cube!");
1136 
1137  }
1138  else {
1139 
1140  giraffe_cube_set_wcs(scube, wcs, transform);
1141 
1142  cx_slist_push_back(scubes, scube);
1143  cx_slist_push_back(simages, simage);
1144 
1145  }
1146 
1147 
1148  if (!failed) {
1149 
1150  ecube = _giraffe_fov_create_cube(variance, _fibers, NULL);
1151  eimage = _giraffe_fov_integrate_cube(ecube, limits);
1152 
1153  if ((ecube == NULL) || (eimage == NULL)) {
1154 
1155  cpl_image_delete(eimage);
1156  eimage = NULL;
1157 
1158  giraffe_cube_delete(ecube);
1159  ecube = NULL;
1160 
1161  failed = TRUE;
1162 
1163  cpl_msg_error(fctid, "Cannot create error cube!");
1164 
1165  }
1166  else {
1167 
1168  giraffe_cube_sqrt(ecube);
1169  cpl_image_power(eimage, 0.5);
1170 
1171  giraffe_cube_set_wcs(ecube, wcs, transform);
1172 
1173  cx_slist_push_back(ecubes, ecube);
1174  cx_slist_push_back(eimages, eimage);
1175 
1176  }
1177 
1178  }
1179 
1180  cpl_propertylist_delete(wcs);
1181  wcs = NULL;
1182 
1183  cpl_matrix_delete(transform);
1184  transform = NULL;
1185 
1186  giraffe_image_delete(variance);
1187  variance = NULL;
1188 
1189  if (failed) {
1190 
1191  cx_slist_destroy(simages, (cx_free_func)cpl_image_delete);
1192  simages = NULL;
1193 
1194  cx_slist_destroy(eimages, (cx_free_func)cpl_image_delete);
1195  eimages = NULL;
1196 
1197  cx_slist_destroy(scubes, (cx_free_func)giraffe_cube_delete);
1198  scubes = NULL;
1199 
1200  cx_slist_destroy(ecubes, (cx_free_func)giraffe_cube_delete);
1201  ecubes = NULL;
1202 
1203  giraffe_range_delete(limits);
1204  limits = NULL;
1205 
1206  return 1;
1207 
1208  }
1209 
1210  break;
1211  }
1212 
1213  default:
1214  return 1;
1215  break;
1216  }
1217 
1218 
1219  /*
1220  * Fill the results container.
1221  */
1222 
1223  result->mode = mode;
1224  result->ssn = ssn;
1225  ssn = NULL;
1226 
1227  properties = giraffe_image_get_properties(rebinning->spectra);
1228  fov = cx_slist_pop_front(simages);
1229 
1230  result->fov.spectra = giraffe_image_new(CPL_TYPE_DOUBLE);
1231  giraffe_image_set(result->fov.spectra, fov);
1232  giraffe_image_set_properties(result->fov.spectra, properties);
1233 
1234  properties = giraffe_image_get_properties(result->fov.spectra);
1235 
1236  /* Clear left over WCS keywords */
1237 
1238  giraffe_propertylist_update_wcs(properties, 0, NULL, NULL, NULL,
1239  NULL, NULL);
1240 
1241  cpl_propertylist_update_double(properties, GIALIAS_FOV_BANDMIN,
1242  giraffe_range_get_min(limits));
1243  cpl_propertylist_set_comment(properties, GIALIAS_FOV_BANDMIN,
1244  "Minimum wavelength of FOV band");
1245 
1246  cpl_propertylist_update_double(properties, GIALIAS_FOV_BANDMAX,
1247  giraffe_range_get_max(limits));
1248  cpl_propertylist_set_comment(properties, GIALIAS_FOV_BANDMAX,
1249  "Maximum wavelength of FOV band");
1250 
1251  cpl_image_delete(fov);
1252  fov = NULL;
1253 
1254 
1255  properties = giraffe_image_get_properties(rebinning->errors);
1256  fov = cx_slist_pop_front(eimages);
1257 
1258  result->fov.errors = giraffe_image_new(CPL_TYPE_DOUBLE);
1259  giraffe_image_set(result->fov.errors, fov);
1260  giraffe_image_set_properties(result->fov.errors, properties);
1261 
1262  properties = giraffe_image_get_properties(result->fov.errors);
1263 
1264  /* Clear left over WCS keywords */
1265 
1266  giraffe_propertylist_update_wcs(properties, 0, NULL, NULL, NULL,
1267  NULL, NULL);
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  if (!cx_slist_empty(simages)) {
1282 
1283  cx_slist_iterator pos = cx_slist_begin(simages);
1284 
1285  result->images.spectra = cx_slist_new();
1286 
1287  while (pos != cx_slist_end(simages)) {
1288 
1289  GiImage* image = giraffe_image_new(CPL_TYPE_DOUBLE);
1290 
1291  giraffe_image_set(image, cx_slist_get(simages, pos));
1292  cx_slist_push_back(result->images.spectra, image);
1293 
1294  pos = cx_slist_next(simages, pos);
1295  }
1296 
1297  }
1298 
1299  if (!cx_slist_empty(eimages)) {
1300 
1301  cx_slist_iterator pos = cx_slist_begin(eimages);
1302 
1303  result->images.errors = cx_slist_new();
1304 
1305  while (pos != cx_slist_end(eimages)) {
1306 
1307  GiImage* image = giraffe_image_new(CPL_TYPE_DOUBLE);
1308 
1309  giraffe_image_set(image, cx_slist_get(eimages, pos));
1310  cx_slist_push_back(result->images.errors, image);
1311 
1312  pos = cx_slist_next(eimages, pos);
1313  }
1314 
1315  }
1316 
1317  if (config->cube == TRUE) {
1318 
1319  if (!cx_slist_empty(scubes)) {
1320  result->cubes.spectra = scubes;
1321  scubes = NULL;
1322  }
1323 
1324  if (!cx_slist_empty(ecubes)) {
1325  result->cubes.errors = ecubes;
1326  ecubes = NULL;
1327  }
1328 
1329  }
1330 
1331 
1332  /*
1333  * Cleanup
1334  */
1335 
1336  giraffe_range_delete(limits);
1337  limits = NULL;
1338 
1339  cx_slist_destroy(simages, (cx_free_func)cpl_image_delete);
1340  simages = NULL;
1341 
1342  cx_slist_destroy(eimages, (cx_free_func)cpl_image_delete);
1343  eimages = NULL;
1344 
1345  if (scubes != NULL) {
1346  cx_slist_destroy(scubes, (cx_free_func)giraffe_cube_delete);
1347  scubes = NULL;
1348  }
1349 
1350  if (ecubes != NULL) {
1351  cx_slist_destroy(ecubes, (cx_free_func)giraffe_cube_delete);
1352  ecubes = NULL;
1353  }
1354 
1355  return 0;
1356 
1357 }
1358 
1359 
1373 GiFieldOfView*
1375 {
1376  GiFieldOfView* self = cx_malloc(sizeof *self);
1377 
1378  self->mode = GIMODE_NONE;
1379  self->ssn = NULL;
1380 
1381  self->fov.spectra = NULL;
1382  self->fov.errors = NULL;
1383 
1384  self->images.spectra = NULL;
1385  self->images.errors = NULL;
1386 
1387  self->cubes.spectra = NULL;
1388  self->cubes.errors = NULL;
1389 
1390  return self;
1391 
1392 }
1393 
1394 
1407 void
1408 giraffe_fov_clear(GiFieldOfView* self)
1409 {
1410 
1411  if (self != NULL) {
1412 
1413  if (self->cubes.errors != NULL) {
1414  cx_slist_destroy(self->cubes.errors,
1415  (cx_free_func)giraffe_cube_delete);
1416  self->cubes.errors = NULL;
1417  }
1418 
1419  if (self->cubes.spectra != NULL) {
1420  cx_slist_destroy(self->cubes.spectra,
1421  (cx_free_func)giraffe_cube_delete);
1422  self->cubes.spectra = NULL;
1423  }
1424 
1425  if (self->images.errors != NULL) {
1426  cx_slist_destroy(self->images.errors,
1427  (cx_free_func)giraffe_image_delete);
1428  self->images.errors = NULL;
1429  }
1430 
1431  if (self->images.spectra != NULL) {
1432  cx_slist_destroy(self->images.spectra,
1433  (cx_free_func)giraffe_image_delete);
1434  self->images.spectra = NULL;
1435  }
1436 
1437  if (self->fov.errors != NULL) {
1438  giraffe_image_delete(self->fov.errors);
1439  self->fov.errors = NULL;
1440  }
1441 
1442  if (self->fov.spectra != NULL) {
1443  giraffe_image_delete(self->fov.spectra);
1444  self->fov.spectra = NULL;
1445  }
1446 
1447  if (self->ssn != NULL) {
1448  cpl_array_delete(self->ssn);
1449  self->ssn = NULL;
1450  }
1451 
1452  self->mode = GIMODE_NONE;
1453 
1454  }
1455 
1456  return;
1457 
1458 }
1459 
1460 
1474 void
1475 giraffe_fov_delete(GiFieldOfView* self)
1476 {
1477 
1478  if (self != NULL) {
1479  giraffe_fov_clear(self);
1480  cx_free(self);
1481  }
1482 
1483  return;
1484 
1485 }
1486 
1487 
1510 cxint
1511 giraffe_fov_save_cubes(const GiFieldOfView* self,
1512  cpl_propertylist* properties,
1513  const cxchar* filename, cxptr data)
1514 {
1515 
1516 
1517  cxint component = 0;
1518 
1519  cx_slist* cubes = NULL;
1520 
1521 
1522  if ((self == NULL) || (properties == NULL) || (filename == NULL)) {
1523  return -1;
1524  }
1525 
1526 
1527  /*
1528  * Get the cube component that should be saved. Spectra or errors.
1529  */
1530 
1531  if (data != NULL) {
1532  component = *((cxuint*)data);
1533  }
1534 
1535  if (component == 0) {
1536  cubes = self->cubes.spectra;
1537  }
1538  else {
1539  cubes = self->cubes.errors;
1540  }
1541 
1542  if (cubes == NULL) {
1543  return -2;
1544  }
1545 
1546 
1547  if (!cx_slist_empty(cubes)) {
1548 
1549  if (self->mode == GIMODE_ARGUS) {
1550 
1551  cxint status = 0;
1552  cxint iomode = CPL_IO_CREATE;
1553 
1554  GiCube* cube = cx_slist_front(cubes);
1555 
1556  status = giraffe_cube_save(cube, properties, filename, &iomode);
1557 
1558  if (status != 0) {
1559  return 1;
1560  }
1561 
1562  }
1563  else {
1564 
1565  cxint nss = 0;
1566  cxint status = 0;
1567  cxint iomode = CPL_IO_CREATE;
1568 
1569  cx_slist_const_iterator pos = cx_slist_begin(cubes);
1570 
1571  cx_string* name = NULL;
1572 
1573  cpl_propertylist* xproperties = NULL;
1574 
1575 
1576  status = giraffe_cube_save(NULL, properties, filename, &iomode);
1577 
1578  if (status != 0) {
1579  return 1;
1580  }
1581 
1582 
1583  name = cx_string_new();
1584  xproperties = cpl_propertylist_new();
1585 
1586  iomode = CPL_IO_EXTEND;
1587 
1588  while (pos != cx_slist_end(cubes)) {
1589 
1590  cxint ssn = cpl_array_get_int(self->ssn, nss, NULL);
1591 
1592  GiCube* cube = cx_slist_get(cubes, pos);
1593 
1594 
1595  cx_string_sprintf(name, "SSN%-d", ssn);
1596  cpl_propertylist_update_string(xproperties, "EXTNAME",
1597  cx_string_get(name));
1598 
1599  status = giraffe_cube_save(cube, xproperties, filename,
1600  &iomode);
1601 
1602  if (status != 0) {
1603 
1604  cpl_propertylist_delete(xproperties);
1605  xproperties = NULL;
1606 
1607  cx_string_delete(name);
1608  name = NULL;
1609 
1610  return 1;
1611 
1612  }
1613 
1614  pos = cx_slist_next(cubes, pos);
1615  ++nss;
1616 
1617  }
1618 
1619  cpl_propertylist_delete(xproperties);
1620  xproperties = NULL;
1621 
1622  cx_string_delete(name);
1623  name = NULL;
1624 
1625  }
1626 
1627  }
1628 
1629  return 0;
1630 
1631 }
1632 
1633 
1653 cxint
1654 giraffe_fov_save_cubes_eso3d(const GiFieldOfView* self,
1655  cpl_propertylist* properties,
1656  const cxchar* filename, cxptr data)
1657 {
1658 
1659  const cxchar* data_name = "SPECTRA";
1660  const cxchar* error_name = "ERRORS";
1661  const cxchar* link_names[2] = {"SCIDATA", "ERRDATA"};
1662 
1663  cx_slist* scubes = NULL;
1664  cx_slist* ecubes = NULL;
1665 
1666 
1667  /* Currently not used. Set to avoid compiler warnings */
1668 
1669  data = NULL;
1670 
1671 
1672  if ((self == NULL) || (properties == NULL) || (filename == NULL)) {
1673  return -1;
1674  }
1675 
1676  if (self->cubes.spectra == NULL) {
1677  return -2;
1678  }
1679 
1680  if ((cpl_propertylist_has(properties, GIALIAS_EQUINOX) == FALSE) ||
1681  (cpl_propertylist_get_type(properties, GIALIAS_EQUINOX)
1682  != CPL_TYPE_DOUBLE)) {
1683  return -2;
1684  }
1685 
1686 
1687  /*
1688  * Get the cube components. If errors are present their number must
1689  * match the number of spectrum cubes!
1690  */
1691 
1692  scubes = self->cubes.spectra;
1693 
1694  if (cx_slist_empty(scubes)) {
1695  return -3;
1696  }
1697 
1698  if (self->cubes.errors != NULL) {
1699 
1700  ecubes = self->cubes.errors;
1701 
1702  if (cx_slist_size(scubes) != cx_slist_size(ecubes)) {
1703  return -4;
1704  }
1705 
1706  }
1707 
1708 
1709  if (self->mode == GIMODE_ARGUS) {
1710 
1711  cxint status = 0;
1712  cxint iomode = CPL_IO_CREATE;
1713 
1714  cxdouble equinox = cpl_propertylist_get_double(properties,
1715  GIALIAS_EQUINOX);
1716 
1717  cpl_propertylist* xproperties = NULL;
1718 
1719  GiCube* scube = cx_slist_front(scubes);
1720 
1721 
1722  status = giraffe_cube_save(NULL, properties, filename, &iomode);
1723 
1724  if (status != 0) {
1725  return 1;
1726  }
1727 
1728 
1729  iomode = CPL_IO_EXTEND;
1730 
1731  xproperties = cpl_propertylist_new();
1732 
1733  cpl_propertylist_update_string(xproperties, GIALIAS_EXTNAME, data_name);
1734  cpl_propertylist_set_comment(xproperties, GIALIAS_EXTNAME,
1735  "FITS Extension name");
1736 
1737  cpl_propertylist_update_string(xproperties, "HDUCLASS", "ESO");
1738  cpl_propertylist_set_comment(xproperties, "HDUCLASS",
1739  "Conforms to ESO data cube conventions");
1740 
1741  cpl_propertylist_update_string(xproperties, "HDUDOC", "DICD");
1742  cpl_propertylist_set_comment(xproperties, "HDUDOC",
1743  "Data format specification document");
1744 
1745  cpl_propertylist_update_string(xproperties, "HDUVERS",
1746  "DICD version 6");
1747  cpl_propertylist_set_comment(xproperties, "HDUVERS",
1748  "Specific version of the data format "
1749  "document");
1750 
1751  cpl_propertylist_update_string(xproperties, "HDUCLAS1", "IMAGE");
1752  cpl_propertylist_set_comment(xproperties, "HDUCLAS1",
1753  "Image data format");
1754 
1755  cpl_propertylist_update_string(xproperties, "HDUCLAS2", "DATA");
1756  cpl_propertylist_set_comment(xproperties, "HDUCLAS2",
1757  "Science data extension");
1758  cpl_propertylist_update_string(xproperties, link_names[1], error_name);
1759  cpl_propertylist_set_comment(xproperties, link_names[1],
1760  "Linked error data extension");
1761 
1762  cpl_propertylist_update_double(xproperties, GIALIAS_EQUINOX,
1763  equinox);
1764 
1765  status = giraffe_cube_save(scube, xproperties, filename,
1766  &iomode);
1767 
1768  if (status != 0) {
1769 
1770  cpl_propertylist_delete(xproperties);
1771  xproperties = NULL;
1772 
1773  return 1;
1774 
1775  }
1776 
1777  cpl_propertylist_erase(xproperties, link_names[1]);
1778  cpl_propertylist_erase(xproperties, "BUNIT");
1779  cpl_propertylist_erase(xproperties, "DATAMIN");
1780  cpl_propertylist_erase(xproperties, "DATAMAX");
1781 
1782 
1783  if (ecubes != NULL) {
1784 
1785  GiCube* ecube = cx_slist_front(ecubes);
1786 
1787 
1788  cpl_propertylist_update_string(xproperties, "EXTNAME", error_name);
1789 
1790  cpl_propertylist_update_string(xproperties, "HDUCLAS2", "ERROR");
1791  cpl_propertylist_set_comment(xproperties, "HDUCLAS2",
1792  "Error data extension");
1793 
1794  cpl_propertylist_update_string(xproperties, "HDUCLAS3", "RMSE");
1795  cpl_propertylist_set_comment(xproperties, "HDUCLAS3",
1796  "Type of error: root mean squared");
1797 
1798  cpl_propertylist_update_string(xproperties, link_names[0],
1799  data_name);
1800  cpl_propertylist_set_comment(xproperties, link_names[0],
1801  "Linked science data extension");
1802 
1803  status = giraffe_cube_save(ecube, xproperties, filename,
1804  &iomode);
1805 
1806  if (status != 0) {
1807 
1808  cpl_propertylist_delete(xproperties);
1809  xproperties = NULL;
1810 
1811  return 1;
1812 
1813  }
1814 
1815  }
1816 
1817  cpl_propertylist_delete(xproperties);
1818  xproperties = NULL;
1819 
1820  }
1821  else {
1822 
1823  cxint nss = 0;
1824  cxint status = 0;
1825  cxint iomode = CPL_IO_CREATE;
1826 
1827  cxdouble equinox = cpl_propertylist_get_double(properties,
1828  GIALIAS_EQUINOX);
1829 
1830  cx_slist_const_iterator spos = cx_slist_begin(scubes);
1831  cx_slist_const_iterator epos = cx_slist_begin(ecubes);
1832 
1833  cx_string* name = NULL;
1834 
1835  cpl_propertylist* xproperties = NULL;
1836 
1837 
1838  status = giraffe_cube_save(NULL, properties, filename, &iomode);
1839 
1840  if (status != 0) {
1841  return 1;
1842  }
1843 
1844 
1845  name = cx_string_new();
1846  xproperties = cpl_propertylist_new();
1847 
1848  iomode = CPL_IO_EXTEND;
1849 
1850  while (spos != cx_slist_end(scubes)) {
1851 
1852  cxint ssn = cpl_array_get_int(self->ssn, nss, NULL);
1853 
1854  GiCube* scube = cx_slist_get(scubes, spos);
1855 
1856 
1857  cx_string_sprintf(name, "SSN%-d.%s", ssn, data_name);
1858 
1859  cpl_propertylist_update_string(xproperties, GIALIAS_EXTNAME,
1860  cx_string_get(name));
1861  cpl_propertylist_set_comment(xproperties, GIALIAS_EXTNAME,
1862  "FITS Extension name");
1863 
1864  cpl_propertylist_update_string(xproperties, "HDUCLASS", "ESO");
1865  cpl_propertylist_set_comment(xproperties, "HDUCLASS",
1866  "Conforms to ESO data cube "
1867  "conventions");
1868 
1869  cpl_propertylist_update_string(xproperties, "HDUDOC", "DICD");
1870  cpl_propertylist_set_comment(xproperties, "HDUDOC",
1871  "Data format specification document");
1872 
1873  cpl_propertylist_update_string(xproperties, "HDUVERS",
1874  "DICD version 6");
1875  cpl_propertylist_set_comment(xproperties, "HDUVERS",
1876  "Specific version of the data format "
1877  "document");
1878 
1879  cpl_propertylist_update_string(xproperties, "HDUCLAS1", "IMAGE");
1880  cpl_propertylist_set_comment(xproperties, "HDUCLAS1",
1881  "Image data format");
1882 
1883  cpl_propertylist_update_string(xproperties, "HDUCLAS2", "DATA");
1884  cpl_propertylist_set_comment(xproperties, "HDUCLAS2",
1885  "Science data extension");
1886 
1887  cx_string_sprintf(name, "SSN%-d.%s", ssn, error_name);
1888 
1889  cpl_propertylist_update_string(xproperties, link_names[1],
1890  cx_string_get(name));
1891  cpl_propertylist_set_comment(xproperties, link_names[1],
1892  "Linked error data extension");
1893 
1894  cpl_propertylist_update_double(xproperties, GIALIAS_EQUINOX,
1895  equinox);
1896 
1897  status = giraffe_cube_save(scube, xproperties, filename,
1898  &iomode);
1899 
1900  if (status != 0) {
1901 
1902  cpl_propertylist_delete(xproperties);
1903  xproperties = NULL;
1904 
1905  cx_string_delete(name);
1906  name = NULL;
1907 
1908  return 1;
1909 
1910  }
1911 
1912  cpl_propertylist_erase(xproperties, link_names[1]);
1913  cpl_propertylist_erase(xproperties, "BUNIT");
1914  cpl_propertylist_erase(xproperties, "DATAMIN");
1915  cpl_propertylist_erase(xproperties, "DATAMAX");
1916 
1917 
1918  if (ecubes != NULL) {
1919 
1920  GiCube* ecube = cx_slist_get(ecubes, epos);
1921 
1922 
1923  cx_string_sprintf(name, "SSN%-d.%s", ssn, error_name);
1924 
1925  cpl_propertylist_update_string(xproperties, "EXTNAME",
1926  cx_string_get(name));
1927 
1928  cpl_propertylist_update_string(xproperties, "HDUCLAS2", "ERROR");
1929  cpl_propertylist_set_comment(xproperties, "HDUCLAS2",
1930  "Error data extension");
1931 
1932  cpl_propertylist_update_string(xproperties, "HDUCLAS3", "RMSE");
1933  cpl_propertylist_set_comment(xproperties, "HDUCLAS3",
1934  "Type of error: root mean squared");
1935 
1936  cx_string_sprintf(name, "SSN%-d.%s", ssn, data_name);
1937 
1938  cpl_propertylist_update_string(xproperties, link_names[0],
1939  cx_string_get(name));
1940  cpl_propertylist_set_comment(xproperties, link_names[0],
1941  "Linked science data extension");
1942 
1943  status = giraffe_cube_save(ecube, xproperties, filename,
1944  &iomode);
1945 
1946 
1947  if (status != 0) {
1948 
1949  cpl_propertylist_delete(xproperties);
1950  xproperties = NULL;
1951 
1952  cx_string_delete(name);
1953  name = NULL;
1954 
1955  return 1;
1956 
1957  }
1958 
1959  epos = cx_slist_next(ecubes, epos);
1960 
1961  }
1962 
1963  spos = cx_slist_next(scubes, spos);
1964  ++nss;
1965 
1966  }
1967 
1968  cpl_propertylist_delete(xproperties);
1969  xproperties = NULL;
1970 
1971  cx_string_delete(name);
1972  name = NULL;
1973 
1974  }
1975 
1976  return 0;
1977 
1978 }
1979 
1980 
1992 GiFieldOfViewConfig*
1993 giraffe_fov_config_create(cpl_parameterlist* list)
1994 {
1995 
1996  const cxchar* s = NULL;
1997 
1998  cpl_parameter* p;
1999 
2000  GiFieldOfViewConfig* config = NULL;
2001 
2002 
2003  if (list == NULL) {
2004  return NULL;
2005  }
2006 
2007  config = cx_calloc(1, sizeof *config);
2008 
2009 
2010  p = cpl_parameterlist_find(list, "giraffe.fov.range.minimum");
2011  config->minimum = cpl_parameter_get_double(p);
2012 
2013  p = cpl_parameterlist_find(list, "giraffe.fov.range.maximum");
2014  config->maximum = cpl_parameter_get_double(p);
2015 
2016  p = cpl_parameterlist_find(list, "giraffe.fov.cube");
2017  config->cube = cpl_parameter_get_bool(p);
2018 
2019  p = cpl_parameterlist_find(list, "giraffe.fov.cube.format");
2020  s = cpl_parameter_get_string(p);
2021 
2022  if (strcmp(s, "single") == 0) {
2023  config->format = GIFOV_FORMAT_SINGLE;
2024  }
2025  else if (strcmp(s, "eso3d") == 0) {
2026  config->format = GIFOV_FORMAT_ESO3D;
2027  }
2028 
2029  return config;
2030 
2031 }
2032 
2033 
2047 void
2048 giraffe_fov_config_destroy(GiFieldOfViewConfig* config)
2049 {
2050 
2051  if (config != NULL) {
2052  cx_free(config);
2053  }
2054 
2055  return;
2056 
2057 }
2058 
2059 
2069 void
2070 giraffe_fov_config_add(cpl_parameterlist* list)
2071 {
2072 
2073  cpl_parameter* p;
2074 
2075 
2076  if (list == NULL) {
2077  return;
2078  }
2079 
2080  p = cpl_parameter_new_value("giraffe.fov.range.minimum",
2081  CPL_TYPE_DOUBLE,
2082  "Minimum wavelength for image reconstruction",
2083  "giraffe.fov.range",
2084  0.);
2085  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "recon-min");
2086  cpl_parameterlist_append(list, p);
2087 
2088 
2089  p = cpl_parameter_new_value("giraffe.fov.range.maximum",
2090  CPL_TYPE_DOUBLE,
2091  "Maximum wavelength for image reconstruction",
2092  "giraffe.fov.range",
2093  0.);
2094  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "recon-max");
2095  cpl_parameterlist_append(list, p);
2096 
2097 
2098  p = cpl_parameter_new_value("giraffe.fov.cube",
2099  CPL_TYPE_BOOL,
2100  "Turns data cube creation on and off",
2101  "giraffe.fov.cube",
2102  TRUE);
2103  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "recon-cube");
2104  cpl_parameterlist_append(list, p);
2105 
2106  p = cpl_parameter_new_enum("giraffe.fov.cube.format",
2107  CPL_TYPE_STRING,
2108  "Selects the file format for cubes",
2109  "giraffe.fov.cube",
2110  "single", 2, "single", "eso3d");
2111  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "recon-format");
2112  cpl_parameterlist_append(list, p);
2113 
2114  return;
2115 
2116 }

This file is part of the GIRAFFE Pipeline Reference Manual 2.12.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Mon Mar 24 2014 11:43:52 by doxygen 1.8.2 written by Dimitri van Heesch, © 1997-2004