GIRAFFE Pipeline Reference Manual

girebinning.c

00001 /* $Id: girebinning.c,v 1.46 2011/12/23 13:41:08 rpalsa Exp $
00002  *
00003  * This file is part of the GIRAFFE Pipeline
00004  * Copyright (C) 2002-2006 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 /*
00022  * $Author: rpalsa $
00023  * $Date: 2011/12/23 13:41:08 $
00024  * $Revision: 1.46 $
00025  * $Name: giraffe-2_9 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #  include <config.h>
00030 #endif
00031 
00032 #include <math.h>
00033 
00034 #include <cxmacros.h>
00035 #include <cxtypes.h>
00036 #include <cxmemory.h>
00037 
00038 #include <cpl_parameter.h>
00039 #include <cpl_parameterlist.h>
00040 #include <cpl_image.h>
00041 #include <cpl_msg.h>
00042 
00043 #include "gimacros.h"
00044 #include "gidebug.h"
00045 #include "gierror.h"
00046 #include "gialias.h"
00047 #include "gimatrix.h"
00048 #include "gimessages.h"
00049 #include "gimath.h"
00050 #include "gimath_lm.h"
00051 #include "gifiberutils.h"
00052 #include "giutils.h"
00053 #include "girebinning.h"
00054 
00055 
00064 #define GIFITS_KEYWORD_MISSING_MSG "FITS KEYWORD [%s] not found!! Aborting..."
00065 #define GIWAVECAL_GRATING_WAVELENGTH_EPSILON 0.0001
00066 
00067 
00068 enum GiLocDataType {
00069     GILOCDATATYPE_UNDEFINED,
00070     GILOCDATATYPE_FITTED_DATA,
00071     GILOCDATATYPE_FIT_COEFFS
00072 };
00073 
00074 typedef enum GiLocDataType GiLocDataType;
00075 
00076 
00077 struct GiGrat {
00078     cx_string *name;         
00079     cx_string *filter_name;  
00080     cx_string *setup_name;   
00081     cx_string *slit_name;    
00082     cxint      order;        
00083     cxdouble   wlen0;        
00084     cxdouble   wlenmin;      
00085     cxdouble   wlenmax;      
00086     cxdouble   band;         
00087     cxdouble   resol;        
00088     cxdouble   space;        
00089     cxdouble   theta;        
00090     cxdouble   fcoll;        
00091     cxdouble   gcam;         
00092     cxdouble   slitdx;       
00093     cxdouble   slitdy;       
00094     cxdouble   slitphi;      
00095 };
00096 
00097 typedef struct GiGrat GiGrat;
00098 
00099 
00100 struct GiFiberPosition {
00101     cpl_matrix *x_fiber;   
00102     cpl_matrix *y_fiber;   
00103 };
00104 
00105 typedef struct GiFiberPosition GiFiberPosition;
00106 
00107 
00108 struct GiLocPosition {
00109     cxint           ydeg;
00110     cxint           wdeg;
00111     GiLocDataType   type;
00112     cpl_image      *centroids;
00113     cpl_image      *widths;
00114 };
00115 
00116 typedef struct GiLocPosition GiLocPosition;
00117 
00118 
00119 struct GiBinnParams {
00120     cxint  xdeg;     
00121     cxint  ydeg;     
00122 };
00123 
00124 typedef struct GiBinnParams GiBinnParams;
00125 
00126 
00127 struct GiSlitGeo {
00128     cxint        nsubslits;
00129     cpl_matrix **subslits;
00130 };
00131 
00132 typedef struct GiSlitGeo GiSlitGeo;
00133 
00134 struct GiWcalSolution {
00135     cxbool subslitfit;
00136     lmrq_model_id opt_mod;
00137     cpl_matrix *opt_mod_params;
00138     GiSlitGeo *wav_coeffs;
00139     GiSlitGeo *wav_limits;
00140 };
00141 
00142 typedef struct GiWcalSolution GiWcalSolution;
00143 
00144 
00145 struct GiRebinInfo {
00146     const cxchar* method;
00147     const cxchar* scale;
00148     const cxchar* range;
00149     const cxchar* units;
00150 
00151     cxdouble wmin;
00152     cxdouble wcenter;
00153     cxdouble wmax;
00154     cxdouble wstep;
00155 
00156     cxint offset;
00157 
00158 };
00159 
00160 typedef struct GiRebinInfo GiRebinInfo;
00161 
00162 
00163 /*
00164  *  Static vars for spline interpolation...
00165  */
00166 
00167 static cxdouble ddb, dde;
00168 
00169 
00170 inline static cxint
00171 _giraffe_resample_update_properties(GiImage* spectra, GiRebinInfo* info)
00172 {
00173 
00174     cpl_image* image = giraffe_image_get(spectra);
00175 
00176     cpl_propertylist* properties = giraffe_image_get_properties(spectra);
00177 
00178 
00179     giraffe_error_push();
00180 
00181     cpl_propertylist_update_double(properties, GIALIAS_DATAMIN,
00182                                    cpl_image_get_min(image));
00183     cpl_propertylist_update_double(properties, GIALIAS_DATAMAX,
00184                                    cpl_image_get_max(image));
00185 
00186     cpl_propertylist_update_string(properties, GIALIAS_GIRFTYPE,
00187                                    "BINSP");
00188 
00189     cpl_propertylist_update_int(properties, GIALIAS_BINWNX,
00190                                 cpl_image_get_size_y(image));
00191     cpl_propertylist_update_int(properties, GIALIAS_BINWNS,
00192                                 cpl_image_get_size_x(image));
00193 
00194     cpl_propertylist_update_string(properties, GIALIAS_CTYPE2,
00195                                    info->units);
00196     cpl_propertylist_update_double(properties, GIALIAS_CRPIX2,
00197                                    info->offset + 1);
00198     cpl_propertylist_update_double(properties, GIALIAS_CRVAL2,
00199                                    info->wmin);
00200     cpl_propertylist_update_double(properties, GIALIAS_CDELT2,
00201                                    info->wstep);
00202 
00203     cpl_propertylist_update_double(properties, GIALIAS_BINWLMIN,
00204                                    info->wmin);
00205     cpl_propertylist_update_double(properties, GIALIAS_BINWL0,
00206                                    info->wcenter);
00207     cpl_propertylist_update_double(properties, GIALIAS_BINWLMAX,
00208                                    info->wmax);
00209     cpl_propertylist_update_double(properties, GIALIAS_BINSTEP,
00210                                    info->wstep);
00211     cpl_propertylist_update_string(properties, GIALIAS_BINMETHOD,
00212                                    info->method);
00213     cpl_propertylist_update_string(properties, GIALIAS_BINSCALE,
00214                                    info->scale);
00215     cpl_propertylist_update_string(properties, GIALIAS_BINRANGE,
00216                                    info->range);
00217 
00218     if (cpl_error_get_code() != CPL_ERROR_NONE) {
00219         return 1;
00220     }
00221 
00222     giraffe_error_pop();
00223 
00224     return 0;
00225 
00226 }
00227 
00228 
00229 static GiGrat*
00230 _giraffe_grating_new(void)
00231 {
00232 
00233     GiGrat *grating = NULL;
00234 
00235     grating = (GiGrat*) cx_calloc(1, (cxsize)sizeof(GiGrat));
00236 
00237     grating->name        = cx_string_create("UNKNOWN");
00238     grating->filter_name = cx_string_create("UNKNOWN");
00239     grating->setup_name  = cx_string_create("UNKNOWN");
00240     grating->slit_name   = cx_string_create("UNKNOWN");
00241 
00242     return grating;
00243 
00244 }
00245 
00246 
00247 static void
00248 _giraffe_grating_delete(GiGrat *grating)
00249 {
00250 
00251     if (grating==NULL) { return; }
00252 
00253     if (grating->name!=NULL) {
00254         cx_string_delete(grating->name);
00255     }
00256     if (grating->filter_name!=NULL) {
00257         cx_string_delete(grating->filter_name);
00258     }
00259     if (grating->setup_name!=NULL) {
00260         cx_string_delete(grating->setup_name);
00261     }
00262     if (grating->slit_name!=NULL) {
00263         cx_string_delete(grating->slit_name);
00264     }
00265     cx_free(grating);
00266 
00267 }
00268 
00269 
00270 static cxint
00271 _giraffe_grating_setup(const GiTable *grating_table,
00272                        const GiImage *grating_ass_img, GiGrat *grating_setup)
00273 {
00274 
00275     /*************************************************************************
00276                                      Variables
00277     *************************************************************************/
00278 
00279     const cxchar *fctid = "_giraffe_grating_setup";
00280 
00281     cxdouble    wlen_match    = 0.0,
00282         wlen          = 0.0,
00283         tmp_gratgrv   = 0.0;
00284 
00285     cxint32     row_match     = 0,
00286         row_nulls,
00287         i             = 0;
00288 
00289     const cxchar *c_name_setup  = "SETUP";
00290     const cxchar *c_name_order  = "ORDER";
00291     const cxchar *c_name_wl0    = "WLEN0";
00292     const cxchar *c_name_wlmin  = "WLMIN";
00293     const cxchar *c_name_wlmax  = "WLMAX";
00294     const cxchar *c_name_band   = "BAND";
00295     const cxchar *c_name_theta  = "THETA";
00296     const cxchar *c_name_fcoll  = "FCOLL";
00297     const cxchar *c_name_gcam   = "GCAM";
00298     const cxchar *c_name_sdx    = "SDX";
00299     const cxchar *c_name_sdy    = "SDY";
00300     const cxchar *c_name_sdphi  = "SPHI";
00301     const cxchar *c_name_rmed   = "RMED";
00302     const cxchar *c_name_rifa   = "RIFA";
00303 
00304     cpl_propertylist  *ref_plimg     = NULL;
00305     cpl_table  *ref_gtable    = NULL;
00306     cx_string  *slit_name     = NULL;
00307 
00308     GiInstrumentMode  instrument_mode;
00309 
00310 
00311     /*************************************************************************
00312                                     Preprocessing
00313     *************************************************************************/
00314 
00315     if (grating_table  ==NULL) { return 1; }
00316     if (grating_ass_img==NULL) { return 1; }
00317     if (grating_setup  ==NULL) { return 1; }
00318 
00319     if ((ref_plimg=giraffe_image_get_properties(grating_ass_img))==NULL) {
00320         return 128;
00321     }
00322 
00323     if ((ref_gtable = giraffe_table_get(grating_table))==NULL) {
00324         return 128;
00325     }
00326 
00327     slit_name = cx_string_new();
00328 
00329     /*************************************************************************
00330                                      Processing
00331     *************************************************************************/
00332 
00333     /*
00334      *  Retrieve Grating information from associated image...
00335      */
00336 
00337     if (!cpl_propertylist_has(ref_plimg, GIALIAS_GRATWLEN)) {
00338         cpl_msg_error(fctid, GIFITS_KEYWORD_MISSING_MSG, GIALIAS_GRATWLEN);
00339         cx_string_delete(slit_name);
00340         return 2;
00341     }
00342     else {
00343         grating_setup->wlen0 = cpl_propertylist_get_double(ref_plimg,
00344                                                            GIALIAS_GRATWLEN);
00345     }
00346 
00347     if (!cpl_propertylist_has(ref_plimg, GIALIAS_GRATORDER)) {
00348         cpl_msg_error(fctid, GIFITS_KEYWORD_MISSING_MSG, GIALIAS_GRATORDER);
00349         cx_string_delete(slit_name);
00350         return 2;
00351     }
00352     else {
00353         grating_setup->order = cpl_propertylist_get_int(ref_plimg, GIALIAS_GRATORDER);
00354     }
00355 
00356     if (!cpl_propertylist_has(ref_plimg, GIALIAS_SLITNAME)) {
00357 
00358         cpl_msg_error(fctid, GIFITS_KEYWORD_MISSING_MSG, GIALIAS_SLITNAME);
00359         cx_string_delete(slit_name);
00360         return 2;
00361     } else {
00362         cx_string_set(slit_name,
00363                       cpl_propertylist_get_string(ref_plimg, GIALIAS_SLITNAME));
00364     }
00365 
00366     if (!cpl_propertylist_has(ref_plimg, GIALIAS_GRATGRV)) {
00367 
00368         cpl_msg_error(fctid, GIFITS_KEYWORD_MISSING_MSG, GIALIAS_GRATGRV);
00369         cx_string_delete(slit_name);
00370         return 2;
00371     } else {
00372         tmp_gratgrv = cpl_propertylist_get_double(ref_plimg, GIALIAS_GRATGRV );
00373     }
00374 
00375     if (!cpl_propertylist_has(ref_plimg, GIALIAS_GRATNAME)) {
00376         cpl_msg_error(fctid, GIFITS_KEYWORD_MISSING_MSG, GIALIAS_GRATNAME);
00377         cx_string_delete(slit_name);
00378         return 2;
00379     } else {
00380         cx_string_set(grating_setup->name,
00381                       cpl_propertylist_get_string(ref_plimg, GIALIAS_GRATNAME));
00382     }
00383 
00384     if (!cpl_propertylist_has(ref_plimg, GIALIAS_FILTNAME)) {
00385         cpl_msg_error(fctid, GIFITS_KEYWORD_MISSING_MSG, GIALIAS_FILTNAME);
00386         cx_string_delete(slit_name);
00387         return 2;
00388     }
00389     else {
00390         cx_string_set(grating_setup->filter_name,
00391                       cpl_propertylist_get_string(ref_plimg, GIALIAS_FILTNAME));
00392     }
00393 
00394 
00395     /*
00396      *  Find wavelength nearest to central wavelength...
00397      */
00398 
00399     for (i = 0; i < cpl_table_get_nrow(ref_gtable); i++) {
00400 
00401         cxint _order = cpl_table_get_int(ref_gtable, c_name_order, i, NULL);
00402 
00403         if (_order == grating_setup->order) {
00404 
00405             wlen = cpl_table_get(ref_gtable, c_name_wl0, i, &row_nulls);
00406 
00407             if (fabs(wlen - grating_setup->wlen0) <
00408                 fabs(wlen_match - grating_setup->wlen0)) {
00409                 wlen_match = wlen;
00410                 row_match  = i;
00411             }
00412 
00413         }
00414     }
00415 
00416 
00417     /*
00418      *  Have we found a match?...
00419      */
00420 
00421     if (fabs(wlen_match - grating_setup->wlen0) >
00422         GIWAVECAL_GRATING_WAVELENGTH_EPSILON) {
00423 
00424         cpl_msg_error(fctid, "Grating setup (wavelength %.2f nm, order %d) "
00425                       "not found in grating table!", grating_setup->wlen0,
00426                       grating_setup->order);
00427         cx_string_delete(slit_name);
00428         return 3;
00429     }
00430     else {
00431         cpl_msg_debug(fctid, "Found wlen0 in grating table at position %d",
00432                       row_match);
00433     }
00434 
00435 
00436     /*
00437      *  Retrieve values associated to matched wavelength from grating table...
00438      */
00439 
00440     cx_string_set(grating_setup->setup_name,
00441                   (cxchar*) cpl_table_get_string(ref_gtable, c_name_setup,
00442                                                  row_match));
00443 
00444     cx_string_set(grating_setup->slit_name, cx_string_get(slit_name));
00445 
00446     grating_setup->wlenmin = cpl_table_get(ref_gtable, c_name_wlmin,
00447                                            row_match, &row_nulls);
00448 
00449     grating_setup->wlenmax = cpl_table_get(ref_gtable, c_name_wlmax,
00450                                            row_match, &row_nulls);
00451 
00452     grating_setup->band = cpl_table_get(ref_gtable, c_name_band,
00453                                         row_match, &row_nulls);
00454 
00455     grating_setup->theta = cpl_table_get(ref_gtable, c_name_theta,
00456                                          row_match, &row_nulls);
00457 
00458     grating_setup->space = 1.0 / fabs(GI_MM_TO_NM * tmp_gratgrv);
00459 
00460 
00461     instrument_mode = giraffe_get_mode(ref_plimg);
00462 
00463     switch (instrument_mode) {
00464         case GIMODE_MEDUSA:
00465             grating_setup->resol = cpl_table_get(ref_gtable, c_name_rmed,
00466                                                  row_match, &row_nulls);
00467             break;
00468 
00469         case GIMODE_IFU:
00470             grating_setup->resol = cpl_table_get(ref_gtable, c_name_rifa,
00471                                                  row_match, &row_nulls);
00472             break;
00473 
00474         case GIMODE_ARGUS:
00475             grating_setup->resol = cpl_table_get(ref_gtable, c_name_rifa,
00476                                                  row_match, &row_nulls);
00477             break;
00478 
00479         default:
00480             grating_setup->resol = -1.0;
00481             break;
00482     }
00483 
00484     grating_setup->fcoll   =
00485         cpl_table_get(ref_gtable, c_name_fcoll, row_match, &row_nulls);
00486 
00487     grating_setup->gcam    =
00488         cpl_table_get(ref_gtable, c_name_gcam,  row_match, &row_nulls);
00489 
00490     grating_setup->slitdx  =
00491         cpl_table_get(ref_gtable, c_name_sdx,   row_match, &row_nulls);
00492 
00493     grating_setup->slitdy  =
00494         cpl_table_get(ref_gtable, c_name_sdy,   row_match, &row_nulls);
00495 
00496     grating_setup->slitphi =
00497         cpl_table_get(ref_gtable, c_name_sdphi, row_match, &row_nulls);
00498 
00499     cx_string_delete(slit_name);
00500 
00501     return 0;
00502 
00503 }
00504 
00505 
00506 static GiFiberPosition*
00507 _giraffe_fiberposition_new(void)
00508 {
00509 
00510     GiFiberPosition* tmp = NULL;
00511 
00512     tmp = (GiFiberPosition*) cx_calloc(1, sizeof(GiFiberPosition));
00513 
00514     tmp->x_fiber = NULL;
00515     tmp->y_fiber = NULL;
00516 
00517     return tmp;
00518 }
00519 
00520 
00521 static void
00522 _giraffe_fiberposition_delete(GiFiberPosition *fp)
00523 {
00524 
00525     if (fp != NULL) {
00526 
00527         if (fp->x_fiber) {
00528             cpl_matrix_delete(fp->x_fiber);
00529         }
00530 
00531         if (fp->y_fiber) {
00532             cpl_matrix_delete(fp->y_fiber);
00533         }
00534 
00535         cx_free(fp);
00536 
00537     }
00538 
00539     return;
00540 
00541 }
00542 
00543 
00544 static GiSlitGeo*
00545 _giraffe_slitgeo_new(void)
00546 {
00547 
00548     GiSlitGeo *sgeometry = NULL;
00549 
00550     sgeometry = cx_malloc(sizeof(GiSlitGeo));
00551 
00552     sgeometry->subslits = NULL;
00553     sgeometry->nsubslits = 0;
00554 
00555     return sgeometry;
00556 
00557 }
00558 
00559 
00560 static void
00561 _giraffe_slitgeo_delete(GiSlitGeo *sgeometry)
00562 {
00563 
00564     if (sgeometry != NULL) {
00565 
00566         if (sgeometry->subslits != NULL) {
00567 
00568             cxint i;
00569 
00570             for (i = 0; i < sgeometry->nsubslits; i++) {
00571                 cpl_matrix_delete(sgeometry->subslits[i]);
00572             }
00573 
00574             cx_free(sgeometry->subslits);
00575         }
00576 
00577         cx_free(sgeometry);
00578 
00579     }
00580 
00581     return;
00582 
00583 }
00584 
00585 
00586 static cxint
00587 _giraffe_slitgeo_size(GiSlitGeo *sgeometry)
00588 {
00589 
00590     if (sgeometry == NULL) {
00591         return -1;
00592     }
00593 
00594     if (sgeometry->subslits != NULL) {
00595         return sgeometry->nsubslits;
00596     }
00597 
00598     return -1;
00599 
00600 }
00601 
00602 
00603 static void
00604 _giraffe_slitgeo_resize(GiSlitGeo *sgeometry, cxint size)
00605 {
00606 
00607     if (sgeometry == NULL) {
00608         return;
00609     }
00610 
00611     if (size == sgeometry->nsubslits) {
00612         return;
00613     }
00614 
00615     if (sgeometry->subslits != NULL) {
00616 
00617         cxint i;
00618 
00619         for (i = 0; i < sgeometry->nsubslits; i++) {
00620             cpl_matrix_delete(sgeometry->subslits[i]);
00621         }
00622     }
00623 
00624     cx_free(sgeometry->subslits);
00625 
00626     sgeometry->nsubslits = size;
00627     sgeometry->subslits = cx_calloc(sgeometry->nsubslits, sizeof(cpl_matrix*));
00628 
00629     return;
00630 
00631 }
00632 
00633 
00634 static void
00635 _giraffe_slitgeo_create(GiSlitGeo *sgeometry, cxint idx, cxint nrow,
00636                         cxint ncol)
00637 {
00638 
00639     if (sgeometry == NULL) {
00640         return;
00641     }
00642 
00643     if (sgeometry->subslits == NULL) {
00644         return;
00645     }
00646 
00647     if ((idx < 0) || (idx > sgeometry->nsubslits)) {
00648         return;
00649     }
00650 
00651     if (sgeometry->subslits[idx] != NULL) {
00652         cpl_matrix_delete(sgeometry->subslits[idx]);
00653     }
00654 
00655     sgeometry->subslits[idx] = cpl_matrix_new(nrow, ncol);
00656 
00657     return;
00658 
00659 }
00660 
00661 
00662 static void
00663 _giraffe_slitgeo_set(GiSlitGeo *sgeometry, cxint idx, cpl_matrix *nm)
00664 {
00665 
00666     if (sgeometry == NULL) {
00667         return;
00668     }
00669 
00670     if (sgeometry->subslits == NULL) {
00671         return;
00672     }
00673 
00674     if ((idx < 0) || (idx > sgeometry->nsubslits)) {
00675         return;
00676     }
00677 
00678     if (sgeometry->subslits[idx] != NULL) {
00679         cpl_matrix_delete(sgeometry->subslits[idx]);
00680     }
00681 
00682     if (nm) {
00683         sgeometry->subslits[idx] = cpl_matrix_duplicate(nm);
00684     }
00685     else {
00686         sgeometry->subslits[idx] = NULL;
00687     }
00688 
00689 }
00690 
00691 
00692 static cpl_matrix*
00693 _giraffe_slitgeo_get(GiSlitGeo *sgeometry, cxint idx)
00694 {
00695 
00696     if (sgeometry == NULL) {
00697         return NULL;
00698     }
00699 
00700     if (sgeometry->subslits == NULL) {
00701         return NULL;
00702     }
00703 
00704     if ((idx < 0)||(idx > sgeometry->nsubslits)) {
00705         return NULL;
00706     }
00707 
00708     return (sgeometry->subslits[idx]);
00709 
00710 }
00711 
00712 
00713 static cxint
00714 _giraffe_slitgeo_setup(const GiTable *slitgeo,
00715                        GiFiberPosition *fiber_slit_position,
00716                        GiSlitGeo *subslits, cxbool fitsubslit)
00717 {
00718 
00719     const cxchar *const fctid = "_giraffe_slitgeo_setup";
00720 
00721 
00722     const cxchar *c_name_xf     = "XF";
00723     const cxchar *c_name_yf     = "YF";
00724     const cxchar *c_name_nspec  = "FPS";
00725     const cxchar *c_name_ssn    = "SSN";
00726 
00727 
00728     cpl_matrix *nspec = NULL;
00729     cpl_matrix *nsubslits = NULL;
00730 
00731     cxint       nr_slitgeo    = 0,
00732         max_nsubslits = 0,
00733         i             = 0,
00734         j             = 0,
00735         row_null      = 0,
00736         count         = 0,
00737         column_index  = 0,
00738         tmp_nspec     = 0,
00739         tmp_nsubslits = 0;
00740 
00741     cxdouble    tmp_xf,
00742         tmp_yf;
00743 
00744     cpl_table  *ref_slitgeo   = NULL;
00745 
00746     cpl_error_code ce_code;
00747 
00748 
00749     /*************************************************************************
00750                                     Preprocessing
00751     *************************************************************************/
00752 
00753     if (slitgeo            ==NULL) { return 1; }
00754     if (fiber_slit_position==NULL) { return 1; }
00755     if (subslits           ==NULL) { return 1; }
00756 
00757     /*************************************************************************
00758                                      Processing
00759     *************************************************************************/
00760 
00761     ref_slitgeo = giraffe_table_get(slitgeo);
00762     nr_slitgeo  = cpl_table_get_nrow(ref_slitgeo);
00763 
00764     fiber_slit_position->x_fiber = cpl_matrix_new(nr_slitgeo, 1);
00765     fiber_slit_position->y_fiber = cpl_matrix_new(nr_slitgeo, 1);
00766 
00767     nspec     = cpl_matrix_new(nr_slitgeo, 1);
00768     nsubslits = cpl_matrix_new(nr_slitgeo, 1);
00769 
00770     /*
00771      *  Copy relevant data to matrices
00772      */
00773 
00774     max_nsubslits = 0;
00775 
00776     for (i = 0; i < nr_slitgeo; i++) {
00777 
00778         tmp_xf = cpl_table_get(ref_slitgeo, c_name_xf, i, &row_null);
00779         tmp_yf = cpl_table_get(ref_slitgeo, c_name_yf, i, &row_null);
00780 
00781         tmp_nspec = cpl_table_get_int(ref_slitgeo, c_name_nspec, i,
00782                                       &row_null) - 1;
00783 
00784         tmp_nsubslits = cpl_table_get_int(ref_slitgeo, c_name_ssn, i,
00785                                           &row_null);
00786 
00787         if (tmp_nsubslits>max_nsubslits) {
00788             max_nsubslits = tmp_nsubslits;
00789         }
00790 
00791         ce_code = cpl_matrix_set(fiber_slit_position->x_fiber, i, 0, tmp_xf);
00792         ce_code = cpl_matrix_set(fiber_slit_position->y_fiber, i, 0, tmp_yf);
00793 
00794         ce_code = cpl_matrix_set(nspec,     i, 0, (cxdouble)tmp_nspec);
00795         ce_code = cpl_matrix_set(nsubslits, i, 0, (cxdouble)tmp_nsubslits);
00796 
00797     }
00798 
00799     /*
00800      *  Create Slit Geometry
00801      */
00802 
00803     if (fitsubslit) {
00804 
00805         /* create multiple subslits */
00806 
00807         _giraffe_slitgeo_resize(subslits, max_nsubslits);
00808 
00809         for (i = 1; i <= max_nsubslits; i++) {
00810 
00811             cpl_matrix *ref_matrix = NULL;
00812             cxint       curr_ssn;
00813 
00814             count = 0;
00815             for (j=0; j<nr_slitgeo; j++) {
00816                 curr_ssn = (cxint) cpl_matrix_get(nsubslits, j, 0);
00817                 if (i==curr_ssn) {
00818                     ++count;
00819                 }
00820             }
00821 
00822             _giraffe_slitgeo_create(subslits, i-1, count, 1);
00823 
00824             ref_matrix = _giraffe_slitgeo_get(subslits, i-1);
00825 
00826             column_index = 0;
00827             for (j = 0; j < nr_slitgeo; j++) {
00828 
00829                 curr_ssn = (cxint) cpl_matrix_get(nsubslits, j, 0);
00830 
00831                 if (i == curr_ssn) {
00832                     ce_code = cpl_matrix_set(ref_matrix, column_index, 0,
00833                                              (cxdouble)j);
00834                     column_index++;
00835                 }
00836 
00837             }
00838         }
00839 
00840         cpl_msg_debug(fctid, "Using multiple slits for Slit Geometry");
00841 
00842     }
00843     else {
00844 
00845         const cxchar *idx = giraffe_fiberlist_query_index(ref_slitgeo);
00846 
00847 
00848         /*
00849          * Create one subslit containing all fibers
00850          */
00851 
00852         cpl_matrix *ref_matrix = NULL;
00853 
00854         _giraffe_slitgeo_resize(subslits, 1);
00855         _giraffe_slitgeo_create(subslits, 0, nr_slitgeo, 1);
00856 
00857         ref_matrix = _giraffe_slitgeo_get(subslits, 0);
00858 
00859         for (j = 0; j < nr_slitgeo; j++) {
00860 
00861             cxint cs = cpl_table_get_int(ref_slitgeo, idx, j, NULL) - 1;
00862             ce_code = cpl_matrix_set(ref_matrix, j, 0, cs);
00863 //            ce_code = cpl_matrix_set(ref_matrix, j, 0, (cxdouble)j);
00864 
00865         }
00866 
00867         cpl_msg_debug(fctid, "Using single slit for Slit Geometry");
00868 
00869     }
00870 
00871     cpl_matrix_delete(nspec);
00872     nspec = NULL;
00873 
00874     cpl_matrix_delete(nsubslits);
00875     nsubslits = NULL;
00876 
00877     return 0;
00878 
00879 }
00880 
00881 
00882 static GiWcalSolution*
00883 _giraffe_wcalsolution_new(void)
00884 {
00885 
00886     GiWcalSolution* tmp = NULL;
00887 
00888     tmp = (GiWcalSolution*) cx_calloc(1, sizeof(GiWcalSolution));
00889 
00890     tmp->subslitfit     = FALSE;
00891     tmp->opt_mod        = LMRQ_UNDEFINED;
00892     tmp->opt_mod_params = NULL;
00893     tmp->wav_coeffs     = NULL;
00894     tmp->wav_limits     = NULL;
00895 
00896     return tmp;
00897 }
00898 
00899 
00900 static void
00901 _giraffe_wcalsolution_delete(GiWcalSolution *ws)
00902 {
00903 
00904     if (ws != NULL) {
00905 
00906         if (ws->opt_mod_params!=NULL) {
00907             cpl_matrix_delete(ws->opt_mod_params);
00908         }
00909 
00910         if (ws->wav_coeffs!=NULL) {
00911             _giraffe_slitgeo_delete(ws->wav_coeffs);
00912         }
00913 
00914         if (ws->wav_limits!=NULL) {
00915             _giraffe_slitgeo_delete(ws->wav_limits);
00916         }
00917 
00918         cx_free(ws);
00919 
00920     }
00921 
00922     return;
00923 
00924 }
00925 
00926 
00927 static GiWcalSolution*
00928 _giraffe_wcalsolution_create(const GiTable *wavesolution)
00929 {
00930 
00931     cxchar buffer[68];
00932 
00933     cxint i             = 0;
00934     cxint poly_x_deg    = 0;
00935     cxint poly_y_deg    = 0;
00936     cxint ncoefficients = 0;
00937 
00938     cxdouble* pd_coefficients = NULL;
00939 
00940     cpl_matrix* coefficients = NULL;
00941     cpl_matrix* limits       = NULL;
00942 
00943     cpl_propertylist* _properties = NULL;
00944 
00945     cpl_table* _table = NULL;
00946 
00947     GiWcalSolution* wavcoeff = NULL;
00948 
00949 
00950 
00951     if (wavesolution == NULL) {
00952         return NULL;
00953     }
00954 
00955     wavcoeff = _giraffe_wcalsolution_new();
00956 
00957     _properties = giraffe_table_get_properties(wavesolution);
00958 
00959 
00960     /*
00961      *  Build up optical model from the wavelength solution properties
00962      */
00963 
00964     if (cpl_propertylist_has(_properties, GIALIAS_OPT_MOD) == TRUE) {
00965 
00966         const cxchar* optmod = cpl_propertylist_get_string(_properties,
00967             GIALIAS_OPT_MOD);
00968 
00969         if (strncmp(optmod, "xoptmod2", 8) == 0) {
00970             wavcoeff->opt_mod = LMRQ_XOPTMOD2;
00971         }
00972         else if (strncmp(optmod, "xoptmod", 7) == 0) {
00973             wavcoeff->opt_mod = LMRQ_XOPTMOD;
00974         }
00975         else {
00976             wavcoeff->opt_mod = LMRQ_UNDEFINED;
00977         }
00978     }
00979 
00980     if (wavcoeff->opt_mod == LMRQ_XOPTMOD2) {
00981 
00982         wavcoeff->opt_mod_params = cpl_matrix_new(7,1);
00983 
00984         if (cpl_propertylist_has(_properties, GIALIAS_OPTMDIR)) {
00985             cpl_matrix_set(
00986                 wavcoeff->opt_mod_params,
00987                 0,
00988                 0,
00989                 cpl_propertylist_get_int(_properties, GIALIAS_OPTMDIR)
00990                 );
00991         } else {
00992             _giraffe_wcalsolution_delete(wavcoeff);
00993             return NULL;
00994         }
00995 
00996         if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMFCOLL)) {
00997             cpl_matrix_set(
00998                 wavcoeff->opt_mod_params,
00999                 1,
01000                 0,
01001                 cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMFCOLL)
01002                 );
01003         } else {
01004             _giraffe_wcalsolution_delete(wavcoeff);
01005             return NULL;
01006         }
01007 
01008         if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMGCAM)) {
01009             cpl_matrix_set(
01010                 wavcoeff->opt_mod_params,
01011                 2,
01012                 0,
01013                 cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMGCAM)
01014                 );
01015         } else {
01016             _giraffe_wcalsolution_delete(wavcoeff);
01017             return NULL;
01018         }
01019 
01020         if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMTHETA)) {
01021             cpl_matrix_set(
01022                 wavcoeff->opt_mod_params,
01023                 3,
01024                 0,
01025                 cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMTHETA)
01026                 );
01027         } else {
01028             _giraffe_wcalsolution_delete(wavcoeff);
01029             return NULL;
01030         }
01031 
01032         if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMSDX)) {
01033             cpl_matrix_set(
01034                 wavcoeff->opt_mod_params,
01035                 4,
01036                 0,
01037                 cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMSDX)
01038                 );
01039         } else {
01040             _giraffe_wcalsolution_delete(wavcoeff);
01041             return NULL;
01042         }
01043 
01044         if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMSDY)) {
01045 
01046 
01047 
01048             cpl_matrix_set(
01049                 wavcoeff->opt_mod_params,
01050                 5,
01051                 0,
01052                 cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMSDY)
01053                 );
01054 
01055         } else {
01056             _giraffe_wcalsolution_delete(wavcoeff);
01057             return NULL;
01058         }
01059 
01060         if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMSPHI)) {
01061             cpl_matrix_set(
01062                 wavcoeff->opt_mod_params,
01063                 6,
01064                 0,
01065                 cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMSPHI)
01066                 );
01067 
01068         } else {
01069             _giraffe_wcalsolution_delete(wavcoeff);
01070             return NULL;
01071         }
01072 
01073     } else if (wavcoeff->opt_mod==LMRQ_XOPTMOD) {
01074 
01075         wavcoeff->opt_mod_params = cpl_matrix_new(4,1);
01076 
01077         if (cpl_propertylist_has(_properties, GIALIAS_OPTMDIR)) {
01078             cpl_matrix_set(
01079                 wavcoeff->opt_mod_params,
01080                 0,
01081                 0,
01082                 cpl_propertylist_get_int(_properties, GIALIAS_OPTMDIR)
01083                 );
01084         } else {
01085             _giraffe_wcalsolution_delete(wavcoeff);
01086             return NULL;
01087         }
01088 
01089         if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMFCOLL)) {
01090             cpl_matrix_set(
01091                 wavcoeff->opt_mod_params,
01092                 1,
01093                 0,
01094                 cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMFCOLL)
01095                 );
01096         } else {
01097             _giraffe_wcalsolution_delete(wavcoeff);
01098             return NULL;
01099         }
01100 
01101         if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMGCAM)) {
01102             cpl_matrix_set(
01103                 wavcoeff->opt_mod_params,
01104                 2,
01105                 0,
01106                 cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMGCAM)
01107                 );
01108         } else {
01109             _giraffe_wcalsolution_delete(wavcoeff);
01110             return NULL;
01111         }
01112 
01113         if (cpl_propertylist_has(_properties, GIALIAS_WSOL_OPTMTHETA)) {
01114             cpl_matrix_set(
01115                 wavcoeff->opt_mod_params,
01116                 3,
01117                 0,
01118                 cpl_propertylist_get_double(_properties, GIALIAS_WSOL_OPTMTHETA)
01119                 );
01120         } else {
01121             _giraffe_wcalsolution_delete(wavcoeff);
01122             return NULL;
01123         }
01124 
01125 
01126     } else {
01127 
01128         _giraffe_wcalsolution_delete(wavcoeff);
01129         return NULL;
01130 
01131     }
01132 
01133 
01134     /*
01135      * Set up the optical model residuals if the given table contains them.
01136      */
01137 
01138     _table = giraffe_table_get(wavesolution);
01139 
01140     if (_table != NULL) {
01141 
01142 
01143         if (cpl_propertylist_has(_properties, GIALIAS_SSF)) {
01144 
01145             if (cpl_propertylist_get_bool(_properties, GIALIAS_SSF) == 0) {
01146                 wavcoeff->subslitfit = FALSE;
01147             }
01148             else {
01149                 wavcoeff->subslitfit = TRUE;
01150             }
01151 
01152         }
01153         else {
01154 
01155             _giraffe_wcalsolution_delete(wavcoeff);
01156             return NULL;
01157 
01158         }
01159 
01160         wavcoeff->wav_limits = _giraffe_slitgeo_new();
01161         _giraffe_slitgeo_resize(wavcoeff->wav_limits, 1);
01162 
01163         limits = cpl_matrix_new(1, 4);
01164         cpl_matrix_fill(limits, -1.);
01165 
01166         if (cpl_table_has_column(_table, "XMIN") &&
01167             cpl_table_has_column(_table, "XMAX")) {
01168             cpl_matrix_set(limits, 0, 0,
01169                            cpl_table_get_double(_table, "XMIN", 0, NULL));
01170             cpl_matrix_set(limits, 0, 1,
01171                            cpl_table_get_double(_table, "XMAX", 0, NULL));
01172         }
01173 
01174         if (cpl_table_has_column(_table, "YMIN") &&
01175             cpl_table_has_column(_table, "YMAX")) {
01176             cpl_matrix_set(limits, 0, 2,
01177                            cpl_table_get_double(_table, "YMIN", 0, NULL));
01178             cpl_matrix_set(limits, 0, 3,
01179                            cpl_table_get_double(_table, "YMAX", 0, NULL));
01180         }
01181 
01182         _giraffe_slitgeo_set(wavcoeff->wav_limits, 0, limits);
01183 
01184         cpl_matrix_delete(limits);
01185         limits = NULL;
01186 
01187         wavcoeff->wav_coeffs = _giraffe_slitgeo_new();
01188         _giraffe_slitgeo_resize(wavcoeff->wav_coeffs, 1);
01189 
01190         if (cpl_propertylist_has(_properties, GIALIAS_XRES_PDEG)) {
01191 
01192             cxchar *l, *r, *tmpstr;
01193 
01194             tmpstr = (cxchar*) cpl_propertylist_get_string(_properties,
01195                                                            GIALIAS_XRES_PDEG);
01196 
01197             l = &(tmpstr[0]);
01198             r = &(tmpstr[2]);
01199 
01200             poly_x_deg = atoi(l) + 1;
01201             poly_y_deg = atoi(r) + 1;
01202 
01203         }
01204         else {
01205 
01206             _giraffe_wcalsolution_delete(wavcoeff);
01207             return NULL;
01208 
01209         }
01210 
01211         ncoefficients = poly_x_deg * poly_y_deg;
01212 
01213         coefficients = cpl_matrix_new(poly_x_deg,poly_y_deg);
01214         pd_coefficients = cpl_matrix_get_data(coefficients);
01215 
01216         for (i=0; i<ncoefficients; i++) {
01217 
01218             snprintf(buffer, sizeof buffer, "XC%-d", i);
01219 
01220             pd_coefficients[i] =
01221                 cpl_table_get_double(_table, buffer, 0, NULL);
01222 
01223         }
01224 
01225         _giraffe_slitgeo_set(wavcoeff->wav_coeffs, 0, coefficients);
01226 
01227         cpl_matrix_delete(coefficients);
01228         coefficients = NULL;
01229 
01230     }
01231 
01232     return wavcoeff;
01233 
01234 }
01235 
01236 
01237 static cpl_image*
01238 _giraffe_compute_pixel_abscissa(cpl_matrix* m_wavelengths,
01239                                 cpl_matrix* m_wloffset,
01240                                 GiFiberPosition* fiber_slit_position,
01241                                 cpl_matrix* m_opt_mod_params,
01242                                 lmrq_model lmrq_opt_mod_x)
01243 {
01244 
01245     /*************************************************************************
01246                                      VARIABLES
01247     *************************************************************************/
01248 
01249     const cxchar *fctid = "_giraffe_compute_pixel_abscissa";
01250 
01251     register cxint n;
01252     register cxint line;
01253     register cxint nwlen;    /* number of reference lines    */
01254     register cxint ns;       /* number of reference spectra  */
01255 
01256     cxint nr_m_opt_mod_params = 0;
01257 
01258     cxdouble xccd = 0.;
01259     cxdouble* pd_xref             = NULL;
01260     cxdouble* pd_m_inputs         = NULL;
01261     cxdouble* pd_m_yfibre         = NULL;
01262     cxdouble* pd_m_xfibre         = NULL;
01263     cxdouble* pd_m_wavelengths    = NULL;
01264     cxdouble* pd_m_opt_mod_params = NULL;
01265 
01266     cpl_image* xref = NULL;
01267 
01268     cpl_matrix* m_inputs = NULL;
01269 
01270 
01271     /************************************************************************
01272                                    INITIALIZATION
01273     ************************************************************************/
01274 
01275     if (m_wavelengths == NULL) {
01276         return NULL;
01277     }
01278 
01279     if ((fiber_slit_position == NULL) ||
01280         (fiber_slit_position->x_fiber == NULL) ||
01281         (fiber_slit_position->y_fiber == NULL)) {
01282         return NULL;
01283     }
01284 
01285     if (m_opt_mod_params == NULL) {
01286         return NULL;
01287     }
01288 
01289 
01290     nwlen = cpl_matrix_get_nrow(m_wavelengths);
01291     ns    = cpl_matrix_get_nrow(fiber_slit_position->y_fiber);
01292 
01293     if ((m_wloffset != NULL) && (cpl_matrix_get_nrow(m_wloffset) != ns)) {
01294         return NULL;
01295     }
01296 
01297 
01298     /************************************************************************
01299                                     PREPROCESSING
01300     ************************************************************************/
01301 
01302     xref       = cpl_image_new(ns, nwlen, CPL_TYPE_DOUBLE);
01303     pd_xref    = cpl_image_get_data_double(xref);
01304 
01305     m_inputs    = cpl_matrix_new(lmrq_opt_mod_x.ninputs, 1);
01306     pd_m_inputs = cpl_matrix_get_data(m_inputs);
01307 
01308     pd_m_yfibre      = cpl_matrix_get_data(fiber_slit_position->y_fiber);
01309     pd_m_xfibre      = cpl_matrix_get_data(fiber_slit_position->x_fiber);
01310     pd_m_wavelengths = cpl_matrix_get_data(m_wavelengths);
01311 
01312     pd_m_opt_mod_params = cpl_matrix_get_data(m_opt_mod_params);
01313     nr_m_opt_mod_params = cpl_matrix_get_nrow(m_opt_mod_params);
01314 
01315 
01316     /************************************************************************
01317                                      PROCESSING
01318     ************************************************************************/
01319 
01320     if (m_wloffset != NULL) {
01321 
01322         cxdouble* pd_m_wloffset = cpl_matrix_get_data(m_wloffset);
01323 
01324         for (n = 0; n < ns; n++) {
01325 
01326             pd_m_inputs[2] = pd_m_yfibre[n];
01327             pd_m_inputs[1] = pd_m_xfibre[n];
01328 
01329             for (line = 0; line < nwlen; line++) {
01330 
01331                 pd_m_inputs[0] = pd_m_wavelengths[line] + pd_m_wloffset[n];
01332 
01333                 lmrq_opt_mod_x.cfunc(pd_m_inputs, pd_m_opt_mod_params,
01334                                      NULL, &xccd, NULL, nr_m_opt_mod_params);
01335 
01336                 pd_xref[line * ns + n] = xccd;
01337 
01338             } /* each line */
01339 
01340         } /* each spectrum */
01341 
01342     }
01343     else {
01344 
01345         for (n = 0; n < ns; n++) {
01346 
01347             pd_m_inputs[2] = pd_m_yfibre[n];
01348             pd_m_inputs[1] = pd_m_xfibre[n];
01349 
01350             for (line = 0; line < nwlen; line++) {
01351 
01352                 pd_m_inputs[0] = pd_m_wavelengths[line];
01353 
01354                 lmrq_opt_mod_x.cfunc(pd_m_inputs, pd_m_opt_mod_params,
01355                                      NULL, &xccd, NULL, nr_m_opt_mod_params);
01356 
01357                 pd_xref[line * ns + n] = xccd;
01358 
01359             } /* each line */
01360 
01361         } /* each spectrum */
01362 
01363     }
01364 
01365     cpl_matrix_delete(m_inputs);
01366 
01367     cpl_msg_debug(fctid, "Processing completed: Returning image [x,y] ="
01368                   " [%" CPL_SIZE_FORMAT ",%" CPL_SIZE_FORMAT "]",
01369                   cpl_image_get_size_x(xref), cpl_image_get_size_y(xref));
01370 
01371     return xref;
01372 
01373 }
01374 
01375 
01376 inline static cpl_matrix *
01377 _giraffe_rebin_setup_model(GiImage *extspectra, GiWcalSolution *wcal)
01378 {
01379 
01380     cxint npixel;
01381 
01382     cxdouble pixelsize;
01383 
01384     cpl_propertylist *properties = NULL;
01385 
01386     cpl_matrix *model = NULL;
01387 
01388 
01389     if (extspectra == NULL) {
01390         return NULL;
01391     }
01392 
01393     if (wcal == NULL) {
01394         return NULL;
01395     }
01396 
01397     properties = giraffe_image_get_properties(extspectra);
01398 
01399     if (properties == NULL) {
01400         return NULL;
01401     }
01402 
01403 
01404     /*
01405      * Get the number of pixels extracted along the dispersion axis.
01406      */
01407 
01408     if (!cpl_propertylist_has(properties, GIALIAS_EXT_NX)) {
01409         return NULL;
01410     }
01411 
01412     npixel = cpl_propertylist_get_int(properties, GIALIAS_EXT_NX);
01413 
01414 
01415     /*
01416      * Compute pixel size along the dispersion axis in terms of mm.
01417      */
01418 
01419     if (!cpl_propertylist_has(properties, GIALIAS_PIXSIZX)) {
01420         return NULL;
01421     }
01422 
01423     pixelsize = cpl_propertylist_get_double(properties, GIALIAS_PIXSIZX);
01424     pixelsize /= 1000.;
01425 
01426 
01427     /*
01428      * Setup the optical model parameters
01429      */
01430 
01431     switch (wcal->opt_mod) {
01432         case LMRQ_XOPTMOD:
01433             if (cpl_matrix_get_nrow(wcal->opt_mod_params) != 4) {
01434                 return NULL;
01435             }
01436             else {
01437 
01438                 cxdouble direction = cpl_matrix_get(wcal->opt_mod_params, 0, 0);
01439                 cxdouble fcoll = cpl_matrix_get(wcal->opt_mod_params, 1, 0);
01440                 cxdouble cfact = cpl_matrix_get(wcal->opt_mod_params, 2, 0);
01441 
01442                 model = cpl_matrix_new(4, 1);
01443 
01444                 cpl_matrix_set(model, 0, 0, npixel * direction);
01445                 cpl_matrix_set(model, 1, 0, pixelsize);
01446                 cpl_matrix_set(model, 2, 0, fcoll);
01447                 cpl_matrix_set(model, 3, 0, cfact);
01448             }
01449             break;
01450 
01451         case LMRQ_XOPTMOD2:
01452             if (cpl_matrix_get_nrow(wcal->opt_mod_params) != 7) {
01453                 return NULL;
01454             }
01455             else {
01456 
01457                 cxdouble direction = cpl_matrix_get(wcal->opt_mod_params, 0, 0);
01458                 cxdouble fcoll = cpl_matrix_get(wcal->opt_mod_params, 1, 0);
01459                 cxdouble cfact = cpl_matrix_get(wcal->opt_mod_params, 2, 0);
01460                 cxdouble sdx = cpl_matrix_get(wcal->opt_mod_params, 4, 0);
01461                 cxdouble sdy = cpl_matrix_get(wcal->opt_mod_params, 5, 0);
01462                 cxdouble sphi = cpl_matrix_get(wcal->opt_mod_params, 6, 0);
01463 
01464                 model = cpl_matrix_new(7, 1);
01465 
01466                 cpl_matrix_set(model, 0, 0, npixel * direction);
01467                 cpl_matrix_set(model, 1, 0, pixelsize);
01468                 cpl_matrix_set(model, 2, 0, fcoll);
01469                 cpl_matrix_set(model, 3, 0, cfact);
01470                 cpl_matrix_set(model, 4, 0, sdx);
01471                 cpl_matrix_set(model, 5, 0, sdy);
01472                 cpl_matrix_set(model, 6, 0, sphi);
01473             }
01474             break;
01475 
01476         default:
01477             return NULL;
01478             break;
01479     }
01480 
01481     cx_assert(model != NULL);
01482 
01483     return model;
01484 
01485 }
01486 
01487 
01488 inline static cpl_matrix *
01489 _giraffe_rebin_setup_grating(GiImage *extspectra, GiTable *grating,
01490                              GiTable *wlsolution)
01491 {
01492 
01493     cxint status = 0;
01494 
01495     cpl_propertylist *properties = NULL;
01496 
01497     cpl_matrix *setup = NULL;
01498 
01499     GiGrat *grating_data = _giraffe_grating_new();
01500 
01501 
01502     status = _giraffe_grating_setup(grating, extspectra, grating_data);
01503 
01504     if (status != 0) {
01505         _giraffe_grating_delete(grating_data);
01506         return NULL;
01507     }
01508 
01509 
01510     properties = giraffe_table_get_properties(wlsolution);
01511 
01512     if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMFCOLL)) {
01513         grating_data->fcoll = cpl_propertylist_get_double(properties,
01514                                                           GIALIAS_WSOL_OMFCOLL);
01515     }
01516 
01517     if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMGCAM)) {
01518         grating_data->gcam = cpl_propertylist_get_double(properties,
01519                                                          GIALIAS_WSOL_OMGCAM);
01520     }
01521 
01522     if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMGTHETA)) {
01523         grating_data->theta = cpl_propertylist_get_double(properties,
01524                                                           GIALIAS_WSOL_OMGTHETA);
01525     }
01526 
01527     if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMSDX)) {
01528         grating_data->slitdx = cpl_propertylist_get_double(properties,
01529                                                            GIALIAS_WSOL_OMSDX);
01530     }
01531 
01532     if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMSDY)) {
01533         grating_data->slitdy = cpl_propertylist_get_double(properties,
01534                                                            GIALIAS_WSOL_OMSDY);
01535     }
01536 
01537     if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMSPHI)) {
01538         grating_data->slitphi = cpl_propertylist_get_double(properties,
01539                                                             GIALIAS_WSOL_OMSPHI);
01540     }
01541 
01542 
01543     setup = cpl_matrix_new(7, 1);
01544 
01545     cpl_matrix_set(setup, 0, 0, grating_data->theta);
01546     cpl_matrix_set(setup, 1, 0, grating_data->order);
01547     cpl_matrix_set(setup, 2, 0, grating_data->wlenmin / GI_MM_TO_NM);
01548     cpl_matrix_set(setup, 3, 0, grating_data->wlen0 / GI_MM_TO_NM);
01549     cpl_matrix_set(setup, 4, 0, grating_data->wlenmax / GI_MM_TO_NM);
01550     cpl_matrix_set(setup, 5, 0, grating_data->resol);
01551     cpl_matrix_set(setup, 6, 0, grating_data->space);
01552 
01553     _giraffe_grating_delete(grating_data);
01554     grating_data = NULL;
01555 
01556     return setup;
01557 
01558 }
01559 
01560 
01573 inline static cxint
01574 _giraffe_spline_calc_circe(cxdouble x, register cxdouble* t, cxint n)
01575 {
01576 
01577     register cxint lo = 0;
01578     register cxint hi = n - 1;
01579 
01580 
01581     if (x >= t[0] && x <= t[n - 1]) {
01582 
01583         while (hi - lo > 1) {
01584 
01585             register cxint mid = (lo + hi) / 2.;
01586 
01587             cxdouble tm = 0.;
01588 
01589             tm = t[mid];
01590 
01591             if (x < tm) {
01592                 hi = mid;
01593             }
01594             else {
01595                 lo = mid;
01596             }
01597         }
01598 
01599         return hi;
01600 
01601     }
01602 
01603     return -1;
01604 
01605 }
01606 
01626 inline static void
01627 _giraffe_spline_calc_tridi(register cxdouble* a, register cxdouble* b,
01628                            register cxdouble* c, register cxdouble* f,
01629                            register cxdouble* x, cxint n)
01630 {
01631 
01632     register cxint i = 0;
01633 
01634     c[0] /= a[0];
01635 
01636     for (i = 1; i < n; i++) {
01637         c[i] /= (a[i] - b[i] * c[i - 1]);
01638     }
01639 
01640     f[0] /= a[0];
01641 
01642     for (i = 1; i < n; i++) {
01643         f[i] = (f[i] - b[i] * f[i - 1]) / (a[i] - b[i] * c[i - 1]);
01644     }
01645 
01646     x[n - 1] = f[n - 1];
01647 
01648     for (i = n - 2; i >= 0; i--) {
01649         x[i] = f[i] - c[i] * x[i + 1];
01650     }
01651 
01652     return;
01653 }
01654 
01674 inline static cxint
01675 _giraffe_spline_calc_interpolate(cxdouble z, cxdouble* val,
01676                                  register cxdouble* x, register cxdouble* y,
01677                                  register cxdouble* k, cxint n)
01678 {
01679 
01680     cxint m = 0;
01681 
01682     cxdouble h = 0.;
01683     cxdouble t = 0.;
01684     cxdouble d = 0.;
01685     cxdouble a = 0.;
01686     cxdouble b = 0.;
01687     cxdouble dx = 0.;
01688 
01689 
01690     m = _giraffe_spline_calc_circe(z, x, n);
01691 
01692     if (m < 0) {
01693 
01694         /* out of bounds */
01695         if (z < x[0]) {
01696             dx   = z - x[0];
01697             *val = y[0] + dx * (k[0] + 0.5 * dx * ddb);
01698         } else {
01699             dx   = z - x[n - 1];
01700             *val = y[n - 1] + dx * (k[n - 1] + 0.5 * dx * dde);
01701         }
01702 
01703         return 1;
01704 
01705     }
01706 
01707     dx   = z - x[m - 1];
01708     h    = x[m] - x[m - 1];
01709     d    = (y[m] - y[m - 1]) / h;
01710     t    = dx / h;
01711     a    = (k[m - 1] - d) * (1 - t);
01712     b    = (k[m] - d) * t;
01713     *val = t * y[m] + (1 - t) * y[m - 1] + h * t * (1 - t) * (a - b);
01714 
01715     return 0;
01716 
01717 }
01718 
01739 inline static cxint
01740 _giraffe_spline_calc_initalize(cxdouble* x, cxdouble* y, cxdouble* k,
01741                                cxint n, cxdouble q2b, cxdouble q2e)
01742 {
01743 
01744     register cxint i = 0;
01745     register cxint ip = 0;
01746 
01747     register cxdouble* a;
01748     register cxdouble* b;
01749     register cxdouble* c;
01750     register cxdouble* f;
01751 
01752     cxdouble hio = 0.;
01753     cxdouble hip = 0.;
01754     cxdouble dio = 0.;
01755     cxdouble dip = 0.;
01756 
01757 
01758 
01759     ddb = q2b;
01760     dde = q2e; /* save end second derivatives */
01761 
01762     a   = (cxdouble*) cx_malloc(4 * n * sizeof(cxdouble));
01763 
01764     b   = a + n;
01765     c   = b + n;
01766     f   = c + n;
01767 
01768     for (i = 0; i < n; i++) {
01769 
01770         hip  = ((ip = i + 1) < n ? x[ip] - x[i] : 0.0);
01771         dip  = (ip < n ? (y[ip] - y[i]) / hip : 0.0);
01772         b[i] = (ip < n ? hip : hio);
01773         a[i] = 2.0 * (hip + hio);
01774         c[i] = (i > 0 ? hio : hip);
01775         f[i] = 3.0 * (hip * dio + hio * dip);
01776 
01777         if (i == 0) {
01778             f[0] = 3.0 * hip * dip - hip * hip * q2b * 0.5;
01779         }
01780         else if (i == n - 1) {
01781             f[n - 1] = 3.0 * hio * dio + hio * hio * q2e * 0.5;
01782         }
01783 
01784         dio = dip;
01785         hio = hip;
01786     }
01787 
01788     _giraffe_spline_calc_tridi(a, b, c, f, k, n);
01789 
01790     cx_free(a);
01791 
01792     return 0;
01793 
01794 }
01795 
01814 inline static cxint
01815 _giraffe_rebin_interpolate_spline(cpl_matrix* x_1, cpl_matrix* y_1,
01816                                   cpl_matrix* x_2, cpl_matrix* y_2)
01817 {
01818 
01819     cxint i = 0;
01820     cxint res = 0;
01821     cxint nr_x1 = 0;
01822     cxint nr_x2 = 0;
01823 
01824     cxdouble* k = NULL;
01825     cxdouble* pd_x1 = NULL;
01826     cxdouble* pd_y1 = NULL;
01827     cxdouble* pd_x2 = NULL;
01828     cxdouble* pd_y2 = NULL;
01829 
01830 
01831 
01832     if (x_1 == NULL || y_1 == NULL || x_2 == NULL || y_2 == NULL) {
01833         return 1;
01834     }
01835 
01836     nr_x1 = cpl_matrix_get_nrow(x_1);
01837     nr_x2 = cpl_matrix_get_nrow(x_2);
01838 
01839     pd_x1 = cpl_matrix_get_data(x_1);
01840     pd_y1 = cpl_matrix_get_data(y_1);
01841     pd_y2 = cpl_matrix_get_data(y_2);
01842     pd_x2 = cpl_matrix_get_data(x_2);
01843 
01844 
01845     /*
01846      * Get storage for spline coefficients and vector y2
01847      */
01848 
01849     k = (cxdouble*) cx_malloc(nr_x1 * sizeof(cxdouble));
01850 
01851 
01852     /*
01853      * Initialise spline calculation...
01854      */
01855 
01856     res = _giraffe_spline_calc_initalize(pd_x1, pd_y1, k, nr_x1, 0.0, 0.0);
01857 
01858     if (res < 0) {
01859         cx_free(k);
01860         return res;
01861     }
01862 
01863     /*
01864      *  Calculate spline...
01865      */
01866 
01867     for (i = 0; i < nr_x2; i++) {
01868         res = _giraffe_spline_calc_interpolate(pd_x2[i], &(pd_y2[i]), pd_x1,
01869                                                pd_y1, k, nr_x1);
01870     }
01871 
01872     cx_free(k);
01873 
01874     return 0;
01875 
01876 }
01877 
01899 inline static cxint
01900 _giraffe_rebin_interpolate_linear(
01901     cpl_matrix *x_1,
01902     cpl_matrix *y_1,
01903     cpl_matrix *x_2,
01904     cpl_matrix *y_2
01905     )
01906 {
01907 
01908     /*************************************************************************
01909                                      Variables
01910     *************************************************************************/
01911 
01912     register cxdouble a, b ;
01913     register cxint    i, j, j_1, found, n1;
01914 
01915     cxint     nr_x1 = 0,
01916         nr_x2 = 0;
01917     cxdouble *pd_x1 = NULL,
01918         *pd_x2 = NULL,
01919         *pd_y2 = NULL,
01920         *pd_y1 = NULL;
01921 
01922     /*************************************************************************
01923                                     Preprocessing
01924     *************************************************************************/
01925 
01926     if (x_1 == NULL) { return 1; }
01927     if (y_1 == NULL) { return 1; }
01928     if (x_2 == NULL) { return 1; }
01929     if (y_2 == NULL) { return 1; }
01930 
01931     nr_x1 = cpl_matrix_get_nrow(x_1);
01932     nr_x2 = cpl_matrix_get_nrow(x_2);
01933     pd_x1 = cpl_matrix_get_data(x_1);
01934     pd_x2 = cpl_matrix_get_data(x_2);
01935     pd_y1 = cpl_matrix_get_data(y_1);
01936     pd_y2 = cpl_matrix_get_data(y_2);
01937 
01938     /*************************************************************************
01939                                      Processing
01940     *************************************************************************/
01941 
01942     n1 = nr_x1 - 1;
01943 
01944     for (i = 0; i < nr_x2; i++) {
01945         /* Find (x1,y1) on the left of the current point */
01946         found = 0;
01947         for (j = 0; j < n1; j++) {
01948             if ((pd_x2[i] >= pd_x1[j]) && (pd_x2[i] <= pd_x1[j+1])) {
01949                 found++ ;
01950                 break ;
01951             }
01952         }
01953 
01954         if (!found) {
01955             pd_y2[i] = 0.0;
01956         } else {
01957             j_1      = j + 1;
01958             a        = (pd_y1[j_1] - pd_y1[j]) / (pd_x1[j_1] - pd_x1[j]);
01959             b        = pd_y1[j] - a * pd_x1[j];
01960             pd_y2[i] = (a * pd_x2[i] + b);
01961 
01962         }
01963     }
01964 
01965     return 0;
01966 
01967 } /* end giraffe_rebin_interpolate_linear() */
01968 
01994 inline static cxint
01995 _giraffe_rebin_interpolate_linear_error(
01996     cpl_matrix *x_1,
01997     cpl_matrix *y_1,
01998     cpl_matrix *y_1err,
01999     cpl_matrix *x_2,
02000     cpl_matrix *y_2,
02001     cpl_matrix *y_2err
02002     ) {
02003 
02004     /*************************************************************************
02005                                      Variables
02006     *************************************************************************/
02007 
02008     register double a, b ,dx;
02009     register int    i, j, j_1, found, n1 ;
02010 
02011     cxint     nr_x1    = 0,
02012         nr_x2    = 0;
02013     cxdouble *pd_x1    = NULL,
02014         *pd_y1    = NULL,
02015         *pd_y1err = NULL,
02016         *pd_x2    = NULL,
02017         *pd_y2    = NULL,
02018         *pd_y2err = NULL;
02019 
02020     /*************************************************************************
02021                                     Preprocessing
02022     *************************************************************************/
02023 
02024     if (x_1 == NULL) { return 1; }
02025     if (y_1 == NULL) { return 1; }
02026     if (y_1err == NULL) { return 1; }
02027     if (x_2 == NULL) { return 1; }
02028     if (y_2 == NULL) { return 1; }
02029     if (y_2err == NULL) { return 1; }
02030 
02031     nr_x1    = cpl_matrix_get_nrow(x_1);
02032     nr_x2    = cpl_matrix_get_nrow(x_2);
02033     pd_x1    = cpl_matrix_get_data(x_1);
02034     pd_y1    = cpl_matrix_get_data(y_1);
02035     pd_y1err = cpl_matrix_get_data(y_1err);
02036     pd_x2    = cpl_matrix_get_data(x_2);
02037     pd_y2    = cpl_matrix_get_data(y_2);
02038     pd_y2err = cpl_matrix_get_data(y_2err);
02039 
02040     /*************************************************************************
02041                                      Processing
02042     *************************************************************************/
02043 
02044     n1 = nr_x1 - 1;
02045 
02046     for (i = 0; i < nr_x2; i++) {
02047         /* Find (x1,y1) on the left of the current point */
02048         found = 0;
02049         for (j = 0; j < n1; j++) {
02050             if ((pd_x2[i] >= pd_x1[j]) && (pd_x2[i] <= pd_x1[j+1])) {
02051                 found++ ;
02052                 break ;
02053             }
02054         }
02055 
02056         if (!found) {
02057             pd_y2[i]    = 0.0;
02058             pd_y2err[i] = 0.0;
02059         } else {
02060 
02061             j_1         = j + 1;
02062             dx          = (pd_x1[j_1] - pd_x1[j]);
02063             a           = (pd_y1[j_1] - pd_y1[j]) / dx;
02064             b           = pd_y1[j] - a * pd_x1[j] ;
02065             pd_y2[i]    = (a * pd_x2[i] + b) ;
02066             a           = (pd_y1err[j_1] - pd_y1err[j]) / dx;
02067             b           = pd_y1err[j] - a * pd_x1[j] ;
02068             pd_y2err[i] = (a * pd_x2[i] + b) ;
02069 
02070         }
02071     }
02072 
02073     return 0;
02074 
02075 } /* end giraffe_rebin_interpolate_linear_error() */
02076 
02096 inline static cxint
02097 _giraffe_resample_linear(cpl_image* rbspectra, cpl_image* rberrors,
02098                          cpl_image* abscissa, cpl_image* exspectra,
02099                          cpl_image* exerrors, cxint opt_direction)
02100 {
02101 
02102     const cxchar* const fctid = "_giraffe_resample_linear";
02103 
02104     register cxlong n = 0;
02105 
02106     cxint status = 0;
02107     cxint nx = 0;         /* size of extracted spectra   */
02108     cxint ns = 0;         /* number of extracted spectra */
02109     cxint nwl = 0;        /* size of rebinned spectra    */
02110 
02111     cxdouble nx1 = 0.;
02112     cxdouble* _mabscissa = NULL;
02113     cxdouble* _mexspectra = NULL;
02114     cxdouble* _mexerrors = NULL;
02115     cxdouble* _mwavelength = NULL;
02116     cxdouble* _mrbspectra = NULL;
02117     cxdouble* _mrberrors = NULL;
02118     cxdouble* _abscissa = NULL;
02119     cxdouble* _exspectra = NULL;
02120     cxdouble* _exerrors = NULL;
02121     cxdouble* _rbspectra = NULL;
02122     cxdouble* _rberrors = NULL;
02123 
02124     cpl_matrix* mabscissa = NULL;
02125     cpl_matrix* mwavelength = NULL;
02126     cpl_matrix* mexspectra = NULL;
02127     cpl_matrix* mexerrors = NULL;
02128     cpl_matrix* mrbspectra = NULL;
02129     cpl_matrix* mrberrors = NULL;
02130 
02131 
02132 
02133     if ((abscissa == NULL) || (exspectra == NULL) || (rbspectra == NULL)) {
02134         return 1;
02135     }
02136 
02137     if ((exerrors != NULL) && (rberrors == NULL)) {
02138         return 1;
02139     }
02140 
02141 
02142     nx = cpl_image_get_size_y(exspectra);
02143     ns = cpl_image_get_size_x(exspectra);
02144     nwl = cpl_image_get_size_y(abscissa);
02145 
02146     if ((exerrors != NULL) &&
02147         ((nx != cpl_image_get_size_y(exerrors)) ||
02148          (ns != cpl_image_get_size_x(exerrors)))) {
02149          return 1;
02150     }
02151 
02152     nx1 = nx - 0.5;
02153 
02154     mabscissa = cpl_matrix_new(nx, 1);
02155     mexspectra = cpl_matrix_new(nx, 1);
02156 
02157     mwavelength = cpl_matrix_new(nwl, 1);
02158     mrbspectra = cpl_matrix_new(nwl, 1);
02159 
02160     _mabscissa = cpl_matrix_get_data(mabscissa);
02161     _mexspectra = cpl_matrix_get_data(mexspectra);
02162     _mwavelength = cpl_matrix_get_data(mwavelength);
02163     _mrbspectra = cpl_matrix_get_data(mrbspectra);
02164 
02165     _abscissa = cpl_image_get_data_double(abscissa);
02166     _exspectra = cpl_image_get_data_double(exspectra);
02167     _rbspectra = cpl_image_get_data_double(rbspectra);
02168 
02169     if (exerrors != NULL) {
02170         mexerrors = cpl_matrix_new(nx, 1);
02171         mrberrors = cpl_matrix_new(nwl, 1);
02172 
02173         _mexerrors = cpl_matrix_get_data(mexerrors);
02174         _mrberrors = cpl_matrix_get_data(mrberrors);
02175 
02176         _exerrors = cpl_image_get_data_double(exerrors);
02177         _rberrors = cpl_image_get_data_double(rberrors);
02178     }
02179 
02180 
02181     /*
02182      * Resample each spectrum to the new grid, taking the direction of the
02183      * optical model into account. If the errors of the spectra are
02184      * available they are also resampled to the new grid.
02185      */
02186 
02187     cpl_msg_debug(fctid, "Rebinning %d spectra, using dispersion direction "
02188                   "%d and linear interpolation", ns, opt_direction);
02189 
02190     for (n = 0; n < ns; n++) {
02191 
02192         register cxlong x = 0;
02193 
02194 
02195         for (x = 0; x < nwl; x++) {
02196             register cxlong j = x * ns + n;
02197             _mwavelength[x] = _abscissa[j];
02198         }
02199 
02200         if (exerrors == NULL) {
02201 
02202             if (opt_direction < 0) {
02203 
02204                 for (x = 0; x < nx; x++) {
02205 
02206                     register cxlong j = x * ns + n;
02207                     register cxlong k = nx - x - 1;
02208 
02209                     _mabscissa[x] = (cxdouble) x;
02210                     _mexspectra[k] = _exspectra[j];
02211                 }
02212 
02213             }
02214             else {
02215 
02216                 for (x = 0; x < nx; x++) {
02217 
02218                     register cxlong j = x * ns + n;
02219 
02220                     _mabscissa[x] = (cxdouble) x;
02221                     _mexspectra[x] = _exspectra[j];
02222 
02223                 }
02224 
02225             }
02226 
02227 
02228             /*
02229              * Linear interpolation of spectra and errors
02230              */
02231 
02232             status = _giraffe_rebin_interpolate_linear(mabscissa,
02233                                                        mexspectra,
02234                                                        mwavelength,
02235                                                        mrbspectra);
02236 
02237             for (x = 0; x < nwl; x++) {
02238 
02239                 register cxlong j = x * ns + n;
02240 
02241                 if ((-0.5 > _mwavelength[x]) || (_mwavelength[x] > nx1)) {
02242                     _rbspectra[j] = 0.;
02243                 }
02244                 else {
02245                     _rbspectra[j] = _mrbspectra[x];
02246                 }
02247 
02248             }
02249 
02250         }
02251         else {
02252 
02253             if (opt_direction < 0) {
02254 
02255                 for (x = 0; x < nx; x++) {
02256 
02257                     register cxlong j = x * ns + n;
02258                     register cxlong k = nx - x - 1;
02259 
02260                     _mabscissa[x] = (cxdouble) x;
02261                     _mexspectra[k] = _exspectra[j];
02262                     _mexerrors[k] = _exerrors[j];
02263                 }
02264 
02265             }
02266             else {
02267 
02268                 for (x = 0; x < nx; x++) {
02269 
02270                     register cxlong j = x * ns + n;
02271 
02272                     _mabscissa[x] = (cxdouble) x;
02273                     _mexspectra[x] = _exspectra[j];
02274                     _mexerrors[x] = _exerrors[j];
02275 
02276                 }
02277 
02278             }
02279 
02280 
02281             /*
02282              * Linear interpolation of spectra and errors
02283              */
02284 
02285             status =
02286                 _giraffe_rebin_interpolate_linear_error(mabscissa,
02287                                                         mexspectra,
02288                                                         mexerrors,
02289                                                         mwavelength,
02290                                                         mrbspectra,
02291                                                         mrberrors);
02292 
02293             for (x = 0; x < nwl; x++) {
02294 
02295                 register cxlong j = x * ns + n;
02296 
02297                 if ((-0.5 > _mwavelength[x]) || (_mwavelength[x] > nx1)) {
02298                     _rbspectra[j] = 0.;
02299                     _rberrors[j] = 0.;
02300                 }
02301                 else {
02302                     _rbspectra[j] = _mrbspectra[x];
02303                     _rberrors[j] = _mrberrors[x];
02304                 }
02305 
02306             }
02307 
02308         }
02309 
02310     } /* each spectrum */
02311 
02312 
02313     cpl_matrix_delete(mrbspectra);
02314     mrbspectra = NULL;
02315 
02316     cpl_matrix_delete(mwavelength);
02317     mwavelength = NULL;
02318 
02319     cpl_matrix_delete(mexspectra);
02320     mexspectra = NULL;
02321 
02322     cpl_matrix_delete(mabscissa);
02323     mabscissa = NULL;
02324 
02325     if (exerrors != NULL) {
02326         cpl_matrix_delete(mrberrors);
02327         mrberrors = NULL;
02328 
02329         cpl_matrix_delete(mexerrors);
02330         mexerrors = NULL;
02331     }
02332 
02333     cpl_msg_debug(fctid, "Rebinned %d spectra", ns);
02334 
02335     return 0;
02336 
02337 }
02338 
02339 
02359 inline static cxint
02360 _giraffe_resample_spline(cpl_image* rbspectra, cpl_image* rberrors,
02361                          cpl_image* abscissa, cpl_image* exspectra,
02362                          cpl_image* exerrors, cxint opt_direction)
02363 {
02364 
02365     const cxchar* const fctid = "_giraffe_resample_spline";
02366 
02367     register cxlong n = 0;
02368 
02369     cxint status = 0;
02370     cxint nx = 0;         /* size of extracted spectra   */
02371     cxint ns = 0;         /* number of extracted spectra */
02372     cxint nwl = 0;        /* size of rebinned spectra    */
02373 
02374     cxdouble nx1 = 0.;
02375     cxdouble* _mabscissa = NULL;
02376     cxdouble* _mexspectra = NULL;
02377     cxdouble* _mexerrors = NULL;
02378     cxdouble* _mwavelength = NULL;
02379     cxdouble* _mrbspectra = NULL;
02380     cxdouble* _mrberrors = NULL;
02381     cxdouble* _abscissa = NULL;
02382     cxdouble* _exspectra = NULL;
02383     cxdouble* _exerrors = NULL;
02384     cxdouble* _rbspectra = NULL;
02385     cxdouble* _rberrors = NULL;
02386 
02387     cpl_matrix* mabscissa = NULL;
02388     cpl_matrix* mwavelength = NULL;
02389     cpl_matrix* mexspectra = NULL;
02390     cpl_matrix* mexerrors = NULL;
02391     cpl_matrix* mrbspectra = NULL;
02392     cpl_matrix* mrberrors = NULL;
02393 
02394 
02395 
02396     if ((abscissa == NULL) || (exspectra == NULL) || (rbspectra == NULL)) {
02397         return 1;
02398     }
02399 
02400     if ((exerrors != NULL) && (rberrors == NULL)) {
02401         return 1;
02402     }
02403 
02404 
02405     nx = cpl_image_get_size_y(exspectra);
02406     ns = cpl_image_get_size_x(exspectra);
02407     nwl = cpl_image_get_size_y(abscissa);
02408 
02409     if ((exerrors != NULL) &&
02410         ((nx != cpl_image_get_size_y(exerrors)) ||
02411          (ns != cpl_image_get_size_x(exerrors)))) {
02412              return 1;
02413          }
02414 
02415     nx1 = nx - 0.5;
02416 
02417     mabscissa = cpl_matrix_new(nx, 1);
02418     mexspectra = cpl_matrix_new(nx, 1);
02419 
02420     mwavelength = cpl_matrix_new(nwl, 1);
02421     mrbspectra = cpl_matrix_new(nwl, 1);
02422 
02423     _mabscissa = cpl_matrix_get_data(mabscissa);
02424     _mexspectra = cpl_matrix_get_data(mexspectra);
02425     _mwavelength = cpl_matrix_get_data(mwavelength);
02426     _mrbspectra = cpl_matrix_get_data(mrbspectra);
02427 
02428     _abscissa = cpl_image_get_data_double(abscissa);
02429     _exspectra = cpl_image_get_data_double(exspectra);
02430     _rbspectra = cpl_image_get_data_double(rbspectra);
02431 
02432     if (exerrors != NULL) {
02433         mexerrors = cpl_matrix_new(nx, 1);
02434         mrberrors = cpl_matrix_new(nwl, 1);
02435 
02436         _mexerrors = cpl_matrix_get_data(mexerrors);
02437         _mrberrors = cpl_matrix_get_data(mrberrors);
02438 
02439         _exerrors = cpl_image_get_data_double(exerrors);
02440         _rberrors = cpl_image_get_data_double(rberrors);
02441     }
02442 
02443 
02444     /*
02445      * Resample each spectrum to the new grid, taking the direction of the
02446      * optical model into account. If the errors of the spectra are
02447      * available they are also resampled to the new grid.
02448      */
02449 
02450     cpl_msg_debug(fctid, "Rebinning %d spectra, using dispersion direction "
02451                   "%d and linear interpolation", ns, opt_direction);
02452 
02453     for (n = 0; n < ns; n++) {
02454 
02455         register cxlong x = 0;
02456 
02457 
02458         for (x = 0; x < nwl; x++) {
02459             register cxlong j = x * ns + n;
02460             _mwavelength[x] = _abscissa[j];
02461         }
02462 
02463         if (exerrors == NULL) {
02464 
02465             if (opt_direction < 0) {
02466 
02467                 for (x = 0; x < nx; x++) {
02468 
02469                     register cxlong j = x * ns + n;
02470                     register cxlong k = nx - x - 1;
02471 
02472                     _mabscissa[x] = (cxdouble) x;
02473                     _mexspectra[k] = _exspectra[j];
02474                 }
02475 
02476             }
02477             else {
02478 
02479                 for (x = 0; x < nx; x++) {
02480 
02481                     register cxlong j = x * ns + n;
02482 
02483                     _mabscissa[x] = (cxdouble) x;
02484                     _mexspectra[x] = _exspectra[j];
02485 
02486                 }
02487 
02488             }
02489 
02490 
02491             /*
02492              * Spline interpolation of spectra and errors
02493              */
02494 
02495             status = _giraffe_rebin_interpolate_spline(mabscissa,
02496                                                        mexspectra,
02497                                                        mwavelength,
02498                                                        mrbspectra);
02499 
02500             for (x = 0; x < nwl; x++) {
02501 
02502                 register cxlong j = x * ns + n;
02503 
02504                 if ((-0.5 > _mwavelength[x]) || (_mwavelength[x] > nx1)) {
02505                     _rbspectra[j] = 0.;
02506                 }
02507                 else {
02508                     _rbspectra[j] = _mrbspectra[x];
02509                 }
02510 
02511             }
02512 
02513         }
02514         else {
02515 
02516             if (opt_direction < 0) {
02517 
02518                 for (x = 0; x < nx; x++) {
02519 
02520                     register cxlong j = x * ns + n;
02521                     register cxlong k = nx - x - 1;
02522 
02523                     _mabscissa[x] = (cxdouble) x;
02524                     _mexspectra[k] = _exspectra[j];
02525                     _mexerrors[k] = _exerrors[j];
02526                 }
02527 
02528             }
02529             else {
02530 
02531                 for (x = 0; x < nx; x++) {
02532 
02533                     register cxlong j = x * ns + n;
02534 
02535                     _mabscissa[x] = (cxdouble) x;
02536                     _mexspectra[x] = _exspectra[j];
02537                     _mexerrors[x] = _exerrors[j];
02538 
02539                 }
02540 
02541             }
02542 
02543 
02544             /*
02545              * Spline interpolation of spectra and linear interpolation of
02546              * errors
02547              */
02548 
02549             status = _giraffe_rebin_interpolate_spline(mabscissa,
02550                                                        mexspectra,
02551                                                        mwavelength,
02552                                                        mrbspectra);
02553 
02554             status = _giraffe_rebin_interpolate_linear(mabscissa,
02555                                                        mexerrors,
02556                                                        mwavelength,
02557                                                        mrberrors);
02558 
02559             for (x = 0; x < nwl; x++) {
02560 
02561                 register cxlong j = x * ns + n;
02562 
02563                 if ((-0.5 > _mwavelength[x]) || (_mwavelength[x] > nx1)) {
02564                     _rbspectra[j] = 0.;
02565                     _rberrors[j] = 0.;
02566                 }
02567                 else {
02568                     _rbspectra[j] = _mrbspectra[x];
02569                     _rberrors[j] = _mrberrors[x];
02570                 }
02571 
02572             }
02573 
02574         }
02575 
02576     } /* each spectrum */
02577 
02578 
02579     cpl_matrix_delete(mrbspectra);
02580     mrbspectra = NULL;
02581 
02582     cpl_matrix_delete(mwavelength);
02583     mwavelength = NULL;
02584 
02585     cpl_matrix_delete(mexspectra);
02586     mexspectra = NULL;
02587 
02588     cpl_matrix_delete(mabscissa);
02589     mabscissa = NULL;
02590 
02591     if (exerrors != NULL) {
02592         cpl_matrix_delete(mrberrors);
02593         mrberrors = NULL;
02594 
02595         cpl_matrix_delete(mexerrors);
02596         mexerrors = NULL;
02597     }
02598 
02599     cpl_msg_debug(fctid, "Rebinned %d spectra", ns);
02600 
02601     return 0;
02602 
02603 }
02604 
02605 
02679 static cxdouble
02680 giraffe_rebin_compute_opt_mod3(cxdouble xccd, cxdouble xfibre,
02681                                cxdouble yfibre, cxdouble nx,
02682                                cxdouble pixsize, cxdouble fcoll,
02683                                cxdouble cfact, cxdouble gtheta,
02684                                cxdouble gorder, cxdouble gspace,
02685                                cxdouble slitdx, cxdouble slitdy,
02686                                cxdouble slitphi)
02687 {
02688 
02689     /*************************************************************************
02690                                      Variables
02691     *************************************************************************/
02692 
02693     cxdouble xf, yf, d, t1, t12, t13, t18, t19, t2, t23, t28,
02694         t3, t31, t32, t36, t37, t39, t4, t40, t5, t62, t8, t9;
02695 
02696     /*************************************************************************
02697                                      Processing
02698     *************************************************************************/
02699 
02700     /* should take care of negative NX value */
02701 
02702     xf = xfibre * (1.0 + slitphi * yfibre) + slitdx;
02703     yf = yfibre * sqrt(1.0 - slitphi * slitphi) + slitdy;
02704     d = sqrt(xf * xf + yf * yf + fcoll * fcoll);
02705     t1 = cos(gtheta);
02706     t2 = xf*t1;
02707     t3 = xccd*xccd;
02708     t4 = pixsize*pixsize;
02709     t5 = t3*t4;
02710     t8 = sin(gtheta);
02711     t9 = fcoll*t8;
02712     t12 = cfact*cfact;
02713     t13 = fcoll*fcoll;
02714     t18 = nx*nx;
02715     t19 = t18*t4;
02716     t23 = xccd*t4*nx;
02717     t28 = t12*t13;
02718     t31 = yf*yf;
02719     t32 = d*d;
02720     t36 = 4.0*t28;
02721     t37 = t19+4.0*t5-4.0*t23+t36;
02722     t39 = t1*t1;
02723     t40 = t39*t4;
02724     t62 = sqrt((-t31+t32)*t37*(4.0*t40*t3-4.0*xccd*nx*t40 +
02725                                8.0*xccd*t1*cfact*t9*pixsize+t19*t39 -
02726                                4.0*cfact*fcoll*t8*nx*t1*pixsize+t36 -
02727                                4.0*t28*t39));
02728 
02729     return((4.0*t2*t5 + 4.0*t9*t5 + 4.0*t12*t13*fcoll*t8+t2*t19+t9*t19 -
02730             4.0*t9*t23 - 4.0*t2*t23 + 4.0*t28*t2+t62)*gspace/t37/gorder/d);
02731 
02732 } /* end giraffe_rebin_compute_opt_mod3() */
02733 
02758 static cxdouble
02759 giraffe_rebin_compute_log_opt_mod3(cxdouble xccd, cxdouble xfibre,
02760                                    cxdouble yfibre, cxdouble nx,
02761                                    cxdouble pixsize, cxdouble fcoll,
02762                                    cxdouble cfact, cxdouble gtheta,
02763                                    cxdouble gorder, cxdouble gspace,
02764                                    cxdouble slitdx, cxdouble slitdy,
02765                                    cxdouble slitphi)
02766 {
02767 
02768     return log(giraffe_rebin_compute_opt_mod3(xccd, xfibre, yfibre, nx,
02769                                               pixsize, fcoll, cfact, gtheta,
02770                                               gorder, gspace, slitdx, slitdy,
02771                                               slitphi));
02772 
02773 } /* end of giraffe_rebin_compute_log_opt_mod3() */
02774 
02821 static cxint
02822 giraffe_rebin_compute_lambda_range(GiFiberPosition *fiber_slit_position,
02823                                    cpl_matrix *opt_mod_params,
02824                                    cpl_matrix *grat_params,
02825                                    cxbool lambda_logarithmic,
02826                                    cxbool wlen_range_common,
02827                                    cxdouble *lambda_min, cxdouble *lambda_max)
02828 {
02829 
02830     /*************************************************************************
02831                                      Variables
02832     *************************************************************************/
02833 
02834     const cxchar *fctid = "giraffe_rebin_compute_lambda_range";
02835 
02836     register cxlong   n, ns;
02837     register cxdouble dx2, dnx, wl1, wl2;
02838 
02839     double (*computeWl) (double, double, double, double, double, double,
02840                          double, double, double, double, double, double,
02841                          double);
02842 
02843     cxdouble    *pd_opt_mod_params = NULL,
02844         *pd_xfiber        = NULL,
02845         *pd_yfiber        = NULL,
02846         *pd_grat_params    = NULL;
02847 
02848     cxint        nr_xfiber;
02849 
02850     /*************************************************************************
02851                                     Preprocessing
02852     *************************************************************************/
02853 
02854     if (fiber_slit_position         ==NULL) { return 1; }
02855     if (fiber_slit_position->x_fiber==NULL) { return 1; }
02856     if (fiber_slit_position->y_fiber==NULL) { return 1; }
02857     if (opt_mod_params              ==NULL) { return 1; }
02858     if (grat_params                 ==NULL) { return 1; }
02859     if (lambda_min                  ==NULL) { return 1; }
02860     if (lambda_max                  ==NULL) { return 1; }
02861 
02862     pd_opt_mod_params = cpl_matrix_get_data(opt_mod_params);
02863 
02864     pd_xfiber = cpl_matrix_get_data(fiber_slit_position->x_fiber);
02865     nr_xfiber = cpl_matrix_get_nrow(fiber_slit_position->x_fiber);
02866 
02867     /*************************************************************************
02868                                      Processing
02869     *************************************************************************/
02870 
02871     if (lambda_logarithmic==TRUE) {
02872         computeWl = giraffe_rebin_compute_log_opt_mod3;
02873     } else {
02874         computeWl = giraffe_rebin_compute_opt_mod3;
02875     }
02876 
02877     dnx = abs(pd_opt_mod_params[O_NX]);
02878     dx2 = dnx - 1.0;
02879     ns  = nr_xfiber;
02880 
02881     if (wlen_range_common==TRUE) {
02882         *lambda_min = 0.0;
02883         *lambda_max = CX_MAXDOUBLE;
02884     } else {
02885         *lambda_min = CX_MAXDOUBLE;
02886         *lambda_max = 0.0;
02887     }
02888 
02889     pd_yfiber = cpl_matrix_get_data(fiber_slit_position->y_fiber);
02890     pd_grat_params = cpl_matrix_get_data(grat_params);
02891 
02892     for (n = 0; n < ns; n++) {
02893 
02894         /* first abcissa  of each spectrum */
02895         wl1 =
02896             computeWl(
02897                 0.0,
02898                 pd_xfiber[n],
02899                 pd_yfiber[n],
02900                 dnx,
02901                 pd_opt_mod_params[O_PXSIZ],
02902                 pd_opt_mod_params[O_FCOLL],
02903                 pd_opt_mod_params[O_CFACT],
02904                 pd_grat_params[G_THETA],
02905                 pd_grat_params[G_ORDER],
02906                 pd_grat_params[G_SPACE],
02907                 pd_opt_mod_params[O_SOFFX],
02908                 pd_opt_mod_params[O_SOFFY],
02909                 pd_opt_mod_params[O_SPHI]
02910                 );
02911 
02912         /* last abcissa  of each spectrum */
02913         wl2 =
02914             computeWl(
02915                 dx2,
02916                 pd_xfiber[n],
02917                 pd_yfiber[n],
02918                 dnx,
02919                 pd_opt_mod_params[O_PXSIZ],
02920                 pd_opt_mod_params[O_FCOLL],
02921                 pd_opt_mod_params[O_CFACT],
02922                 pd_grat_params[G_THETA],
02923                 pd_grat_params[G_ORDER],
02924                 pd_grat_params[G_SPACE],
02925                 pd_opt_mod_params[O_SOFFX],
02926                 pd_opt_mod_params[O_SOFFY],
02927                 pd_opt_mod_params[O_SPHI]
02928                 );
02929 
02930         if (wlen_range_common==TRUE) {
02931 
02932             /* common range = [max(wlen_min), min(wlen_max)] */
02933 
02934             if (pd_opt_mod_params[O_NX] < 0) {
02935                 *lambda_max = CX_MIN(*lambda_max, wl1);
02936                 *lambda_min = CX_MAX(*lambda_min, wl2);
02937             } else {
02938                 *lambda_max = CX_MIN(*lambda_max, wl2);
02939                 *lambda_min = CX_MAX(*lambda_min, wl1);
02940             }
02941 
02942         } else {
02943 
02944             /* full range = [min(wlen_min), max(wlen_max)] */
02945 
02946             if (pd_opt_mod_params[O_NX] < 0) {
02947                 *lambda_max = CX_MAX(*lambda_max, wl1);
02948                 *lambda_min = CX_MIN(*lambda_min, wl2);
02949             } else {
02950                 *lambda_max = CX_MAX(*lambda_max, wl2);
02951                 *lambda_min = CX_MIN(*lambda_min, wl1);
02952             }
02953 
02954         }
02955 
02956     } /* for each spectrum */
02957 
02958     if (wlen_range_common==TRUE) {
02959         /* round to minimum range in integer nanometers */
02960         *lambda_max = floor((*lambda_max) * GI_MM_TO_NM) / GI_MM_TO_NM;
02961         *lambda_min = ceil( (*lambda_min) * GI_MM_TO_NM) / GI_MM_TO_NM;
02962     } else {
02963         /* round to maximum range in integer nanometers */
02964         *lambda_max = ceil( (*lambda_max) * GI_MM_TO_NM) / GI_MM_TO_NM;
02965         *lambda_min = floor((*lambda_min) * GI_MM_TO_NM) / GI_MM_TO_NM;
02966     }
02967 
02968     cpl_msg_debug(fctid, "Rebinning lambda range now: [%12.6f,%12.6f]",
02969                   *lambda_min, *lambda_max);
02970 
02971     return 0;
02972 
02973 } /* end giraffe_rebin_compute_lambda_range() */
02974 
02997 static cpl_image*
02998 giraffe_rebin_compute_pixel_x_residuals(
02999     GiLocPosition   *locPos,
03000     cpl_image       *abcissa,
03001     GiSlitGeo  *slitGeo,
03002     GiSlitGeo  *xresiduals_limits,
03003     GiSlitGeo  *xresiduals_coeff
03004     ) {
03005 
03006     /*************************************************************************
03007                                      Variables
03008     *************************************************************************/
03009 
03010     const cxchar *fctid = "giraffe_rebin_compute_pixel_x_residuals";
03011 
03012     cxdouble xmin, xmax, ymin, ymax, yup, ylo, yccd, ywid;
03013     cxint    n, m, x, xx, x0, i, j, k, l, xxp, x0p;
03014 
03015     cxint             subslit,
03016         nfibers,
03017         nmin,
03018         nmax,
03019         nlen,
03020         nx,       /* size of original spectra */
03021         ns,       /* number of spectra */
03022         nwl,      /* size of rebinned spectra */
03023         nf,
03024         nstart,
03025         ndata,
03026         nr_fit,
03027         nc_fit;
03028 
03029     cpl_matrix       *xss                = NULL,
03030         *yss                = NULL,
03031         *fit                = NULL,
03032         *curr_xres_limits   = NULL,
03033         *curr_xres_coeff    = NULL;
03034 
03035     cpl_image        *x_residuals_img    = NULL;
03036 
03037     cpl_matrix       *curr_subslit       = NULL;
03038 
03039     cxdouble         *pd_curr_subslit    = NULL,
03040         *pd_abcissa         = NULL,
03041         *pd_xss             = NULL,
03042         *pd_yss             = NULL;
03043 
03044     cxdouble         *pd_locy            = NULL,
03045         *pd_locw            = NULL,
03046         *buffer             = NULL,
03047         *pd_fit             = NULL,
03048         *pd_x_residuals_img = NULL;
03049 
03050 
03051     /*************************************************************************
03052                                     Preprocessing
03053     *************************************************************************/
03054 
03055     if (locPos            ==NULL) { return NULL; }
03056     if (locPos->centroids ==NULL) { return NULL; }
03057     if (locPos->widths    ==NULL) { return NULL; }
03058     if (abcissa           ==NULL) { return NULL; }
03059     if (slitGeo           ==NULL) { return NULL; }
03060     if (xresiduals_limits ==NULL) { return NULL; }
03061     if (xresiduals_coeff  ==NULL) { return NULL; }
03062 
03063     nx  = cpl_image_get_size_y(locPos->centroids);
03064     ns  = cpl_image_get_size_x(locPos->centroids);
03065     nf  = cpl_image_get_size_x(abcissa);
03066     nwl = cpl_image_get_size_y(abcissa);
03067 
03068     cpl_msg_debug(
03069         fctid,
03070         "Computing pixel x residuals, using nr spec/nr lines/orig abcissa "
03071         "size: %d/%d/%d",
03072         ns,
03073         nwl,
03074         nx
03075         );
03076 
03077     /*************************************************************************
03078                                      Processing
03079     *************************************************************************/
03080 
03081     x_residuals_img    = cpl_image_new(nf, nwl, CPL_TYPE_DOUBLE);
03082     pd_x_residuals_img = cpl_image_get_data_double(x_residuals_img);
03083     pd_abcissa         = cpl_image_get_data_double(abcissa);
03084 
03085     nstart = 0;
03086 
03087     for (subslit = 0; subslit<_giraffe_slitgeo_size(slitGeo); subslit++) {
03088 
03089         curr_subslit    = _giraffe_slitgeo_get(slitGeo, subslit);
03090         pd_curr_subslit = cpl_matrix_get_data(curr_subslit);
03091 
03092         giraffe_matrix_sort(curr_subslit);
03093 
03094         curr_xres_limits =
03095             cpl_matrix_duplicate(
03096                 _giraffe_slitgeo_get(xresiduals_limits, subslit)
03097                 );
03098 
03099         curr_xres_coeff =
03100             cpl_matrix_duplicate(
03101                 _giraffe_slitgeo_get(xresiduals_coeff, subslit)
03102                 );
03103 
03104         /* Get spectra/fibers range for current subslit */
03105         nfibers = cpl_matrix_get_nrow(curr_subslit);
03106 
03107         nmin    = (cxint) pd_curr_subslit[0];
03108         nmax    = (cxint) pd_curr_subslit[nfibers - 1];
03109         nlen    = nmax - nmin + 1;
03110         ndata   = nwl * nfibers;
03111 
03112         ymax    = 0.0;
03113         ymin    = CX_MAXDOUBLE;   /* has to be smaller than this one! */
03114 
03115         xss     = cpl_matrix_new(ndata, 1); /* X abcissas for subslit  */
03116         yss     = cpl_matrix_new(ndata, 1); /* Y ordinates             */
03117 
03118         pd_xss  = cpl_matrix_get_data(xss);
03119         pd_yss  = cpl_matrix_get_data(yss);
03120 
03121         pd_locy = cpl_image_get_data_double(locPos->centroids);
03122         pd_locw = cpl_image_get_data_double(locPos->widths);
03123 
03124 
03125         k = 0;
03126 
03127         for (m = 0, n = 0; n < nfibers; n++, m++) {
03128 
03129             i = 0;  /* running index for valid points */
03130 
03131             for (x = 0; x < nwl; x++) {
03132 
03133                 j  = x * nf + (nstart + n);
03134                 x0 = (cxint) floor(pd_abcissa[j]);
03135                 xx = (cxint) ceil(pd_abcissa[j]);
03136 
03137                 x0 = CX_MAX(CX_MIN(x0, nx - 1), 0);
03138                 xx = CX_MAX(CX_MIN(xx, nx - 1), 0);
03139 
03140                 l   = i  * nfibers + m;
03141                 xxp = xx * ns   + cpl_matrix_get(curr_subslit, n, 0);
03142                 x0p = x0 * ns   + cpl_matrix_get(curr_subslit, n, 0);
03143 
03144                 pd_xss[l] = pd_abcissa[j];
03145 
03146                 /*
03147                  * Corresponding Y centroid  and width using
03148                  * linear interpolation)
03149                  */
03150 
03151                 yccd      = pd_locy[x0p];
03152                 pd_yss[l] = yccd + ((pd_locy[xxp] - yccd) * (pd_xss[l] - x0));
03153 
03154                 ywid = pd_locw[x0p];
03155                 ywid = ywid + ((pd_locw[xxp] - ywid) * (pd_xss[l] - x0));
03156 
03157                 /* Get y range for current subslit */
03158                 yup = yccd + ywid;
03159                 ylo = yccd - ywid;
03160 
03161                 /* determine minimum and maximum */
03162                 if (ymax < yup) {
03163                     ymax = yup;
03164                 }
03165 
03166                 if (ymin > ylo) {
03167                     ymin = ylo;
03168                 }
03169 
03170                 ++i;
03171                 ++k;
03172 
03173             }
03174         }
03175 
03176         /* resize matrices to number of points found */
03177         cpl_matrix_set_size(xss, k, 1);
03178         cpl_matrix_set_size(yss, k, 1);
03179         pd_xss = cpl_matrix_get_data(xss);
03180         pd_yss = cpl_matrix_get_data(yss);
03181 
03182         xmin = cpl_matrix_get(curr_xres_limits, 0, 0);
03183         xmax = cpl_matrix_get(curr_xres_limits, 0, 1);
03184         ymin = cpl_matrix_get(curr_xres_limits, 0, 2);
03185         ymax = cpl_matrix_get(curr_xres_limits, 0, 3);
03186 
03187         xmin = xmin < 0. ? 0. : xmin;
03188         xmax = xmax < 0. ? (cxdouble)nx : xmax;
03189 
03190         ymin = ymin < 0. ? 0. : ymin;
03191         ymax = ymax < 0. ? 2048. : ymax;
03192 
03193         /* do chebyshev fit */
03194         fit =
03195             giraffe_chebyshev_fit2d(
03196                 xmin, ymin,
03197                 (xmax - xmin),
03198                 (ymax - ymin + 1.0),
03199                 curr_xres_coeff,
03200                 xss,
03201                 yss
03202                 );
03203 
03204         cpl_matrix_delete(yss);
03205         cpl_matrix_delete(xss);
03206         cpl_matrix_delete(curr_xres_coeff);
03207         cpl_matrix_delete(curr_xres_limits);
03208 
03209         /* resize fit found to match image dimensions */
03210         buffer = cpl_matrix_get_data(fit);
03211         cpl_matrix_unwrap(fit);
03212         fit = NULL;
03213 
03214         fit = cpl_matrix_wrap(nwl, nfibers, buffer);
03215         pd_fit = cpl_matrix_get_data(fit);
03216         nr_fit = cpl_matrix_get_nrow(fit);
03217         nc_fit = cpl_matrix_get_ncol(fit);
03218 
03219         /* subslit fit goes into whole fit */
03220         for (x = 0; x < nr_fit; x++) {
03221             for (k = nstart, n = 0; n < nc_fit; n++, k++) {
03222                 pd_x_residuals_img[x * nf + k] = pd_fit[x * nc_fit + n];
03223             }
03224         }
03225 
03226         cpl_matrix_delete(fit);
03227         fit = NULL;
03228 
03229         nstart += nfibers;
03230 
03231     } /* for each subslit */
03232 
03233     cpl_msg_debug(
03234         fctid,
03235         "Computed pixel x residuals, returning image [%d,%d]",
03236         ns,
03237         nwl
03238         );
03239 
03240     return x_residuals_img;
03241 
03242 } /* end giraffe_rebin_compute_pixel_x_residuals() */
03243 
03244 
03277 static cpl_image*
03278 giraffe_rebin_compute_rebin_abcissa(GiFiberPosition* fiber_slit_position,
03279                                     GiLocPosition* locPos,
03280                                     GiSlitGeo* slitGeo,
03281                                     GiSlitGeo* xresiduals_limits,
03282                                     GiSlitGeo* xresiduals_coeff,
03283                                     cpl_matrix* grat_params,
03284                                     cpl_matrix* opt_mod_params,
03285                                     cpl_matrix* wloffsets,
03286                                     lmrq_model lmrq_opt_mod_x,
03287                                     GiRebinParams binPrms)
03288 {
03289 
03290     /*************************************************************************
03291                                      Variables
03292     *************************************************************************/
03293 
03294     const cxchar* const fctid = "giraffe_rebin_compute_rebin_abcissa";
03295 
03296     cpl_matrix* wlengths    = NULL;
03297     cpl_matrix* temp_params = NULL;
03298 
03299     cpl_image* abcissa         = NULL;
03300     cpl_image* x_residuals_img = NULL;
03301 
03302     cxdouble* pd_wlengths       = NULL;
03303     cxdouble* pd_temp_params    = NULL;
03304     cxdouble* pd_opt_mod_params = NULL;
03305     cxdouble* pd_grat_params    = NULL;
03306 
03307     /*************************************************************************
03308                                     Preprocessing
03309     *************************************************************************/
03310 
03311     if (fiber_slit_position == NULL) {
03312         return NULL;
03313     }
03314 
03315     if (locPos == NULL) {
03316         return NULL;
03317     }
03318 
03319     if (slitGeo == NULL) {
03320         return NULL;
03321     }
03322 
03323     if (grat_params == NULL) {
03324         return NULL;
03325     }
03326 
03327     if (opt_mod_params == NULL) {
03328         return NULL;
03329     }
03330 
03331     wlengths    = cpl_matrix_new(binPrms.size, 1);
03332     pd_wlengths = cpl_matrix_get_data(wlengths);
03333 
03334     temp_params = cpl_matrix_new(lmrq_opt_mod_x.nparams, 1);
03335 
03336     pd_temp_params    = cpl_matrix_get_data(temp_params);
03337     pd_opt_mod_params = cpl_matrix_get_data(opt_mod_params);
03338     pd_grat_params    = cpl_matrix_get_data(grat_params);
03339 
03340     pd_temp_params[OG_NX]    = pd_opt_mod_params[O_NX];
03341     pd_temp_params[OG_PXSIZ] = pd_opt_mod_params[O_PXSIZ];
03342     pd_temp_params[OG_FCOLL] = pd_opt_mod_params[O_FCOLL];
03343     pd_temp_params[OG_CFACT] = pd_opt_mod_params[O_CFACT];
03344     pd_temp_params[OG_THETA] = pd_grat_params[G_THETA];
03345     pd_temp_params[OG_ORDER] = pd_grat_params[G_ORDER];
03346     pd_temp_params[OG_SPACE] = pd_grat_params[G_SPACE];
03347 
03348     if (lmrq_opt_mod_x.nparams > OG_SOFFX) {
03349         pd_temp_params[OG_SOFFX] = pd_opt_mod_params[O_SOFFX];
03350         pd_temp_params[OG_SOFFY] = pd_opt_mod_params[O_SOFFY];
03351         pd_temp_params[OG_SPHI]  = pd_opt_mod_params[O_SPHI];
03352     }
03353 
03354     /*************************************************************************
03355                                      Processing
03356     *************************************************************************/
03357 
03358     /*
03359      *  Compute lambda abcissa for rebinning
03360      */
03361 
03362     if (binPrms.log==TRUE) {
03363         /* lambda was specified in log(lambda) */
03364         cxint i;
03365         for (i = 0; i < binPrms.size; i++) {
03366             pd_wlengths[i] = exp(binPrms.min + (cxdouble) i * binPrms.step);
03367         }
03368     } else {
03369         cxint i;
03370         for (i = 0; i < binPrms.size; i++) {
03371             pd_wlengths[i] = binPrms.min + (cxdouble) i * binPrms.step;
03372         }
03373     }
03374 
03375     abcissa = _giraffe_compute_pixel_abscissa(wlengths, wloffsets,
03376                                               fiber_slit_position,
03377                                               temp_params, lmrq_opt_mod_x);
03378 
03379 
03380     /*
03381      *  If X residuals use, specified, calculate them and subtract
03382      *  them from the computed abcissa...
03383      */
03384 
03385     if ((binPrms.xres==TRUE) && (xresiduals_coeff!=NULL)) {
03386 
03387         x_residuals_img =
03388             giraffe_rebin_compute_pixel_x_residuals(
03389                 locPos,
03390                 abcissa,
03391                 slitGeo,
03392                 xresiduals_limits,
03393                 xresiduals_coeff
03394                 );
03395 
03396         cpl_image_subtract(abcissa, x_residuals_img);
03397         cpl_image_delete(x_residuals_img);
03398 
03399     }
03400 
03401     cpl_matrix_delete(wlengths);
03402     cpl_matrix_delete(temp_params);
03403 
03404     cpl_msg_debug(fctid, "Processing complete : returning image "
03405                   "[%" CPL_SIZE_FORMAT ", %" CPL_SIZE_FORMAT "]",
03406                   cpl_image_get_size_x(abcissa), cpl_image_get_size_y(abcissa));
03407 
03408     return abcissa;
03409 
03410 } /* end giraffe_rebin_compute_rebin_abcissa() */
03411 
03439 inline static cxint
03440 _giraffe_resample_spectra(GiRebinning* result,
03441                           const GiExtraction* extraction,
03442                           const GiLocalization* localization,
03443                           GiFiberPosition* fiber_position,
03444                           GiSlitGeo* subslits,
03445                           GiSlitGeo* xres_limits,
03446                           GiSlitGeo* xres_coeff,
03447                           GiBinnParams* xres_order,
03448                           cpl_matrix* grating_data,
03449                           cpl_matrix* optical_model,
03450                           cpl_matrix* wlen_offsets,
03451                           cxdouble rbstep,
03452                           GiRebinMethod method,
03453                           GiRebinRange range,
03454                           GiRebinScale scale)
03455 {
03456 
03457     const cxchar* const fctid = "_giraffe_resample_spectra";
03458 
03459 
03460     cxbool log_scale = FALSE;
03461 
03462     cxint i = 0;
03463     cxint status = 0;
03464     cxint om_sign = 0;
03465     cxint rbsize = 0;
03466     cxint nspectra = 0;
03467 
03468     cxdouble wlmin = 0.;
03469     cxdouble wlmax = 0.;
03470     cxdouble* _optical_model = NULL;
03471 
03472     cpl_matrix* wavelengths = NULL;
03473 
03474     cpl_image* _exspectra = NULL;
03475     cpl_image* _exerrors = NULL;
03476     cpl_image* _rbspectra = NULL;
03477     cpl_image* _rberrors = NULL;
03478     cpl_image* abscissa = NULL;
03479 
03480     cpl_propertylist* properties = NULL;
03481 
03482     GiImage* rbspectra = NULL;
03483     GiImage* rberrors = NULL;
03484 
03485     GiLocPosition locPos;
03486 
03487     GiRebinParams binPrms;
03488 
03489     GiRebinInfo setup;
03490 
03491 
03492     /*
03493      * default opt model is xoptmod2, python code
03494      * can not handle anything else anyway
03495      */
03496 
03497      lmrq_model_id opt_mod_id = LMRQ_XOPTMOD2;
03498 
03499 
03500     if (result == NULL || extraction == NULL || localization == NULL) {
03501         return 1;
03502     }
03503 
03504     if (result->spectra != NULL || result->errors != NULL) {
03505         return 1;
03506     }
03507 
03508     if (extraction->spectra == NULL) {
03509         return 1;
03510     }
03511 
03512     if (localization->locy == NULL || localization->locw == NULL) {
03513         return 1;
03514     }
03515 
03516     if (fiber_position == NULL) {
03517         return 1;
03518     }
03519 
03520     if (subslits == NULL) {
03521         return 1;
03522     }
03523 
03524     if (grating_data == NULL) {
03525         return 1;
03526     }
03527 
03528     if (optical_model == NULL) {
03529         return 1;
03530     }
03531 
03532 
03533     if (xres_coeff != NULL) {
03534         if (xres_limits == NULL || xres_order == NULL) {
03535             return 1;
03536         }
03537     }
03538 
03539 
03540     /*
03541      * FIXME: Should we set opt_mod_id to opt_mod_id used by wave
03542      *        calibration? Yes!!!
03543      */
03544 
03545     _exspectra = giraffe_image_get(extraction->spectra);
03546 
03547     if (extraction->error != NULL) {
03548         _exerrors = giraffe_image_get(extraction->error);
03549     }
03550 
03551     _optical_model = cpl_matrix_get_data(optical_model);
03552 
03553     nspectra = cpl_image_get_size_x(_exspectra);
03554 
03555     om_sign = (_optical_model[O_NX] >= 0) ? 1 : -1;
03556 
03557     if (scale == GIREBIN_SCALE_LOG) {
03558         log_scale = TRUE;
03559     }
03560 
03561 
03562     /*
03563      *  Find wavelength range
03564      */
03565 
03566      if (range == GIREBIN_RANGE_SETUP) {
03567 
03568         /*
03569          * Wavelength range taken from observed mode
03570          */
03571 
03572         wlmin = cpl_matrix_get(grating_data, 2, 0);
03573         wlmax = cpl_matrix_get(grating_data, 4, 0);
03574 
03575         if (log_scale == TRUE) {
03576             wlmin = log(wlmin);
03577             wlmax = log(wlmax);
03578         }
03579 
03580     }
03581     else {
03582 
03583         /*
03584          * Spectral range based on max/min wavelengths
03585          */
03586 
03587         status = giraffe_rebin_compute_lambda_range(fiber_position,
03588                                                     optical_model,
03589                                                     grating_data, log_scale,
03590                                                     TRUE, &wlmin, &wlmax);
03591 
03592     }
03593 
03594     rbsize = 1 + (cxint) ((wlmax - wlmin) / rbstep);
03595 
03596     if (rbsize < 0) {
03597 
03598         cpl_msg_debug(fctid, "Invalid dispersion direction [%d], changing "
03599                       "optical model orientation", om_sign);
03600 
03601         om_sign = -om_sign;
03602         _optical_model[O_NX] = -_optical_model[O_NX];
03603 
03604         status = giraffe_rebin_compute_lambda_range(fiber_position,
03605                                                     optical_model,
03606                                                     grating_data, log_scale,
03607                                                     TRUE, &wlmin, &wlmax);
03608 
03609         rbsize = 1 + (cxint) ((wlmax - wlmin) / rbstep);
03610 
03611     }
03612 
03613     if (rbsize < 1) {
03614         cpl_msg_error(fctid, "Invalid size %d of rebinned spectra, "
03615                       "aborting...", rbsize);
03616         return 2;
03617     }
03618 
03619 
03620     /*
03621      *  Calculate rebinned X positions...
03622      */
03623 
03624     locPos.type      = GILOCDATATYPE_FITTED_DATA;
03625     locPos.centroids = giraffe_image_get(localization->locy);
03626     locPos.widths    = giraffe_image_get(localization->locw);
03627 
03628     binPrms.min  = wlmin;
03629     binPrms.step = rbstep;
03630     binPrms.size = rbsize;
03631     binPrms.log  = log_scale;
03632 
03633     if (xres_coeff == NULL || (xres_order->xdeg == 0 &&
03634                                xres_order->ydeg == 0)) {
03635         binPrms.xres = FALSE;
03636     }
03637     else {
03638         binPrms.xres = TRUE;
03639     }
03640 
03641     abscissa = giraffe_rebin_compute_rebin_abcissa(fiber_position, &locPos,
03642                                                    subslits, xres_limits,
03643                                                    xres_coeff, grating_data,
03644                                                    optical_model, wlen_offsets,
03645                                                    lmrq_models[opt_mod_id],
03646                                                    binPrms);
03647 
03648 
03649     /*
03650      *  Perform rebinng of spectra and associated errors...
03651      */
03652 
03653     wavelengths = cpl_matrix_new(rbsize, 1);
03654 
03655     for (i = 0; i < rbsize; i++) {
03656         cpl_matrix_set(wavelengths, i, 0, wlmin + (cxdouble) i * rbstep);
03657     }
03658 
03659     rbspectra = giraffe_image_create(CPL_TYPE_DOUBLE, nspectra, rbsize);
03660     _rbspectra = giraffe_image_get(rbspectra);
03661 
03662     if (_exerrors != NULL) {
03663         rberrors = giraffe_image_create(CPL_TYPE_DOUBLE, nspectra, rbsize);
03664         _rberrors = giraffe_image_get(rberrors);
03665     }
03666 
03667     switch (method) {
03668     case GIREBIN_METHOD_LINEAR:
03669         status = _giraffe_resample_linear(_rbspectra, _rberrors, abscissa,
03670                                           _exspectra, _exerrors, om_sign);
03671         break;
03672 
03673     case GIREBIN_METHOD_SPLINE:
03674         status = _giraffe_resample_spline(_rbspectra, _rberrors, abscissa,
03675                                           _exspectra, _exerrors, om_sign);
03676         break;
03677 
03678     default:
03679 
03680         /* We should never get to this point! */
03681 
03682         gi_error("Invalid rebinning method!");
03683         break;
03684     }
03685 
03686     cpl_image_delete(abscissa);
03687     abscissa = NULL;
03688 
03689     if (status != 0) {
03690         cpl_msg_error(fctid, "Error during rebinning, aborting...");
03691 
03692         cpl_matrix_delete(wavelengths);
03693         wavelengths = NULL;
03694 
03695         giraffe_image_delete(rbspectra);
03696         rbspectra = NULL;
03697 
03698         if (rberrors != NULL) {
03699             giraffe_image_delete(rberrors);
03700             rberrors = NULL;
03701         }
03702 
03703         return 3;
03704     }
03705 
03706 
03707 
03708     /*
03709      *  Add calculated image, keywords etc. to rebinned spectrum frame...
03710      */
03711 
03712     switch (scale) {
03713     case GIREBIN_SCALE_LOG:
03714         {
03715             cxsize nw = cpl_matrix_get_nrow(wavelengths);
03716 
03717             cxdouble mm2nm = log(GI_MM_TO_NM);
03718 
03719             setup.wmin = mm2nm + cpl_matrix_get(wavelengths, 0, 0);
03720             setup.wcenter = mm2nm + cpl_matrix_get(wavelengths, nw / 2, 0);
03721             setup.wmax = mm2nm + cpl_matrix_get(wavelengths, nw - 1, 0);
03722             setup.wstep  = rbstep;
03723 
03724             setup.units = "log(nm)";
03725             setup.offset = 0;
03726         }
03727         break;
03728 
03729     case GIREBIN_SCALE_LINEAR:
03730         {
03731             cxsize nw = cpl_matrix_get_nrow(wavelengths);
03732 
03733             setup.wmin = GI_MM_TO_NM * cpl_matrix_get(wavelengths, 0, 0);
03734             setup.wcenter = GI_MM_TO_NM * cpl_matrix_get(wavelengths,
03735                                                          nw / 2, 0);
03736             setup.wmax = GI_MM_TO_NM * cpl_matrix_get(wavelengths,
03737                                                       nw - 1, 0);
03738             setup.wstep  = GI_MM_TO_NM * rbstep;
03739 
03740             setup.units = "nm";
03741             setup.offset = 0;
03742         }
03743         break;
03744 
03745     default:
03746 
03747         /* We should never get here */
03748 
03749         gi_error("Invalid scaling option!");
03750         break;
03751     }
03752 
03753     cpl_matrix_delete(wavelengths);
03754     wavelengths = NULL;
03755 
03756 
03757     switch (method) {
03758     case GIREBIN_METHOD_LINEAR:
03759         setup.method = "linear";
03760         break;
03761 
03762     case GIREBIN_METHOD_SPLINE:
03763         setup.method = "spline";
03764         break;
03765 
03766     default:
03767 
03768         /* We should never get here */
03769 
03770         gi_error("Invalid rebinning method!");
03771         break;
03772     }
03773 
03774 
03775     switch (scale) {
03776     case GIREBIN_SCALE_LINEAR:
03777         setup.scale = "linear";
03778         break;
03779 
03780     case GIREBIN_SCALE_LOG:
03781         setup.scale = "logarithmic";
03782         break;
03783 
03784     default:
03785 
03786         /* We should never get here */
03787 
03788         gi_error("Invalid scaling option!");
03789         break;
03790     }
03791 
03792     switch (range) {
03793     case GIREBIN_RANGE_SETUP:
03794         setup.range = "setup";
03795         break;
03796 
03797     case GIREBIN_RANGE_COMMON:
03798         setup.range = "common";
03799         break;
03800 
03801     default:
03802 
03803         /* We should never get here */
03804 
03805         gi_error("Invalid range option!");
03806         break;
03807     }
03808 
03809 
03810     /*
03811      * Finalize resampled spectra
03812      */
03813 
03814     giraffe_error_push();
03815 
03816     properties = giraffe_image_get_properties(extraction->spectra);
03817     giraffe_image_set_properties(rbspectra, properties);
03818 
03819     if (cpl_error_get_code() != CPL_ERROR_NONE) {
03820         giraffe_image_delete(rbspectra);
03821         rbspectra = NULL;
03822 
03823         if (rberrors != NULL) {
03824             giraffe_image_delete(rberrors);
03825             rberrors = NULL;
03826         }
03827 
03828         return 4;
03829     }
03830 
03831     giraffe_error_pop();
03832 
03833     status = _giraffe_resample_update_properties(rbspectra, &setup);
03834 
03835     if (status != 0) {
03836         giraffe_image_delete(rbspectra);
03837         rbspectra = NULL;
03838 
03839         if (rberrors != NULL) {
03840             giraffe_image_delete(rberrors);
03841             rberrors = NULL;
03842         }
03843 
03844         return 4;
03845     }
03846 
03847 
03848     /*
03849      * Finalize resampled spectra errors if they are available
03850      */
03851 
03852     if (_rberrors != NULL) {
03853 
03854         giraffe_error_push();
03855 
03856         properties =  giraffe_image_get_properties(extraction->error);
03857         giraffe_image_set_properties(rberrors, properties);
03858 
03859         if (cpl_error_get_code() != CPL_ERROR_NONE) {
03860             giraffe_image_delete(rbspectra);
03861             rbspectra = NULL;
03862 
03863             if (rberrors != NULL) {
03864                 giraffe_image_delete(rberrors);
03865                 rberrors = NULL;
03866             }
03867 
03868             return 5;
03869         }
03870 
03871         giraffe_error_pop();
03872 
03873         status = _giraffe_resample_update_properties(rberrors, &setup);
03874 
03875         if (status != 0) {
03876             giraffe_image_delete(rbspectra);
03877             rbspectra = NULL;
03878 
03879             if (rberrors != NULL) {
03880                 giraffe_image_delete(rberrors);
03881                 rberrors = NULL;
03882             }
03883 
03884             return 5;
03885         }
03886 
03887     }
03888 
03889     result->spectra = rbspectra;
03890     result->errors = rberrors;
03891 
03892     return 0;
03893 
03894 }
03895 
03896 
03904 GiRange *
03905 giraffe_rebin_get_wavelength_range(GiImage *spectra, GiTable *wlsolution,
03906                                    GiTable *grating, GiTable *slitgeometry,
03907                                    cxbool common)
03908 {
03909 
03910     cxint status = 0;
03911 
03912     cxdouble min = 0.;
03913     cxdouble max = 0.;
03914 
03915     cpl_matrix *optical_model = NULL;
03916     cpl_matrix *grating_data = NULL;
03917 
03918     GiFiberPosition *positions = NULL;
03919     GiSlitGeo *subslits = NULL;
03920 
03921     GiWcalSolution *wcal = NULL;
03922 
03923     GiRange *range = NULL;
03924 
03925 
03926     if (spectra == NULL) {
03927         return NULL;
03928     }
03929 
03930     if (grating == NULL) {
03931         return NULL;
03932     }
03933 
03934     if (slitgeometry == NULL) {
03935         return NULL;
03936     }
03937 
03938 
03939     wcal = _giraffe_wcalsolution_create(wlsolution);
03940 
03941     if (wcal == NULL) {
03942         return NULL;
03943     }
03944 
03945     optical_model = _giraffe_rebin_setup_model(spectra, wcal);
03946 
03947     if (optical_model == NULL) {
03948         _giraffe_wcalsolution_delete(wcal);
03949         return NULL;
03950     }
03951 
03952     _giraffe_wcalsolution_delete(wcal);
03953 
03954     grating_data = _giraffe_rebin_setup_grating(spectra, grating,
03955                                                 wlsolution);
03956 
03957     if (grating_data == NULL) {
03958 
03959         cpl_matrix_delete(grating_data);
03960         cpl_matrix_delete(optical_model);
03961 
03962         return NULL;
03963 
03964     }
03965 
03966     positions = _giraffe_fiberposition_new();
03967     subslits = _giraffe_slitgeo_new();
03968 
03969     status = _giraffe_slitgeo_setup(slitgeometry, positions, subslits,
03970                                     FALSE);
03971 
03972     if (status != 0) {
03973 
03974         _giraffe_slitgeo_delete(subslits);
03975         _giraffe_fiberposition_delete(positions);
03976 
03977         cpl_matrix_delete(grating_data);
03978         cpl_matrix_delete(optical_model);
03979 
03980         return NULL;
03981 
03982     }
03983 
03984     status = giraffe_rebin_compute_lambda_range(positions, optical_model,
03985                                                 grating_data,
03986                                                 GIREBIN_SCALE_LINEAR,
03987                                                 common, &min, &max);
03988 
03989     /*
03990      * Convert wavelength from millimeters to nanometers.
03991      */
03992 
03993     min *= GI_MM_TO_NM;
03994     max *= GI_MM_TO_NM;
03995 
03996     _giraffe_slitgeo_delete(subslits);
03997     _giraffe_fiberposition_delete(positions);
03998 
03999     cpl_matrix_delete(grating_data);
04000     cpl_matrix_delete(optical_model);
04001 
04002     range = giraffe_range_create(min, max);
04003 
04004     return range;
04005 
04006 }
04007 
04008 
04042 cxint
04043 giraffe_rebin_spectra(GiRebinning *rebinning,
04044                       const GiExtraction *extraction,
04045                       const GiTable *fibers,
04046                       const GiLocalization *localization,
04047                       const GiTable *grating,
04048                       const GiTable *slitgeo,
04049                       const GiTable *solution,
04050                       const GiRebinConfig *config)
04051 {
04052 
04053     const cxchar* const fctid = "giraffe_rebin_spectra";
04054 
04055 
04056     cxint status = 0;
04057     cxint ex_sp_extr_pixels = 0;
04058     cxint calc_rebinned_size = 0;
04059     cxint default_rebinned_size = GIREBIN_SIZE_Y_DEFAULT;
04060 
04061     cxdouble rbin_multiplier = 0.;
04062     cxdouble ex_sp_pixsize_x = 0.;
04063     cxdouble rbin_stepsize = 0.;
04064 
04065     cpl_matrix* grat_params    = NULL;
04066     cpl_matrix* opt_mod_params = NULL;
04067     cpl_matrix* wloffsets      = NULL;
04068 
04069     cpl_table* _fibers = NULL;
04070 
04071     cpl_propertylist* _pl_ext_sp = NULL;
04072     cpl_propertylist* _pl_wsol   = NULL;
04073 
04074     GiImage* ex_sp_frame = NULL;
04075     GiImage* ex_sp_err_frame = NULL;
04076     GiImage* loc_y_frame = NULL;
04077     GiImage* loc_w_frame = NULL;
04078 
04079     GiSlitGeo* subslit_fibers = NULL;
04080     GiSlitGeo* wav_coeffs = NULL;
04081     GiSlitGeo* wav_limits = NULL;
04082 
04083     GiGrat* grating_data = NULL;
04084 
04085     GiFiberPosition* fiber_slit_position  = NULL;
04086 
04087     GiWcalSolution* wcalib_solution = NULL;
04088 
04089     GiBinnParams xres_polynom_deg = {0, 0};
04090 
04091 
04092 
04093     /*
04094      * Preprocessing
04095      */
04096 
04097     if (extraction == NULL) {
04098         cpl_msg_error(fctid, "No extracted data, aborting...");
04099         return 1;
04100     }
04101 
04102     if (extraction->spectra == NULL) {
04103         cpl_msg_error(fctid, "No extracted spectra, aborting...");
04104         return 1;
04105     }
04106 
04107     if (fibers == NULL) {
04108         cpl_msg_error(fctid, "No fiber table, aborting ...");
04109         return 1;
04110     }
04111 
04112     if (localization == NULL) {
04113         cpl_msg_error(fctid, "No localization data, aborting...");
04114         return 1;
04115     }
04116 
04117     if (localization->locy == NULL) {
04118         cpl_msg_error(fctid, "No localization centroids, aborting...");
04119         return 1;
04120     }
04121 
04122     if (localization->locw == NULL) {
04123         cpl_msg_error(fctid, "No localization widths, aborting...");
04124         return 1;
04125     }
04126 
04127     if (grating == NULL) {
04128         cpl_msg_error(fctid, "No grating data, aborting...");
04129         return 1;
04130     }
04131 
04132     if (rebinning == NULL) {
04133         cpl_msg_error(fctid, "No rebinning results container, aborting...");
04134         return 1;
04135     }
04136 
04137     if (config == NULL) {
04138         cpl_msg_error(fctid, "No rebinning configuration data, aborting...");
04139         return 1;
04140     }
04141 
04142     if (solution == NULL) {
04143         cpl_msg_error(fctid, "No wavecalibration solution, aborting...");
04144         return 1;
04145     }
04146 
04147     ex_sp_frame          = extraction->spectra;
04148     ex_sp_err_frame      = extraction->error;
04149     loc_y_frame          = localization->locy;
04150     loc_w_frame          = localization->locw;
04151 
04152     _pl_ext_sp           = giraffe_image_get_properties(ex_sp_frame);
04153     _pl_wsol             = giraffe_table_get_properties(solution);
04154 
04155 
04156     _fibers = giraffe_table_get(fibers);
04157     cx_assert(_fibers != NULL);
04158 
04159 
04160 
04161     /*
04162      * Initialization
04163      */
04164 
04165     /*
04166      *  Retrieve necessary values from FITS keywords
04167      */
04168 
04169     if (cpl_propertylist_has(_pl_ext_sp, GIALIAS_PIXSIZX) == TRUE) {
04170         ex_sp_pixsize_x = cpl_propertylist_get_double(_pl_ext_sp,
04171                                                       GIALIAS_PIXSIZX);
04172 
04173     }
04174     else {
04175         cpl_msg_error(fctid, "%s Keyword missing in Extracted Spectra "
04176                       "Frame, aborting ...", GIALIAS_PIXSIZX);
04177         return 2;
04178     }
04179 
04180 
04181     /*
04182      * Convert pixel size to microns
04183      */
04184 
04185     if (ex_sp_pixsize_x > 1.) {
04186         ex_sp_pixsize_x /= 1000.;
04187     }
04188 
04189 
04190     /*
04191      * Determine rebinning step size multiplier
04192      */
04193 
04194     if (cpl_propertylist_has(_pl_ext_sp, GIALIAS_GRATNAME) == TRUE) {
04195 
04196         const cxchar* _string = NULL;
04197 
04198         _string = cpl_propertylist_get_string(_pl_ext_sp, GIALIAS_GRATNAME);
04199 
04200         if (strncmp(_string, "LR", 2) == 0) {
04201             rbin_multiplier = 4.;
04202         }
04203         else if (strncmp(_string, "HR", 2) == 0) {
04204             rbin_multiplier = 1.;
04205         }
04206         else {
04207             rbin_multiplier = 1.;
04208         }
04209 
04210     }
04211     else {
04212         cpl_msg_error(fctid, "%s Keyword missing in Extracted Spectra Frame, "
04213                       "aborting ...", GIALIAS_GRATNAME);
04214         return 2;
04215     }
04216 
04217 
04218     /*
04219      * find number of pixel per spectrum
04220      */
04221 
04222     if (cpl_propertylist_has(_pl_ext_sp, GIALIAS_EXT_NX) == TRUE) {
04223         ex_sp_extr_pixels = cpl_propertylist_get_int(_pl_ext_sp,
04224                                                      GIALIAS_EXT_NX);
04225 
04226     }
04227     else {
04228         cpl_msg_error(fctid, "%s Keyword missing in Extracted Spectra Frame, "
04229                       "aborting ...", GIALIAS_EXT_NX);
04230         return 2;
04231     }
04232 
04233 
04234     /*
04235      *  Retrieve Grating information
04236      */
04237 
04238     grating_data = _giraffe_grating_new();
04239 
04240     status = _giraffe_grating_setup(grating, ex_sp_frame, grating_data);
04241 
04242     if (status != 0) {
04243         cpl_msg_error(fctid, "Unable to retrieve grating information, "
04244                       "aborting...");
04245         _giraffe_grating_delete(grating_data);
04246         return 3;
04247     }
04248 
04249     /*
04250      *  Retrieve Slit Geometry Information
04251      */
04252 
04253     fiber_slit_position = _giraffe_fiberposition_new();
04254     subslit_fibers = _giraffe_slitgeo_new();
04255 
04256     status = _giraffe_slitgeo_setup(slitgeo, fiber_slit_position,
04257                                     subslit_fibers, FALSE);
04258 
04259     if (status != 0) {
04260         cpl_msg_error(fctid, "Unable to retrieve slit geometry information, "
04261                       "aborting...");
04262         _giraffe_grating_delete(grating_data);
04263         _giraffe_fiberposition_delete(fiber_slit_position);
04264         _giraffe_slitgeo_delete(subslit_fibers);
04265         return 7;
04266     }
04267 
04268 
04269     wcalib_solution = _giraffe_wcalsolution_create(solution);
04270 
04271     if (wcalib_solution == NULL) {
04272         cpl_msg_error(fctid, "Cannot create wavelength solution, "
04273                       "aborting ...");
04274         _giraffe_grating_delete(grating_data);
04275         _giraffe_fiberposition_delete(fiber_slit_position);
04276         _giraffe_slitgeo_delete(subslit_fibers);
04277         return 4;
04278     }
04279 
04280     if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMFCOLL) == TRUE) {
04281         grating_data->fcoll =
04282             cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMFCOLL);
04283     }
04284 
04285     if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMGCAM) == TRUE) {
04286         grating_data->gcam =
04287             cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMGCAM);
04288     }
04289 
04290     if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMGTHETA) == TRUE) {
04291         grating_data->theta =
04292             cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMGTHETA);
04293     }
04294 
04295     if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMSDX) == TRUE) {
04296         grating_data->slitdx =
04297             cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMSDX);
04298     }
04299 
04300     if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMSDY) == TRUE) {
04301         grating_data->slitdy =
04302             cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMSDY);
04303     }
04304 
04305     if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMSPHI) == TRUE) {
04306         grating_data->slitphi =
04307             cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMSPHI);
04308     }
04309 
04310 
04311     /*
04312      * If wavelength corrections were provided, convert the wavelength
04313      * offsets from nanometers to millimeters and store them as a
04314      * matrix (nfibers x 1).
04315      */
04316 
04317     if (cpl_table_has_column(_fibers, "WLRES") != 0) {
04318 
04319         cxint fiber = 0;
04320         cxint nfibers = cpl_table_get_nrow(_fibers);
04321 
04322 
04323         wloffsets  = cpl_matrix_new(nfibers, 1);
04324 
04325         for (fiber = 0; fiber < nfibers; ++fiber) {
04326 
04327             cxdouble wloffset = cpl_table_get_double(_fibers, "WLRES",
04328                 fiber, NULL);
04329 
04330 
04331             wloffset *= -GI_NM_TO_MM;
04332             cpl_matrix_set(wloffsets, fiber, 0, wloffset);
04333 
04334         }
04335 
04336         cpl_msg_info(fctid, "Applying SIMCAL wavelength corrections ...");
04337 
04338     }
04339 
04340 
04341 
04342     /*
04343      * Processing
04344      */
04345 
04346 
04347     /*
04348      *  Determine rebinning stepsize and size in y direction after rebinning
04349      */
04350 
04351     if (config->scmethod == GIREBIN_SCALE_LOG) {
04352 
04353         cxint rebin_size;
04354 
04355         cxdouble wlenmax;
04356         cxdouble wlenmin;
04357 
04358         rebin_size = default_rebinned_size;
04359 
04360         wlenmin = log(grating_data->wlenmin / GI_MM_TO_NM);
04361         wlenmax = log(grating_data->wlenmax / GI_MM_TO_NM);
04362 
04363         if ((config->size != rebin_size) && (config->size != 0)) {
04364             rebin_size = config->size;
04365         }
04366 
04367         rbin_stepsize = (wlenmax - wlenmin) / rebin_size;
04368 
04369         calc_rebinned_size = 1 + (cxint) ((wlenmax-wlenmin)/ rbin_stepsize);
04370 
04371     }
04372     else {
04373 
04374         cxint rebin_size;
04375 
04376         cxdouble wlenmax;
04377         cxdouble wlenmin;
04378 
04379         wlenmin = grating_data->wlenmin / GI_MM_TO_NM;
04380         wlenmax = grating_data->wlenmax / GI_MM_TO_NM;
04381 
04382         rbin_stepsize = (config->lstep / GI_MM_TO_NM) * rbin_multiplier;
04383         rebin_size    = (wlenmax - wlenmin) / rbin_stepsize;
04384 
04385         if ((config->size != rebin_size) && (config->size != 0)) {
04386             rebin_size = config->size;
04387             rbin_stepsize = (wlenmax - wlenmin) / rebin_size;
04388         }
04389 
04390         calc_rebinned_size = 1 + (cxint) ((wlenmax-wlenmin) / rbin_stepsize);
04391 
04392     }
04393 
04394     /*
04395      *  Retrieve Wavecalibration Solution Physical Optical Paramters
04396      */
04397 
04398     if (wcalib_solution!=NULL) {
04399 
04400         if (wcalib_solution->opt_mod==LMRQ_XOPTMOD) {
04401 
04402             cxint    nrow;
04403             cxdouble opt_direction, fcoll, cfact;
04404 
04405             nrow = cpl_matrix_get_nrow(wcalib_solution->opt_mod_params);
04406             if (nrow==4) {
04407                 opt_direction =
04408                     cpl_matrix_get(wcalib_solution->opt_mod_params, 0, 0);
04409                 fcoll =
04410                     cpl_matrix_get(wcalib_solution->opt_mod_params, 1, 0);
04411                 cfact =
04412                     cpl_matrix_get(wcalib_solution->opt_mod_params, 2, 0);
04413 
04414                 opt_mod_params = cpl_matrix_new(4,1);
04415                 cpl_matrix_set(opt_mod_params, 0, 0,
04416                                ex_sp_extr_pixels * opt_direction);
04417                 cpl_matrix_set(opt_mod_params, 1, 0, ex_sp_pixsize_x);
04418                 cpl_matrix_set(opt_mod_params, 2, 0, fcoll);
04419                 cpl_matrix_set(opt_mod_params, 3, 0, cfact);
04420             }
04421             else {
04422                 cpl_msg_error(fctid, "Invalid number of physical optical "
04423                               "parameters, aborting...");
04424 
04425                 if (wloffsets != NULL) {
04426                     cpl_matrix_delete(wloffsets);
04427                 }
04428 
04429                 _giraffe_wcalsolution_delete(wcalib_solution);
04430                 _giraffe_grating_delete(grating_data);
04431                 _giraffe_fiberposition_delete(fiber_slit_position);
04432                 _giraffe_slitgeo_delete(subslit_fibers);
04433                 return 6;
04434             }
04435 
04436         }
04437         else if (wcalib_solution->opt_mod==LMRQ_XOPTMOD2) {
04438 
04439             cxint nrow;
04440             cxdouble opt_direction, fcoll, cfact, gtheta, slitdx,
04441                 slitdy, slitphi;
04442 
04443             nrow = cpl_matrix_get_nrow(wcalib_solution->opt_mod_params);
04444             if (nrow==7) {
04445                 opt_direction =
04446                     cpl_matrix_get(wcalib_solution->opt_mod_params, 0, 0);
04447                 fcoll   =
04448                     cpl_matrix_get(wcalib_solution->opt_mod_params, 1, 0);
04449                 cfact   =
04450                     cpl_matrix_get(wcalib_solution->opt_mod_params, 2, 0);
04451                 gtheta  =
04452                     cpl_matrix_get(wcalib_solution->opt_mod_params, 3, 0);
04453                 slitdx  =
04454                     cpl_matrix_get(wcalib_solution->opt_mod_params, 4, 0);
04455                 slitdy  =
04456                     cpl_matrix_get(wcalib_solution->opt_mod_params, 5, 0);
04457                 slitphi =
04458                     cpl_matrix_get(wcalib_solution->opt_mod_params, 6, 0);
04459 
04460                 opt_mod_params = cpl_matrix_new(7,1);
04461                 cpl_matrix_set(opt_mod_params, 0, 0,
04462                                ex_sp_extr_pixels * opt_direction);
04463                 cpl_matrix_set(opt_mod_params, 1, 0, ex_sp_pixsize_x);
04464                 cpl_matrix_set(opt_mod_params, 2, 0, fcoll);
04465                 cpl_matrix_set(opt_mod_params, 3, 0, cfact);
04466                 cpl_matrix_set(opt_mod_params, 4, 0, slitdx);
04467                 cpl_matrix_set(opt_mod_params, 5, 0, slitdy);
04468                 cpl_matrix_set(opt_mod_params, 6, 0, slitphi);
04469 
04470             }
04471             else {
04472                 cpl_msg_error(fctid, "Invalid number of physical optical "
04473                               "parameters, aborting...");
04474 
04475                 if (wloffsets != NULL) {
04476                     cpl_matrix_delete(wloffsets);
04477                 }
04478 
04479                 _giraffe_wcalsolution_delete(wcalib_solution);
04480                 _giraffe_grating_delete(grating_data);
04481                 _giraffe_fiberposition_delete(fiber_slit_position);
04482                 _giraffe_slitgeo_delete(subslit_fibers);
04483                 return 6;
04484             }
04485 
04486         }
04487         else {
04488             cpl_msg_error(fctid, "Invalid optical model, aborting...");
04489 
04490             if (wloffsets != NULL) {
04491                 cpl_matrix_delete(wloffsets);
04492             }
04493 
04494             _giraffe_wcalsolution_delete(wcalib_solution);
04495             _giraffe_grating_delete(grating_data);
04496             _giraffe_fiberposition_delete(fiber_slit_position);
04497             _giraffe_slitgeo_delete(subslit_fibers);
04498             return 5;
04499         }
04500 
04501 
04502         if (wcalib_solution->wav_coeffs != NULL) {
04503 
04504             GiSlitGeo* coeffs = wcalib_solution->wav_coeffs;
04505 
04506             xres_polynom_deg.xdeg =
04507                 cpl_matrix_get_nrow(_giraffe_slitgeo_get(coeffs, 0));
04508             xres_polynom_deg.ydeg =
04509                 cpl_matrix_get_ncol(_giraffe_slitgeo_get(coeffs, 0));
04510         }
04511 
04512     }
04513     else {
04514         cpl_msg_error(fctid, "No Wavelength Calibration solution found, "
04515                       "aborting...");
04516 
04517         if (wloffsets != NULL) {
04518             cpl_matrix_delete(wloffsets);
04519         }
04520 
04521         _giraffe_wcalsolution_delete(wcalib_solution);
04522         _giraffe_grating_delete(grating_data);
04523         _giraffe_fiberposition_delete(fiber_slit_position);
04524         _giraffe_slitgeo_delete(subslit_fibers);
04525         return 4;
04526     }
04527 
04528     if (config->xresiduals==FALSE) {
04529         xres_polynom_deg.xdeg = 0;
04530         xres_polynom_deg.ydeg = 0;
04531     }
04532 
04533     if (wcalib_solution->wav_coeffs!=NULL) {
04534         wav_coeffs = wcalib_solution->wav_coeffs;
04535     }
04536 
04537     if (wcalib_solution->wav_limits!=NULL) {
04538         wav_limits = wcalib_solution->wav_limits;
04539     }
04540 
04541 
04542     /*
04543      *  Setup Rebinning grating parameters
04544      */
04545 
04546     grat_params = cpl_matrix_new(7,1);
04547 
04548     cpl_matrix_set(grat_params, 0, 0, grating_data->theta);
04549     cpl_matrix_set(grat_params, 1, 0, grating_data->order);
04550     cpl_matrix_set(grat_params, 2, 0, grating_data->wlenmin / GI_MM_TO_NM);
04551     cpl_matrix_set(grat_params, 3, 0, grating_data->wlen0   / GI_MM_TO_NM);
04552     cpl_matrix_set(grat_params, 4, 0, grating_data->wlenmax / GI_MM_TO_NM);
04553     cpl_matrix_set(grat_params, 5, 0, grating_data->resol);
04554     cpl_matrix_set(grat_params, 6, 0, grating_data->space );
04555 
04556 
04557     /*
04558      *  Give user some feedback...
04559      */
04560 
04561     cpl_msg_info(fctid, "Performing Rebinning of spectra, stepsize=%.4f "
04562                  "[nm], resulting image size=%d, using x residuals : %s",
04563                  rbin_stepsize * GI_MM_TO_NM, calc_rebinned_size,
04564                  config->xresiduals ? "Yes" : "No");
04565 
04566 
04567     switch (config->rmethod) {
04568         case GIREBIN_METHOD_LINEAR:
04569             cpl_msg_info(fctid, "Rebinning method    : linear");
04570             break;
04571 
04572         case GIREBIN_METHOD_SPLINE:
04573             cpl_msg_info(fctid, "Rebinning method    : spline");
04574             break;
04575 
04576         default:
04577             cpl_msg_info(fctid, "Rebinning method    : undefined");
04578             break;
04579     }
04580 
04581     switch (config->scmethod) {
04582         case GIREBIN_SCALE_LOG:
04583             cpl_msg_info(fctid, "Scaling method      : logarithmic, "
04584                          "log(wavelength [nm]): min,max,range = %.3f, %.3f, %.3f",
04585                          log(grating_data->wlenmin),
04586                          log(grating_data->wlenmax),
04587                          log(grating_data->wlenmax) -
04588                          log(grating_data->wlenmin));
04589             break;
04590 
04591         case GIREBIN_SCALE_LINEAR:
04592             cpl_msg_info(fctid, "Scaling method      : linear, wavelength [nm]: "
04593                          "min,max,range = %.3f, %.3f, %.3f",
04594                          grating_data->wlenmin,
04595                          grating_data->wlenmax,
04596                          grating_data->wlenmax - grating_data->wlenmin);
04597             break;
04598 
04599         default:
04600             cpl_msg_info(fctid, "Scaling method      : undefined");
04601             break;
04602     }
04603 
04604     switch (config->range) {
04605         case GIREBIN_RANGE_SETUP:
04606             cpl_msg_info(fctid, "Wavelength range    : Setup");
04607             break;
04608 
04609         case GIREBIN_RANGE_COMMON:
04610             cpl_msg_info(fctid, "Wavelength range    : Common");
04611             break;
04612 
04613         default:
04614             cpl_msg_info(fctid, "Wavelength range    : undefined");
04615             break;
04616     }
04617 
04618 
04619     /*
04620      * Resample the spectra to the wavelength grid
04621      */
04622 
04623     status = _giraffe_resample_spectra(rebinning, extraction,
04624                                        localization, fiber_slit_position,
04625                                        subslit_fibers, wav_limits,
04626                                        wav_coeffs, &xres_polynom_deg,
04627                                        grat_params, opt_mod_params,
04628                                        wloffsets, rbin_stepsize,
04629                                        config->rmethod, config->range,
04630                                        config->scmethod);
04631 
04632     if (status != 0) {
04633 
04634         if (wloffsets != NULL) {
04635             cpl_matrix_delete(wloffsets);
04636         }
04637 
04638         cpl_matrix_delete(opt_mod_params);
04639         cpl_matrix_delete(grat_params);
04640 
04641         _giraffe_wcalsolution_delete(wcalib_solution);
04642         _giraffe_grating_delete(grating_data);
04643         _giraffe_fiberposition_delete(fiber_slit_position);
04644         _giraffe_slitgeo_delete(subslit_fibers);
04645 
04646         return 8;
04647 
04648     }
04649 
04650 
04651     /*
04652      *  Cleanup...
04653      */
04654 
04655     if (wloffsets != NULL) {
04656         cpl_matrix_delete(wloffsets);
04657     }
04658 
04659     cpl_matrix_delete(opt_mod_params);
04660     cpl_matrix_delete(grat_params);
04661 
04662     _giraffe_wcalsolution_delete(wcalib_solution);
04663     _giraffe_grating_delete(grating_data);
04664     _giraffe_fiberposition_delete(fiber_slit_position);
04665     _giraffe_slitgeo_delete(subslit_fibers);
04666 
04667     return 0;
04668 
04669 } /* end giraffe_rebin_spectra() */
04670 
04671 
04684 GiRebinning*
04685 giraffe_rebinning_new(void)
04686 {
04687 
04688     GiRebinning *rebinn = cx_malloc(sizeof(GiRebinning));
04689 
04690     rebinn->spectra = NULL;
04691     rebinn->errors  = NULL;
04692 
04693     return rebinn;
04694 
04695 }
04696 
04713 GiRebinning*
04714 giraffe_rebinning_create(GiImage *spectra, GiImage *errors)
04715 {
04716 
04717     GiRebinning *rebin = giraffe_rebinning_new();
04718 
04719     if (spectra) {
04720         rebin->spectra = spectra;
04721     }
04722 
04723     if (errors) {
04724         rebin->errors = errors;
04725     }
04726 
04727     return rebin;
04728 
04729 }
04730 
04731 
04750 void
04751 giraffe_rebinning_delete(GiRebinning *rebinning)
04752 {
04753 
04754     if (rebinning) {
04755         cx_free(rebinning);
04756     }
04757 
04758     return;
04759 
04760 }
04761 
04762 
04778 void
04779 giraffe_rebinning_destroy(GiRebinning *rebinning)
04780 {
04781 
04782     if (rebinning) {
04783 
04784         if (rebinning->spectra) {
04785             giraffe_image_delete(rebinning->spectra);
04786             rebinning->spectra = NULL;
04787         }
04788 
04789         if (rebinning->errors) {
04790             giraffe_image_delete(rebinning->errors);
04791             rebinning->errors = NULL;
04792         }
04793 
04794         cx_free(rebinning);
04795     }
04796 
04797     return;
04798 
04799 }
04800 
04801 
04816 GiRebinConfig *
04817 giraffe_rebin_config_create(cpl_parameterlist *list)
04818 {
04819 
04820     const cxchar *fctid = "giraffe_rebin_config_create";
04821 
04822     const cxchar *s;
04823 
04824     cpl_parameter *p;
04825 
04826     GiRebinConfig *config = NULL;
04827 
04828 
04829     if (!list) {
04830         return NULL;
04831     }
04832 
04833     config = cx_calloc(1, sizeof *config);
04834 
04835 
04836     config->rmethod    = GIREBIN_METHOD_UNDEFINED;
04837     config->xresiduals = FALSE;
04838     config->lstep      = 0.0;
04839     config->scmethod   = GIREBIN_SCALE_UNDEFINED;
04840     config->size       = 0;
04841     config->range      = GIREBIN_RANGE_UNDEFINED;
04842 
04843 
04844     p = cpl_parameterlist_find(list, "giraffe.rebinning.method");
04845     s = cpl_parameter_get_string(p);
04846     if (strcmp(s, "linear")==0) {
04847         config->rmethod = GIREBIN_METHOD_LINEAR;
04848     } else if (strcmp(s, "spline")==0) {
04849         config->rmethod = GIREBIN_METHOD_SPLINE;
04850     }
04851 
04852     p = cpl_parameterlist_find(list, "giraffe.rebinning.xresiduals");
04853     config->xresiduals = cpl_parameter_get_bool(p);
04854 
04855     p = cpl_parameterlist_find(list, "giraffe.rebinning.lstep");
04856     config->lstep = cpl_parameter_get_double(p);
04857 
04858     p = cpl_parameterlist_find(list, "giraffe.rebinning.scalemethod");
04859     s = cpl_parameter_get_string(p);
04860     if (strcmp(s, "log")==0) {
04861         config->scmethod = GIREBIN_SCALE_LOG;
04862     } else if (strcmp(s, "linear")==0) {
04863         config->scmethod = GIREBIN_SCALE_LINEAR;
04864     }
04865 
04866     p = cpl_parameterlist_find(list, "giraffe.rebinning.size");
04867     config->size = cpl_parameter_get_int(p);
04868 
04869     p = cpl_parameterlist_find(list, "giraffe.rebinning.range");
04870     s = cpl_parameter_get_string(p);
04871     if (strcmp(s, "setup")==0) {
04872         config->range = GIREBIN_RANGE_SETUP;
04873     } else if (strcmp(s, "common")==0) {
04874         config->range = GIREBIN_RANGE_COMMON;
04875     }
04876 
04877     /* Validate */
04878 
04879     if (config->rmethod==GIREBIN_METHOD_UNDEFINED) {
04880         cpl_msg_info(fctid, "Invalid Rebinning method, aborting");
04881         cx_free(config);
04882         return NULL;
04883     }
04884 
04885     if (config->scmethod==GIREBIN_SCALE_UNDEFINED) {
04886         cpl_msg_info(fctid, "Invalid Rebinning scaling method, aborting");
04887         cx_free(config);
04888         return NULL;
04889     }
04890 
04891     if (config->range==GIREBIN_RANGE_UNDEFINED) {
04892         cpl_msg_info(fctid, "Invalid Rebinning range, aborting");
04893         cx_free(config);
04894         return NULL;
04895     }
04896 
04897     return config;
04898 
04899 }
04900 
04901 
04916 void
04917 giraffe_rebin_config_destroy(GiRebinConfig *config)
04918 {
04919 
04920     if (config) {
04921         cx_free(config);
04922     }
04923 
04924     return;
04925 
04926 }
04927 
04940 void
04941 giraffe_rebin_config_add(cpl_parameterlist *list)
04942 {
04943 
04944     cpl_parameter *p;
04945 
04946     if (!list) {
04947         return;
04948     }
04949 
04950     p = cpl_parameter_new_enum("giraffe.rebinning.method",
04951                                CPL_TYPE_STRING,
04952                                "Method to use : `linear' or `spline'",
04953                                "giraffe.rebinning.method",
04954                                "linear", 2, "linear", "spline");
04955     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-method");
04956     cpl_parameterlist_append(list, p);
04957 
04958     p = cpl_parameter_new_value("giraffe.rebinning.xresiduals",
04959                                 CPL_TYPE_BOOL,
04960                                 "Use x residuals during rebinning? `true'/"
04961                                 "`false'",
04962                                 "giraffe.rebinning.xresiduals",
04963                                 TRUE);
04964     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-xresid");
04965     cpl_parameterlist_append(list, p);
04966 
04967     p = cpl_parameter_new_value("giraffe.rebinning.lstep",
04968                                 CPL_TYPE_DOUBLE,
04969                                 "Lambda step size, only used if "
04970                                 "scaling method is 'linear'",
04971                                 "giraffe.rebinning.lstep",
04972                                 0.005);
04973     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-lstep");
04974     cpl_parameterlist_append(list, p);
04975 
04976     p = cpl_parameter_new_enum("giraffe.rebinning.scalemethod",
04977                                CPL_TYPE_STRING,
04978                                "Scaling method: `log' or `linear'",
04979                                "giraffe.rebinning.scalemethod",
04980                                "linear", 2, "linear", "log");
04981     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-scmethod");
04982     cpl_parameterlist_append(list, p);
04983 
04984     p = cpl_parameter_new_value("giraffe.rebinning.size",
04985                                 CPL_TYPE_INT,
04986                                 "Size of output rebinned spectra, 0 means "
04987                                 "calculate size based on wavelength range "
04988                                 "and lambda stepsize",
04989                                 "giraffe.rebinning.size",
04990                                 0);
04991     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-size");
04992     cpl_parameterlist_append(list, p);
04993 
04994     p = cpl_parameter_new_enum("giraffe.rebinning.range",
04995                                CPL_TYPE_STRING,
04996                                "Rebinning range: `setup' or `common'",
04997                                "giraffe.rebinning.scalemethod",
04998                                "setup", 2, "setup", "common");
04999     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-range");
05000     cpl_parameterlist_append(list, p);
05001 
05002     return;
05003 
05004 }

This file is part of the GIRAFFE Pipeline Reference Manual 2.9.0.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Thu Jan 26 14:20:28 2012 by doxygen 1.6.3 written by Dimitri van Heesch, © 1997-2004