GIRAFFE Pipeline Reference Manual

girebinning.c
1 /*
2  * This file is part of the GIRAFFE Pipeline
3  * Copyright (C) 2002-2019 European Southern Observatory
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23 
24 #include <math.h>
25 
26 #include <cxmacros.h>
27 #include <cxtypes.h>
28 #include <cxmemory.h>
29 
30 #include <cpl_parameter.h>
31 #include <cpl_parameterlist.h>
32 #include <cpl_image.h>
33 #include <cpl_msg.h>
34 
35 #include "gimacros.h"
36 #include "gidebug.h"
37 #include "gierror.h"
38 #include "gialias.h"
39 #include "gimatrix.h"
40 #include "gimessages.h"
41 #include "gimath.h"
42 #include "gimath_lm.h"
43 #include "gifiberutils.h"
44 #include "giutils.h"
45 #include "girebinning.h"
46 
47 
56 #define GIFITS_KEYWORD_MISSING_MSG "FITS KEYWORD [%s] not found!! Aborting..."
57 #define GIWAVECAL_GRATING_WAVELENGTH_EPSILON 0.0001
58 
59 
64 };
65 
66 typedef enum GiLocDataType GiLocDataType;
67 
68 
69 struct GiGrat {
70  cx_string *name;
71  cx_string *filter_name;
72  cx_string *setup_name;
73  cx_string *slit_name;
74  cxint order;
75  cxdouble wlen0;
76  cxdouble wlenmin;
77  cxdouble wlenmax;
78  cxdouble band;
79  cxdouble resol;
80  cxdouble space;
81  cxdouble theta;
82  cxdouble fcoll;
83  cxdouble gcam;
84  cxdouble slitdx;
85  cxdouble slitdy;
86  cxdouble slitphi;
87 };
88 
89 typedef struct GiGrat GiGrat;
90 
91 
92 struct GiFiberPosition {
93  cpl_matrix *x_fiber;
94  cpl_matrix *y_fiber;
95 };
96 
97 typedef struct GiFiberPosition GiFiberPosition;
98 
99 
100 struct GiLocPosition {
101  cxint ydeg;
102  cxint wdeg;
103  GiLocDataType type;
104  cpl_image *centroids;
105  cpl_image *widths;
106 };
107 
108 typedef struct GiLocPosition GiLocPosition;
109 
110 
111 struct GiBinnParams {
112  cxint xdeg;
113  cxint ydeg;
114 };
115 
116 typedef struct GiBinnParams GiBinnParams;
117 
118 
119 struct GiSlitGeo {
120  cxint nsubslits;
121  cpl_matrix **subslits;
122 };
123 
124 typedef struct GiSlitGeo GiSlitGeo;
125 
126 struct GiWcalSolution {
127  cxbool subslitfit;
128  lmrq_model_id opt_mod;
129  cpl_matrix *opt_mod_params;
130  GiSlitGeo *wav_coeffs;
131  GiSlitGeo *wav_limits;
132 };
133 
134 typedef struct GiWcalSolution GiWcalSolution;
135 
136 
137 struct GiRebinInfo {
138  const cxchar* method;
139  const cxchar* scale;
140  const cxchar* range;
141  const cxchar* units;
142 
143  cxdouble wmin;
144  cxdouble wcenter;
145  cxdouble wmax;
146  cxdouble wstep;
147 
148  cxint offset;
149 
150 };
151 
152 typedef struct GiRebinInfo GiRebinInfo;
153 
154 
155 /*
156  * Static vars for spline interpolation...
157  */
158 
159 static cxdouble ddb, dde;
160 
161 
162 inline static cxint
163 _giraffe_resample_update_properties(GiImage* spectra, GiRebinInfo* info)
164 {
165 
166  cpl_image* image = giraffe_image_get(spectra);
167 
168  cpl_propertylist* properties = giraffe_image_get_properties(spectra);
169 
170 
171  giraffe_error_push();
172 
173  cpl_propertylist_update_double(properties, GIALIAS_DATAMIN,
174  cpl_image_get_min(image));
175  cpl_propertylist_update_double(properties, GIALIAS_DATAMAX,
176  cpl_image_get_max(image));
177 
178  cpl_propertylist_update_string(properties, GIALIAS_GIRFTYPE,
179  "BINSP");
180 
181  cpl_propertylist_update_int(properties, GIALIAS_BINWNX,
182  cpl_image_get_size_y(image));
183  cpl_propertylist_update_int(properties, GIALIAS_BINWNS,
184  cpl_image_get_size_x(image));
185 
186  cpl_propertylist_update_string(properties, GIALIAS_BUNIT,
187  "adu");
188 
189  cpl_propertylist_update_string(properties, GIALIAS_CTYPE1,
190  "INDEX");
191  cpl_propertylist_update_string(properties, GIALIAS_CUNIT1,
192  "");
193  cpl_propertylist_update_double(properties, GIALIAS_CRPIX1,
194  1.);
195  cpl_propertylist_update_double(properties, GIALIAS_CRVAL1,
196  1.);
197  cpl_propertylist_update_double(properties, GIALIAS_CDELT1,
198  1.);
199 
200  cpl_propertylist_update_string(properties, GIALIAS_CTYPE2,
201  "AWAV");
202  cpl_propertylist_update_string(properties, GIALIAS_CUNIT2,
203  info->units);
204  cpl_propertylist_update_double(properties, GIALIAS_CRPIX2,
205  info->offset + 1);
206  cpl_propertylist_update_double(properties, GIALIAS_CRVAL2,
207  info->wmin);
208  cpl_propertylist_update_double(properties, GIALIAS_CDELT2,
209  info->wstep);
210 
211  cpl_propertylist_update_double(properties, GIALIAS_BINWLMIN,
212  info->wmin);
213  cpl_propertylist_update_double(properties, GIALIAS_BINWL0,
214  info->wcenter);
215  cpl_propertylist_update_double(properties, GIALIAS_BINWLMAX,
216  info->wmax);
217  cpl_propertylist_update_double(properties, GIALIAS_BINSTEP,
218  info->wstep);
219  cpl_propertylist_update_string(properties, GIALIAS_BINMETHOD,
220  info->method);
221  cpl_propertylist_update_string(properties, GIALIAS_BINSCALE,
222  info->scale);
223  cpl_propertylist_update_string(properties, GIALIAS_BINRANGE,
224  info->range);
225 
226  if (cpl_error_get_code() != CPL_ERROR_NONE) {
227  return 1;
228  }
229 
230  giraffe_error_pop();
231 
232  return 0;
233 
234 }
235 
236 
237 static GiGrat*
238 _giraffe_grating_new(void)
239 {
240 
241  GiGrat *grating = NULL;
242 
243  grating = (GiGrat*) cx_calloc(1, (cxsize)sizeof(GiGrat));
244 
245  grating->name = cx_string_create("UNKNOWN");
246  grating->filter_name = cx_string_create("UNKNOWN");
247  grating->setup_name = cx_string_create("UNKNOWN");
248  grating->slit_name = cx_string_create("UNKNOWN");
249 
250  return grating;
251 
252 }
253 
254 
255 static void
256 _giraffe_grating_delete(GiGrat *grating)
257 {
258 
259  if (grating==NULL) { return; }
260 
261  if (grating->name!=NULL) {
262  cx_string_delete(grating->name);
263  }
264  if (grating->filter_name!=NULL) {
265  cx_string_delete(grating->filter_name);
266  }
267  if (grating->setup_name!=NULL) {
268  cx_string_delete(grating->setup_name);
269  }
270  if (grating->slit_name!=NULL) {
271  cx_string_delete(grating->slit_name);
272  }
273  cx_free(grating);
274 
275 }
276 
277 
278 static cxint
279 _giraffe_grating_setup(const GiTable *grating_table,
280  const GiImage *grating_ass_img, GiGrat *grating_setup)
281 {
282 
283  /*************************************************************************
284  Variables
285  *************************************************************************/
286 
287  const cxchar *fctid = "_giraffe_grating_setup";
288 
289  cxdouble wlen_match = 0.0,
290  wlen = 0.0,
291  tmp_gratgrv = 0.0;
292 
293  cxint32 row_match = 0,
294  row_nulls,
295  i = 0;
296 
297  const cxchar *c_name_setup = "SETUP";
298  const cxchar *c_name_order = "ORDER";
299  const cxchar *c_name_wl0 = "WLEN0";
300  const cxchar *c_name_wlmin = "WLMIN";
301  const cxchar *c_name_wlmax = "WLMAX";
302  const cxchar *c_name_band = "BAND";
303  const cxchar *c_name_theta = "THETA";
304  const cxchar *c_name_fcoll = "FCOLL";
305  const cxchar *c_name_gcam = "GCAM";
306  const cxchar *c_name_sdx = "SDX";
307  const cxchar *c_name_sdy = "SDY";
308  const cxchar *c_name_sdphi = "SPHI";
309  const cxchar *c_name_rmed = "RMED";
310  const cxchar *c_name_rifa = "RIFA";
311 
312  cpl_propertylist *ref_plimg = NULL;
313  cpl_table *ref_gtable = NULL;
314  cx_string *slit_name = NULL;
315 
316  GiInstrumentMode instrument_mode;
317 
318 
319  /*************************************************************************
320  Preprocessing
321  *************************************************************************/
322 
323  if (grating_table ==NULL) { return 1; }
324  if (grating_ass_img==NULL) { return 1; }
325  if (grating_setup ==NULL) { return 1; }
326 
327  if ((ref_plimg=giraffe_image_get_properties(grating_ass_img))==NULL) {
328  return 128;
329  }
330 
331  if ((ref_gtable = giraffe_table_get(grating_table))==NULL) {
332  return 128;
333  }
334 
335  slit_name = cx_string_new();
336 
337  /*************************************************************************
338  Processing
339  *************************************************************************/
340 
341  /*
342  * Retrieve Grating information from associated image...
343  */
344 
345  if (!cpl_propertylist_has(ref_plimg, GIALIAS_GRATWLEN)) {
346  cpl_msg_error(fctid, GIFITS_KEYWORD_MISSING_MSG, GIALIAS_GRATWLEN);
347  cx_string_delete(slit_name);
348  return 2;
349  }
350  else {
351  grating_setup->wlen0 = cpl_propertylist_get_double(ref_plimg,
352  GIALIAS_GRATWLEN);
353  }
354 
355  if (!cpl_propertylist_has(ref_plimg, GIALIAS_GRATORDER)) {
356  cpl_msg_error(fctid, GIFITS_KEYWORD_MISSING_MSG, GIALIAS_GRATORDER);
357  cx_string_delete(slit_name);
358  return 2;
359  }
360  else {
361  grating_setup->order = cpl_propertylist_get_int(ref_plimg, GIALIAS_GRATORDER);
362  }
363 
364  if (!cpl_propertylist_has(ref_plimg, GIALIAS_SLITNAME)) {
365 
366  cpl_msg_error(fctid, GIFITS_KEYWORD_MISSING_MSG, GIALIAS_SLITNAME);
367  cx_string_delete(slit_name);
368  return 2;
369  } else {
370  cx_string_set(slit_name,
371  cpl_propertylist_get_string(ref_plimg, GIALIAS_SLITNAME));
372  }
373 
374  if (!cpl_propertylist_has(ref_plimg, GIALIAS_GRATGRV)) {
375 
376  cpl_msg_error(fctid, GIFITS_KEYWORD_MISSING_MSG, GIALIAS_GRATGRV);
377  cx_string_delete(slit_name);
378  return 2;
379  } else {
380  tmp_gratgrv = cpl_propertylist_get_double(ref_plimg, GIALIAS_GRATGRV );
381  }
382 
383  if (!cpl_propertylist_has(ref_plimg, GIALIAS_GRATNAME)) {
384  cpl_msg_error(fctid, GIFITS_KEYWORD_MISSING_MSG, GIALIAS_GRATNAME);
385  cx_string_delete(slit_name);
386  return 2;
387  } else {
388  cx_string_set(grating_setup->name,
389  cpl_propertylist_get_string(ref_plimg, GIALIAS_GRATNAME));
390  }
391 
392  if (!cpl_propertylist_has(ref_plimg, GIALIAS_FILTNAME)) {
393  cpl_msg_error(fctid, GIFITS_KEYWORD_MISSING_MSG, GIALIAS_FILTNAME);
394  cx_string_delete(slit_name);
395  return 2;
396  }
397  else {
398  cx_string_set(grating_setup->filter_name,
399  cpl_propertylist_get_string(ref_plimg, GIALIAS_FILTNAME));
400  }
401 
402 
403  /*
404  * Find wavelength nearest to central wavelength...
405  */
406 
407  for (i = 0; i < cpl_table_get_nrow(ref_gtable); i++) {
408 
409  cxint _order = cpl_table_get_int(ref_gtable, c_name_order, i, NULL);
410 
411  if (_order == grating_setup->order) {
412 
413  wlen = cpl_table_get(ref_gtable, c_name_wl0, i, &row_nulls);
414 
415  if (fabs(wlen - grating_setup->wlen0) <
416  fabs(wlen_match - grating_setup->wlen0)) {
417  wlen_match = wlen;
418  row_match = i;
419  }
420 
421  }
422  }
423 
424 
425  /*
426  * Have we found a match?...
427  */
428 
429  if (fabs(wlen_match - grating_setup->wlen0) >
430  GIWAVECAL_GRATING_WAVELENGTH_EPSILON) {
431 
432  cpl_msg_error(fctid, "Grating setup (wavelength %.2f nm, order %d) "
433  "not found in grating table!", grating_setup->wlen0,
434  grating_setup->order);
435  cx_string_delete(slit_name);
436  return 3;
437  }
438  else {
439  cpl_msg_debug(fctid, "Found wlen0 in grating table at position %d",
440  row_match);
441  }
442 
443 
444  /*
445  * Retrieve values associated to matched wavelength from grating table...
446  */
447 
448  cx_string_set(grating_setup->setup_name,
449  (cxchar*) cpl_table_get_string(ref_gtable, c_name_setup,
450  row_match));
451 
452  cx_string_set(grating_setup->slit_name, cx_string_get(slit_name));
453 
454  grating_setup->wlenmin = cpl_table_get(ref_gtable, c_name_wlmin,
455  row_match, &row_nulls);
456 
457  grating_setup->wlenmax = cpl_table_get(ref_gtable, c_name_wlmax,
458  row_match, &row_nulls);
459 
460  grating_setup->band = cpl_table_get(ref_gtable, c_name_band,
461  row_match, &row_nulls);
462 
463  grating_setup->theta = cpl_table_get(ref_gtable, c_name_theta,
464  row_match, &row_nulls);
465 
466  grating_setup->space = 1.0 / fabs(GI_MM_TO_NM * tmp_gratgrv);
467 
468 
469  instrument_mode = giraffe_get_mode(ref_plimg);
470 
471  switch (instrument_mode) {
472  case GIMODE_MEDUSA:
473  grating_setup->resol = cpl_table_get(ref_gtable, c_name_rmed,
474  row_match, &row_nulls);
475  break;
476 
477  case GIMODE_IFU:
478  grating_setup->resol = cpl_table_get(ref_gtable, c_name_rifa,
479  row_match, &row_nulls);
480  break;
481 
482  case GIMODE_ARGUS:
483  grating_setup->resol = cpl_table_get(ref_gtable, c_name_rifa,
484  row_match, &row_nulls);
485  break;
486 
487  default:
488  grating_setup->resol = -1.0;
489  break;
490  }
491 
492  grating_setup->fcoll =
493  cpl_table_get(ref_gtable, c_name_fcoll, row_match, &row_nulls);
494 
495  grating_setup->gcam =
496  cpl_table_get(ref_gtable, c_name_gcam, row_match, &row_nulls);
497 
498  grating_setup->slitdx =
499  cpl_table_get(ref_gtable, c_name_sdx, row_match, &row_nulls);
500 
501  grating_setup->slitdy =
502  cpl_table_get(ref_gtable, c_name_sdy, row_match, &row_nulls);
503 
504  grating_setup->slitphi =
505  cpl_table_get(ref_gtable, c_name_sdphi, row_match, &row_nulls);
506 
507  cx_string_delete(slit_name);
508 
509  return 0;
510 
511 }
512 
513 
514 static GiFiberPosition*
515 _giraffe_fiberposition_new(void)
516 {
517 
518  GiFiberPosition* tmp = NULL;
519 
520  tmp = (GiFiberPosition*) cx_calloc(1, sizeof(GiFiberPosition));
521 
522  tmp->x_fiber = NULL;
523  tmp->y_fiber = NULL;
524 
525  return tmp;
526 }
527 
528 
529 static void
530 _giraffe_fiberposition_delete(GiFiberPosition *fp)
531 {
532 
533  if (fp != NULL) {
534 
535  if (fp->x_fiber) {
536  cpl_matrix_delete(fp->x_fiber);
537  }
538 
539  if (fp->y_fiber) {
540  cpl_matrix_delete(fp->y_fiber);
541  }
542 
543  cx_free(fp);
544 
545  }
546 
547  return;
548 
549 }
550 
551 
552 static GiSlitGeo*
553 _giraffe_slitgeo_new(void)
554 {
555 
556  GiSlitGeo *sgeometry = NULL;
557 
558  sgeometry = cx_malloc(sizeof(GiSlitGeo));
559 
560  sgeometry->subslits = NULL;
561  sgeometry->nsubslits = 0;
562 
563  return sgeometry;
564 
565 }
566 
567 
568 static void
569 _giraffe_slitgeo_delete(GiSlitGeo *sgeometry)
570 {
571 
572  if (sgeometry != NULL) {
573 
574  if (sgeometry->subslits != NULL) {
575 
576  cxint i;
577 
578  for (i = 0; i < sgeometry->nsubslits; i++) {
579  cpl_matrix_delete(sgeometry->subslits[i]);
580  }
581 
582  cx_free(sgeometry->subslits);
583  }
584 
585  cx_free(sgeometry);
586 
587  }
588 
589  return;
590 
591 }
592 
593 
594 static cxint
595 _giraffe_slitgeo_size(GiSlitGeo *sgeometry)
596 {
597 
598  if (sgeometry == NULL) {
599  return -1;
600  }
601 
602  if (sgeometry->subslits != NULL) {
603  return sgeometry->nsubslits;
604  }
605 
606  return -1;
607 
608 }
609 
610 
611 static void
612 _giraffe_slitgeo_resize(GiSlitGeo *sgeometry, cxint size)
613 {
614 
615  if (sgeometry == NULL) {
616  return;
617  }
618 
619  if (size == sgeometry->nsubslits) {
620  return;
621  }
622 
623  if (sgeometry->subslits != NULL) {
624 
625  cxint i;
626 
627  for (i = 0; i < sgeometry->nsubslits; i++) {
628  cpl_matrix_delete(sgeometry->subslits[i]);
629  }
630  }
631 
632  cx_free(sgeometry->subslits);
633 
634  sgeometry->nsubslits = size;
635  sgeometry->subslits = cx_calloc(sgeometry->nsubslits, sizeof(cpl_matrix*));
636 
637  return;
638 
639 }
640 
641 
642 static void
643 _giraffe_slitgeo_create(GiSlitGeo *sgeometry, cxint idx, cxint nrow,
644  cxint ncol)
645 {
646 
647  if (sgeometry == NULL) {
648  return;
649  }
650 
651  if (sgeometry->subslits == NULL) {
652  return;
653  }
654 
655  if ((idx < 0) || (idx > sgeometry->nsubslits)) {
656  return;
657  }
658 
659  if (sgeometry->subslits[idx] != NULL) {
660  cpl_matrix_delete(sgeometry->subslits[idx]);
661  }
662 
663  sgeometry->subslits[idx] = cpl_matrix_new(nrow, ncol);
664 
665  return;
666 
667 }
668 
669 
670 static void
671 _giraffe_slitgeo_set(GiSlitGeo *sgeometry, cxint idx, cpl_matrix *nm)
672 {
673 
674  if (sgeometry == NULL) {
675  return;
676  }
677 
678  if (sgeometry->subslits == NULL) {
679  return;
680  }
681 
682  if ((idx < 0) || (idx > sgeometry->nsubslits)) {
683  return;
684  }
685 
686  if (sgeometry->subslits[idx] != NULL) {
687  cpl_matrix_delete(sgeometry->subslits[idx]);
688  }
689 
690  if (nm) {
691  sgeometry->subslits[idx] = cpl_matrix_duplicate(nm);
692  }
693  else {
694  sgeometry->subslits[idx] = NULL;
695  }
696 
697 }
698 
699 
700 static cpl_matrix*
701 _giraffe_slitgeo_get(GiSlitGeo *sgeometry, cxint idx)
702 {
703 
704  if (sgeometry == NULL) {
705  return NULL;
706  }
707 
708  if (sgeometry->subslits == NULL) {
709  return NULL;
710  }
711 
712  if ((idx < 0)||(idx > sgeometry->nsubslits)) {
713  return NULL;
714  }
715 
716  return (sgeometry->subslits[idx]);
717 
718 }
719 
720 
721 static cxint
722 _giraffe_slitgeo_setup(const GiTable *slitgeo,
723  GiFiberPosition *fiber_slit_position,
724  GiSlitGeo *subslits, cxbool fitsubslit)
725 {
726 
727  const cxchar *const fctid = "_giraffe_slitgeo_setup";
728 
729 
730  const cxchar *c_name_xf = "XF";
731  const cxchar *c_name_yf = "YF";
732  const cxchar *c_name_nspec = "FPS";
733  const cxchar *c_name_ssn = "SSN";
734 
735 
736  cpl_matrix *nspec = NULL;
737  cpl_matrix *nsubslits = NULL;
738 
739  cxint nr_slitgeo = 0,
740  max_nsubslits = 0,
741  i = 0,
742  j = 0,
743  row_null = 0,
744  count = 0,
745  column_index = 0,
746  tmp_nspec = 0,
747  tmp_nsubslits = 0;
748 
749  cxdouble tmp_xf,
750  tmp_yf;
751 
752  cpl_table *ref_slitgeo = NULL;
753 
754  /*cpl_error_code ce_code;*/
755 
756 
757  /*************************************************************************
758  Preprocessing
759  *************************************************************************/
760 
761  if (slitgeo ==NULL) { return 1; }
762  if (fiber_slit_position==NULL) { return 1; }
763  if (subslits ==NULL) { return 1; }
764 
765  /*************************************************************************
766  Processing
767  *************************************************************************/
768 
769  ref_slitgeo = giraffe_table_get(slitgeo);
770  nr_slitgeo = cpl_table_get_nrow(ref_slitgeo);
771 
772  fiber_slit_position->x_fiber = cpl_matrix_new(nr_slitgeo, 1);
773  fiber_slit_position->y_fiber = cpl_matrix_new(nr_slitgeo, 1);
774 
775  nspec = cpl_matrix_new(nr_slitgeo, 1);
776  nsubslits = cpl_matrix_new(nr_slitgeo, 1);
777 
778  /*
779  * Copy relevant data to matrices
780  */
781 
782  max_nsubslits = 0;
783 
784  for (i = 0; i < nr_slitgeo; i++) {
785 
786  tmp_xf = cpl_table_get(ref_slitgeo, c_name_xf, i, &row_null);
787  tmp_yf = cpl_table_get(ref_slitgeo, c_name_yf, i, &row_null);
788 
789  tmp_nspec = cpl_table_get_int(ref_slitgeo, c_name_nspec, i,
790  &row_null) - 1;
791 
792  tmp_nsubslits = cpl_table_get_int(ref_slitgeo, c_name_ssn, i,
793  &row_null);
794 
795  if (tmp_nsubslits>max_nsubslits) {
796  max_nsubslits = tmp_nsubslits;
797  }
798 
799  /*ce_code =*/ cpl_matrix_set(fiber_slit_position->x_fiber, i, 0, tmp_xf);
800  /*ce_code =*/ cpl_matrix_set(fiber_slit_position->y_fiber, i, 0, tmp_yf);
801 
802  /*ce_code =*/ cpl_matrix_set(nspec, i, 0, (cxdouble)tmp_nspec);
803  /*ce_code =*/ cpl_matrix_set(nsubslits, i, 0, (cxdouble)tmp_nsubslits);
804 
805  }
806 
807  /*
808  * Create Slit Geometry
809  */
810 
811  if (fitsubslit) {
812 
813  /* create multiple subslits */
814 
815  _giraffe_slitgeo_resize(subslits, max_nsubslits);
816 
817  for (i = 1; i <= max_nsubslits; i++) {
818 
819  cpl_matrix *ref_matrix = NULL;
820  cxint curr_ssn;
821 
822  count = 0;
823  for (j=0; j<nr_slitgeo; j++) {
824  curr_ssn = (cxint) cpl_matrix_get(nsubslits, j, 0);
825  if (i==curr_ssn) {
826  ++count;
827  }
828  }
829 
830  _giraffe_slitgeo_create(subslits, i-1, count, 1);
831 
832  ref_matrix = _giraffe_slitgeo_get(subslits, i-1);
833 
834  column_index = 0;
835  for (j = 0; j < nr_slitgeo; j++) {
836 
837  curr_ssn = (cxint) cpl_matrix_get(nsubslits, j, 0);
838 
839  if (i == curr_ssn) {
840  /*ce_code =*/ cpl_matrix_set(ref_matrix, column_index, 0,
841  (cxdouble)j);
842  column_index++;
843  }
844 
845  }
846  }
847 
848  cpl_msg_debug(fctid, "Using multiple slits for Slit Geometry");
849 
850  }
851  else {
852 
853  const cxchar *idx = giraffe_fiberlist_query_index(ref_slitgeo);
854 
855 
856  /*
857  * Create one subslit containing all fibers
858  */
859 
860  cpl_matrix *ref_matrix = NULL;
861 
862  _giraffe_slitgeo_resize(subslits, 1);
863  _giraffe_slitgeo_create(subslits, 0, nr_slitgeo, 1);
864 
865  ref_matrix = _giraffe_slitgeo_get(subslits, 0);
866 
867  for (j = 0; j < nr_slitgeo; j++) {
868 
869  cxint cs = cpl_table_get_int(ref_slitgeo, idx, j, NULL) - 1;
870  /*ce_code =*/ cpl_matrix_set(ref_matrix, j, 0, cs);
871 // ce_code = cpl_matrix_set(ref_matrix, j, 0, (cxdouble)j);
872 
873  }
874 
875  cpl_msg_debug(fctid, "Using single slit for Slit Geometry");
876 
877  }
878 
879  cpl_matrix_delete(nspec);
880  nspec = NULL;
881 
882  cpl_matrix_delete(nsubslits);
883  nsubslits = NULL;
884 
885  return 0;
886 
887 }
888 
889 
890 static GiWcalSolution*
891 _giraffe_wcalsolution_new(void)
892 {
893 
894  GiWcalSolution* tmp = NULL;
895 
896  tmp = (GiWcalSolution*) cx_calloc(1, sizeof(GiWcalSolution));
897 
898  tmp->subslitfit = FALSE;
899  tmp->opt_mod = LMRQ_UNDEFINED;
900  tmp->opt_mod_params = NULL;
901  tmp->wav_coeffs = NULL;
902  tmp->wav_limits = NULL;
903 
904  return tmp;
905 }
906 
907 
908 static void
909 _giraffe_wcalsolution_delete(GiWcalSolution *ws)
910 {
911 
912  if (ws != NULL) {
913 
914  if (ws->opt_mod_params!=NULL) {
915  cpl_matrix_delete(ws->opt_mod_params);
916  }
917 
918  if (ws->wav_coeffs!=NULL) {
919  _giraffe_slitgeo_delete(ws->wav_coeffs);
920  }
921 
922  if (ws->wav_limits!=NULL) {
923  _giraffe_slitgeo_delete(ws->wav_limits);
924  }
925 
926  cx_free(ws);
927 
928  }
929 
930  return;
931 
932 }
933 
934 
935 static GiWcalSolution*
936 _giraffe_wcalsolution_create(const GiTable *wavesolution)
937 {
938 
939  cxchar buffer[68];
940 
941  cxint i = 0;
942  cxint poly_x_deg = 0;
943  cxint poly_y_deg = 0;
944  cxint ncoefficients = 0;
945 
946  cxdouble* pd_coefficients = NULL;
947 
948  cpl_matrix* coefficients = NULL;
949  cpl_matrix* limits = NULL;
950 
951  cpl_propertylist* _properties = NULL;
952 
953  cpl_table* _table = NULL;
954 
955  GiWcalSolution* wavcoeff = NULL;
956 
957 
958 
959  if (wavesolution == NULL) {
960  return NULL;
961  }
962 
963  wavcoeff = _giraffe_wcalsolution_new();
964 
965  _properties = giraffe_table_get_properties(wavesolution);
966 
967 
968  /*
969  * Build up optical model from the wavelength solution properties
970  */
971 
972  if (cpl_propertylist_has(_properties, GIALIAS_OPT_MOD) == TRUE) {
973 
974  const cxchar* optmod = cpl_propertylist_get_string(_properties,
975  GIALIAS_OPT_MOD);
976 
977  if (strncmp(optmod, "xoptmod2", 8) == 0) {
978  wavcoeff->opt_mod = LMRQ_XOPTMOD2;
979  }
980  else if (strncmp(optmod, "xoptmod", 7) == 0) {
981  wavcoeff->opt_mod = LMRQ_XOPTMOD;
982  }
983  else {
984  wavcoeff->opt_mod = LMRQ_UNDEFINED;
985  }
986  }
987 
988  if (wavcoeff->opt_mod == LMRQ_XOPTMOD2) {
989 
990  wavcoeff->opt_mod_params = cpl_matrix_new(7,1);
991 
992  if (cpl_propertylist_has(_properties, GIALIAS_OPTMDIR)) {
993  cpl_matrix_set(
994  wavcoeff->opt_mod_params,
995  0,
996  0,
997  cpl_propertylist_get_int(_properties, GIALIAS_OPTMDIR)
998  );
999  } else {
1000  _giraffe_wcalsolution_delete(wavcoeff);
1001  return NULL;
1002  }
1003 
1004  if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMFCOLL)) {
1005  cpl_matrix_set(
1006  wavcoeff->opt_mod_params,
1007  1,
1008  0,
1009  cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMFCOLL)
1010  );
1011  } else {
1012  _giraffe_wcalsolution_delete(wavcoeff);
1013  return NULL;
1014  }
1015 
1016  if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMGCAM)) {
1017  cpl_matrix_set(
1018  wavcoeff->opt_mod_params,
1019  2,
1020  0,
1021  cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMGCAM)
1022  );
1023  } else {
1024  _giraffe_wcalsolution_delete(wavcoeff);
1025  return NULL;
1026  }
1027 
1028  if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMTHETA)) {
1029  cpl_matrix_set(
1030  wavcoeff->opt_mod_params,
1031  3,
1032  0,
1033  cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMTHETA)
1034  );
1035  } else {
1036  _giraffe_wcalsolution_delete(wavcoeff);
1037  return NULL;
1038  }
1039 
1040  if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMSDX)) {
1041  cpl_matrix_set(
1042  wavcoeff->opt_mod_params,
1043  4,
1044  0,
1045  cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMSDX)
1046  );
1047  } else {
1048  _giraffe_wcalsolution_delete(wavcoeff);
1049  return NULL;
1050  }
1051 
1052  if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMSDY)) {
1053 
1054 
1055 
1056  cpl_matrix_set(
1057  wavcoeff->opt_mod_params,
1058  5,
1059  0,
1060  cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMSDY)
1061  );
1062 
1063  } else {
1064  _giraffe_wcalsolution_delete(wavcoeff);
1065  return NULL;
1066  }
1067 
1068  if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMSPHI)) {
1069  cpl_matrix_set(
1070  wavcoeff->opt_mod_params,
1071  6,
1072  0,
1073  cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMSPHI)
1074  );
1075 
1076  } else {
1077  _giraffe_wcalsolution_delete(wavcoeff);
1078  return NULL;
1079  }
1080 
1081  } else if (wavcoeff->opt_mod==LMRQ_XOPTMOD) {
1082 
1083  wavcoeff->opt_mod_params = cpl_matrix_new(4,1);
1084 
1085  if (cpl_propertylist_has(_properties, GIALIAS_OPTMDIR)) {
1086  cpl_matrix_set(
1087  wavcoeff->opt_mod_params,
1088  0,
1089  0,
1090  cpl_propertylist_get_int(_properties, GIALIAS_OPTMDIR)
1091  );
1092  } else {
1093  _giraffe_wcalsolution_delete(wavcoeff);
1094  return NULL;
1095  }
1096 
1097  if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMFCOLL)) {
1098  cpl_matrix_set(
1099  wavcoeff->opt_mod_params,
1100  1,
1101  0,
1102  cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMFCOLL)
1103  );
1104  } else {
1105  _giraffe_wcalsolution_delete(wavcoeff);
1106  return NULL;
1107  }
1108 
1109  if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMGCAM)) {
1110  cpl_matrix_set(
1111  wavcoeff->opt_mod_params,
1112  2,
1113  0,
1114  cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMGCAM)
1115  );
1116  } else {
1117  _giraffe_wcalsolution_delete(wavcoeff);
1118  return NULL;
1119  }
1120 
1121  if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMTHETA)) {
1122  cpl_matrix_set(
1123  wavcoeff->opt_mod_params,
1124  3,
1125  0,
1126  cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMTHETA)
1127  );
1128  } else {
1129  _giraffe_wcalsolution_delete(wavcoeff);
1130  return NULL;
1131  }
1132 
1133 
1134  } else {
1135 
1136  _giraffe_wcalsolution_delete(wavcoeff);
1137  return NULL;
1138 
1139  }
1140 
1141 
1142  /*
1143  * Set up the optical model residuals if the given table contains them.
1144  */
1145 
1146  _table = giraffe_table_get(wavesolution);
1147 
1148  if (_table != NULL) {
1149 
1150 
1151  if (cpl_propertylist_has(_properties, GIALIAS_SSF)) {
1152 
1153  if (cpl_propertylist_get_bool(_properties, GIALIAS_SSF) == 0) {
1154  wavcoeff->subslitfit = FALSE;
1155  }
1156  else {
1157  wavcoeff->subslitfit = TRUE;
1158  }
1159 
1160  }
1161  else {
1162 
1163  _giraffe_wcalsolution_delete(wavcoeff);
1164  return NULL;
1165 
1166  }
1167 
1168  wavcoeff->wav_limits = _giraffe_slitgeo_new();
1169  _giraffe_slitgeo_resize(wavcoeff->wav_limits, 1);
1170 
1171  limits = cpl_matrix_new(1, 4);
1172  cpl_matrix_fill(limits, -1.);
1173 
1174  if (cpl_table_has_column(_table, "XMIN") &&
1175  cpl_table_has_column(_table, "XMAX")) {
1176  cpl_matrix_set(limits, 0, 0,
1177  cpl_table_get_double(_table, "XMIN", 0, NULL));
1178  cpl_matrix_set(limits, 0, 1,
1179  cpl_table_get_double(_table, "XMAX", 0, NULL));
1180  }
1181 
1182  if (cpl_table_has_column(_table, "YMIN") &&
1183  cpl_table_has_column(_table, "YMAX")) {
1184  cpl_matrix_set(limits, 0, 2,
1185  cpl_table_get_double(_table, "YMIN", 0, NULL));
1186  cpl_matrix_set(limits, 0, 3,
1187  cpl_table_get_double(_table, "YMAX", 0, NULL));
1188  }
1189 
1190  _giraffe_slitgeo_set(wavcoeff->wav_limits, 0, limits);
1191 
1192  cpl_matrix_delete(limits);
1193  limits = NULL;
1194 
1195  wavcoeff->wav_coeffs = _giraffe_slitgeo_new();
1196  _giraffe_slitgeo_resize(wavcoeff->wav_coeffs, 1);
1197 
1198  if (cpl_propertylist_has(_properties, GIALIAS_XRES_PDEG)) {
1199 
1200  cxchar *l, *r, *tmpstr;
1201 
1202  tmpstr = (cxchar*) cpl_propertylist_get_string(_properties,
1203  GIALIAS_XRES_PDEG);
1204 
1205  l = &(tmpstr[0]);
1206  r = &(tmpstr[2]);
1207 
1208  poly_x_deg = atoi(l) + 1;
1209  poly_y_deg = atoi(r) + 1;
1210 
1211  }
1212  else {
1213 
1214  _giraffe_wcalsolution_delete(wavcoeff);
1215  return NULL;
1216 
1217  }
1218 
1219  ncoefficients = poly_x_deg * poly_y_deg;
1220 
1221  coefficients = cpl_matrix_new(poly_x_deg,poly_y_deg);
1222  pd_coefficients = cpl_matrix_get_data(coefficients);
1223 
1224  for (i=0; i<ncoefficients; i++) {
1225 
1226  snprintf(buffer, sizeof buffer, "XC%-d", i);
1227 
1228  pd_coefficients[i] =
1229  cpl_table_get_double(_table, buffer, 0, NULL);
1230 
1231  }
1232 
1233  _giraffe_slitgeo_set(wavcoeff->wav_coeffs, 0, coefficients);
1234 
1235  cpl_matrix_delete(coefficients);
1236  coefficients = NULL;
1237 
1238  }
1239 
1240  return wavcoeff;
1241 
1242 }
1243 
1244 
1245 static cpl_image*
1246 _giraffe_compute_pixel_abscissa(cpl_matrix* m_wavelengths,
1247  cpl_matrix* m_wloffset,
1248  GiFiberPosition* fiber_slit_position,
1249  cpl_matrix* m_opt_mod_params,
1250  lmrq_model lmrq_opt_mod_x)
1251 {
1252 
1253  /*************************************************************************
1254  VARIABLES
1255  *************************************************************************/
1256 
1257  const cxchar *fctid = "_giraffe_compute_pixel_abscissa";
1258 
1259  register cxint n;
1260  register cxint line;
1261  register cxint nwlen; /* number of reference lines */
1262  register cxint ns; /* number of reference spectra */
1263 
1264  cxint nr_m_opt_mod_params = 0;
1265 
1266  cxdouble xccd = 0.;
1267  cxdouble* pd_xref = NULL;
1268  cxdouble* pd_m_inputs = NULL;
1269  cxdouble* pd_m_yfibre = NULL;
1270  cxdouble* pd_m_xfibre = NULL;
1271  cxdouble* pd_m_wavelengths = NULL;
1272  cxdouble* pd_m_opt_mod_params = NULL;
1273 
1274  cpl_image* xref = NULL;
1275 
1276  cpl_matrix* m_inputs = NULL;
1277 
1278 
1279  /************************************************************************
1280  INITIALIZATION
1281  ************************************************************************/
1282 
1283  if (m_wavelengths == NULL) {
1284  return NULL;
1285  }
1286 
1287  if ((fiber_slit_position == NULL) ||
1288  (fiber_slit_position->x_fiber == NULL) ||
1289  (fiber_slit_position->y_fiber == NULL)) {
1290  return NULL;
1291  }
1292 
1293  if (m_opt_mod_params == NULL) {
1294  return NULL;
1295  }
1296 
1297 
1298  nwlen = cpl_matrix_get_nrow(m_wavelengths);
1299  ns = cpl_matrix_get_nrow(fiber_slit_position->y_fiber);
1300 
1301  if ((m_wloffset != NULL) && (cpl_matrix_get_nrow(m_wloffset) != ns)) {
1302  return NULL;
1303  }
1304 
1305 
1306  /************************************************************************
1307  PREPROCESSING
1308  ************************************************************************/
1309 
1310  xref = cpl_image_new(ns, nwlen, CPL_TYPE_DOUBLE);
1311  pd_xref = cpl_image_get_data_double(xref);
1312 
1313  m_inputs = cpl_matrix_new(lmrq_opt_mod_x.ninputs, 1);
1314  pd_m_inputs = cpl_matrix_get_data(m_inputs);
1315 
1316  pd_m_yfibre = cpl_matrix_get_data(fiber_slit_position->y_fiber);
1317  pd_m_xfibre = cpl_matrix_get_data(fiber_slit_position->x_fiber);
1318  pd_m_wavelengths = cpl_matrix_get_data(m_wavelengths);
1319 
1320  pd_m_opt_mod_params = cpl_matrix_get_data(m_opt_mod_params);
1321  nr_m_opt_mod_params = cpl_matrix_get_nrow(m_opt_mod_params);
1322 
1323 
1324  /************************************************************************
1325  PROCESSING
1326  ************************************************************************/
1327 
1328  if (m_wloffset != NULL) {
1329 
1330  cxdouble* pd_m_wloffset = cpl_matrix_get_data(m_wloffset);
1331 
1332  for (n = 0; n < ns; n++) {
1333 
1334  pd_m_inputs[2] = pd_m_yfibre[n];
1335  pd_m_inputs[1] = pd_m_xfibre[n];
1336 
1337  for (line = 0; line < nwlen; line++) {
1338 
1339  pd_m_inputs[0] = pd_m_wavelengths[line] + pd_m_wloffset[n];
1340 
1341  lmrq_opt_mod_x.cfunc(pd_m_inputs, pd_m_opt_mod_params,
1342  NULL, &xccd, NULL, nr_m_opt_mod_params);
1343 
1344  pd_xref[line * ns + n] = xccd;
1345 
1346  } /* each line */
1347 
1348  } /* each spectrum */
1349 
1350  }
1351  else {
1352 
1353  for (n = 0; n < ns; n++) {
1354 
1355  pd_m_inputs[2] = pd_m_yfibre[n];
1356  pd_m_inputs[1] = pd_m_xfibre[n];
1357 
1358  for (line = 0; line < nwlen; line++) {
1359 
1360  pd_m_inputs[0] = pd_m_wavelengths[line];
1361 
1362  lmrq_opt_mod_x.cfunc(pd_m_inputs, pd_m_opt_mod_params,
1363  NULL, &xccd, NULL, nr_m_opt_mod_params);
1364 
1365  pd_xref[line * ns + n] = xccd;
1366 
1367  } /* each line */
1368 
1369  } /* each spectrum */
1370 
1371  }
1372 
1373  cpl_matrix_delete(m_inputs);
1374 
1375  cpl_msg_debug(fctid, "Processing completed: Returning image [x,y] ="
1376  " [%" CPL_SIZE_FORMAT ",%" CPL_SIZE_FORMAT "]",
1377  cpl_image_get_size_x(xref), cpl_image_get_size_y(xref));
1378 
1379  return xref;
1380 
1381 }
1382 
1383 
1384 inline static cpl_matrix *
1385 _giraffe_rebin_setup_model(GiImage *extspectra, GiWcalSolution *wcal)
1386 {
1387 
1388  cxint npixel;
1389 
1390  cxdouble pixelsize;
1391 
1392  cpl_propertylist *properties = NULL;
1393 
1394  cpl_matrix *model = NULL;
1395 
1396 
1397  if (extspectra == NULL) {
1398  return NULL;
1399  }
1400 
1401  if (wcal == NULL) {
1402  return NULL;
1403  }
1404 
1405  properties = giraffe_image_get_properties(extspectra);
1406 
1407  if (properties == NULL) {
1408  return NULL;
1409  }
1410 
1411 
1412  /*
1413  * Get the number of pixels extracted along the dispersion axis.
1414  */
1415 
1416  if (!cpl_propertylist_has(properties, GIALIAS_EXT_NX)) {
1417  return NULL;
1418  }
1419 
1420  npixel = cpl_propertylist_get_int(properties, GIALIAS_EXT_NX);
1421 
1422 
1423  /*
1424  * Compute pixel size along the dispersion axis in terms of mm.
1425  */
1426 
1427  if (!cpl_propertylist_has(properties, GIALIAS_PIXSIZX)) {
1428  return NULL;
1429  }
1430 
1431  pixelsize = cpl_propertylist_get_double(properties, GIALIAS_PIXSIZX);
1432  pixelsize /= 1000.;
1433 
1434 
1435  /*
1436  * Setup the optical model parameters
1437  */
1438 
1439  switch (wcal->opt_mod) {
1440  case LMRQ_XOPTMOD:
1441  if (cpl_matrix_get_nrow(wcal->opt_mod_params) != 4) {
1442  return NULL;
1443  }
1444  else {
1445 
1446  cxdouble direction = cpl_matrix_get(wcal->opt_mod_params, 0, 0);
1447  cxdouble fcoll = cpl_matrix_get(wcal->opt_mod_params, 1, 0);
1448  cxdouble cfact = cpl_matrix_get(wcal->opt_mod_params, 2, 0);
1449 
1450  model = cpl_matrix_new(4, 1);
1451 
1452  cpl_matrix_set(model, 0, 0, npixel * direction);
1453  cpl_matrix_set(model, 1, 0, pixelsize);
1454  cpl_matrix_set(model, 2, 0, fcoll);
1455  cpl_matrix_set(model, 3, 0, cfact);
1456  }
1457  break;
1458 
1459  case LMRQ_XOPTMOD2:
1460  if (cpl_matrix_get_nrow(wcal->opt_mod_params) != 7) {
1461  return NULL;
1462  }
1463  else {
1464 
1465  cxdouble direction = cpl_matrix_get(wcal->opt_mod_params, 0, 0);
1466  cxdouble fcoll = cpl_matrix_get(wcal->opt_mod_params, 1, 0);
1467  cxdouble cfact = cpl_matrix_get(wcal->opt_mod_params, 2, 0);
1468  cxdouble sdx = cpl_matrix_get(wcal->opt_mod_params, 4, 0);
1469  cxdouble sdy = cpl_matrix_get(wcal->opt_mod_params, 5, 0);
1470  cxdouble sphi = cpl_matrix_get(wcal->opt_mod_params, 6, 0);
1471 
1472  model = cpl_matrix_new(7, 1);
1473 
1474  cpl_matrix_set(model, 0, 0, npixel * direction);
1475  cpl_matrix_set(model, 1, 0, pixelsize);
1476  cpl_matrix_set(model, 2, 0, fcoll);
1477  cpl_matrix_set(model, 3, 0, cfact);
1478  cpl_matrix_set(model, 4, 0, sdx);
1479  cpl_matrix_set(model, 5, 0, sdy);
1480  cpl_matrix_set(model, 6, 0, sphi);
1481  }
1482  break;
1483 
1484  default:
1485  return NULL;
1486  break;
1487  }
1488 
1489  cx_assert(model != NULL);
1490 
1491  return model;
1492 
1493 }
1494 
1495 
1496 inline static cpl_matrix *
1497 _giraffe_rebin_setup_grating(GiImage *extspectra, GiTable *grating,
1498  GiTable *wlsolution)
1499 {
1500 
1501  cxint status = 0;
1502 
1503  cpl_propertylist *properties = NULL;
1504 
1505  cpl_matrix *setup = NULL;
1506 
1507  GiGrat *grating_data = _giraffe_grating_new();
1508 
1509 
1510  status = _giraffe_grating_setup(grating, extspectra, grating_data);
1511 
1512  if (status != 0) {
1513  _giraffe_grating_delete(grating_data);
1514  return NULL;
1515  }
1516 
1517 
1518  properties = giraffe_table_get_properties(wlsolution);
1519 
1520  if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMFCOLL)) {
1521  grating_data->fcoll = cpl_propertylist_get_double(properties,
1522  GIALIAS_WSOL_OMFCOLL);
1523  }
1524 
1525  if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMGCAM)) {
1526  grating_data->gcam = cpl_propertylist_get_double(properties,
1527  GIALIAS_WSOL_OMGCAM);
1528  }
1529 
1530  if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMGTHETA)) {
1531  grating_data->theta = cpl_propertylist_get_double(properties,
1532  GIALIAS_WSOL_OMGTHETA);
1533  }
1534 
1535  if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMSDX)) {
1536  grating_data->slitdx = cpl_propertylist_get_double(properties,
1537  GIALIAS_WSOL_OMSDX);
1538  }
1539 
1540  if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMSDY)) {
1541  grating_data->slitdy = cpl_propertylist_get_double(properties,
1542  GIALIAS_WSOL_OMSDY);
1543  }
1544 
1545  if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMSPHI)) {
1546  grating_data->slitphi = cpl_propertylist_get_double(properties,
1547  GIALIAS_WSOL_OMSPHI);
1548  }
1549 
1550 
1551  setup = cpl_matrix_new(7, 1);
1552 
1553  cpl_matrix_set(setup, 0, 0, grating_data->theta);
1554  cpl_matrix_set(setup, 1, 0, grating_data->order);
1555  cpl_matrix_set(setup, 2, 0, grating_data->wlenmin / GI_MM_TO_NM);
1556  cpl_matrix_set(setup, 3, 0, grating_data->wlen0 / GI_MM_TO_NM);
1557  cpl_matrix_set(setup, 4, 0, grating_data->wlenmax / GI_MM_TO_NM);
1558  cpl_matrix_set(setup, 5, 0, grating_data->resol);
1559  cpl_matrix_set(setup, 6, 0, grating_data->space);
1560 
1561  _giraffe_grating_delete(grating_data);
1562  grating_data = NULL;
1563 
1564  return setup;
1565 
1566 }
1567 
1568 
1581 inline static cxint
1582 _giraffe_spline_calc_circe(cxdouble x, register cxdouble* t, cxint n)
1583 {
1584 
1585  register cxint lo = 0;
1586  register cxint hi = n - 1;
1587 
1588 
1589  if (x >= t[0] && x <= t[n - 1]) {
1590 
1591  while (hi - lo > 1) {
1592 
1593  register cxint mid = (lo + hi) / 2.;
1594 
1595  cxdouble tm = 0.;
1596 
1597  tm = t[mid];
1598 
1599  if (x < tm) {
1600  hi = mid;
1601  }
1602  else {
1603  lo = mid;
1604  }
1605  }
1606 
1607  return hi;
1608 
1609  }
1610 
1611  return -1;
1612 
1613 }
1614 
1634 inline static void
1635 _giraffe_spline_calc_tridi(register cxdouble* a, register cxdouble* b,
1636  register cxdouble* c, register cxdouble* f,
1637  register cxdouble* x, cxint n)
1638 {
1639 
1640  register cxint i = 0;
1641 
1642  c[0] /= a[0];
1643 
1644  for (i = 1; i < n; i++) {
1645  c[i] /= (a[i] - b[i] * c[i - 1]);
1646  }
1647 
1648  f[0] /= a[0];
1649 
1650  for (i = 1; i < n; i++) {
1651  f[i] = (f[i] - b[i] * f[i - 1]) / (a[i] - b[i] * c[i - 1]);
1652  }
1653 
1654  x[n - 1] = f[n - 1];
1655 
1656  for (i = n - 2; i >= 0; i--) {
1657  x[i] = f[i] - c[i] * x[i + 1];
1658  }
1659 
1660  return;
1661 }
1662 
1682 inline static cxint
1683 _giraffe_spline_calc_interpolate(cxdouble z, cxdouble* val,
1684  register cxdouble* x, register cxdouble* y,
1685  register cxdouble* k, cxint n)
1686 {
1687 
1688  cxint m = 0;
1689 
1690  cxdouble h = 0.;
1691  cxdouble t = 0.;
1692  cxdouble d = 0.;
1693  cxdouble a = 0.;
1694  cxdouble b = 0.;
1695  cxdouble dx = 0.;
1696 
1697 
1698  m = _giraffe_spline_calc_circe(z, x, n);
1699 
1700  if (m < 0) {
1701 
1702  /* out of bounds */
1703  if (z < x[0]) {
1704  dx = z - x[0];
1705  *val = y[0] + dx * (k[0] + 0.5 * dx * ddb);
1706  } else {
1707  dx = z - x[n - 1];
1708  *val = y[n - 1] + dx * (k[n - 1] + 0.5 * dx * dde);
1709  }
1710 
1711  return 1;
1712 
1713  }
1714 
1715  dx = z - x[m - 1];
1716  h = x[m] - x[m - 1];
1717  d = (y[m] - y[m - 1]) / h;
1718  t = dx / h;
1719  a = (k[m - 1] - d) * (1 - t);
1720  b = (k[m] - d) * t;
1721  *val = t * y[m] + (1 - t) * y[m - 1] + h * t * (1 - t) * (a - b);
1722 
1723  return 0;
1724 
1725 }
1726 
1747 inline static cxint
1748 _giraffe_spline_calc_initalize(cxdouble* x, cxdouble* y, cxdouble* k,
1749  cxint n, cxdouble q2b, cxdouble q2e)
1750 {
1751 
1752  register cxint i = 0;
1753  register cxint ip = 0;
1754 
1755  register cxdouble* a;
1756  register cxdouble* b;
1757  register cxdouble* c;
1758  register cxdouble* f;
1759 
1760  cxdouble hio = 0.;
1761  cxdouble hip = 0.;
1762  cxdouble dio = 0.;
1763  cxdouble dip = 0.;
1764 
1765 
1766 
1767  ddb = q2b;
1768  dde = q2e; /* save end second derivatives */
1769 
1770  a = (cxdouble*) cx_malloc(4 * n * sizeof(cxdouble));
1771 
1772  b = a + n;
1773  c = b + n;
1774  f = c + n;
1775 
1776  for (i = 0; i < n; i++) {
1777 
1778  hip = ((ip = i + 1) < n ? x[ip] - x[i] : 0.0);
1779  dip = (ip < n ? (y[ip] - y[i]) / hip : 0.0);
1780  b[i] = (ip < n ? hip : hio);
1781  a[i] = 2.0 * (hip + hio);
1782  c[i] = (i > 0 ? hio : hip);
1783  f[i] = 3.0 * (hip * dio + hio * dip);
1784 
1785  if (i == 0) {
1786  f[0] = 3.0 * hip * dip - hip * hip * q2b * 0.5;
1787  }
1788  else if (i == n - 1) {
1789  f[n - 1] = 3.0 * hio * dio + hio * hio * q2e * 0.5;
1790  }
1791 
1792  dio = dip;
1793  hio = hip;
1794  }
1795 
1796  _giraffe_spline_calc_tridi(a, b, c, f, k, n);
1797 
1798  cx_free(a);
1799 
1800  return 0;
1801 
1802 }
1803 
1822 inline static cxint
1823 _giraffe_rebin_interpolate_spline(cpl_matrix* x_1, cpl_matrix* y_1,
1824  cpl_matrix* x_2, cpl_matrix* y_2)
1825 {
1826 
1827  cxint i = 0;
1828  cxint res = 0;
1829  cxint nr_x1 = 0;
1830  cxint nr_x2 = 0;
1831 
1832  cxdouble* k = NULL;
1833  cxdouble* pd_x1 = NULL;
1834  cxdouble* pd_y1 = NULL;
1835  cxdouble* pd_x2 = NULL;
1836  cxdouble* pd_y2 = NULL;
1837 
1838 
1839 
1840  if (x_1 == NULL || y_1 == NULL || x_2 == NULL || y_2 == NULL) {
1841  return 1;
1842  }
1843 
1844  nr_x1 = cpl_matrix_get_nrow(x_1);
1845  nr_x2 = cpl_matrix_get_nrow(x_2);
1846 
1847  pd_x1 = cpl_matrix_get_data(x_1);
1848  pd_y1 = cpl_matrix_get_data(y_1);
1849  pd_y2 = cpl_matrix_get_data(y_2);
1850  pd_x2 = cpl_matrix_get_data(x_2);
1851 
1852 
1853  /*
1854  * Get storage for spline coefficients and vector y2
1855  */
1856 
1857  k = (cxdouble*) cx_malloc(nr_x1 * sizeof(cxdouble));
1858 
1859 
1860  /*
1861  * Initialise spline calculation...
1862  */
1863 
1864  res = _giraffe_spline_calc_initalize(pd_x1, pd_y1, k, nr_x1, 0.0, 0.0);
1865 
1866  if (res < 0) {
1867  cx_free(k);
1868  return res;
1869  }
1870 
1871  /*
1872  * Calculate spline...
1873  */
1874 
1875  for (i = 0; i < nr_x2; i++) {
1876  res = _giraffe_spline_calc_interpolate(pd_x2[i], &(pd_y2[i]), pd_x1,
1877  pd_y1, k, nr_x1);
1878  }
1879 
1880  cx_free(k);
1881 
1882  return 0;
1883 
1884 }
1885 
1907 inline static cxint
1908 _giraffe_rebin_interpolate_linear(
1909  cpl_matrix *x_1,
1910  cpl_matrix *y_1,
1911  cpl_matrix *x_2,
1912  cpl_matrix *y_2
1913  )
1914 {
1915 
1916  /*************************************************************************
1917  Variables
1918  *************************************************************************/
1919 
1920  register cxdouble a, b ;
1921  register cxint i, j, j_1, found, n1;
1922 
1923  cxint nr_x1 = 0,
1924  nr_x2 = 0;
1925  cxdouble *pd_x1 = NULL,
1926  *pd_x2 = NULL,
1927  *pd_y2 = NULL,
1928  *pd_y1 = NULL;
1929 
1930  /*************************************************************************
1931  Preprocessing
1932  *************************************************************************/
1933 
1934  if (x_1 == NULL) { return 1; }
1935  if (y_1 == NULL) { return 1; }
1936  if (x_2 == NULL) { return 1; }
1937  if (y_2 == NULL) { return 1; }
1938 
1939  nr_x1 = cpl_matrix_get_nrow(x_1);
1940  nr_x2 = cpl_matrix_get_nrow(x_2);
1941  pd_x1 = cpl_matrix_get_data(x_1);
1942  pd_x2 = cpl_matrix_get_data(x_2);
1943  pd_y1 = cpl_matrix_get_data(y_1);
1944  pd_y2 = cpl_matrix_get_data(y_2);
1945 
1946  /*************************************************************************
1947  Processing
1948  *************************************************************************/
1949 
1950  n1 = nr_x1 - 1;
1951 
1952  for (i = 0; i < nr_x2; i++) {
1953  /* Find (x1,y1) on the left of the current point */
1954  found = 0;
1955  for (j = 0; j < n1; j++) {
1956  if ((pd_x2[i] >= pd_x1[j]) && (pd_x2[i] <= pd_x1[j+1])) {
1957  found++ ;
1958  break ;
1959  }
1960  }
1961 
1962  if (!found) {
1963  pd_y2[i] = 0.0;
1964  } else {
1965  j_1 = j + 1;
1966  a = (pd_y1[j_1] - pd_y1[j]) / (pd_x1[j_1] - pd_x1[j]);
1967  b = pd_y1[j] - a * pd_x1[j];
1968  pd_y2[i] = (a * pd_x2[i] + b);
1969 
1970  }
1971  }
1972 
1973  return 0;
1974 
1975 } /* end giraffe_rebin_interpolate_linear() */
1976 
2002 inline static cxint
2003 _giraffe_rebin_interpolate_linear_error(
2004  cpl_matrix *x_1,
2005  cpl_matrix *y_1,
2006  cpl_matrix *y_1err,
2007  cpl_matrix *x_2,
2008  cpl_matrix *y_2,
2009  cpl_matrix *y_2err
2010  ) {
2011 
2012  /*************************************************************************
2013  Variables
2014  *************************************************************************/
2015 
2016  register double a, b ,dx;
2017  register int i, j, j_1, found, n1 ;
2018 
2019  cxint nr_x1 = 0,
2020  nr_x2 = 0;
2021  cxdouble *pd_x1 = NULL,
2022  *pd_y1 = NULL,
2023  *pd_y1err = NULL,
2024  *pd_x2 = NULL,
2025  *pd_y2 = NULL,
2026  *pd_y2err = NULL;
2027 
2028  /*************************************************************************
2029  Preprocessing
2030  *************************************************************************/
2031 
2032  if (x_1 == NULL) { return 1; }
2033  if (y_1 == NULL) { return 1; }
2034  if (y_1err == NULL) { return 1; }
2035  if (x_2 == NULL) { return 1; }
2036  if (y_2 == NULL) { return 1; }
2037  if (y_2err == NULL) { return 1; }
2038 
2039  nr_x1 = cpl_matrix_get_nrow(x_1);
2040  nr_x2 = cpl_matrix_get_nrow(x_2);
2041  pd_x1 = cpl_matrix_get_data(x_1);
2042  pd_y1 = cpl_matrix_get_data(y_1);
2043  pd_y1err = cpl_matrix_get_data(y_1err);
2044  pd_x2 = cpl_matrix_get_data(x_2);
2045  pd_y2 = cpl_matrix_get_data(y_2);
2046  pd_y2err = cpl_matrix_get_data(y_2err);
2047 
2048  /*************************************************************************
2049  Processing
2050  *************************************************************************/
2051 
2052  n1 = nr_x1 - 1;
2053 
2054  for (i = 0; i < nr_x2; i++) {
2055  /* Find (x1,y1) on the left of the current point */
2056  found = 0;
2057  for (j = 0; j < n1; j++) {
2058  if ((pd_x2[i] >= pd_x1[j]) && (pd_x2[i] <= pd_x1[j+1])) {
2059  found++ ;
2060  break ;
2061  }
2062  }
2063 
2064  if (!found) {
2065  pd_y2[i] = 0.0;
2066  pd_y2err[i] = 0.0;
2067  } else {
2068 
2069  j_1 = j + 1;
2070  dx = (pd_x1[j_1] - pd_x1[j]);
2071  a = (pd_y1[j_1] - pd_y1[j]) / dx;
2072  b = pd_y1[j] - a * pd_x1[j] ;
2073  pd_y2[i] = (a * pd_x2[i] + b) ;
2074  a = (pd_y1err[j_1] - pd_y1err[j]) / dx;
2075  b = pd_y1err[j] - a * pd_x1[j] ;
2076  pd_y2err[i] = (a * pd_x2[i] + b) ;
2077 
2078  }
2079  }
2080 
2081  return 0;
2082 
2083 } /* end giraffe_rebin_interpolate_linear_error() */
2084 
2104 inline static cxint
2105 _giraffe_resample_linear(cpl_image* rbspectra, cpl_image* rberrors,
2106  cpl_image* abscissa, cpl_image* exspectra,
2107  cpl_image* exerrors, cxint opt_direction)
2108 {
2109 
2110  const cxchar* const fctid = "_giraffe_resample_linear";
2111 
2112  register cxlong n = 0;
2113 
2114  /*cxint status = 0;*/
2115  cxint nx = 0; /* size of extracted spectra */
2116  cxint ns = 0; /* number of extracted spectra */
2117  cxint nwl = 0; /* size of rebinned spectra */
2118 
2119  cxdouble nx1 = 0.;
2120  cxdouble* _mabscissa = NULL;
2121  cxdouble* _mexspectra = NULL;
2122  cxdouble* _mexerrors = NULL;
2123  cxdouble* _mwavelength = NULL;
2124  cxdouble* _mrbspectra = NULL;
2125  cxdouble* _mrberrors = NULL;
2126  cxdouble* _abscissa = NULL;
2127  cxdouble* _exspectra = NULL;
2128  cxdouble* _exerrors = NULL;
2129  cxdouble* _rbspectra = NULL;
2130  cxdouble* _rberrors = NULL;
2131 
2132  cpl_matrix* mabscissa = NULL;
2133  cpl_matrix* mwavelength = NULL;
2134  cpl_matrix* mexspectra = NULL;
2135  cpl_matrix* mexerrors = NULL;
2136  cpl_matrix* mrbspectra = NULL;
2137  cpl_matrix* mrberrors = NULL;
2138 
2139 
2140 
2141  if ((abscissa == NULL) || (exspectra == NULL) || (rbspectra == NULL)) {
2142  return 1;
2143  }
2144 
2145  if ((exerrors != NULL) && (rberrors == NULL)) {
2146  return 1;
2147  }
2148 
2149 
2150  nx = cpl_image_get_size_y(exspectra);
2151  ns = cpl_image_get_size_x(exspectra);
2152  nwl = cpl_image_get_size_y(abscissa);
2153 
2154  if ((exerrors != NULL) &&
2155  ((nx != cpl_image_get_size_y(exerrors)) ||
2156  (ns != cpl_image_get_size_x(exerrors)))) {
2157  return 1;
2158  }
2159 
2160  nx1 = nx - 0.5;
2161 
2162  mabscissa = cpl_matrix_new(nx, 1);
2163  mexspectra = cpl_matrix_new(nx, 1);
2164 
2165  mwavelength = cpl_matrix_new(nwl, 1);
2166  mrbspectra = cpl_matrix_new(nwl, 1);
2167 
2168  _mabscissa = cpl_matrix_get_data(mabscissa);
2169  _mexspectra = cpl_matrix_get_data(mexspectra);
2170  _mwavelength = cpl_matrix_get_data(mwavelength);
2171  _mrbspectra = cpl_matrix_get_data(mrbspectra);
2172 
2173  _abscissa = cpl_image_get_data_double(abscissa);
2174  _exspectra = cpl_image_get_data_double(exspectra);
2175  _rbspectra = cpl_image_get_data_double(rbspectra);
2176 
2177  if (exerrors != NULL) {
2178  mexerrors = cpl_matrix_new(nx, 1);
2179  mrberrors = cpl_matrix_new(nwl, 1);
2180 
2181  _mexerrors = cpl_matrix_get_data(mexerrors);
2182  _mrberrors = cpl_matrix_get_data(mrberrors);
2183 
2184  _exerrors = cpl_image_get_data_double(exerrors);
2185  _rberrors = cpl_image_get_data_double(rberrors);
2186  }
2187 
2188 
2189  /*
2190  * Resample each spectrum to the new grid, taking the direction of the
2191  * optical model into account. If the errors of the spectra are
2192  * available they are also resampled to the new grid.
2193  */
2194 
2195  cpl_msg_debug(fctid, "Rebinning %d spectra, using dispersion direction "
2196  "%d and linear interpolation", ns, opt_direction);
2197 
2198  for (n = 0; n < ns; n++) {
2199 
2200  register cxlong x = 0;
2201 
2202 
2203  for (x = 0; x < nwl; x++) {
2204  register cxlong j = x * ns + n;
2205  _mwavelength[x] = _abscissa[j];
2206  }
2207 
2208  if (exerrors == NULL) {
2209 
2210  if (opt_direction < 0) {
2211 
2212  for (x = 0; x < nx; x++) {
2213 
2214  register cxlong j = x * ns + n;
2215  register cxlong k = nx - x - 1;
2216 
2217  _mabscissa[x] = (cxdouble) x;
2218  _mexspectra[k] = _exspectra[j];
2219  }
2220 
2221  }
2222  else {
2223 
2224  for (x = 0; x < nx; x++) {
2225 
2226  register cxlong j = x * ns + n;
2227 
2228  _mabscissa[x] = (cxdouble) x;
2229  _mexspectra[x] = _exspectra[j];
2230 
2231  }
2232 
2233  }
2234 
2235 
2236  /*
2237  * Linear interpolation of spectra and errors
2238  */
2239 
2240  /*status =*/ _giraffe_rebin_interpolate_linear(mabscissa,
2241  mexspectra,
2242  mwavelength,
2243  mrbspectra);
2244 
2245  for (x = 0; x < nwl; x++) {
2246 
2247  register cxlong j = x * ns + n;
2248 
2249  if ((-0.5 > _mwavelength[x]) || (_mwavelength[x] > nx1)) {
2250  _rbspectra[j] = 0.;
2251  }
2252  else {
2253  _rbspectra[j] = _mrbspectra[x];
2254  }
2255 
2256  }
2257 
2258  }
2259  else {
2260 
2261  if (opt_direction < 0) {
2262 
2263  for (x = 0; x < nx; x++) {
2264 
2265  register cxlong j = x * ns + n;
2266  register cxlong k = nx - x - 1;
2267 
2268  _mabscissa[x] = (cxdouble) x;
2269  _mexspectra[k] = _exspectra[j];
2270  _mexerrors[k] = _exerrors[j];
2271  }
2272 
2273  }
2274  else {
2275 
2276  for (x = 0; x < nx; x++) {
2277 
2278  register cxlong j = x * ns + n;
2279 
2280  _mabscissa[x] = (cxdouble) x;
2281  _mexspectra[x] = _exspectra[j];
2282  _mexerrors[x] = _exerrors[j];
2283 
2284  }
2285 
2286  }
2287 
2288 
2289  /*
2290  * Linear interpolation of spectra and errors
2291  */
2292 
2293  /*status =*/
2294  _giraffe_rebin_interpolate_linear_error(mabscissa,
2295  mexspectra,
2296  mexerrors,
2297  mwavelength,
2298  mrbspectra,
2299  mrberrors);
2300 
2301  for (x = 0; x < nwl; x++) {
2302 
2303  register cxlong j = x * ns + n;
2304 
2305  if ((-0.5 > _mwavelength[x]) || (_mwavelength[x] > nx1)) {
2306  _rbspectra[j] = 0.;
2307  _rberrors[j] = 0.;
2308  }
2309  else {
2310  _rbspectra[j] = _mrbspectra[x];
2311  _rberrors[j] = _mrberrors[x];
2312  }
2313 
2314  }
2315 
2316  }
2317 
2318  } /* each spectrum */
2319 
2320 
2321  cpl_matrix_delete(mrbspectra);
2322  mrbspectra = NULL;
2323 
2324  cpl_matrix_delete(mwavelength);
2325  mwavelength = NULL;
2326 
2327  cpl_matrix_delete(mexspectra);
2328  mexspectra = NULL;
2329 
2330  cpl_matrix_delete(mabscissa);
2331  mabscissa = NULL;
2332 
2333  if (exerrors != NULL) {
2334  cpl_matrix_delete(mrberrors);
2335  mrberrors = NULL;
2336 
2337  cpl_matrix_delete(mexerrors);
2338  mexerrors = NULL;
2339  }
2340 
2341  cpl_msg_debug(fctid, "Rebinned %d spectra", ns);
2342 
2343  return 0;
2344 
2345 }
2346 
2347 
2367 inline static cxint
2368 _giraffe_resample_spline(cpl_image* rbspectra, cpl_image* rberrors,
2369  cpl_image* abscissa, cpl_image* exspectra,
2370  cpl_image* exerrors, cxint opt_direction)
2371 {
2372 
2373  const cxchar* const fctid = "_giraffe_resample_spline";
2374 
2375  register cxlong n = 0;
2376 
2377  /*cxint status = 0;*/
2378  cxint nx = 0; /* size of extracted spectra */
2379  cxint ns = 0; /* number of extracted spectra */
2380  cxint nwl = 0; /* size of rebinned spectra */
2381 
2382  cxdouble nx1 = 0.;
2383  cxdouble* _mabscissa = NULL;
2384  cxdouble* _mexspectra = NULL;
2385  cxdouble* _mexerrors = NULL;
2386  cxdouble* _mwavelength = NULL;
2387  cxdouble* _mrbspectra = NULL;
2388  cxdouble* _mrberrors = NULL;
2389  cxdouble* _abscissa = NULL;
2390  cxdouble* _exspectra = NULL;
2391  cxdouble* _exerrors = NULL;
2392  cxdouble* _rbspectra = NULL;
2393  cxdouble* _rberrors = NULL;
2394 
2395  cpl_matrix* mabscissa = NULL;
2396  cpl_matrix* mwavelength = NULL;
2397  cpl_matrix* mexspectra = NULL;
2398  cpl_matrix* mexerrors = NULL;
2399  cpl_matrix* mrbspectra = NULL;
2400  cpl_matrix* mrberrors = NULL;
2401 
2402 
2403 
2404  if ((abscissa == NULL) || (exspectra == NULL) || (rbspectra == NULL)) {
2405  return 1;
2406  }
2407 
2408  if ((exerrors != NULL) && (rberrors == NULL)) {
2409  return 1;
2410  }
2411 
2412 
2413  nx = cpl_image_get_size_y(exspectra);
2414  ns = cpl_image_get_size_x(exspectra);
2415  nwl = cpl_image_get_size_y(abscissa);
2416 
2417  if ((exerrors != NULL) &&
2418  ((nx != cpl_image_get_size_y(exerrors)) ||
2419  (ns != cpl_image_get_size_x(exerrors)))) {
2420  return 1;
2421  }
2422 
2423  nx1 = nx - 0.5;
2424 
2425  mabscissa = cpl_matrix_new(nx, 1);
2426  mexspectra = cpl_matrix_new(nx, 1);
2427 
2428  mwavelength = cpl_matrix_new(nwl, 1);
2429  mrbspectra = cpl_matrix_new(nwl, 1);
2430 
2431  _mabscissa = cpl_matrix_get_data(mabscissa);
2432  _mexspectra = cpl_matrix_get_data(mexspectra);
2433  _mwavelength = cpl_matrix_get_data(mwavelength);
2434  _mrbspectra = cpl_matrix_get_data(mrbspectra);
2435 
2436  _abscissa = cpl_image_get_data_double(abscissa);
2437  _exspectra = cpl_image_get_data_double(exspectra);
2438  _rbspectra = cpl_image_get_data_double(rbspectra);
2439 
2440  if (exerrors != NULL) {
2441  mexerrors = cpl_matrix_new(nx, 1);
2442  mrberrors = cpl_matrix_new(nwl, 1);
2443 
2444  _mexerrors = cpl_matrix_get_data(mexerrors);
2445  _mrberrors = cpl_matrix_get_data(mrberrors);
2446 
2447  _exerrors = cpl_image_get_data_double(exerrors);
2448  _rberrors = cpl_image_get_data_double(rberrors);
2449  }
2450 
2451 
2452  /*
2453  * Resample each spectrum to the new grid, taking the direction of the
2454  * optical model into account. If the errors of the spectra are
2455  * available they are also resampled to the new grid.
2456  */
2457 
2458  cpl_msg_debug(fctid, "Rebinning %d spectra, using dispersion direction "
2459  "%d and linear interpolation", ns, opt_direction);
2460 
2461  for (n = 0; n < ns; n++) {
2462 
2463  register cxlong x = 0;
2464 
2465 
2466  for (x = 0; x < nwl; x++) {
2467  register cxlong j = x * ns + n;
2468  _mwavelength[x] = _abscissa[j];
2469  }
2470 
2471  if (exerrors == NULL) {
2472 
2473  if (opt_direction < 0) {
2474 
2475  for (x = 0; x < nx; x++) {
2476 
2477  register cxlong j = x * ns + n;
2478  register cxlong k = nx - x - 1;
2479 
2480  _mabscissa[x] = (cxdouble) x;
2481  _mexspectra[k] = _exspectra[j];
2482  }
2483 
2484  }
2485  else {
2486 
2487  for (x = 0; x < nx; x++) {
2488 
2489  register cxlong j = x * ns + n;
2490 
2491  _mabscissa[x] = (cxdouble) x;
2492  _mexspectra[x] = _exspectra[j];
2493 
2494  }
2495 
2496  }
2497 
2498 
2499  /*
2500  * Spline interpolation of spectra and errors
2501  */
2502 
2503  /*status =*/ _giraffe_rebin_interpolate_spline(mabscissa,
2504  mexspectra,
2505  mwavelength,
2506  mrbspectra);
2507 
2508  for (x = 0; x < nwl; x++) {
2509 
2510  register cxlong j = x * ns + n;
2511 
2512  if ((-0.5 > _mwavelength[x]) || (_mwavelength[x] > nx1)) {
2513  _rbspectra[j] = 0.;
2514  }
2515  else {
2516  _rbspectra[j] = _mrbspectra[x];
2517  }
2518 
2519  }
2520 
2521  }
2522  else {
2523 
2524  if (opt_direction < 0) {
2525 
2526  for (x = 0; x < nx; x++) {
2527 
2528  register cxlong j = x * ns + n;
2529  register cxlong k = nx - x - 1;
2530 
2531  _mabscissa[x] = (cxdouble) x;
2532  _mexspectra[k] = _exspectra[j];
2533  _mexerrors[k] = _exerrors[j];
2534  }
2535 
2536  }
2537  else {
2538 
2539  for (x = 0; x < nx; x++) {
2540 
2541  register cxlong j = x * ns + n;
2542 
2543  _mabscissa[x] = (cxdouble) x;
2544  _mexspectra[x] = _exspectra[j];
2545  _mexerrors[x] = _exerrors[j];
2546 
2547  }
2548 
2549  }
2550 
2551 
2552  /*
2553  * Spline interpolation of spectra and linear interpolation of
2554  * errors
2555  */
2556 
2557  /*status =*/ _giraffe_rebin_interpolate_spline(mabscissa,
2558  mexspectra,
2559  mwavelength,
2560  mrbspectra);
2561 
2562  /*status =*/ _giraffe_rebin_interpolate_linear(mabscissa,
2563  mexerrors,
2564  mwavelength,
2565  mrberrors);
2566 
2567  for (x = 0; x < nwl; x++) {
2568 
2569  register cxlong j = x * ns + n;
2570 
2571  if ((-0.5 > _mwavelength[x]) || (_mwavelength[x] > nx1)) {
2572  _rbspectra[j] = 0.;
2573  _rberrors[j] = 0.;
2574  }
2575  else {
2576  _rbspectra[j] = _mrbspectra[x];
2577  _rberrors[j] = _mrberrors[x];
2578  }
2579 
2580  }
2581 
2582  }
2583 
2584  } /* each spectrum */
2585 
2586 
2587  cpl_matrix_delete(mrbspectra);
2588  mrbspectra = NULL;
2589 
2590  cpl_matrix_delete(mwavelength);
2591  mwavelength = NULL;
2592 
2593  cpl_matrix_delete(mexspectra);
2594  mexspectra = NULL;
2595 
2596  cpl_matrix_delete(mabscissa);
2597  mabscissa = NULL;
2598 
2599  if (exerrors != NULL) {
2600  cpl_matrix_delete(mrberrors);
2601  mrberrors = NULL;
2602 
2603  cpl_matrix_delete(mexerrors);
2604  mexerrors = NULL;
2605  }
2606 
2607  cpl_msg_debug(fctid, "Rebinned %d spectra", ns);
2608 
2609  return 0;
2610 
2611 }
2612 
2613 
2687 static cxdouble
2688 giraffe_rebin_compute_opt_mod3(cxdouble xccd, cxdouble xfibre,
2689  cxdouble yfibre, cxdouble nx,
2690  cxdouble pixsize, cxdouble fcoll,
2691  cxdouble cfact, cxdouble gtheta,
2692  cxdouble gorder, cxdouble gspace,
2693  cxdouble slitdx, cxdouble slitdy,
2694  cxdouble slitphi)
2695 {
2696 
2697  /*************************************************************************
2698  Variables
2699  *************************************************************************/
2700 
2701  cxdouble xf, yf, d, t1, t12, t13, t18, t19, t2, t23, t28,
2702  t3, t31, t32, t36, t37, t39, t4, t40, t5, t62, t8, t9;
2703 
2704  /*************************************************************************
2705  Processing
2706  *************************************************************************/
2707 
2708  /* should take care of negative NX value */
2709 
2710  xf = xfibre * (1.0 + slitphi * yfibre) + slitdx;
2711  yf = yfibre * sqrt(1.0 - slitphi * slitphi) + slitdy;
2712  d = sqrt(xf * xf + yf * yf + fcoll * fcoll);
2713  t1 = cos(gtheta);
2714  t2 = xf*t1;
2715  t3 = xccd*xccd;
2716  t4 = pixsize*pixsize;
2717  t5 = t3*t4;
2718  t8 = sin(gtheta);
2719  t9 = fcoll*t8;
2720  t12 = cfact*cfact;
2721  t13 = fcoll*fcoll;
2722  t18 = nx*nx;
2723  t19 = t18*t4;
2724  t23 = xccd*t4*nx;
2725  t28 = t12*t13;
2726  t31 = yf*yf;
2727  t32 = d*d;
2728  t36 = 4.0*t28;
2729  t37 = t19+4.0*t5-4.0*t23+t36;
2730  t39 = t1*t1;
2731  t40 = t39*t4;
2732  t62 = sqrt((-t31+t32)*t37*(4.0*t40*t3-4.0*xccd*nx*t40 +
2733  8.0*xccd*t1*cfact*t9*pixsize+t19*t39 -
2734  4.0*cfact*fcoll*t8*nx*t1*pixsize+t36 -
2735  4.0*t28*t39));
2736 
2737  return((4.0*t2*t5 + 4.0*t9*t5 + 4.0*t12*t13*fcoll*t8+t2*t19+t9*t19 -
2738  4.0*t9*t23 - 4.0*t2*t23 + 4.0*t28*t2+t62)*gspace/t37/gorder/d);
2739 
2740 } /* end giraffe_rebin_compute_opt_mod3() */
2741 
2766 static cxdouble
2767 giraffe_rebin_compute_log_opt_mod3(cxdouble xccd, cxdouble xfibre,
2768  cxdouble yfibre, cxdouble nx,
2769  cxdouble pixsize, cxdouble fcoll,
2770  cxdouble cfact, cxdouble gtheta,
2771  cxdouble gorder, cxdouble gspace,
2772  cxdouble slitdx, cxdouble slitdy,
2773  cxdouble slitphi)
2774 {
2775 
2776  return log(giraffe_rebin_compute_opt_mod3(xccd, xfibre, yfibre, nx,
2777  pixsize, fcoll, cfact, gtheta,
2778  gorder, gspace, slitdx, slitdy,
2779  slitphi));
2780 
2781 } /* end of giraffe_rebin_compute_log_opt_mod3() */
2782 
2829 static cxint
2830 giraffe_rebin_compute_lambda_range(GiFiberPosition *fiber_slit_position,
2831  cpl_matrix *opt_mod_params,
2832  cpl_matrix *grat_params,
2833  cxbool lambda_logarithmic,
2834  cxbool wlen_range_common,
2835  cxdouble *lambda_min, cxdouble *lambda_max)
2836 {
2837 
2838  /*************************************************************************
2839  Variables
2840  *************************************************************************/
2841 
2842  const cxchar *fctid = "giraffe_rebin_compute_lambda_range";
2843 
2844  register cxlong n, ns;
2845  register cxdouble dx2, dnx, wl1, wl2;
2846 
2847  double (*computeWl) (double, double, double, double, double, double,
2848  double, double, double, double, double, double,
2849  double);
2850 
2851  cxdouble *pd_opt_mod_params = NULL,
2852  *pd_xfiber = NULL,
2853  *pd_yfiber = NULL,
2854  *pd_grat_params = NULL;
2855 
2856  cxint nr_xfiber;
2857 
2858  /*************************************************************************
2859  Preprocessing
2860  *************************************************************************/
2861 
2862  if (fiber_slit_position ==NULL) { return 1; }
2863  if (fiber_slit_position->x_fiber==NULL) { return 1; }
2864  if (fiber_slit_position->y_fiber==NULL) { return 1; }
2865  if (opt_mod_params ==NULL) { return 1; }
2866  if (grat_params ==NULL) { return 1; }
2867  if (lambda_min ==NULL) { return 1; }
2868  if (lambda_max ==NULL) { return 1; }
2869 
2870  pd_opt_mod_params = cpl_matrix_get_data(opt_mod_params);
2871 
2872  pd_xfiber = cpl_matrix_get_data(fiber_slit_position->x_fiber);
2873  nr_xfiber = cpl_matrix_get_nrow(fiber_slit_position->x_fiber);
2874 
2875  /*************************************************************************
2876  Processing
2877  *************************************************************************/
2878 
2879  if (lambda_logarithmic==TRUE) {
2880  computeWl = giraffe_rebin_compute_log_opt_mod3;
2881  } else {
2882  computeWl = giraffe_rebin_compute_opt_mod3;
2883  }
2884 
2885  dnx = abs(pd_opt_mod_params[O_NX]);
2886  dx2 = dnx - 1.0;
2887  ns = nr_xfiber;
2888 
2889  if (wlen_range_common==TRUE) {
2890  *lambda_min = 0.0;
2891  *lambda_max = CX_MAXDOUBLE;
2892  } else {
2893  *lambda_min = CX_MAXDOUBLE;
2894  *lambda_max = 0.0;
2895  }
2896 
2897  pd_yfiber = cpl_matrix_get_data(fiber_slit_position->y_fiber);
2898  pd_grat_params = cpl_matrix_get_data(grat_params);
2899 
2900  for (n = 0; n < ns; n++) {
2901 
2902  /* first abcissa of each spectrum */
2903  wl1 =
2904  computeWl(
2905  0.0,
2906  pd_xfiber[n],
2907  pd_yfiber[n],
2908  dnx,
2909  pd_opt_mod_params[O_PXSIZ],
2910  pd_opt_mod_params[O_FCOLL],
2911  pd_opt_mod_params[O_CFACT],
2912  pd_grat_params[G_THETA],
2913  pd_grat_params[G_ORDER],
2914  pd_grat_params[G_SPACE],
2915  pd_opt_mod_params[O_SOFFX],
2916  pd_opt_mod_params[O_SOFFY],
2917  pd_opt_mod_params[O_SPHI]
2918  );
2919 
2920  /* last abcissa of each spectrum */
2921  wl2 =
2922  computeWl(
2923  dx2,
2924  pd_xfiber[n],
2925  pd_yfiber[n],
2926  dnx,
2927  pd_opt_mod_params[O_PXSIZ],
2928  pd_opt_mod_params[O_FCOLL],
2929  pd_opt_mod_params[O_CFACT],
2930  pd_grat_params[G_THETA],
2931  pd_grat_params[G_ORDER],
2932  pd_grat_params[G_SPACE],
2933  pd_opt_mod_params[O_SOFFX],
2934  pd_opt_mod_params[O_SOFFY],
2935  pd_opt_mod_params[O_SPHI]
2936  );
2937 
2938  if (wlen_range_common==TRUE) {
2939 
2940  /* common range = [max(wlen_min), min(wlen_max)] */
2941 
2942  if (pd_opt_mod_params[O_NX] < 0) {
2943  *lambda_max = CX_MIN(*lambda_max, wl1);
2944  *lambda_min = CX_MAX(*lambda_min, wl2);
2945  } else {
2946  *lambda_max = CX_MIN(*lambda_max, wl2);
2947  *lambda_min = CX_MAX(*lambda_min, wl1);
2948  }
2949 
2950  } else {
2951 
2952  /* full range = [min(wlen_min), max(wlen_max)] */
2953 
2954  if (pd_opt_mod_params[O_NX] < 0) {
2955  *lambda_max = CX_MAX(*lambda_max, wl1);
2956  *lambda_min = CX_MIN(*lambda_min, wl2);
2957  } else {
2958  *lambda_max = CX_MAX(*lambda_max, wl2);
2959  *lambda_min = CX_MIN(*lambda_min, wl1);
2960  }
2961 
2962  }
2963 
2964  } /* for each spectrum */
2965 
2966  if (wlen_range_common==TRUE) {
2967  /* round to minimum range in integer nanometers */
2968  *lambda_max = floor((*lambda_max) * GI_MM_TO_NM) / GI_MM_TO_NM;
2969  *lambda_min = ceil( (*lambda_min) * GI_MM_TO_NM) / GI_MM_TO_NM;
2970  } else {
2971  /* round to maximum range in integer nanometers */
2972  *lambda_max = ceil( (*lambda_max) * GI_MM_TO_NM) / GI_MM_TO_NM;
2973  *lambda_min = floor((*lambda_min) * GI_MM_TO_NM) / GI_MM_TO_NM;
2974  }
2975 
2976  cpl_msg_debug(fctid, "Rebinning lambda range now: [%12.6f,%12.6f]",
2977  *lambda_min, *lambda_max);
2978 
2979  return 0;
2980 
2981 } /* end giraffe_rebin_compute_lambda_range() */
2982 
3005 static cpl_image*
3006 giraffe_rebin_compute_pixel_x_residuals(
3007  GiLocPosition *locPos,
3008  cpl_image *abcissa,
3009  GiSlitGeo *slitGeo,
3010  GiSlitGeo *xresiduals_limits,
3011  GiSlitGeo *xresiduals_coeff
3012  ) {
3013 
3014  /*************************************************************************
3015  Variables
3016  *************************************************************************/
3017 
3018  const cxchar *fctid = "giraffe_rebin_compute_pixel_x_residuals";
3019 
3020  cxdouble xmin, xmax, ymin, ymax, yup, ylo, yccd, ywid;
3021  cxint n, m, x, xx, x0, i, j, k, l, xxp, x0p;
3022 
3023  cxint subslit,
3024  nfibers,
3025  /*nmin,*/
3026  /*nmax,*/
3027  /*nlen,*/
3028  nx, /* size of original spectra */
3029  ns, /* number of spectra */
3030  nwl, /* size of rebinned spectra */
3031  nf,
3032  nstart,
3033  ndata,
3034  nr_fit,
3035  nc_fit;
3036 
3037  cpl_matrix *xss = NULL,
3038  *yss = NULL,
3039  *fit = NULL,
3040  *curr_xres_limits = NULL,
3041  *curr_xres_coeff = NULL;
3042 
3043  cpl_image *x_residuals_img = NULL;
3044 
3045  cpl_matrix *curr_subslit = NULL;
3046 
3047  cxdouble /* *pd_curr_subslit = NULL,*/
3048  *pd_abcissa = NULL,
3049  *pd_xss = NULL,
3050  *pd_yss = NULL;
3051 
3052  cxdouble *pd_locy = NULL,
3053  *pd_locw = NULL,
3054  *buffer = NULL,
3055  *pd_fit = NULL,
3056  *pd_x_residuals_img = NULL;
3057 
3058 
3059  /*************************************************************************
3060  Preprocessing
3061  *************************************************************************/
3062 
3063  if (locPos ==NULL) { return NULL; }
3064  if (locPos->centroids ==NULL) { return NULL; }
3065  if (locPos->widths ==NULL) { return NULL; }
3066  if (abcissa ==NULL) { return NULL; }
3067  if (slitGeo ==NULL) { return NULL; }
3068  if (xresiduals_limits ==NULL) { return NULL; }
3069  if (xresiduals_coeff ==NULL) { return NULL; }
3070 
3071  nx = cpl_image_get_size_y(locPos->centroids);
3072  ns = cpl_image_get_size_x(locPos->centroids);
3073  nf = cpl_image_get_size_x(abcissa);
3074  nwl = cpl_image_get_size_y(abcissa);
3075 
3076  cpl_msg_debug(
3077  fctid,
3078  "Computing pixel x residuals, using nr spec/nr lines/orig abcissa "
3079  "size: %d/%d/%d",
3080  ns,
3081  nwl,
3082  nx
3083  );
3084 
3085  /*************************************************************************
3086  Processing
3087  *************************************************************************/
3088 
3089  x_residuals_img = cpl_image_new(nf, nwl, CPL_TYPE_DOUBLE);
3090  pd_x_residuals_img = cpl_image_get_data_double(x_residuals_img);
3091  pd_abcissa = cpl_image_get_data_double(abcissa);
3092 
3093  nstart = 0;
3094 
3095  for (subslit = 0; subslit<_giraffe_slitgeo_size(slitGeo); subslit++) {
3096 
3097  curr_subslit = _giraffe_slitgeo_get(slitGeo, subslit);
3098  /*pd_curr_subslit = cpl_matrix_get_data(curr_subslit);*/
3099 
3100  giraffe_matrix_sort(curr_subslit);
3101 
3102  curr_xres_limits =
3103  cpl_matrix_duplicate(
3104  _giraffe_slitgeo_get(xresiduals_limits, subslit)
3105  );
3106 
3107  curr_xres_coeff =
3108  cpl_matrix_duplicate(
3109  _giraffe_slitgeo_get(xresiduals_coeff, subslit)
3110  );
3111 
3112  /* Get spectra/fibers range for current subslit */
3113  nfibers = cpl_matrix_get_nrow(curr_subslit);
3114 
3115  /*nmin = (cxint) pd_curr_subslit[0];*/
3116  /*nmax = (cxint) pd_curr_subslit[nfibers - 1];*/
3117  /*nlen = nmax - nmin + 1;*/
3118  ndata = nwl * nfibers;
3119 
3120  ymax = 0.0;
3121  ymin = CX_MAXDOUBLE; /* has to be smaller than this one! */
3122 
3123  xss = cpl_matrix_new(ndata, 1); /* X abcissas for subslit */
3124  yss = cpl_matrix_new(ndata, 1); /* Y ordinates */
3125 
3126  pd_xss = cpl_matrix_get_data(xss);
3127  pd_yss = cpl_matrix_get_data(yss);
3128 
3129  pd_locy = cpl_image_get_data_double(locPos->centroids);
3130  pd_locw = cpl_image_get_data_double(locPos->widths);
3131 
3132 
3133  k = 0;
3134 
3135  for (m = 0, n = 0; n < nfibers; n++, m++) {
3136 
3137  i = 0; /* running index for valid points */
3138 
3139  for (x = 0; x < nwl; x++) {
3140 
3141  j = x * nf + (nstart + n);
3142  x0 = (cxint) floor(pd_abcissa[j]);
3143  xx = (cxint) ceil(pd_abcissa[j]);
3144 
3145  x0 = CX_MAX(CX_MIN(x0, nx - 1), 0);
3146  xx = CX_MAX(CX_MIN(xx, nx - 1), 0);
3147 
3148  l = i * nfibers + m;
3149  xxp = xx * ns + cpl_matrix_get(curr_subslit, n, 0);
3150  x0p = x0 * ns + cpl_matrix_get(curr_subslit, n, 0);
3151 
3152  pd_xss[l] = pd_abcissa[j];
3153 
3154  /*
3155  * Corresponding Y centroid and width using
3156  * linear interpolation)
3157  */
3158 
3159  yccd = pd_locy[x0p];
3160  pd_yss[l] = yccd + ((pd_locy[xxp] - yccd) * (pd_xss[l] - x0));
3161 
3162  ywid = pd_locw[x0p];
3163  ywid = ywid + ((pd_locw[xxp] - ywid) * (pd_xss[l] - x0));
3164 
3165  /* Get y range for current subslit */
3166  yup = yccd + ywid;
3167  ylo = yccd - ywid;
3168 
3169  /* determine minimum and maximum */
3170  if (ymax < yup) {
3171  ymax = yup;
3172  }
3173 
3174  if (ymin > ylo) {
3175  ymin = ylo;
3176  }
3177 
3178  ++i;
3179  ++k;
3180 
3181  }
3182  }
3183 
3184  /* resize matrices to number of points found */
3185  cpl_matrix_set_size(xss, k, 1);
3186  cpl_matrix_set_size(yss, k, 1);
3187  pd_xss = cpl_matrix_get_data(xss);
3188  pd_yss = cpl_matrix_get_data(yss);
3189 
3190  xmin = cpl_matrix_get(curr_xres_limits, 0, 0);
3191  xmax = cpl_matrix_get(curr_xres_limits, 0, 1);
3192  ymin = cpl_matrix_get(curr_xres_limits, 0, 2);
3193  ymax = cpl_matrix_get(curr_xres_limits, 0, 3);
3194 
3195  xmin = xmin < 0. ? 0. : xmin;
3196  xmax = xmax < 0. ? (cxdouble)nx : xmax;
3197 
3198  ymin = ymin < 0. ? 0. : ymin;
3199  ymax = ymax < 0. ? 2048. : ymax;
3200 
3201  /* do chebyshev fit */
3202  fit =
3203  giraffe_chebyshev_fit2d(
3204  xmin, ymin,
3205  (xmax - xmin),
3206  (ymax - ymin + 1.0),
3207  curr_xres_coeff,
3208  xss,
3209  yss
3210  );
3211 
3212  cpl_matrix_delete(yss);
3213  cpl_matrix_delete(xss);
3214  cpl_matrix_delete(curr_xres_coeff);
3215  cpl_matrix_delete(curr_xres_limits);
3216 
3217  /* resize fit found to match image dimensions */
3218  buffer = cpl_matrix_get_data(fit);
3219  cpl_matrix_unwrap(fit);
3220  fit = NULL;
3221 
3222  fit = cpl_matrix_wrap(nwl, nfibers, buffer);
3223  pd_fit = cpl_matrix_get_data(fit);
3224  nr_fit = cpl_matrix_get_nrow(fit);
3225  nc_fit = cpl_matrix_get_ncol(fit);
3226 
3227  /* subslit fit goes into whole fit */
3228  for (x = 0; x < nr_fit; x++) {
3229  for (k = nstart, n = 0; n < nc_fit; n++, k++) {
3230  pd_x_residuals_img[x * nf + k] = pd_fit[x * nc_fit + n];
3231  }
3232  }
3233 
3234  cpl_matrix_delete(fit);
3235  fit = NULL;
3236 
3237  nstart += nfibers;
3238 
3239  } /* for each subslit */
3240 
3241  cpl_msg_debug(
3242  fctid,
3243  "Computed pixel x residuals, returning image [%d,%d]",
3244  ns,
3245  nwl
3246  );
3247 
3248  return x_residuals_img;
3249 
3250 } /* end giraffe_rebin_compute_pixel_x_residuals() */
3251 
3252 
3285 static cpl_image*
3286 giraffe_rebin_compute_rebin_abcissa(GiFiberPosition* fiber_slit_position,
3287  GiLocPosition* locPos,
3288  GiSlitGeo* slitGeo,
3289  GiSlitGeo* xresiduals_limits,
3290  GiSlitGeo* xresiduals_coeff,
3291  cpl_matrix* grat_params,
3292  cpl_matrix* opt_mod_params,
3293  cpl_matrix* wloffsets,
3294  lmrq_model lmrq_opt_mod_x,
3295  GiRebinParams binPrms)
3296 {
3297 
3298  /*************************************************************************
3299  Variables
3300  *************************************************************************/
3301 
3302  const cxchar* const fctid = "giraffe_rebin_compute_rebin_abcissa";
3303 
3304  cpl_matrix* wlengths = NULL;
3305  cpl_matrix* temp_params = NULL;
3306 
3307  cpl_image* abcissa = NULL;
3308  cpl_image* x_residuals_img = NULL;
3309 
3310  cxdouble* pd_wlengths = NULL;
3311  cxdouble* pd_temp_params = NULL;
3312  cxdouble* pd_opt_mod_params = NULL;
3313  cxdouble* pd_grat_params = NULL;
3314 
3315  /*************************************************************************
3316  Preprocessing
3317  *************************************************************************/
3318 
3319  if (fiber_slit_position == NULL) {
3320  return NULL;
3321  }
3322 
3323  if (locPos == NULL) {
3324  return NULL;
3325  }
3326 
3327  if (slitGeo == NULL) {
3328  return NULL;
3329  }
3330 
3331  if (grat_params == NULL) {
3332  return NULL;
3333  }
3334 
3335  if (opt_mod_params == NULL) {
3336  return NULL;
3337  }
3338 
3339  wlengths = cpl_matrix_new(binPrms.size, 1);
3340  pd_wlengths = cpl_matrix_get_data(wlengths);
3341 
3342  temp_params = cpl_matrix_new(lmrq_opt_mod_x.nparams, 1);
3343 
3344  pd_temp_params = cpl_matrix_get_data(temp_params);
3345  pd_opt_mod_params = cpl_matrix_get_data(opt_mod_params);
3346  pd_grat_params = cpl_matrix_get_data(grat_params);
3347 
3348  pd_temp_params[OG_NX] = pd_opt_mod_params[O_NX];
3349  pd_temp_params[OG_PXSIZ] = pd_opt_mod_params[O_PXSIZ];
3350  pd_temp_params[OG_FCOLL] = pd_opt_mod_params[O_FCOLL];
3351  pd_temp_params[OG_CFACT] = pd_opt_mod_params[O_CFACT];
3352  pd_temp_params[OG_THETA] = pd_grat_params[G_THETA];
3353  pd_temp_params[OG_ORDER] = pd_grat_params[G_ORDER];
3354  pd_temp_params[OG_SPACE] = pd_grat_params[G_SPACE];
3355 
3356  if (lmrq_opt_mod_x.nparams > OG_SOFFX) {
3357  pd_temp_params[OG_SOFFX] = pd_opt_mod_params[O_SOFFX];
3358  pd_temp_params[OG_SOFFY] = pd_opt_mod_params[O_SOFFY];
3359  pd_temp_params[OG_SPHI] = pd_opt_mod_params[O_SPHI];
3360  }
3361 
3362  /*************************************************************************
3363  Processing
3364  *************************************************************************/
3365 
3366  /*
3367  * Compute lambda abcissa for rebinning
3368  */
3369 
3370  if (binPrms.log==TRUE) {
3371  /* lambda was specified in log(lambda) */
3372  cxint i;
3373  for (i = 0; i < binPrms.size; i++) {
3374  pd_wlengths[i] = exp(binPrms.min + (cxdouble) i * binPrms.step);
3375  }
3376  } else {
3377  cxint i;
3378  for (i = 0; i < binPrms.size; i++) {
3379  pd_wlengths[i] = binPrms.min + (cxdouble) i * binPrms.step;
3380  }
3381  }
3382 
3383  abcissa = _giraffe_compute_pixel_abscissa(wlengths, wloffsets,
3384  fiber_slit_position,
3385  temp_params, lmrq_opt_mod_x);
3386 
3387 
3388  /*
3389  * If X residuals use, specified, calculate them and subtract
3390  * them from the computed abcissa...
3391  */
3392 
3393  if ((binPrms.xres==TRUE) && (xresiduals_coeff!=NULL)) {
3394 
3395  x_residuals_img =
3396  giraffe_rebin_compute_pixel_x_residuals(
3397  locPos,
3398  abcissa,
3399  slitGeo,
3400  xresiduals_limits,
3401  xresiduals_coeff
3402  );
3403 
3404  cpl_image_subtract(abcissa, x_residuals_img);
3405  cpl_image_delete(x_residuals_img);
3406 
3407  }
3408 
3409  cpl_matrix_delete(wlengths);
3410  cpl_matrix_delete(temp_params);
3411 
3412  cpl_msg_debug(fctid, "Processing complete : returning image "
3413  "[%" CPL_SIZE_FORMAT ", %" CPL_SIZE_FORMAT "]",
3414  cpl_image_get_size_x(abcissa), cpl_image_get_size_y(abcissa));
3415 
3416  return abcissa;
3417 
3418 } /* end giraffe_rebin_compute_rebin_abcissa() */
3419 
3447 inline static cxint
3448 _giraffe_resample_spectra(GiRebinning* result,
3449  const GiExtraction* extraction,
3450  const GiLocalization* localization,
3451  GiFiberPosition* fiber_position,
3452  GiSlitGeo* subslits,
3453  GiSlitGeo* xres_limits,
3454  GiSlitGeo* xres_coeff,
3455  GiBinnParams* xres_order,
3456  cpl_matrix* grating_data,
3457  cpl_matrix* optical_model,
3458  cpl_matrix* wlen_offsets,
3459  cxdouble rbstep,
3460  GiRebinMethod method,
3461  GiRebinRange range,
3462  GiRebinScale scale)
3463 {
3464 
3465  const cxchar* const fctid = "_giraffe_resample_spectra";
3466 
3467 
3468  cxbool log_scale = FALSE;
3469 
3470  cxint i = 0;
3471  cxint status = 0;
3472  cxint om_sign = 0;
3473  cxint rbsize = 0;
3474  cxint nspectra = 0;
3475 
3476  cxdouble wlmin = 0.;
3477  cxdouble wlmax = 0.;
3478  cxdouble* _optical_model = NULL;
3479 
3480  cpl_matrix* wavelengths = NULL;
3481 
3482  cpl_image* _exspectra = NULL;
3483  cpl_image* _exerrors = NULL;
3484  cpl_image* _rbspectra = NULL;
3485  cpl_image* _rberrors = NULL;
3486  cpl_image* abscissa = NULL;
3487 
3488  cpl_propertylist* properties = NULL;
3489 
3490  GiImage* rbspectra = NULL;
3491  GiImage* rberrors = NULL;
3492 
3493  GiLocPosition locPos;
3494 
3495  GiRebinParams binPrms;
3496 
3497  GiRebinInfo setup;
3498 
3499 
3500  /*
3501  * default opt model is xoptmod2, python code
3502  * can not handle anything else anyway
3503  */
3504 
3505  lmrq_model_id opt_mod_id = LMRQ_XOPTMOD2;
3506 
3507 
3508  if (result == NULL || extraction == NULL || localization == NULL) {
3509  return 1;
3510  }
3511 
3512  if (result->spectra != NULL || result->errors != NULL) {
3513  return 1;
3514  }
3515 
3516  if (extraction->spectra == NULL) {
3517  return 1;
3518  }
3519 
3520  if (localization->locy == NULL || localization->locw == NULL) {
3521  return 1;
3522  }
3523 
3524  if (fiber_position == NULL) {
3525  return 1;
3526  }
3527 
3528  if (subslits == NULL) {
3529  return 1;
3530  }
3531 
3532  if (grating_data == NULL) {
3533  return 1;
3534  }
3535 
3536  if (optical_model == NULL) {
3537  return 1;
3538  }
3539 
3540 
3541  if (xres_coeff != NULL) {
3542  if (xres_limits == NULL || xres_order == NULL) {
3543  return 1;
3544  }
3545  }
3546 
3547 
3548  /*
3549  * FIXME: Should we set opt_mod_id to opt_mod_id used by wave
3550  * calibration? Yes!!!
3551  */
3552 
3553  _exspectra = giraffe_image_get(extraction->spectra);
3554 
3555  if (extraction->error != NULL) {
3556  _exerrors = giraffe_image_get(extraction->error);
3557  }
3558 
3559  _optical_model = cpl_matrix_get_data(optical_model);
3560 
3561  nspectra = cpl_image_get_size_x(_exspectra);
3562 
3563  om_sign = (_optical_model[O_NX] >= 0) ? 1 : -1;
3564 
3565  if (scale == GIREBIN_SCALE_LOG) {
3566  log_scale = TRUE;
3567  }
3568 
3569 
3570  /*
3571  * Find wavelength range
3572  */
3573 
3574  if (range == GIREBIN_RANGE_SETUP) {
3575 
3576  /*
3577  * Wavelength range taken from observed mode
3578  */
3579 
3580  wlmin = cpl_matrix_get(grating_data, 2, 0);
3581  wlmax = cpl_matrix_get(grating_data, 4, 0);
3582 
3583  if (log_scale == TRUE) {
3584  wlmin = log(wlmin);
3585  wlmax = log(wlmax);
3586  }
3587 
3588  }
3589  else {
3590 
3591  /*
3592  * Spectral range based on max/min wavelengths
3593  */
3594 
3595  status = giraffe_rebin_compute_lambda_range(fiber_position,
3596  optical_model,
3597  grating_data, log_scale,
3598  TRUE, &wlmin, &wlmax);
3599 
3600  }
3601 
3602  rbsize = 1 + (cxint) ((wlmax - wlmin) / rbstep);
3603 
3604  if (rbsize < 0) {
3605 
3606  cpl_msg_debug(fctid, "Invalid dispersion direction [%d], changing "
3607  "optical model orientation", om_sign);
3608 
3609  om_sign = -om_sign;
3610  _optical_model[O_NX] = -_optical_model[O_NX];
3611 
3612  status = giraffe_rebin_compute_lambda_range(fiber_position,
3613  optical_model,
3614  grating_data, log_scale,
3615  TRUE, &wlmin, &wlmax);
3616 
3617  rbsize = 1 + (cxint) ((wlmax - wlmin) / rbstep);
3618 
3619  }
3620 
3621  if (rbsize < 1) {
3622  cpl_msg_error(fctid, "Invalid size %d of rebinned spectra, "
3623  "aborting...", rbsize);
3624  return 2;
3625  }
3626 
3627 
3628  /*
3629  * Calculate rebinned X positions...
3630  */
3631 
3632  locPos.type = GILOCDATATYPE_FITTED_DATA;
3633  locPos.centroids = giraffe_image_get(localization->locy);
3634  locPos.widths = giraffe_image_get(localization->locw);
3635 
3636  binPrms.min = wlmin;
3637  binPrms.step = rbstep;
3638  binPrms.size = rbsize;
3639  binPrms.log = log_scale;
3640 
3641  if (xres_coeff == NULL || (xres_order->xdeg == 0 &&
3642  xres_order->ydeg == 0)) {
3643  binPrms.xres = FALSE;
3644  }
3645  else {
3646  binPrms.xres = TRUE;
3647  }
3648 
3649  abscissa = giraffe_rebin_compute_rebin_abcissa(fiber_position, &locPos,
3650  subslits, xres_limits,
3651  xres_coeff, grating_data,
3652  optical_model, wlen_offsets,
3653  lmrq_models[opt_mod_id],
3654  binPrms);
3655 
3656 
3657  /*
3658  * Perform rebinng of spectra and associated errors...
3659  */
3660 
3661  wavelengths = cpl_matrix_new(rbsize, 1);
3662 
3663  for (i = 0; i < rbsize; i++) {
3664  cpl_matrix_set(wavelengths, i, 0, wlmin + (cxdouble) i * rbstep);
3665  }
3666 
3667  rbspectra = giraffe_image_create(CPL_TYPE_DOUBLE, nspectra, rbsize);
3668  _rbspectra = giraffe_image_get(rbspectra);
3669 
3670  if (_exerrors != NULL) {
3671  rberrors = giraffe_image_create(CPL_TYPE_DOUBLE, nspectra, rbsize);
3672  _rberrors = giraffe_image_get(rberrors);
3673  }
3674 
3675  switch (method) {
3676  case GIREBIN_METHOD_LINEAR:
3677  status = _giraffe_resample_linear(_rbspectra, _rberrors, abscissa,
3678  _exspectra, _exerrors, om_sign);
3679  break;
3680 
3681  case GIREBIN_METHOD_SPLINE:
3682  status = _giraffe_resample_spline(_rbspectra, _rberrors, abscissa,
3683  _exspectra, _exerrors, om_sign);
3684  break;
3685 
3686  default:
3687 
3688  /* We should never get to this point! */
3689 
3690  gi_error("Invalid rebinning method!");
3691  break;
3692  }
3693 
3694  cpl_image_delete(abscissa);
3695  abscissa = NULL;
3696 
3697  if (status != 0) {
3698  cpl_msg_error(fctid, "Error during rebinning, aborting...");
3699 
3700  cpl_matrix_delete(wavelengths);
3701  wavelengths = NULL;
3702 
3703  giraffe_image_delete(rbspectra);
3704  rbspectra = NULL;
3705 
3706  if (rberrors != NULL) {
3707  giraffe_image_delete(rberrors);
3708  rberrors = NULL;
3709  }
3710 
3711  return 3;
3712  }
3713 
3714 
3715 
3716  /*
3717  * Add calculated image, keywords etc. to rebinned spectrum frame...
3718  */
3719 
3720  switch (scale) {
3721  case GIREBIN_SCALE_LOG:
3722  {
3723  cxsize nw = cpl_matrix_get_nrow(wavelengths);
3724 
3725  cxdouble mm2nm = log(GI_MM_TO_NM);
3726 
3727  setup.wmin = mm2nm + cpl_matrix_get(wavelengths, 0, 0);
3728  setup.wcenter = mm2nm + cpl_matrix_get(wavelengths, nw / 2, 0);
3729  setup.wmax = mm2nm + cpl_matrix_get(wavelengths, nw - 1, 0);
3730  setup.wstep = rbstep;
3731 
3732  setup.units = "log(nm)";
3733  setup.offset = 0;
3734  }
3735  break;
3736 
3737  case GIREBIN_SCALE_LINEAR:
3738  {
3739  cxsize nw = cpl_matrix_get_nrow(wavelengths);
3740 
3741  setup.wmin = GI_MM_TO_NM * cpl_matrix_get(wavelengths, 0, 0);
3742  setup.wcenter = GI_MM_TO_NM * cpl_matrix_get(wavelengths,
3743  nw / 2, 0);
3744  setup.wmax = GI_MM_TO_NM * cpl_matrix_get(wavelengths,
3745  nw - 1, 0);
3746  setup.wstep = GI_MM_TO_NM * rbstep;
3747 
3748  setup.units = "nm";
3749  setup.offset = 0;
3750  }
3751  break;
3752 
3753  default:
3754 
3755  /* We should never get here */
3756 
3757  gi_error("Invalid scaling option!");
3758  break;
3759  }
3760 
3761  cpl_matrix_delete(wavelengths);
3762  wavelengths = NULL;
3763 
3764 
3765  switch (method) {
3766  case GIREBIN_METHOD_LINEAR:
3767  setup.method = "linear";
3768  break;
3769 
3770  case GIREBIN_METHOD_SPLINE:
3771  setup.method = "spline";
3772  break;
3773 
3774  default:
3775 
3776  /* We should never get here */
3777 
3778  gi_error("Invalid rebinning method!");
3779  break;
3780  }
3781 
3782 
3783  switch (scale) {
3784  case GIREBIN_SCALE_LINEAR:
3785  setup.scale = "linear";
3786  break;
3787 
3788  case GIREBIN_SCALE_LOG:
3789  setup.scale = "logarithmic";
3790  break;
3791 
3792  default:
3793 
3794  /* We should never get here */
3795 
3796  gi_error("Invalid scaling option!");
3797  break;
3798  }
3799 
3800  switch (range) {
3801  case GIREBIN_RANGE_SETUP:
3802  setup.range = "setup";
3803  break;
3804 
3805  case GIREBIN_RANGE_COMMON:
3806  setup.range = "common";
3807  break;
3808 
3809  default:
3810 
3811  /* We should never get here */
3812 
3813  gi_error("Invalid range option!");
3814  break;
3815  }
3816 
3817 
3818  /*
3819  * Finalize resampled spectra
3820  */
3821 
3822  giraffe_error_push();
3823 
3824  properties = giraffe_image_get_properties(extraction->spectra);
3825  giraffe_image_set_properties(rbspectra, properties);
3826 
3827  if (cpl_error_get_code() != CPL_ERROR_NONE) {
3828  giraffe_image_delete(rbspectra);
3829  rbspectra = NULL;
3830 
3831  if (rberrors != NULL) {
3832  giraffe_image_delete(rberrors);
3833  rberrors = NULL;
3834  }
3835 
3836  return 4;
3837  }
3838 
3839  giraffe_error_pop();
3840 
3841  status = _giraffe_resample_update_properties(rbspectra, &setup);
3842 
3843  if (status != 0) {
3844  giraffe_image_delete(rbspectra);
3845  rbspectra = NULL;
3846 
3847  if (rberrors != NULL) {
3848  giraffe_image_delete(rberrors);
3849  rberrors = NULL;
3850  }
3851 
3852  return 4;
3853  }
3854 
3855 
3856  /*
3857  * Finalize resampled spectra errors if they are available
3858  */
3859 
3860  if (_rberrors != NULL) {
3861 
3862  giraffe_error_push();
3863 
3864  properties = giraffe_image_get_properties(extraction->error);
3865  giraffe_image_set_properties(rberrors, properties);
3866 
3867  if (cpl_error_get_code() != CPL_ERROR_NONE) {
3868  giraffe_image_delete(rbspectra);
3869  rbspectra = NULL;
3870 
3871  if (rberrors != NULL) {
3872  giraffe_image_delete(rberrors);
3873  rberrors = NULL;
3874  }
3875 
3876  return 5;
3877  }
3878 
3879  giraffe_error_pop();
3880 
3881  status = _giraffe_resample_update_properties(rberrors, &setup);
3882 
3883  if (status != 0) {
3884  giraffe_image_delete(rbspectra);
3885  rbspectra = NULL;
3886 
3887  if (rberrors != NULL) {
3888  giraffe_image_delete(rberrors);
3889  rberrors = NULL;
3890  }
3891 
3892  return 5;
3893  }
3894 
3895  }
3896 
3897  result->spectra = rbspectra;
3898  result->errors = rberrors;
3899 
3900  return 0;
3901 
3902 }
3903 
3904 
3912 GiRange *
3913 giraffe_rebin_get_wavelength_range(GiImage *spectra, GiTable *wlsolution,
3914  GiTable *grating, GiTable *slitgeometry,
3915  cxbool common)
3916 {
3917 
3918  cxint status = 0;
3919 
3920  cxdouble min = 0.;
3921  cxdouble max = 0.;
3922 
3923  cpl_matrix *optical_model = NULL;
3924  cpl_matrix *grating_data = NULL;
3925 
3926  GiFiberPosition *positions = NULL;
3927  GiSlitGeo *subslits = NULL;
3928 
3929  GiWcalSolution *wcal = NULL;
3930 
3931  GiRange *range = NULL;
3932 
3933 
3934  if (spectra == NULL) {
3935  return NULL;
3936  }
3937 
3938  if (grating == NULL) {
3939  return NULL;
3940  }
3941 
3942  if (slitgeometry == NULL) {
3943  return NULL;
3944  }
3945 
3946 
3947  wcal = _giraffe_wcalsolution_create(wlsolution);
3948 
3949  if (wcal == NULL) {
3950  return NULL;
3951  }
3952 
3953  optical_model = _giraffe_rebin_setup_model(spectra, wcal);
3954 
3955  if (optical_model == NULL) {
3956  _giraffe_wcalsolution_delete(wcal);
3957  return NULL;
3958  }
3959 
3960  _giraffe_wcalsolution_delete(wcal);
3961 
3962  grating_data = _giraffe_rebin_setup_grating(spectra, grating,
3963  wlsolution);
3964 
3965  if (grating_data == NULL) {
3966 
3967  cpl_matrix_delete(grating_data);
3968  cpl_matrix_delete(optical_model);
3969 
3970  return NULL;
3971 
3972  }
3973 
3974  positions = _giraffe_fiberposition_new();
3975  subslits = _giraffe_slitgeo_new();
3976 
3977  status = _giraffe_slitgeo_setup(slitgeometry, positions, subslits,
3978  FALSE);
3979 
3980  if (status != 0) {
3981 
3982  _giraffe_slitgeo_delete(subslits);
3983  _giraffe_fiberposition_delete(positions);
3984 
3985  cpl_matrix_delete(grating_data);
3986  cpl_matrix_delete(optical_model);
3987 
3988  return NULL;
3989 
3990  }
3991 
3992  status = giraffe_rebin_compute_lambda_range(positions, optical_model,
3993  grating_data,
3994  GIREBIN_SCALE_LINEAR,
3995  common, &min, &max);
3996 
3997  /*
3998  * Convert wavelength from millimeters to nanometers.
3999  */
4000 
4001  min *= GI_MM_TO_NM;
4002  max *= GI_MM_TO_NM;
4003 
4004  _giraffe_slitgeo_delete(subslits);
4005  _giraffe_fiberposition_delete(positions);
4006 
4007  cpl_matrix_delete(grating_data);
4008  cpl_matrix_delete(optical_model);
4009 
4010  range = giraffe_range_create(min, max);
4011 
4012  return range;
4013 
4014 }
4015 
4016 
4050 cxint
4051 giraffe_rebin_spectra(GiRebinning *rebinning,
4052  const GiExtraction *extraction,
4053  const GiTable *fibers,
4054  const GiLocalization *localization,
4055  const GiTable *grating,
4056  const GiTable *slitgeo,
4057  const GiTable *solution,
4058  const GiRebinConfig *config)
4059 {
4060 
4061  const cxchar* const fctid = "giraffe_rebin_spectra";
4062 
4063 
4064  cxint status = 0;
4065  cxint ex_sp_extr_pixels = 0;
4066  cxint calc_rebinned_size = 0;
4067  cxint default_rebinned_size = GIREBIN_SIZE_Y_DEFAULT;
4068 
4069  cxdouble rbin_multiplier = 0.;
4070  cxdouble ex_sp_pixsize_x = 0.;
4071  cxdouble rbin_stepsize = 0.;
4072 
4073  cpl_matrix* grat_params = NULL;
4074  cpl_matrix* opt_mod_params = NULL;
4075  cpl_matrix* wloffsets = NULL;
4076 
4077  cpl_table* _fibers = NULL;
4078 
4079  cpl_propertylist* _pl_ext_sp = NULL;
4080  cpl_propertylist* _pl_wsol = NULL;
4081 
4082  GiImage* ex_sp_frame = NULL;
4083  /*GiImage* ex_sp_err_frame = NULL;*/
4084  /*GiImage* loc_y_frame = NULL;*/
4085  /*GiImage* loc_w_frame = NULL;*/
4086 
4087  GiSlitGeo* subslit_fibers = NULL;
4088  GiSlitGeo* wav_coeffs = NULL;
4089  GiSlitGeo* wav_limits = NULL;
4090 
4091  GiGrat* grating_data = NULL;
4092 
4093  GiFiberPosition* fiber_slit_position = NULL;
4094 
4095  GiWcalSolution* wcalib_solution = NULL;
4096 
4097  GiBinnParams xres_polynom_deg = {0, 0};
4098 
4099 
4100 
4101  /*
4102  * Preprocessing
4103  */
4104 
4105  if (extraction == NULL) {
4106  cpl_msg_error(fctid, "No extracted data, aborting...");
4107  return 1;
4108  }
4109 
4110  if (extraction->spectra == NULL) {
4111  cpl_msg_error(fctid, "No extracted spectra, aborting...");
4112  return 1;
4113  }
4114 
4115  if (fibers == NULL) {
4116  cpl_msg_error(fctid, "No fiber table, aborting ...");
4117  return 1;
4118  }
4119 
4120  if (localization == NULL) {
4121  cpl_msg_error(fctid, "No localization data, aborting...");
4122  return 1;
4123  }
4124 
4125  if (localization->locy == NULL) {
4126  cpl_msg_error(fctid, "No localization centroids, aborting...");
4127  return 1;
4128  }
4129 
4130  if (localization->locw == NULL) {
4131  cpl_msg_error(fctid, "No localization widths, aborting...");
4132  return 1;
4133  }
4134 
4135  if (grating == NULL) {
4136  cpl_msg_error(fctid, "No grating data, aborting...");
4137  return 1;
4138  }
4139 
4140  if (rebinning == NULL) {
4141  cpl_msg_error(fctid, "No rebinning results container, aborting...");
4142  return 1;
4143  }
4144 
4145  if (config == NULL) {
4146  cpl_msg_error(fctid, "No rebinning configuration data, aborting...");
4147  return 1;
4148  }
4149 
4150  if (solution == NULL) {
4151  cpl_msg_error(fctid, "No wavecalibration solution, aborting...");
4152  return 1;
4153  }
4154 
4155  ex_sp_frame = extraction->spectra;
4156  /*ex_sp_err_frame = extraction->error;*/
4157  /*loc_y_frame = localization->locy;*/
4158  /*loc_w_frame = localization->locw;*/
4159 
4160  _pl_ext_sp = giraffe_image_get_properties(ex_sp_frame);
4161  _pl_wsol = giraffe_table_get_properties(solution);
4162 
4163 
4164  _fibers = giraffe_table_get(fibers);
4165  cx_assert(_fibers != NULL);
4166 
4167 
4168 
4169  /*
4170  * Initialization
4171  */
4172 
4173  /*
4174  * Retrieve necessary values from FITS keywords
4175  */
4176 
4177  if (cpl_propertylist_has(_pl_ext_sp, GIALIAS_PIXSIZX) == TRUE) {
4178  ex_sp_pixsize_x = cpl_propertylist_get_double(_pl_ext_sp,
4179  GIALIAS_PIXSIZX);
4180 
4181  }
4182  else {
4183  cpl_msg_error(fctid, "%s Keyword missing in Extracted Spectra "
4184  "Frame, aborting ...", GIALIAS_PIXSIZX);
4185  return 2;
4186  }
4187 
4188 
4189  /*
4190  * Convert pixel size to microns
4191  */
4192 
4193  if (ex_sp_pixsize_x > 1.) {
4194  ex_sp_pixsize_x /= 1000.;
4195  }
4196 
4197 
4198  /*
4199  * Determine rebinning step size multiplier
4200  */
4201 
4202  if (cpl_propertylist_has(_pl_ext_sp, GIALIAS_GRATNAME) == TRUE) {
4203 
4204  const cxchar* _string = NULL;
4205 
4206  _string = cpl_propertylist_get_string(_pl_ext_sp, GIALIAS_GRATNAME);
4207 
4208  if (strncmp(_string, "LR", 2) == 0) {
4209  rbin_multiplier = 4.;
4210  }
4211  else if (strncmp(_string, "HR", 2) == 0) {
4212  rbin_multiplier = 1.;
4213  }
4214  else {
4215  rbin_multiplier = 1.;
4216  }
4217 
4218  }
4219  else {
4220  cpl_msg_error(fctid, "%s Keyword missing in Extracted Spectra Frame, "
4221  "aborting ...", GIALIAS_GRATNAME);
4222  return 2;
4223  }
4224 
4225 
4226  /*
4227  * find number of pixel per spectrum
4228  */
4229 
4230  if (cpl_propertylist_has(_pl_ext_sp, GIALIAS_EXT_NX) == TRUE) {
4231  ex_sp_extr_pixels = cpl_propertylist_get_int(_pl_ext_sp,
4232  GIALIAS_EXT_NX);
4233 
4234  }
4235  else {
4236  cpl_msg_error(fctid, "%s Keyword missing in Extracted Spectra Frame, "
4237  "aborting ...", GIALIAS_EXT_NX);
4238  return 2;
4239  }
4240 
4241 
4242  /*
4243  * Retrieve Grating information
4244  */
4245 
4246  grating_data = _giraffe_grating_new();
4247 
4248  status = _giraffe_grating_setup(grating, ex_sp_frame, grating_data);
4249 
4250  if (status != 0) {
4251  cpl_msg_error(fctid, "Unable to retrieve grating information, "
4252  "aborting...");
4253  _giraffe_grating_delete(grating_data);
4254  return 3;
4255  }
4256 
4257  /*
4258  * Retrieve Slit Geometry Information
4259  */
4260 
4261  fiber_slit_position = _giraffe_fiberposition_new();
4262  subslit_fibers = _giraffe_slitgeo_new();
4263 
4264  status = _giraffe_slitgeo_setup(slitgeo, fiber_slit_position,
4265  subslit_fibers, FALSE);
4266 
4267  if (status != 0) {
4268  cpl_msg_error(fctid, "Unable to retrieve slit geometry information, "
4269  "aborting...");
4270  _giraffe_grating_delete(grating_data);
4271  _giraffe_fiberposition_delete(fiber_slit_position);
4272  _giraffe_slitgeo_delete(subslit_fibers);
4273  return 7;
4274  }
4275 
4276 
4277  wcalib_solution = _giraffe_wcalsolution_create(solution);
4278 
4279  if (wcalib_solution == NULL) {
4280  cpl_msg_error(fctid, "Cannot create wavelength solution, "
4281  "aborting ...");
4282  _giraffe_grating_delete(grating_data);
4283  _giraffe_fiberposition_delete(fiber_slit_position);
4284  _giraffe_slitgeo_delete(subslit_fibers);
4285  return 4;
4286  }
4287 
4288  if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMFCOLL) == TRUE) {
4289  grating_data->fcoll =
4290  cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMFCOLL);
4291  }
4292 
4293  if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMGCAM) == TRUE) {
4294  grating_data->gcam =
4295  cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMGCAM);
4296  }
4297 
4298  if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMGTHETA) == TRUE) {
4299  grating_data->theta =
4300  cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMGTHETA);
4301  }
4302 
4303  if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMSDX) == TRUE) {
4304  grating_data->slitdx =
4305  cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMSDX);
4306  }
4307 
4308  if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMSDY) == TRUE) {
4309  grating_data->slitdy =
4310  cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMSDY);
4311  }
4312 
4313  if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMSPHI) == TRUE) {
4314  grating_data->slitphi =
4315  cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMSPHI);
4316  }
4317 
4318 
4319  /*
4320  * If wavelength corrections were provided, convert the wavelength
4321  * offsets from nanometers to millimeters and store them as a
4322  * matrix (nfibers x 1).
4323  */
4324 
4325  if (cpl_table_has_column(_fibers, "WLRES") != 0) {
4326 
4327  cxint fiber = 0;
4328  cxint nfibers = cpl_table_get_nrow(_fibers);
4329 
4330 
4331  wloffsets = cpl_matrix_new(nfibers, 1);
4332 
4333  for (fiber = 0; fiber < nfibers; ++fiber) {
4334 
4335  cxdouble wloffset = cpl_table_get_double(_fibers, "WLRES",
4336  fiber, NULL);
4337 
4338 
4339  wloffset *= -GI_NM_TO_MM;
4340  cpl_matrix_set(wloffsets, fiber, 0, wloffset);
4341 
4342  }
4343 
4344  cpl_msg_info(fctid, "Applying SIMCAL wavelength corrections ...");
4345 
4346  }
4347 
4348 
4349 
4350  /*
4351  * Processing
4352  */
4353 
4354 
4355  /*
4356  * Determine rebinning stepsize and size in y direction after rebinning
4357  */
4358 
4359  if (config->scmethod == GIREBIN_SCALE_LOG) {
4360 
4361  cxint rebin_size;
4362 
4363  cxdouble wlenmax;
4364  cxdouble wlenmin;
4365 
4366  rebin_size = default_rebinned_size;
4367 
4368  wlenmin = log(grating_data->wlenmin / GI_MM_TO_NM);
4369  wlenmax = log(grating_data->wlenmax / GI_MM_TO_NM);
4370 
4371  if ((config->size != rebin_size) && (config->size != 0)) {
4372  rebin_size = config->size;
4373  }
4374 
4375  rbin_stepsize = (wlenmax - wlenmin) / rebin_size;
4376 
4377  calc_rebinned_size = 1 + (cxint) ((wlenmax-wlenmin)/ rbin_stepsize);
4378 
4379  }
4380  else {
4381 
4382  cxint rebin_size;
4383 
4384  cxdouble wlenmax;
4385  cxdouble wlenmin;
4386 
4387  wlenmin = grating_data->wlenmin / GI_MM_TO_NM;
4388  wlenmax = grating_data->wlenmax / GI_MM_TO_NM;
4389 
4390  rbin_stepsize = (config->lstep / GI_MM_TO_NM) * rbin_multiplier;
4391  rebin_size = (wlenmax - wlenmin) / rbin_stepsize;
4392 
4393  if ((config->size != rebin_size) && (config->size != 0)) {
4394  rebin_size = config->size;
4395  rbin_stepsize = (wlenmax - wlenmin) / rebin_size;
4396  }
4397 
4398  calc_rebinned_size = 1 + (cxint) ((wlenmax-wlenmin) / rbin_stepsize);
4399 
4400  }
4401 
4402  /*
4403  * Retrieve Wavecalibration Solution Physical Optical Paramters
4404  */
4405 
4406  if (wcalib_solution!=NULL) {
4407 
4408  if (wcalib_solution->opt_mod==LMRQ_XOPTMOD) {
4409 
4410  cxint nrow;
4411  cxdouble opt_direction, fcoll, cfact;
4412 
4413  nrow = cpl_matrix_get_nrow(wcalib_solution->opt_mod_params);
4414  if (nrow==4) {
4415  opt_direction =
4416  cpl_matrix_get(wcalib_solution->opt_mod_params, 0, 0);
4417  fcoll =
4418  cpl_matrix_get(wcalib_solution->opt_mod_params, 1, 0);
4419  cfact =
4420  cpl_matrix_get(wcalib_solution->opt_mod_params, 2, 0);
4421 
4422  opt_mod_params = cpl_matrix_new(4,1);
4423  cpl_matrix_set(opt_mod_params, 0, 0,
4424  ex_sp_extr_pixels * opt_direction);
4425  cpl_matrix_set(opt_mod_params, 1, 0, ex_sp_pixsize_x);
4426  cpl_matrix_set(opt_mod_params, 2, 0, fcoll);
4427  cpl_matrix_set(opt_mod_params, 3, 0, cfact);
4428  }
4429  else {
4430  cpl_msg_error(fctid, "Invalid number of physical optical "
4431  "parameters, aborting...");
4432 
4433  if (wloffsets != NULL) {
4434  cpl_matrix_delete(wloffsets);
4435  }
4436 
4437  _giraffe_wcalsolution_delete(wcalib_solution);
4438  _giraffe_grating_delete(grating_data);
4439  _giraffe_fiberposition_delete(fiber_slit_position);
4440  _giraffe_slitgeo_delete(subslit_fibers);
4441  return 6;
4442  }
4443 
4444  }
4445  else if (wcalib_solution->opt_mod==LMRQ_XOPTMOD2) {
4446 
4447  cxint nrow;
4448  cxdouble opt_direction, fcoll, cfact, /*gtheta,*/ slitdx,
4449  slitdy, slitphi;
4450 
4451  nrow = cpl_matrix_get_nrow(wcalib_solution->opt_mod_params);
4452  if (nrow==7) {
4453  opt_direction =
4454  cpl_matrix_get(wcalib_solution->opt_mod_params, 0, 0);
4455  fcoll =
4456  cpl_matrix_get(wcalib_solution->opt_mod_params, 1, 0);
4457  cfact =
4458  cpl_matrix_get(wcalib_solution->opt_mod_params, 2, 0);
4459  /*gtheta =
4460  cpl_matrix_get(wcalib_solution->opt_mod_params, 3, 0);*/
4461  slitdx =
4462  cpl_matrix_get(wcalib_solution->opt_mod_params, 4, 0);
4463  slitdy =
4464  cpl_matrix_get(wcalib_solution->opt_mod_params, 5, 0);
4465  slitphi =
4466  cpl_matrix_get(wcalib_solution->opt_mod_params, 6, 0);
4467 
4468  opt_mod_params = cpl_matrix_new(7,1);
4469  cpl_matrix_set(opt_mod_params, 0, 0,
4470  ex_sp_extr_pixels * opt_direction);
4471  cpl_matrix_set(opt_mod_params, 1, 0, ex_sp_pixsize_x);
4472  cpl_matrix_set(opt_mod_params, 2, 0, fcoll);
4473  cpl_matrix_set(opt_mod_params, 3, 0, cfact);
4474  cpl_matrix_set(opt_mod_params, 4, 0, slitdx);
4475  cpl_matrix_set(opt_mod_params, 5, 0, slitdy);
4476  cpl_matrix_set(opt_mod_params, 6, 0, slitphi);
4477 
4478  }
4479  else {
4480  cpl_msg_error(fctid, "Invalid number of physical optical "
4481  "parameters, aborting...");
4482 
4483  if (wloffsets != NULL) {
4484  cpl_matrix_delete(wloffsets);
4485  }
4486 
4487  _giraffe_wcalsolution_delete(wcalib_solution);
4488  _giraffe_grating_delete(grating_data);
4489  _giraffe_fiberposition_delete(fiber_slit_position);
4490  _giraffe_slitgeo_delete(subslit_fibers);
4491  return 6;
4492  }
4493 
4494  }
4495  else {
4496  cpl_msg_error(fctid, "Invalid optical model, aborting...");
4497 
4498  if (wloffsets != NULL) {
4499  cpl_matrix_delete(wloffsets);
4500  }
4501 
4502  _giraffe_wcalsolution_delete(wcalib_solution);
4503  _giraffe_grating_delete(grating_data);
4504  _giraffe_fiberposition_delete(fiber_slit_position);
4505  _giraffe_slitgeo_delete(subslit_fibers);
4506  return 5;
4507  }
4508 
4509 
4510  if (wcalib_solution->wav_coeffs != NULL) {
4511 
4512  GiSlitGeo* coeffs = wcalib_solution->wav_coeffs;
4513 
4514  xres_polynom_deg.xdeg =
4515  cpl_matrix_get_nrow(_giraffe_slitgeo_get(coeffs, 0));
4516  xres_polynom_deg.ydeg =
4517  cpl_matrix_get_ncol(_giraffe_slitgeo_get(coeffs, 0));
4518  }
4519 
4520  }
4521  else {
4522  cpl_msg_error(fctid, "No Wavelength Calibration solution found, "
4523  "aborting...");
4524 
4525  if (wloffsets != NULL) {
4526  cpl_matrix_delete(wloffsets);
4527  }
4528 
4529  _giraffe_wcalsolution_delete(wcalib_solution);
4530  _giraffe_grating_delete(grating_data);
4531  _giraffe_fiberposition_delete(fiber_slit_position);
4532  _giraffe_slitgeo_delete(subslit_fibers);
4533  return 4;
4534  }
4535 
4536  if (config->xresiduals==FALSE) {
4537  xres_polynom_deg.xdeg = 0;
4538  xres_polynom_deg.ydeg = 0;
4539  }
4540 
4541  if (wcalib_solution->wav_coeffs!=NULL) {
4542  wav_coeffs = wcalib_solution->wav_coeffs;
4543  }
4544 
4545  if (wcalib_solution->wav_limits!=NULL) {
4546  wav_limits = wcalib_solution->wav_limits;
4547  }
4548 
4549 
4550  /*
4551  * Setup Rebinning grating parameters
4552  */
4553 
4554  grat_params = cpl_matrix_new(7,1);
4555 
4556  cpl_matrix_set(grat_params, 0, 0, grating_data->theta);
4557  cpl_matrix_set(grat_params, 1, 0, grating_data->order);
4558  cpl_matrix_set(grat_params, 2, 0, grating_data->wlenmin / GI_MM_TO_NM);
4559  cpl_matrix_set(grat_params, 3, 0, grating_data->wlen0 / GI_MM_TO_NM);
4560  cpl_matrix_set(grat_params, 4, 0, grating_data->wlenmax / GI_MM_TO_NM);
4561  cpl_matrix_set(grat_params, 5, 0, grating_data->resol);
4562  cpl_matrix_set(grat_params, 6, 0, grating_data->space );
4563 
4564 
4565  /*
4566  * Give user some feedback...
4567  */
4568 
4569  cpl_msg_info(fctid, "Performing Rebinning of spectra, stepsize=%.4f "
4570  "[nm], resulting image size=%d, using x residuals : %s",
4571  rbin_stepsize * GI_MM_TO_NM, calc_rebinned_size,
4572  config->xresiduals ? "Yes" : "No");
4573 
4574 
4575  switch (config->rmethod) {
4576  case GIREBIN_METHOD_LINEAR:
4577  cpl_msg_info(fctid, "Rebinning method : linear");
4578  break;
4579 
4580  case GIREBIN_METHOD_SPLINE:
4581  cpl_msg_info(fctid, "Rebinning method : spline");
4582  break;
4583 
4584  default:
4585  cpl_msg_info(fctid, "Rebinning method : undefined");
4586  break;
4587  }
4588 
4589  switch (config->scmethod) {
4590  case GIREBIN_SCALE_LOG:
4591  cpl_msg_info(fctid, "Scaling method : logarithmic, "
4592  "log(wavelength [nm]): min,max,range = %.3f, %.3f, %.3f",
4593  log(grating_data->wlenmin),
4594  log(grating_data->wlenmax),
4595  log(grating_data->wlenmax) -
4596  log(grating_data->wlenmin));
4597  break;
4598 
4599  case GIREBIN_SCALE_LINEAR:
4600  cpl_msg_info(fctid, "Scaling method : linear, wavelength [nm]: "
4601  "min,max,range = %.3f, %.3f, %.3f",
4602  grating_data->wlenmin,
4603  grating_data->wlenmax,
4604  grating_data->wlenmax - grating_data->wlenmin);
4605  break;
4606 
4607  default:
4608  cpl_msg_info(fctid, "Scaling method : undefined");
4609  break;
4610  }
4611 
4612  switch (config->range) {
4613  case GIREBIN_RANGE_SETUP:
4614  cpl_msg_info(fctid, "Wavelength range : Setup");
4615  break;
4616 
4617  case GIREBIN_RANGE_COMMON:
4618  cpl_msg_info(fctid, "Wavelength range : Common");
4619  break;
4620 
4621  default:
4622  cpl_msg_info(fctid, "Wavelength range : undefined");
4623  break;
4624  }
4625 
4626 
4627  /*
4628  * Resample the spectra to the wavelength grid
4629  */
4630 
4631  status = _giraffe_resample_spectra(rebinning, extraction,
4632  localization, fiber_slit_position,
4633  subslit_fibers, wav_limits,
4634  wav_coeffs, &xres_polynom_deg,
4635  grat_params, opt_mod_params,
4636  wloffsets, rbin_stepsize,
4637  config->rmethod, config->range,
4638  config->scmethod);
4639 
4640  if (status != 0) {
4641 
4642  if (wloffsets != NULL) {
4643  cpl_matrix_delete(wloffsets);
4644  }
4645 
4646  cpl_matrix_delete(opt_mod_params);
4647  cpl_matrix_delete(grat_params);
4648 
4649  _giraffe_wcalsolution_delete(wcalib_solution);
4650  _giraffe_grating_delete(grating_data);
4651  _giraffe_fiberposition_delete(fiber_slit_position);
4652  _giraffe_slitgeo_delete(subslit_fibers);
4653 
4654  return 8;
4655 
4656  }
4657 
4658 
4659  /*
4660  * Cleanup...
4661  */
4662 
4663  if (wloffsets != NULL) {
4664  cpl_matrix_delete(wloffsets);
4665  }
4666 
4667  cpl_matrix_delete(opt_mod_params);
4668  cpl_matrix_delete(grat_params);
4669 
4670  _giraffe_wcalsolution_delete(wcalib_solution);
4671  _giraffe_grating_delete(grating_data);
4672  _giraffe_fiberposition_delete(fiber_slit_position);
4673  _giraffe_slitgeo_delete(subslit_fibers);
4674 
4675  return 0;
4676 
4677 } /* end giraffe_rebin_spectra() */
4678 
4679 
4692 GiRebinning*
4694 {
4695 
4696  GiRebinning *rebinn = cx_malloc(sizeof(GiRebinning));
4697 
4698  rebinn->spectra = NULL;
4699  rebinn->errors = NULL;
4700 
4701  return rebinn;
4702 
4703 }
4704 
4721 GiRebinning*
4722 giraffe_rebinning_create(GiImage *spectra, GiImage *errors)
4723 {
4724 
4725  GiRebinning *rebin = giraffe_rebinning_new();
4726 
4727  if (spectra) {
4728  rebin->spectra = spectra;
4729  }
4730 
4731  if (errors) {
4732  rebin->errors = errors;
4733  }
4734 
4735  return rebin;
4736 
4737 }
4738 
4739 
4758 void
4759 giraffe_rebinning_delete(GiRebinning *rebinning)
4760 {
4761 
4762  if (rebinning) {
4763  cx_free(rebinning);
4764  }
4765 
4766  return;
4767 
4768 }
4769 
4770 
4786 void
4787 giraffe_rebinning_destroy(GiRebinning *rebinning)
4788 {
4789 
4790  if (rebinning) {
4791 
4792  if (rebinning->spectra) {
4793  giraffe_image_delete(rebinning->spectra);
4794  rebinning->spectra = NULL;
4795  }
4796 
4797  if (rebinning->errors) {
4798  giraffe_image_delete(rebinning->errors);
4799  rebinning->errors = NULL;
4800  }
4801 
4802  cx_free(rebinning);
4803  }
4804 
4805  return;
4806 
4807 }
4808 
4809 
4824 GiRebinConfig *
4825 giraffe_rebin_config_create(cpl_parameterlist *list)
4826 {
4827 
4828  const cxchar *fctid = "giraffe_rebin_config_create";
4829 
4830  const cxchar *s;
4831 
4832  cpl_parameter *p;
4833 
4834  GiRebinConfig *config = NULL;
4835 
4836 
4837  if (!list) {
4838  return NULL;
4839  }
4840 
4841  config = cx_calloc(1, sizeof *config);
4842 
4843 
4844  config->rmethod = GIREBIN_METHOD_UNDEFINED;
4845  config->xresiduals = FALSE;
4846  config->lstep = 0.0;
4847  config->scmethod = GIREBIN_SCALE_UNDEFINED;
4848  config->size = 0;
4849  config->range = GIREBIN_RANGE_UNDEFINED;
4850 
4851 
4852  p = cpl_parameterlist_find(list, "giraffe.rebinning.method");
4853  s = cpl_parameter_get_string(p);
4854  if (strcmp(s, "linear")==0) {
4855  config->rmethod = GIREBIN_METHOD_LINEAR;
4856  } else if (strcmp(s, "spline")==0) {
4857  config->rmethod = GIREBIN_METHOD_SPLINE;
4858  }
4859 
4860  p = cpl_parameterlist_find(list, "giraffe.rebinning.xresiduals");
4861  config->xresiduals = cpl_parameter_get_bool(p);
4862 
4863  p = cpl_parameterlist_find(list, "giraffe.rebinning.lstep");
4864  config->lstep = cpl_parameter_get_double(p);
4865 
4866  p = cpl_parameterlist_find(list, "giraffe.rebinning.scalemethod");
4867  s = cpl_parameter_get_string(p);
4868  if (strcmp(s, "log")==0) {
4869  config->scmethod = GIREBIN_SCALE_LOG;
4870  } else if (strcmp(s, "linear")==0) {
4871  config->scmethod = GIREBIN_SCALE_LINEAR;
4872  }
4873 
4874  p = cpl_parameterlist_find(list, "giraffe.rebinning.size");
4875  config->size = cpl_parameter_get_int(p);
4876 
4877  p = cpl_parameterlist_find(list, "giraffe.rebinning.range");
4878  s = cpl_parameter_get_string(p);
4879  if (strcmp(s, "setup")==0) {
4880  config->range = GIREBIN_RANGE_SETUP;
4881  } else if (strcmp(s, "common")==0) {
4882  config->range = GIREBIN_RANGE_COMMON;
4883  }
4884 
4885  /* Validate */
4886 
4887  if (config->rmethod==GIREBIN_METHOD_UNDEFINED) {
4888  cpl_msg_info(fctid, "Invalid Rebinning method, aborting");
4889  cx_free(config);
4890  return NULL;
4891  }
4892 
4893  if (config->scmethod==GIREBIN_SCALE_UNDEFINED) {
4894  cpl_msg_info(fctid, "Invalid Rebinning scaling method, aborting");
4895  cx_free(config);
4896  return NULL;
4897  }
4898 
4899  if (config->range==GIREBIN_RANGE_UNDEFINED) {
4900  cpl_msg_info(fctid, "Invalid Rebinning range, aborting");
4901  cx_free(config);
4902  return NULL;
4903  }
4904 
4905  return config;
4906 
4907 }
4908 
4909 
4924 void
4925 giraffe_rebin_config_destroy(GiRebinConfig *config)
4926 {
4927 
4928  if (config) {
4929  cx_free(config);
4930  }
4931 
4932  return;
4933 
4934 }
4935 
4948 void
4949 giraffe_rebin_config_add(cpl_parameterlist *list)
4950 {
4951 
4952  cpl_parameter *p;
4953 
4954  if (!list) {
4955  return;
4956  }
4957 
4958  p = cpl_parameter_new_enum("giraffe.rebinning.method",
4959  CPL_TYPE_STRING,
4960  "Method to use : `linear' or `spline'",
4961  "giraffe.rebinning.method",
4962  "linear", 2, "linear", "spline");
4963  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-method");
4964  cpl_parameterlist_append(list, p);
4965 
4966  p = cpl_parameter_new_value("giraffe.rebinning.xresiduals",
4967  CPL_TYPE_BOOL,
4968  "Use x residuals during rebinning? `true'/"
4969  "`false'",
4970  "giraffe.rebinning.xresiduals",
4971  TRUE);
4972  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-xresid");
4973  cpl_parameterlist_append(list, p);
4974 
4975  p = cpl_parameter_new_value("giraffe.rebinning.lstep",
4976  CPL_TYPE_DOUBLE,
4977  "Lambda step size, only used if "
4978  "scaling method is 'linear'",
4979  "giraffe.rebinning.lstep",
4980  0.005);
4981  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-lstep");
4982  cpl_parameterlist_append(list, p);
4983 
4984  p = cpl_parameter_new_enum("giraffe.rebinning.scalemethod",
4985  CPL_TYPE_STRING,
4986  "Scaling method: `log' or `linear'",
4987  "giraffe.rebinning.scalemethod",
4988  "linear", 2, "linear", "log");
4989  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-scmethod");
4990  cpl_parameterlist_append(list, p);
4991 
4992  p = cpl_parameter_new_value("giraffe.rebinning.size",
4993  CPL_TYPE_INT,
4994  "Size of output rebinned spectra, 0 means "
4995  "calculate size based on wavelength range "
4996  "and lambda stepsize",
4997  "giraffe.rebinning.size",
4998  0);
4999  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-size");
5000  cpl_parameterlist_append(list, p);
5001 
5002  p = cpl_parameter_new_enum("giraffe.rebinning.range",
5003  CPL_TYPE_STRING,
5004  "Rebinning range: `setup' or `common'",
5005  "giraffe.rebinning.scalemethod",
5006  "setup", 2, "setup", "common");
5007  cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-range");
5008  cpl_parameterlist_append(list, p);
5009 
5010  return;
5011 
5012 }
const cxchar * giraffe_fiberlist_query_index(const cpl_table *fibers)
Query a fiber list for the name of the fiber reference index column.
void giraffe_image_delete(GiImage *self)
Destroys an image.
Definition: giimage.c:181
cpl_propertylist * giraffe_image_get_properties(const GiImage *self)
Get the properties of an image.
Definition: giimage.c:282
cpl_image * giraffe_image_get(const GiImage *self)
Gets the image data.
Definition: giimage.c:218
GiImage * giraffe_image_create(cpl_type type, cxint nx, cxint ny)
Creates an image container of a given type.
Definition: giimage.c:95
cxint giraffe_image_set_properties(GiImage *self, cpl_propertylist *properties)
Attaches a property list to an image.
Definition: giimage.c:312
cxint giraffe_matrix_sort(cpl_matrix *mA)
Sort in place the matrix elements in ascending order.
Definition: gimatrix.c:380
void gi_error(const cxchar *format,...)
Log an error message.
Definition: gimessages.c:59
GiRange * giraffe_range_create(cxdouble min, cxdouble max)
Creates a new range from the given minimum and maximum values.
Definition: girange.c:83
void giraffe_rebin_config_destroy(GiRebinConfig *config)
Destroys a spectrum extraction setup structure.
Definition: girebinning.c:4925
cxint giraffe_rebin_spectra(GiRebinning *rebinning, const GiExtraction *extraction, const GiTable *fibers, const GiLocalization *localization, const GiTable *grating, const GiTable *slitgeo, const GiTable *solution, const GiRebinConfig *config)
Rebin an Extracted Spectra Frame and associated Errors Frame.
Definition: girebinning.c:4051
void giraffe_rebinning_delete(GiRebinning *rebinning)
Destroys a rebinning results container.
Definition: girebinning.c:4759
void giraffe_rebinning_destroy(GiRebinning *rebinning)
Destroys a rebinning results container and its contents.
Definition: girebinning.c:4787
GiRebinning * giraffe_rebinning_new(void)
Create an empty rebinning results container.
Definition: girebinning.c:4693
GiRebinConfig * giraffe_rebin_config_create(cpl_parameterlist *list)
Creates a setup structure for the rebinning.
Definition: girebinning.c:4825
GiRebinning * giraffe_rebinning_create(GiImage *spectra, GiImage *errors)
Fills a rebinning results container.
Definition: girebinning.c:4722
void giraffe_rebin_config_add(cpl_parameterlist *list)
Adds parameters for the rebinning.
Definition: girebinning.c:4949
GiLocDataType
Definition: girebinning.c:60
@ GILOCDATATYPE_UNDEFINED
@ GILOCDATATYPE_FIT_COEFFS
@ GILOCDATATYPE_FITTED_DATA
GiRange * giraffe_rebin_get_wavelength_range(GiImage *spectra, GiTable *wlsolution, GiTable *grating, GiTable *slitgeometry, cxbool common)
Compute the wavelenght range of spectra.
Definition: girebinning.c:3913
cpl_propertylist * giraffe_table_get_properties(const GiTable *self)
Gets the table properties.
Definition: gitable.c:489
cpl_table * giraffe_table_get(const GiTable *self)
Get the table data from a Giraffe table.
Definition: gitable.c:433
GiInstrumentMode giraffe_get_mode(cpl_propertylist *properties)
Determines the instrument mode from a property list.
Definition: giutils.c:440
struct definition to handle model functions
Definition: gimath_lm.h:138
fitted_func cfunc
Definition: gimath_lm.h:140
cxint ninputs
Definition: gimath_lm.h:142
cxint nparams
Definition: gimath_lm.h:141

This file is part of the GIRAFFE Pipeline Reference Manual 2.16.10.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Thu Dec 15 2022 21:18:51 by doxygen 1.9.1 written by Dimitri van Heesch, © 1997-2004