GIRAFFE Pipeline Reference Manual

girebinning.c

00001 /* $Id: girebinning.c,v 1.45 2010/07/01 08:33:23 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: 2010/07/01 08:33:23 $
00024  * $Revision: 1.45 $
00025  * $Name: giraffe-2_8_8 $
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(
01368         fctid,
01369         "Processing completed: Returning image [x,y] = [%d,%d]",
01370         cpl_image_get_size_x(xref),
01371         cpl_image_get_size_y(xref)
01372         );
01373 
01374     return xref;
01375 
01376 }
01377 
01378 
01379 inline static cpl_matrix *
01380 _giraffe_rebin_setup_model(GiImage *extspectra, GiWcalSolution *wcal)
01381 {
01382 
01383     cxint npixel;
01384 
01385     cxdouble pixelsize;
01386 
01387     cpl_propertylist *properties = NULL;
01388 
01389     cpl_matrix *model = NULL;
01390 
01391 
01392     if (extspectra == NULL) {
01393         return NULL;
01394     }
01395 
01396     if (wcal == NULL) {
01397         return NULL;
01398     }
01399 
01400     properties = giraffe_image_get_properties(extspectra);
01401 
01402     if (properties == NULL) {
01403         return NULL;
01404     }
01405 
01406 
01407     /*
01408      * Get the number of pixels extracted along the dispersion axis.
01409      */
01410 
01411     if (!cpl_propertylist_has(properties, GIALIAS_EXT_NX)) {
01412         return NULL;
01413     }
01414 
01415     npixel = cpl_propertylist_get_int(properties, GIALIAS_EXT_NX);
01416 
01417 
01418     /*
01419      * Compute pixel size along the dispersion axis in terms of mm.
01420      */
01421 
01422     if (!cpl_propertylist_has(properties, GIALIAS_PIXSIZX)) {
01423         return NULL;
01424     }
01425 
01426     pixelsize = cpl_propertylist_get_double(properties, GIALIAS_PIXSIZX);
01427     pixelsize /= 1000.;
01428 
01429 
01430     /*
01431      * Setup the optical model parameters
01432      */
01433 
01434     switch (wcal->opt_mod) {
01435         case LMRQ_XOPTMOD:
01436             if (cpl_matrix_get_nrow(wcal->opt_mod_params) != 4) {
01437                 return NULL;
01438             }
01439             else {
01440 
01441                 cxdouble direction = cpl_matrix_get(wcal->opt_mod_params, 0, 0);
01442                 cxdouble fcoll = cpl_matrix_get(wcal->opt_mod_params, 1, 0);
01443                 cxdouble cfact = cpl_matrix_get(wcal->opt_mod_params, 2, 0);
01444 
01445                 model = cpl_matrix_new(4, 1);
01446 
01447                 cpl_matrix_set(model, 0, 0, npixel * direction);
01448                 cpl_matrix_set(model, 1, 0, pixelsize);
01449                 cpl_matrix_set(model, 2, 0, fcoll);
01450                 cpl_matrix_set(model, 3, 0, cfact);
01451             }
01452             break;
01453 
01454         case LMRQ_XOPTMOD2:
01455             if (cpl_matrix_get_nrow(wcal->opt_mod_params) != 7) {
01456                 return NULL;
01457             }
01458             else {
01459 
01460                 cxdouble direction = cpl_matrix_get(wcal->opt_mod_params, 0, 0);
01461                 cxdouble fcoll = cpl_matrix_get(wcal->opt_mod_params, 1, 0);
01462                 cxdouble cfact = cpl_matrix_get(wcal->opt_mod_params, 2, 0);
01463                 cxdouble sdx = cpl_matrix_get(wcal->opt_mod_params, 4, 0);
01464                 cxdouble sdy = cpl_matrix_get(wcal->opt_mod_params, 5, 0);
01465                 cxdouble sphi = cpl_matrix_get(wcal->opt_mod_params, 6, 0);
01466 
01467                 model = cpl_matrix_new(7, 1);
01468 
01469                 cpl_matrix_set(model, 0, 0, npixel * direction);
01470                 cpl_matrix_set(model, 1, 0, pixelsize);
01471                 cpl_matrix_set(model, 2, 0, fcoll);
01472                 cpl_matrix_set(model, 3, 0, cfact);
01473                 cpl_matrix_set(model, 4, 0, sdx);
01474                 cpl_matrix_set(model, 5, 0, sdy);
01475                 cpl_matrix_set(model, 6, 0, sphi);
01476             }
01477             break;
01478 
01479         default:
01480             return NULL;
01481             break;
01482     }
01483 
01484     cx_assert(model != NULL);
01485 
01486     return model;
01487 
01488 }
01489 
01490 
01491 inline static cpl_matrix *
01492 _giraffe_rebin_setup_grating(GiImage *extspectra, GiTable *grating,
01493                              GiTable *wlsolution)
01494 {
01495 
01496     cxint status = 0;
01497 
01498     cpl_propertylist *properties = NULL;
01499 
01500     cpl_matrix *setup = NULL;
01501 
01502     GiGrat *grating_data = _giraffe_grating_new();
01503 
01504 
01505     status = _giraffe_grating_setup(grating, extspectra, grating_data);
01506 
01507     if (status != 0) {
01508         _giraffe_grating_delete(grating_data);
01509         return NULL;
01510     }
01511 
01512 
01513     properties = giraffe_table_get_properties(wlsolution);
01514 
01515     if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMFCOLL)) {
01516         grating_data->fcoll = cpl_propertylist_get_double(properties,
01517                                                           GIALIAS_WSOL_OMFCOLL);
01518     }
01519 
01520     if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMGCAM)) {
01521         grating_data->gcam = cpl_propertylist_get_double(properties,
01522                                                          GIALIAS_WSOL_OMGCAM);
01523     }
01524 
01525     if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMGTHETA)) {
01526         grating_data->theta = cpl_propertylist_get_double(properties,
01527                                                           GIALIAS_WSOL_OMGTHETA);
01528     }
01529 
01530     if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMSDX)) {
01531         grating_data->slitdx = cpl_propertylist_get_double(properties,
01532                                                            GIALIAS_WSOL_OMSDX);
01533     }
01534 
01535     if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMSDY)) {
01536         grating_data->slitdy = cpl_propertylist_get_double(properties,
01537                                                            GIALIAS_WSOL_OMSDY);
01538     }
01539 
01540     if (cpl_propertylist_has(properties, GIALIAS_WSOL_OMSPHI)) {
01541         grating_data->slitphi = cpl_propertylist_get_double(properties,
01542                                                             GIALIAS_WSOL_OMSPHI);
01543     }
01544 
01545 
01546     setup = cpl_matrix_new(7, 1);
01547 
01548     cpl_matrix_set(setup, 0, 0, grating_data->theta);
01549     cpl_matrix_set(setup, 1, 0, grating_data->order);
01550     cpl_matrix_set(setup, 2, 0, grating_data->wlenmin / GI_MM_TO_NM);
01551     cpl_matrix_set(setup, 3, 0, grating_data->wlen0 / GI_MM_TO_NM);
01552     cpl_matrix_set(setup, 4, 0, grating_data->wlenmax / GI_MM_TO_NM);
01553     cpl_matrix_set(setup, 5, 0, grating_data->resol);
01554     cpl_matrix_set(setup, 6, 0, grating_data->space);
01555 
01556     _giraffe_grating_delete(grating_data);
01557     grating_data = NULL;
01558 
01559     return setup;
01560 
01561 }
01562 
01563 
01576 inline static cxint
01577 _giraffe_spline_calc_circe(cxdouble x, register cxdouble* t, cxint n)
01578 {
01579 
01580     register cxint lo = 0;
01581     register cxint hi = n - 1;
01582 
01583 
01584     if (x >= t[0] && x <= t[n - 1]) {
01585 
01586         while (hi - lo > 1) {
01587 
01588             register cxint mid = (lo + hi) / 2.;
01589 
01590             cxdouble tm = 0.;
01591 
01592             tm = t[mid];
01593 
01594             if (x < tm) {
01595                 hi = mid;
01596             }
01597             else {
01598                 lo = mid;
01599             }
01600         }
01601 
01602         return hi;
01603 
01604     }
01605 
01606     return -1;
01607 
01608 }
01609 
01629 inline static void
01630 _giraffe_spline_calc_tridi(register cxdouble* a, register cxdouble* b,
01631                            register cxdouble* c, register cxdouble* f,
01632                            register cxdouble* x, cxint n)
01633 {
01634 
01635     register cxint i = 0;
01636 
01637     c[0] /= a[0];
01638 
01639     for (i = 1; i < n; i++) {
01640         c[i] /= (a[i] - b[i] * c[i - 1]);
01641     }
01642 
01643     f[0] /= a[0];
01644 
01645     for (i = 1; i < n; i++) {
01646         f[i] = (f[i] - b[i] * f[i - 1]) / (a[i] - b[i] * c[i - 1]);
01647     }
01648 
01649     x[n - 1] = f[n - 1];
01650 
01651     for (i = n - 2; i >= 0; i--) {
01652         x[i] = f[i] - c[i] * x[i + 1];
01653     }
01654 
01655     return;
01656 }
01657 
01677 inline static cxint
01678 _giraffe_spline_calc_interpolate(cxdouble z, cxdouble* val,
01679                                  register cxdouble* x, register cxdouble* y,
01680                                  register cxdouble* k, cxint n)
01681 {
01682 
01683     cxint m = 0;
01684 
01685     cxdouble h = 0.;
01686     cxdouble t = 0.;
01687     cxdouble d = 0.;
01688     cxdouble a = 0.;
01689     cxdouble b = 0.;
01690     cxdouble dx = 0.;
01691 
01692 
01693     m = _giraffe_spline_calc_circe(z, x, n);
01694 
01695     if (m < 0) {
01696 
01697         /* out of bounds */
01698         if (z < x[0]) {
01699             dx   = z - x[0];
01700             *val = y[0] + dx * (k[0] + 0.5 * dx * ddb);
01701         } else {
01702             dx   = z - x[n - 1];
01703             *val = y[n - 1] + dx * (k[n - 1] + 0.5 * dx * dde);
01704         }
01705 
01706         return 1;
01707 
01708     }
01709 
01710     dx   = z - x[m - 1];
01711     h    = x[m] - x[m - 1];
01712     d    = (y[m] - y[m - 1]) / h;
01713     t    = dx / h;
01714     a    = (k[m - 1] - d) * (1 - t);
01715     b    = (k[m] - d) * t;
01716     *val = t * y[m] + (1 - t) * y[m - 1] + h * t * (1 - t) * (a - b);
01717 
01718     return 0;
01719 
01720 }
01721 
01742 inline static cxint
01743 _giraffe_spline_calc_initalize(cxdouble* x, cxdouble* y, cxdouble* k,
01744                                cxint n, cxdouble q2b, cxdouble q2e)
01745 {
01746 
01747     register cxint i = 0;
01748     register cxint ip = 0;
01749 
01750     register cxdouble* a;
01751     register cxdouble* b;
01752     register cxdouble* c;
01753     register cxdouble* f;
01754 
01755     cxdouble hio = 0.;
01756     cxdouble hip = 0.;
01757     cxdouble dio = 0.;
01758     cxdouble dip = 0.;
01759 
01760 
01761 
01762     ddb = q2b;
01763     dde = q2e; /* save end second derivatives */
01764 
01765     a   = (cxdouble*) cx_malloc(4 * n * sizeof(cxdouble));
01766 
01767     b   = a + n;
01768     c   = b + n;
01769     f   = c + n;
01770 
01771     for (i = 0; i < n; i++) {
01772 
01773         hip  = ((ip = i + 1) < n ? x[ip] - x[i] : 0.0);
01774         dip  = (ip < n ? (y[ip] - y[i]) / hip : 0.0);
01775         b[i] = (ip < n ? hip : hio);
01776         a[i] = 2.0 * (hip + hio);
01777         c[i] = (i > 0 ? hio : hip);
01778         f[i] = 3.0 * (hip * dio + hio * dip);
01779 
01780         if (i == 0) {
01781             f[0] = 3.0 * hip * dip - hip * hip * q2b * 0.5;
01782         }
01783         else if (i == n - 1) {
01784             f[n - 1] = 3.0 * hio * dio + hio * hio * q2e * 0.5;
01785         }
01786 
01787         dio = dip;
01788         hio = hip;
01789     }
01790 
01791     _giraffe_spline_calc_tridi(a, b, c, f, k, n);
01792 
01793     cx_free(a);
01794 
01795     return 0;
01796 
01797 }
01798 
01817 inline static cxint
01818 _giraffe_rebin_interpolate_spline(cpl_matrix* x_1, cpl_matrix* y_1,
01819                                   cpl_matrix* x_2, cpl_matrix* y_2)
01820 {
01821 
01822     cxint i = 0;
01823     cxint res = 0;
01824     cxint nr_x1 = 0;
01825     cxint nr_x2 = 0;
01826 
01827     cxdouble* k = NULL;
01828     cxdouble* pd_x1 = NULL;
01829     cxdouble* pd_y1 = NULL;
01830     cxdouble* pd_x2 = NULL;
01831     cxdouble* pd_y2 = NULL;
01832 
01833 
01834 
01835     if (x_1 == NULL || y_1 == NULL || x_2 == NULL || y_2 == NULL) {
01836         return 1;
01837     }
01838 
01839     nr_x1 = cpl_matrix_get_nrow(x_1);
01840     nr_x2 = cpl_matrix_get_nrow(x_2);
01841 
01842     pd_x1 = cpl_matrix_get_data(x_1);
01843     pd_y1 = cpl_matrix_get_data(y_1);
01844     pd_y2 = cpl_matrix_get_data(y_2);
01845     pd_x2 = cpl_matrix_get_data(x_2);
01846 
01847 
01848     /*
01849      * Get storage for spline coefficients and vector y2
01850      */
01851 
01852     k = (cxdouble*) cx_malloc(nr_x1 * sizeof(cxdouble));
01853 
01854 
01855     /*
01856      * Initialise spline calculation...
01857      */
01858 
01859     res = _giraffe_spline_calc_initalize(pd_x1, pd_y1, k, nr_x1, 0.0, 0.0);
01860 
01861     if (res < 0) {
01862         cx_free(k);
01863         return res;
01864     }
01865 
01866     /*
01867      *  Calculate spline...
01868      */
01869 
01870     for (i = 0; i < nr_x2; i++) {
01871         res = _giraffe_spline_calc_interpolate(pd_x2[i], &(pd_y2[i]), pd_x1,
01872                                                pd_y1, k, nr_x1);
01873     }
01874 
01875     cx_free(k);
01876 
01877     return 0;
01878 
01879 }
01880 
01902 inline static cxint
01903 _giraffe_rebin_interpolate_linear(
01904     cpl_matrix *x_1,
01905     cpl_matrix *y_1,
01906     cpl_matrix *x_2,
01907     cpl_matrix *y_2
01908     )
01909 {
01910 
01911     /*************************************************************************
01912                                      Variables
01913     *************************************************************************/
01914 
01915     register cxdouble a, b ;
01916     register cxint    i, j, j_1, found, n1;
01917 
01918     cxint     nr_x1 = 0,
01919         nr_x2 = 0;
01920     cxdouble *pd_x1 = NULL,
01921         *pd_x2 = NULL,
01922         *pd_y2 = NULL,
01923         *pd_y1 = NULL;
01924 
01925     /*************************************************************************
01926                                     Preprocessing
01927     *************************************************************************/
01928 
01929     if (x_1 == NULL) { return 1; }
01930     if (y_1 == NULL) { return 1; }
01931     if (x_2 == NULL) { return 1; }
01932     if (y_2 == NULL) { return 1; }
01933 
01934     nr_x1 = cpl_matrix_get_nrow(x_1);
01935     nr_x2 = cpl_matrix_get_nrow(x_2);
01936     pd_x1 = cpl_matrix_get_data(x_1);
01937     pd_x2 = cpl_matrix_get_data(x_2);
01938     pd_y1 = cpl_matrix_get_data(y_1);
01939     pd_y2 = cpl_matrix_get_data(y_2);
01940 
01941     /*************************************************************************
01942                                      Processing
01943     *************************************************************************/
01944 
01945     n1 = nr_x1 - 1;
01946 
01947     for (i = 0; i < nr_x2; i++) {
01948         /* Find (x1,y1) on the left of the current point */
01949         found = 0;
01950         for (j = 0; j < n1; j++) {
01951             if ((pd_x2[i] >= pd_x1[j]) && (pd_x2[i] <= pd_x1[j+1])) {
01952                 found++ ;
01953                 break ;
01954             }
01955         }
01956 
01957         if (!found) {
01958             pd_y2[i] = 0.0;
01959         } else {
01960             j_1      = j + 1;
01961             a        = (pd_y1[j_1] - pd_y1[j]) / (pd_x1[j_1] - pd_x1[j]);
01962             b        = pd_y1[j] - a * pd_x1[j];
01963             pd_y2[i] = (a * pd_x2[i] + b);
01964 
01965         }
01966     }
01967 
01968     return 0;
01969 
01970 } /* end giraffe_rebin_interpolate_linear() */
01971 
01997 inline static cxint
01998 _giraffe_rebin_interpolate_linear_error(
01999     cpl_matrix *x_1,
02000     cpl_matrix *y_1,
02001     cpl_matrix *y_1err,
02002     cpl_matrix *x_2,
02003     cpl_matrix *y_2,
02004     cpl_matrix *y_2err
02005     ) {
02006 
02007     /*************************************************************************
02008                                      Variables
02009     *************************************************************************/
02010 
02011     register double a, b ,dx;
02012     register int    i, j, j_1, found, n1 ;
02013 
02014     cxint     nr_x1    = 0,
02015         nr_x2    = 0;
02016     cxdouble *pd_x1    = NULL,
02017         *pd_y1    = NULL,
02018         *pd_y1err = NULL,
02019         *pd_x2    = NULL,
02020         *pd_y2    = NULL,
02021         *pd_y2err = NULL;
02022 
02023     /*************************************************************************
02024                                     Preprocessing
02025     *************************************************************************/
02026 
02027     if (x_1 == NULL) { return 1; }
02028     if (y_1 == NULL) { return 1; }
02029     if (y_1err == NULL) { return 1; }
02030     if (x_2 == NULL) { return 1; }
02031     if (y_2 == NULL) { return 1; }
02032     if (y_2err == NULL) { return 1; }
02033 
02034     nr_x1    = cpl_matrix_get_nrow(x_1);
02035     nr_x2    = cpl_matrix_get_nrow(x_2);
02036     pd_x1    = cpl_matrix_get_data(x_1);
02037     pd_y1    = cpl_matrix_get_data(y_1);
02038     pd_y1err = cpl_matrix_get_data(y_1err);
02039     pd_x2    = cpl_matrix_get_data(x_2);
02040     pd_y2    = cpl_matrix_get_data(y_2);
02041     pd_y2err = cpl_matrix_get_data(y_2err);
02042 
02043     /*************************************************************************
02044                                      Processing
02045     *************************************************************************/
02046 
02047     n1 = nr_x1 - 1;
02048 
02049     for (i = 0; i < nr_x2; i++) {
02050         /* Find (x1,y1) on the left of the current point */
02051         found = 0;
02052         for (j = 0; j < n1; j++) {
02053             if ((pd_x2[i] >= pd_x1[j]) && (pd_x2[i] <= pd_x1[j+1])) {
02054                 found++ ;
02055                 break ;
02056             }
02057         }
02058 
02059         if (!found) {
02060             pd_y2[i]    = 0.0;
02061             pd_y2err[i] = 0.0;
02062         } else {
02063 
02064             j_1         = j + 1;
02065             dx          = (pd_x1[j_1] - pd_x1[j]);
02066             a           = (pd_y1[j_1] - pd_y1[j]) / dx;
02067             b           = pd_y1[j] - a * pd_x1[j] ;
02068             pd_y2[i]    = (a * pd_x2[i] + b) ;
02069             a           = (pd_y1err[j_1] - pd_y1err[j]) / dx;
02070             b           = pd_y1err[j] - a * pd_x1[j] ;
02071             pd_y2err[i] = (a * pd_x2[i] + b) ;
02072 
02073         }
02074     }
02075 
02076     return 0;
02077 
02078 } /* end giraffe_rebin_interpolate_linear_error() */
02079 
02099 inline static cxint
02100 _giraffe_resample_linear(cpl_image* rbspectra, cpl_image* rberrors,
02101                          cpl_image* abscissa, cpl_image* exspectra,
02102                          cpl_image* exerrors, cxint opt_direction)
02103 {
02104 
02105     const cxchar* const fctid = "_giraffe_resample_linear";
02106 
02107     register cxlong n = 0;
02108 
02109     cxint status = 0;
02110     cxint nx = 0;         /* size of extracted spectra   */
02111     cxint ns = 0;         /* number of extracted spectra */
02112     cxint nwl = 0;        /* size of rebinned spectra    */
02113 
02114     cxdouble nx1 = 0.;
02115     cxdouble* _mabscissa = NULL;
02116     cxdouble* _mexspectra = NULL;
02117     cxdouble* _mexerrors = NULL;
02118     cxdouble* _mwavelength = NULL;
02119     cxdouble* _mrbspectra = NULL;
02120     cxdouble* _mrberrors = NULL;
02121     cxdouble* _abscissa = NULL;
02122     cxdouble* _exspectra = NULL;
02123     cxdouble* _exerrors = NULL;
02124     cxdouble* _rbspectra = NULL;
02125     cxdouble* _rberrors = NULL;
02126 
02127     cpl_matrix* mabscissa = NULL;
02128     cpl_matrix* mwavelength = NULL;
02129     cpl_matrix* mexspectra = NULL;
02130     cpl_matrix* mexerrors = NULL;
02131     cpl_matrix* mrbspectra = NULL;
02132     cpl_matrix* mrberrors = NULL;
02133 
02134 
02135 
02136     if ((abscissa == NULL) || (exspectra == NULL) || (rbspectra == NULL)) {
02137         return 1;
02138     }
02139 
02140     if ((exerrors != NULL) && (rberrors == NULL)) {
02141         return 1;
02142     }
02143 
02144 
02145     nx = cpl_image_get_size_y(exspectra);
02146     ns = cpl_image_get_size_x(exspectra);
02147     nwl = cpl_image_get_size_y(abscissa);
02148 
02149     if ((exerrors != NULL) &&
02150         ((nx != cpl_image_get_size_y(exerrors)) ||
02151          (ns != cpl_image_get_size_x(exerrors)))) {
02152          return 1;
02153     }
02154 
02155     nx1 = nx - 0.5;
02156 
02157     mabscissa = cpl_matrix_new(nx, 1);
02158     mexspectra = cpl_matrix_new(nx, 1);
02159 
02160     mwavelength = cpl_matrix_new(nwl, 1);
02161     mrbspectra = cpl_matrix_new(nwl, 1);
02162 
02163     _mabscissa = cpl_matrix_get_data(mabscissa);
02164     _mexspectra = cpl_matrix_get_data(mexspectra);
02165     _mwavelength = cpl_matrix_get_data(mwavelength);
02166     _mrbspectra = cpl_matrix_get_data(mrbspectra);
02167 
02168     _abscissa = cpl_image_get_data_double(abscissa);
02169     _exspectra = cpl_image_get_data_double(exspectra);
02170     _rbspectra = cpl_image_get_data_double(rbspectra);
02171 
02172     if (exerrors != NULL) {
02173         mexerrors = cpl_matrix_new(nx, 1);
02174         mrberrors = cpl_matrix_new(nwl, 1);
02175 
02176         _mexerrors = cpl_matrix_get_data(mexerrors);
02177         _mrberrors = cpl_matrix_get_data(mrberrors);
02178 
02179         _exerrors = cpl_image_get_data_double(exerrors);
02180         _rberrors = cpl_image_get_data_double(rberrors);
02181     }
02182 
02183 
02184     /*
02185      * Resample each spectrum to the new grid, taking the direction of the
02186      * optical model into account. If the errors of the spectra are
02187      * available they are also resampled to the new grid.
02188      */
02189 
02190     cpl_msg_debug(fctid, "Rebinning %d spectra, using dispersion direction "
02191                   "%d and linear interpolation", ns, opt_direction);
02192 
02193     for (n = 0; n < ns; n++) {
02194 
02195         register cxlong x = 0;
02196 
02197 
02198         for (x = 0; x < nwl; x++) {
02199             register cxlong j = x * ns + n;
02200             _mwavelength[x] = _abscissa[j];
02201         }
02202 
02203         if (exerrors == NULL) {
02204 
02205             if (opt_direction < 0) {
02206 
02207                 for (x = 0; x < nx; x++) {
02208 
02209                     register cxlong j = x * ns + n;
02210                     register cxlong k = nx - x - 1;
02211 
02212                     _mabscissa[x] = (cxdouble) x;
02213                     _mexspectra[k] = _exspectra[j];
02214                 }
02215 
02216             }
02217             else {
02218 
02219                 for (x = 0; x < nx; x++) {
02220 
02221                     register cxlong j = x * ns + n;
02222 
02223                     _mabscissa[x] = (cxdouble) x;
02224                     _mexspectra[x] = _exspectra[j];
02225 
02226                 }
02227 
02228             }
02229 
02230 
02231             /*
02232              * Linear interpolation of spectra and errors
02233              */
02234 
02235             status = _giraffe_rebin_interpolate_linear(mabscissa,
02236                                                        mexspectra,
02237                                                        mwavelength,
02238                                                        mrbspectra);
02239 
02240             for (x = 0; x < nwl; x++) {
02241 
02242                 register cxlong j = x * ns + n;
02243 
02244                 if ((-0.5 > _mwavelength[x]) || (_mwavelength[x] > nx1)) {
02245                     _rbspectra[j] = 0.;
02246                 }
02247                 else {
02248                     _rbspectra[j] = _mrbspectra[x];
02249                 }
02250 
02251             }
02252 
02253         }
02254         else {
02255 
02256             if (opt_direction < 0) {
02257 
02258                 for (x = 0; x < nx; x++) {
02259 
02260                     register cxlong j = x * ns + n;
02261                     register cxlong k = nx - x - 1;
02262 
02263                     _mabscissa[x] = (cxdouble) x;
02264                     _mexspectra[k] = _exspectra[j];
02265                     _mexerrors[k] = _exerrors[j];
02266                 }
02267 
02268             }
02269             else {
02270 
02271                 for (x = 0; x < nx; x++) {
02272 
02273                     register cxlong j = x * ns + n;
02274 
02275                     _mabscissa[x] = (cxdouble) x;
02276                     _mexspectra[x] = _exspectra[j];
02277                     _mexerrors[x] = _exerrors[j];
02278 
02279                 }
02280 
02281             }
02282 
02283 
02284             /*
02285              * Linear interpolation of spectra and errors
02286              */
02287 
02288             status =
02289                 _giraffe_rebin_interpolate_linear_error(mabscissa,
02290                                                         mexspectra,
02291                                                         mexerrors,
02292                                                         mwavelength,
02293                                                         mrbspectra,
02294                                                         mrberrors);
02295 
02296             for (x = 0; x < nwl; x++) {
02297 
02298                 register cxlong j = x * ns + n;
02299 
02300                 if ((-0.5 > _mwavelength[x]) || (_mwavelength[x] > nx1)) {
02301                     _rbspectra[j] = 0.;
02302                     _rberrors[j] = 0.;
02303                 }
02304                 else {
02305                     _rbspectra[j] = _mrbspectra[x];
02306                     _rberrors[j] = _mrberrors[x];
02307                 }
02308 
02309             }
02310 
02311         }
02312 
02313     } /* each spectrum */
02314 
02315 
02316     cpl_matrix_delete(mrbspectra);
02317     mrbspectra = NULL;
02318 
02319     cpl_matrix_delete(mwavelength);
02320     mwavelength = NULL;
02321 
02322     cpl_matrix_delete(mexspectra);
02323     mexspectra = NULL;
02324 
02325     cpl_matrix_delete(mabscissa);
02326     mabscissa = NULL;
02327 
02328     if (exerrors != NULL) {
02329         cpl_matrix_delete(mrberrors);
02330         mrberrors = NULL;
02331 
02332         cpl_matrix_delete(mexerrors);
02333         mexerrors = NULL;
02334     }
02335 
02336     cpl_msg_debug(fctid, "Rebinned %d spectra", ns);
02337 
02338     return 0;
02339 
02340 }
02341 
02342 
02362 inline static cxint
02363 _giraffe_resample_spline(cpl_image* rbspectra, cpl_image* rberrors,
02364                          cpl_image* abscissa, cpl_image* exspectra,
02365                          cpl_image* exerrors, cxint opt_direction)
02366 {
02367 
02368     const cxchar* const fctid = "_giraffe_resample_spline";
02369 
02370     register cxlong n = 0;
02371 
02372     cxint status = 0;
02373     cxint nx = 0;         /* size of extracted spectra   */
02374     cxint ns = 0;         /* number of extracted spectra */
02375     cxint nwl = 0;        /* size of rebinned spectra    */
02376 
02377     cxdouble nx1 = 0.;
02378     cxdouble* _mabscissa = NULL;
02379     cxdouble* _mexspectra = NULL;
02380     cxdouble* _mexerrors = NULL;
02381     cxdouble* _mwavelength = NULL;
02382     cxdouble* _mrbspectra = NULL;
02383     cxdouble* _mrberrors = NULL;
02384     cxdouble* _abscissa = NULL;
02385     cxdouble* _exspectra = NULL;
02386     cxdouble* _exerrors = NULL;
02387     cxdouble* _rbspectra = NULL;
02388     cxdouble* _rberrors = NULL;
02389 
02390     cpl_matrix* mabscissa = NULL;
02391     cpl_matrix* mwavelength = NULL;
02392     cpl_matrix* mexspectra = NULL;
02393     cpl_matrix* mexerrors = NULL;
02394     cpl_matrix* mrbspectra = NULL;
02395     cpl_matrix* mrberrors = NULL;
02396 
02397 
02398 
02399     if ((abscissa == NULL) || (exspectra == NULL) || (rbspectra == NULL)) {
02400         return 1;
02401     }
02402 
02403     if ((exerrors != NULL) && (rberrors == NULL)) {
02404         return 1;
02405     }
02406 
02407 
02408     nx = cpl_image_get_size_y(exspectra);
02409     ns = cpl_image_get_size_x(exspectra);
02410     nwl = cpl_image_get_size_y(abscissa);
02411 
02412     if ((exerrors != NULL) &&
02413         ((nx != cpl_image_get_size_y(exerrors)) ||
02414          (ns != cpl_image_get_size_x(exerrors)))) {
02415              return 1;
02416          }
02417 
02418     nx1 = nx - 0.5;
02419 
02420     mabscissa = cpl_matrix_new(nx, 1);
02421     mexspectra = cpl_matrix_new(nx, 1);
02422 
02423     mwavelength = cpl_matrix_new(nwl, 1);
02424     mrbspectra = cpl_matrix_new(nwl, 1);
02425 
02426     _mabscissa = cpl_matrix_get_data(mabscissa);
02427     _mexspectra = cpl_matrix_get_data(mexspectra);
02428     _mwavelength = cpl_matrix_get_data(mwavelength);
02429     _mrbspectra = cpl_matrix_get_data(mrbspectra);
02430 
02431     _abscissa = cpl_image_get_data_double(abscissa);
02432     _exspectra = cpl_image_get_data_double(exspectra);
02433     _rbspectra = cpl_image_get_data_double(rbspectra);
02434 
02435     if (exerrors != NULL) {
02436         mexerrors = cpl_matrix_new(nx, 1);
02437         mrberrors = cpl_matrix_new(nwl, 1);
02438 
02439         _mexerrors = cpl_matrix_get_data(mexerrors);
02440         _mrberrors = cpl_matrix_get_data(mrberrors);
02441 
02442         _exerrors = cpl_image_get_data_double(exerrors);
02443         _rberrors = cpl_image_get_data_double(rberrors);
02444     }
02445 
02446 
02447     /*
02448      * Resample each spectrum to the new grid, taking the direction of the
02449      * optical model into account. If the errors of the spectra are
02450      * available they are also resampled to the new grid.
02451      */
02452 
02453     cpl_msg_debug(fctid, "Rebinning %d spectra, using dispersion direction "
02454                   "%d and linear interpolation", ns, opt_direction);
02455 
02456     for (n = 0; n < ns; n++) {
02457 
02458         register cxlong x = 0;
02459 
02460 
02461         for (x = 0; x < nwl; x++) {
02462             register cxlong j = x * ns + n;
02463             _mwavelength[x] = _abscissa[j];
02464         }
02465 
02466         if (exerrors == NULL) {
02467 
02468             if (opt_direction < 0) {
02469 
02470                 for (x = 0; x < nx; x++) {
02471 
02472                     register cxlong j = x * ns + n;
02473                     register cxlong k = nx - x - 1;
02474 
02475                     _mabscissa[x] = (cxdouble) x;
02476                     _mexspectra[k] = _exspectra[j];
02477                 }
02478 
02479             }
02480             else {
02481 
02482                 for (x = 0; x < nx; x++) {
02483 
02484                     register cxlong j = x * ns + n;
02485 
02486                     _mabscissa[x] = (cxdouble) x;
02487                     _mexspectra[x] = _exspectra[j];
02488 
02489                 }
02490 
02491             }
02492 
02493 
02494             /*
02495              * Spline interpolation of spectra and errors
02496              */
02497 
02498             status = _giraffe_rebin_interpolate_spline(mabscissa,
02499                                                        mexspectra,
02500                                                        mwavelength,
02501                                                        mrbspectra);
02502 
02503             for (x = 0; x < nwl; x++) {
02504 
02505                 register cxlong j = x * ns + n;
02506 
02507                 if ((-0.5 > _mwavelength[x]) || (_mwavelength[x] > nx1)) {
02508                     _rbspectra[j] = 0.;
02509                 }
02510                 else {
02511                     _rbspectra[j] = _mrbspectra[x];
02512                 }
02513 
02514             }
02515 
02516         }
02517         else {
02518 
02519             if (opt_direction < 0) {
02520 
02521                 for (x = 0; x < nx; x++) {
02522 
02523                     register cxlong j = x * ns + n;
02524                     register cxlong k = nx - x - 1;
02525 
02526                     _mabscissa[x] = (cxdouble) x;
02527                     _mexspectra[k] = _exspectra[j];
02528                     _mexerrors[k] = _exerrors[j];
02529                 }
02530 
02531             }
02532             else {
02533 
02534                 for (x = 0; x < nx; x++) {
02535 
02536                     register cxlong j = x * ns + n;
02537 
02538                     _mabscissa[x] = (cxdouble) x;
02539                     _mexspectra[x] = _exspectra[j];
02540                     _mexerrors[x] = _exerrors[j];
02541 
02542                 }
02543 
02544             }
02545 
02546 
02547             /*
02548              * Spline interpolation of spectra and linear interpolation of
02549              * errors
02550              */
02551 
02552             status = _giraffe_rebin_interpolate_spline(mabscissa,
02553                                                        mexspectra,
02554                                                        mwavelength,
02555                                                        mrbspectra);
02556 
02557             status = _giraffe_rebin_interpolate_linear(mabscissa,
02558                                                        mexerrors,
02559                                                        mwavelength,
02560                                                        mrberrors);
02561 
02562             for (x = 0; x < nwl; x++) {
02563 
02564                 register cxlong j = x * ns + n;
02565 
02566                 if ((-0.5 > _mwavelength[x]) || (_mwavelength[x] > nx1)) {
02567                     _rbspectra[j] = 0.;
02568                     _rberrors[j] = 0.;
02569                 }
02570                 else {
02571                     _rbspectra[j] = _mrbspectra[x];
02572                     _rberrors[j] = _mrberrors[x];
02573                 }
02574 
02575             }
02576 
02577         }
02578 
02579     } /* each spectrum */
02580 
02581 
02582     cpl_matrix_delete(mrbspectra);
02583     mrbspectra = NULL;
02584 
02585     cpl_matrix_delete(mwavelength);
02586     mwavelength = NULL;
02587 
02588     cpl_matrix_delete(mexspectra);
02589     mexspectra = NULL;
02590 
02591     cpl_matrix_delete(mabscissa);
02592     mabscissa = NULL;
02593 
02594     if (exerrors != NULL) {
02595         cpl_matrix_delete(mrberrors);
02596         mrberrors = NULL;
02597 
02598         cpl_matrix_delete(mexerrors);
02599         mexerrors = NULL;
02600     }
02601 
02602     cpl_msg_debug(fctid, "Rebinned %d spectra", ns);
02603 
02604     return 0;
02605 
02606 }
02607 
02608 
02682 static cxdouble
02683 giraffe_rebin_compute_opt_mod3(cxdouble xccd, cxdouble xfibre,
02684                                cxdouble yfibre, cxdouble nx,
02685                                cxdouble pixsize, cxdouble fcoll,
02686                                cxdouble cfact, cxdouble gtheta,
02687                                cxdouble gorder, cxdouble gspace,
02688                                cxdouble slitdx, cxdouble slitdy,
02689                                cxdouble slitphi)
02690 {
02691 
02692     /*************************************************************************
02693                                      Variables
02694     *************************************************************************/
02695 
02696     cxdouble xf, yf, d, t1, t12, t13, t18, t19, t2, t23, t28,
02697         t3, t31, t32, t36, t37, t39, t4, t40, t5, t62, t8, t9;
02698 
02699     /*************************************************************************
02700                                      Processing
02701     *************************************************************************/
02702 
02703     /* should take care of negative NX value */
02704 
02705     xf = xfibre * (1.0 + slitphi * yfibre) + slitdx;
02706     yf = yfibre * sqrt(1.0 - slitphi * slitphi) + slitdy;
02707     d = sqrt(xf * xf + yf * yf + fcoll * fcoll);
02708     t1 = cos(gtheta);
02709     t2 = xf*t1;
02710     t3 = xccd*xccd;
02711     t4 = pixsize*pixsize;
02712     t5 = t3*t4;
02713     t8 = sin(gtheta);
02714     t9 = fcoll*t8;
02715     t12 = cfact*cfact;
02716     t13 = fcoll*fcoll;
02717     t18 = nx*nx;
02718     t19 = t18*t4;
02719     t23 = xccd*t4*nx;
02720     t28 = t12*t13;
02721     t31 = yf*yf;
02722     t32 = d*d;
02723     t36 = 4.0*t28;
02724     t37 = t19+4.0*t5-4.0*t23+t36;
02725     t39 = t1*t1;
02726     t40 = t39*t4;
02727     t62 = sqrt((-t31+t32)*t37*(4.0*t40*t3-4.0*xccd*nx*t40 +
02728                                8.0*xccd*t1*cfact*t9*pixsize+t19*t39 -
02729                                4.0*cfact*fcoll*t8*nx*t1*pixsize+t36 -
02730                                4.0*t28*t39));
02731 
02732     return((4.0*t2*t5 + 4.0*t9*t5 + 4.0*t12*t13*fcoll*t8+t2*t19+t9*t19 -
02733             4.0*t9*t23 - 4.0*t2*t23 + 4.0*t28*t2+t62)*gspace/t37/gorder/d);
02734 
02735 } /* end giraffe_rebin_compute_opt_mod3() */
02736 
02761 static cxdouble
02762 giraffe_rebin_compute_log_opt_mod3(cxdouble xccd, cxdouble xfibre,
02763                                    cxdouble yfibre, cxdouble nx,
02764                                    cxdouble pixsize, cxdouble fcoll,
02765                                    cxdouble cfact, cxdouble gtheta,
02766                                    cxdouble gorder, cxdouble gspace,
02767                                    cxdouble slitdx, cxdouble slitdy,
02768                                    cxdouble slitphi)
02769 {
02770 
02771     return log(giraffe_rebin_compute_opt_mod3(xccd, xfibre, yfibre, nx,
02772                                               pixsize, fcoll, cfact, gtheta,
02773                                               gorder, gspace, slitdx, slitdy,
02774                                               slitphi));
02775 
02776 } /* end of giraffe_rebin_compute_log_opt_mod3() */
02777 
02824 static cxint
02825 giraffe_rebin_compute_lambda_range(GiFiberPosition *fiber_slit_position,
02826                                    cpl_matrix *opt_mod_params,
02827                                    cpl_matrix *grat_params,
02828                                    cxbool lambda_logarithmic,
02829                                    cxbool wlen_range_common,
02830                                    cxdouble *lambda_min, cxdouble *lambda_max)
02831 {
02832 
02833     /*************************************************************************
02834                                      Variables
02835     *************************************************************************/
02836 
02837     const cxchar *fctid = "giraffe_rebin_compute_lambda_range";
02838 
02839     register cxlong   n, ns;
02840     register cxdouble dx2, dnx, wl1, wl2;
02841 
02842     double (*computeWl) (double, double, double, double, double, double,
02843                          double, double, double, double, double, double,
02844                          double);
02845 
02846     cxdouble    *pd_opt_mod_params = NULL,
02847         *pd_xfiber        = NULL,
02848         *pd_yfiber        = NULL,
02849         *pd_grat_params    = NULL;
02850 
02851     cxint        nr_xfiber;
02852 
02853     /*************************************************************************
02854                                     Preprocessing
02855     *************************************************************************/
02856 
02857     if (fiber_slit_position         ==NULL) { return 1; }
02858     if (fiber_slit_position->x_fiber==NULL) { return 1; }
02859     if (fiber_slit_position->y_fiber==NULL) { return 1; }
02860     if (opt_mod_params              ==NULL) { return 1; }
02861     if (grat_params                 ==NULL) { return 1; }
02862     if (lambda_min                  ==NULL) { return 1; }
02863     if (lambda_max                  ==NULL) { return 1; }
02864 
02865     pd_opt_mod_params = cpl_matrix_get_data(opt_mod_params);
02866 
02867     pd_xfiber = cpl_matrix_get_data(fiber_slit_position->x_fiber);
02868     nr_xfiber = cpl_matrix_get_nrow(fiber_slit_position->x_fiber);
02869 
02870     /*************************************************************************
02871                                      Processing
02872     *************************************************************************/
02873 
02874     if (lambda_logarithmic==TRUE) {
02875         computeWl = giraffe_rebin_compute_log_opt_mod3;
02876     } else {
02877         computeWl = giraffe_rebin_compute_opt_mod3;
02878     }
02879 
02880     dnx = abs(pd_opt_mod_params[O_NX]);
02881     dx2 = dnx - 1.0;
02882     ns  = nr_xfiber;
02883 
02884     if (wlen_range_common==TRUE) {
02885         *lambda_min = 0.0;
02886         *lambda_max = CX_MAXDOUBLE;
02887     } else {
02888         *lambda_min = CX_MAXDOUBLE;
02889         *lambda_max = 0.0;
02890     }
02891 
02892     pd_yfiber = cpl_matrix_get_data(fiber_slit_position->y_fiber);
02893     pd_grat_params = cpl_matrix_get_data(grat_params);
02894 
02895     for (n = 0; n < ns; n++) {
02896 
02897         /* first abcissa  of each spectrum */
02898         wl1 =
02899             computeWl(
02900                 0.0,
02901                 pd_xfiber[n],
02902                 pd_yfiber[n],
02903                 dnx,
02904                 pd_opt_mod_params[O_PXSIZ],
02905                 pd_opt_mod_params[O_FCOLL],
02906                 pd_opt_mod_params[O_CFACT],
02907                 pd_grat_params[G_THETA],
02908                 pd_grat_params[G_ORDER],
02909                 pd_grat_params[G_SPACE],
02910                 pd_opt_mod_params[O_SOFFX],
02911                 pd_opt_mod_params[O_SOFFY],
02912                 pd_opt_mod_params[O_SPHI]
02913                 );
02914 
02915         /* last abcissa  of each spectrum */
02916         wl2 =
02917             computeWl(
02918                 dx2,
02919                 pd_xfiber[n],
02920                 pd_yfiber[n],
02921                 dnx,
02922                 pd_opt_mod_params[O_PXSIZ],
02923                 pd_opt_mod_params[O_FCOLL],
02924                 pd_opt_mod_params[O_CFACT],
02925                 pd_grat_params[G_THETA],
02926                 pd_grat_params[G_ORDER],
02927                 pd_grat_params[G_SPACE],
02928                 pd_opt_mod_params[O_SOFFX],
02929                 pd_opt_mod_params[O_SOFFY],
02930                 pd_opt_mod_params[O_SPHI]
02931                 );
02932 
02933         if (wlen_range_common==TRUE) {
02934 
02935             /* common range = [max(wlen_min), min(wlen_max)] */
02936 
02937             if (pd_opt_mod_params[O_NX] < 0) {
02938                 *lambda_max = CX_MIN(*lambda_max, wl1);
02939                 *lambda_min = CX_MAX(*lambda_min, wl2);
02940             } else {
02941                 *lambda_max = CX_MIN(*lambda_max, wl2);
02942                 *lambda_min = CX_MAX(*lambda_min, wl1);
02943             }
02944 
02945         } else {
02946 
02947             /* full range = [min(wlen_min), max(wlen_max)] */
02948 
02949             if (pd_opt_mod_params[O_NX] < 0) {
02950                 *lambda_max = CX_MAX(*lambda_max, wl1);
02951                 *lambda_min = CX_MIN(*lambda_min, wl2);
02952             } else {
02953                 *lambda_max = CX_MAX(*lambda_max, wl2);
02954                 *lambda_min = CX_MIN(*lambda_min, wl1);
02955             }
02956 
02957         }
02958 
02959     } /* for each spectrum */
02960 
02961     if (wlen_range_common==TRUE) {
02962         /* round to minimum range in integer nanometers */
02963         *lambda_max = floor((*lambda_max) * GI_MM_TO_NM) / GI_MM_TO_NM;
02964         *lambda_min = ceil( (*lambda_min) * GI_MM_TO_NM) / GI_MM_TO_NM;
02965     } else {
02966         /* round to maximum range in integer nanometers */
02967         *lambda_max = ceil( (*lambda_max) * GI_MM_TO_NM) / GI_MM_TO_NM;
02968         *lambda_min = floor((*lambda_min) * GI_MM_TO_NM) / GI_MM_TO_NM;
02969     }
02970 
02971     cpl_msg_debug(fctid, "Rebinning lambda range now: [%12.6f,%12.6f]",
02972                   *lambda_min, *lambda_max);
02973 
02974     return 0;
02975 
02976 } /* end giraffe_rebin_compute_lambda_range() */
02977 
03000 static cpl_image*
03001 giraffe_rebin_compute_pixel_x_residuals(
03002     GiLocPosition   *locPos,
03003     cpl_image       *abcissa,
03004     GiSlitGeo  *slitGeo,
03005     GiSlitGeo  *xresiduals_limits,
03006     GiSlitGeo  *xresiduals_coeff
03007     ) {
03008 
03009     /*************************************************************************
03010                                      Variables
03011     *************************************************************************/
03012 
03013     const cxchar *fctid = "giraffe_rebin_compute_pixel_x_residuals";
03014 
03015     cxdouble xmin, xmax, ymin, ymax, yup, ylo, yccd, ywid;
03016     cxint    n, m, x, xx, x0, i, j, k, l, xxp, x0p;
03017 
03018     cxint             subslit,
03019         nfibers,
03020         nmin,
03021         nmax,
03022         nlen,
03023         nx,       /* size of original spectra */
03024         ns,       /* number of spectra */
03025         nwl,      /* size of rebinned spectra */
03026         nf,
03027         nstart,
03028         ndata,
03029         nr_fit,
03030         nc_fit;
03031 
03032     cpl_matrix       *xss                = NULL,
03033         *yss                = NULL,
03034         *fit                = NULL,
03035         *curr_xres_limits   = NULL,
03036         *curr_xres_coeff    = NULL;
03037 
03038     cpl_image        *x_residuals_img    = NULL;
03039 
03040     cpl_matrix       *curr_subslit       = NULL;
03041 
03042     cxdouble         *pd_curr_subslit    = NULL,
03043         *pd_abcissa         = NULL,
03044         *pd_xss             = NULL,
03045         *pd_yss             = NULL;
03046 
03047     cxdouble         *pd_locy            = NULL,
03048         *pd_locw            = NULL,
03049         *buffer             = NULL,
03050         *pd_fit             = NULL,
03051         *pd_x_residuals_img = NULL;
03052 
03053 
03054     /*************************************************************************
03055                                     Preprocessing
03056     *************************************************************************/
03057 
03058     if (locPos            ==NULL) { return NULL; }
03059     if (locPos->centroids ==NULL) { return NULL; }
03060     if (locPos->widths    ==NULL) { return NULL; }
03061     if (abcissa           ==NULL) { return NULL; }
03062     if (slitGeo           ==NULL) { return NULL; }
03063     if (xresiduals_limits ==NULL) { return NULL; }
03064     if (xresiduals_coeff  ==NULL) { return NULL; }
03065 
03066     nx  = cpl_image_get_size_y(locPos->centroids);
03067     ns  = cpl_image_get_size_x(locPos->centroids);
03068     nf  = cpl_image_get_size_x(abcissa);
03069     nwl = cpl_image_get_size_y(abcissa);
03070 
03071     cpl_msg_debug(
03072         fctid,
03073         "Computing pixel x residuals, using nr spec/nr lines/orig abcissa "
03074         "size: %d/%d/%d",
03075         ns,
03076         nwl,
03077         nx
03078         );
03079 
03080     /*************************************************************************
03081                                      Processing
03082     *************************************************************************/
03083 
03084     x_residuals_img    = cpl_image_new(nf, nwl, CPL_TYPE_DOUBLE);
03085     pd_x_residuals_img = cpl_image_get_data_double(x_residuals_img);
03086     pd_abcissa         = cpl_image_get_data_double(abcissa);
03087 
03088     nstart = 0;
03089 
03090     for (subslit = 0; subslit<_giraffe_slitgeo_size(slitGeo); subslit++) {
03091 
03092         curr_subslit    = _giraffe_slitgeo_get(slitGeo, subslit);
03093         pd_curr_subslit = cpl_matrix_get_data(curr_subslit);
03094 
03095         giraffe_matrix_sort(curr_subslit);
03096 
03097         curr_xres_limits =
03098             cpl_matrix_duplicate(
03099                 _giraffe_slitgeo_get(xresiduals_limits, subslit)
03100                 );
03101 
03102         curr_xres_coeff =
03103             cpl_matrix_duplicate(
03104                 _giraffe_slitgeo_get(xresiduals_coeff, subslit)
03105                 );
03106 
03107         /* Get spectra/fibers range for current subslit */
03108         nfibers = cpl_matrix_get_nrow(curr_subslit);
03109 
03110         nmin    = (cxint) pd_curr_subslit[0];
03111         nmax    = (cxint) pd_curr_subslit[nfibers - 1];
03112         nlen    = nmax - nmin + 1;
03113         ndata   = nwl * nfibers;
03114 
03115         ymax    = 0.0;
03116         ymin    = CX_MAXDOUBLE;   /* has to be smaller than this one! */
03117 
03118         xss     = cpl_matrix_new(ndata, 1); /* X abcissas for subslit  */
03119         yss     = cpl_matrix_new(ndata, 1); /* Y ordinates             */
03120 
03121         pd_xss  = cpl_matrix_get_data(xss);
03122         pd_yss  = cpl_matrix_get_data(yss);
03123 
03124         pd_locy = cpl_image_get_data_double(locPos->centroids);
03125         pd_locw = cpl_image_get_data_double(locPos->widths);
03126 
03127 
03128         k = 0;
03129 
03130         for (m = 0, n = 0; n < nfibers; n++, m++) {
03131 
03132             i = 0;  /* running index for valid points */
03133 
03134             for (x = 0; x < nwl; x++) {
03135 
03136                 j  = x * nf + (nstart + n);
03137                 x0 = (cxint) floor(pd_abcissa[j]);
03138                 xx = (cxint) ceil(pd_abcissa[j]);
03139 
03140                 x0 = CX_MAX(CX_MIN(x0, nx - 1), 0);
03141                 xx = CX_MAX(CX_MIN(xx, nx - 1), 0);
03142 
03143                 l   = i  * nfibers + m;
03144                 xxp = xx * ns   + cpl_matrix_get(curr_subslit, n, 0);
03145                 x0p = x0 * ns   + cpl_matrix_get(curr_subslit, n, 0);
03146 
03147                 pd_xss[l] = pd_abcissa[j];
03148 
03149                 /*
03150                  * Corresponding Y centroid  and width using
03151                  * linear interpolation)
03152                  */
03153 
03154                 yccd      = pd_locy[x0p];
03155                 pd_yss[l] = yccd + ((pd_locy[xxp] - yccd) * (pd_xss[l] - x0));
03156 
03157                 ywid = pd_locw[x0p];
03158                 ywid = ywid + ((pd_locw[xxp] - ywid) * (pd_xss[l] - x0));
03159 
03160                 /* Get y range for current subslit */
03161                 yup = yccd + ywid;
03162                 ylo = yccd - ywid;
03163 
03164                 /* determine minimum and maximum */
03165                 if (ymax < yup) {
03166                     ymax = yup;
03167                 }
03168 
03169                 if (ymin > ylo) {
03170                     ymin = ylo;
03171                 }
03172 
03173                 ++i;
03174                 ++k;
03175 
03176             }
03177         }
03178 
03179         /* resize matrices to number of points found */
03180         cpl_matrix_set_size(xss, k, 1);
03181         cpl_matrix_set_size(yss, k, 1);
03182         pd_xss = cpl_matrix_get_data(xss);
03183         pd_yss = cpl_matrix_get_data(yss);
03184 
03185         xmin = cpl_matrix_get(curr_xres_limits, 0, 0);
03186         xmax = cpl_matrix_get(curr_xres_limits, 0, 1);
03187         ymin = cpl_matrix_get(curr_xres_limits, 0, 2);
03188         ymax = cpl_matrix_get(curr_xres_limits, 0, 3);
03189 
03190         xmin = xmin < 0. ? 0. : xmin;
03191         xmax = xmax < 0. ? (cxdouble)nx : xmax;
03192 
03193         ymin = ymin < 0. ? 0. : ymin;
03194         ymax = ymax < 0. ? 2048. : ymax;
03195 
03196         /* do chebyshev fit */
03197         fit =
03198             giraffe_chebyshev_fit2d(
03199                 xmin, ymin,
03200                 (xmax - xmin),
03201                 (ymax - ymin + 1.0),
03202                 curr_xres_coeff,
03203                 xss,
03204                 yss
03205                 );
03206 
03207         cpl_matrix_delete(yss);
03208         cpl_matrix_delete(xss);
03209         cpl_matrix_delete(curr_xres_coeff);
03210         cpl_matrix_delete(curr_xres_limits);
03211 
03212         /* resize fit found to match image dimensions */
03213         buffer = cpl_matrix_get_data(fit);
03214         cpl_matrix_unwrap(fit);
03215         fit = NULL;
03216 
03217         fit = cpl_matrix_wrap(nwl, nfibers, buffer);
03218         pd_fit = cpl_matrix_get_data(fit);
03219         nr_fit = cpl_matrix_get_nrow(fit);
03220         nc_fit = cpl_matrix_get_ncol(fit);
03221 
03222         /* subslit fit goes into whole fit */
03223         for (x = 0; x < nr_fit; x++) {
03224             for (k = nstart, n = 0; n < nc_fit; n++, k++) {
03225                 pd_x_residuals_img[x * nf + k] = pd_fit[x * nc_fit + n];
03226             }
03227         }
03228 
03229         cpl_matrix_delete(fit);
03230         fit = NULL;
03231 
03232         nstart += nfibers;
03233 
03234     } /* for each subslit */
03235 
03236     cpl_msg_debug(
03237         fctid,
03238         "Computed pixel x residuals, returning image [%d,%d]",
03239         ns,
03240         nwl
03241         );
03242 
03243     return x_residuals_img;
03244 
03245 } /* end giraffe_rebin_compute_pixel_x_residuals() */
03246 
03247 
03280 static cpl_image*
03281 giraffe_rebin_compute_rebin_abcissa(GiFiberPosition* fiber_slit_position,
03282                                     GiLocPosition* locPos,
03283                                     GiSlitGeo* slitGeo,
03284                                     GiSlitGeo* xresiduals_limits,
03285                                     GiSlitGeo* xresiduals_coeff,
03286                                     cpl_matrix* grat_params,
03287                                     cpl_matrix* opt_mod_params,
03288                                     cpl_matrix* wloffsets,
03289                                     lmrq_model lmrq_opt_mod_x,
03290                                     GiRebinParams binPrms)
03291 {
03292 
03293     /*************************************************************************
03294                                      Variables
03295     *************************************************************************/
03296 
03297     const cxchar* const fctid = "giraffe_rebin_compute_rebin_abcissa";
03298 
03299     cpl_matrix* wlengths    = NULL;
03300     cpl_matrix* temp_params = NULL;
03301 
03302     cpl_image* abcissa         = NULL;
03303     cpl_image* x_residuals_img = NULL;
03304 
03305     cxdouble* pd_wlengths       = NULL;
03306     cxdouble* pd_temp_params    = NULL;
03307     cxdouble* pd_opt_mod_params = NULL;
03308     cxdouble* pd_grat_params    = NULL;
03309 
03310     /*************************************************************************
03311                                     Preprocessing
03312     *************************************************************************/
03313 
03314     if (fiber_slit_position == NULL) {
03315         return NULL;
03316     }
03317 
03318     if (locPos == NULL) {
03319         return NULL;
03320     }
03321 
03322     if (slitGeo == NULL) {
03323         return NULL;
03324     }
03325 
03326     if (grat_params == NULL) {
03327         return NULL;
03328     }
03329 
03330     if (opt_mod_params == NULL) {
03331         return NULL;
03332     }
03333 
03334     wlengths    = cpl_matrix_new(binPrms.size, 1);
03335     pd_wlengths = cpl_matrix_get_data(wlengths);
03336 
03337     temp_params = cpl_matrix_new(lmrq_opt_mod_x.nparams, 1);
03338 
03339     pd_temp_params    = cpl_matrix_get_data(temp_params);
03340     pd_opt_mod_params = cpl_matrix_get_data(opt_mod_params);
03341     pd_grat_params    = cpl_matrix_get_data(grat_params);
03342 
03343     pd_temp_params[OG_NX]    = pd_opt_mod_params[O_NX];
03344     pd_temp_params[OG_PXSIZ] = pd_opt_mod_params[O_PXSIZ];
03345     pd_temp_params[OG_FCOLL] = pd_opt_mod_params[O_FCOLL];
03346     pd_temp_params[OG_CFACT] = pd_opt_mod_params[O_CFACT];
03347     pd_temp_params[OG_THETA] = pd_grat_params[G_THETA];
03348     pd_temp_params[OG_ORDER] = pd_grat_params[G_ORDER];
03349     pd_temp_params[OG_SPACE] = pd_grat_params[G_SPACE];
03350 
03351     if (lmrq_opt_mod_x.nparams > OG_SOFFX) {
03352         pd_temp_params[OG_SOFFX] = pd_opt_mod_params[O_SOFFX];
03353         pd_temp_params[OG_SOFFY] = pd_opt_mod_params[O_SOFFY];
03354         pd_temp_params[OG_SPHI]  = pd_opt_mod_params[O_SPHI];
03355     }
03356 
03357     /*************************************************************************
03358                                      Processing
03359     *************************************************************************/
03360 
03361     /*
03362      *  Compute lambda abcissa for rebinning
03363      */
03364 
03365     if (binPrms.log==TRUE) {
03366         /* lambda was specified in log(lambda) */
03367         cxint i;
03368         for (i = 0; i < binPrms.size; i++) {
03369             pd_wlengths[i] = exp(binPrms.min + (cxdouble) i * binPrms.step);
03370         }
03371     } else {
03372         cxint i;
03373         for (i = 0; i < binPrms.size; i++) {
03374             pd_wlengths[i] = binPrms.min + (cxdouble) i * binPrms.step;
03375         }
03376     }
03377 
03378     abcissa = _giraffe_compute_pixel_abscissa(wlengths, wloffsets,
03379                                               fiber_slit_position,
03380                                               temp_params, lmrq_opt_mod_x);
03381 
03382 
03383     /*
03384      *  If X residuals use, specified, calculate them and subtract
03385      *  them from the computed abcissa...
03386      */
03387 
03388     if ((binPrms.xres==TRUE) && (xresiduals_coeff!=NULL)) {
03389 
03390         x_residuals_img =
03391             giraffe_rebin_compute_pixel_x_residuals(
03392                 locPos,
03393                 abcissa,
03394                 slitGeo,
03395                 xresiduals_limits,
03396                 xresiduals_coeff
03397                 );
03398 
03399         cpl_image_subtract(abcissa, x_residuals_img);
03400         cpl_image_delete(x_residuals_img);
03401 
03402     }
03403 
03404     cpl_matrix_delete(wlengths);
03405     cpl_matrix_delete(temp_params);
03406 
03407     cpl_msg_debug(
03408         fctid,
03409         "Processing complete : returning image [%d, %d]",
03410         cpl_image_get_size_x(abcissa),
03411         cpl_image_get_size_y(abcissa)
03412         );
03413 
03414     return abcissa;
03415 
03416 } /* end giraffe_rebin_compute_rebin_abcissa() */
03417 
03445 inline static cxint
03446 _giraffe_resample_spectra(GiRebinning* result,
03447                           const GiExtraction* extraction,
03448                           const GiLocalization* localization,
03449                           GiFiberPosition* fiber_position,
03450                           GiSlitGeo* subslits,
03451                           GiSlitGeo* xres_limits,
03452                           GiSlitGeo* xres_coeff,
03453                           GiBinnParams* xres_order,
03454                           cpl_matrix* grating_data,
03455                           cpl_matrix* optical_model,
03456                           cpl_matrix* wlen_offsets,
03457                           cxdouble rbstep,
03458                           GiRebinMethod method,
03459                           GiRebinRange range,
03460                           GiRebinScale scale)
03461 {
03462 
03463     const cxchar* const fctid = "_giraffe_resample_spectra";
03464 
03465 
03466     cxbool log_scale = FALSE;
03467 
03468     cxint i = 0;
03469     cxint status = 0;
03470     cxint om_sign = 0;
03471     cxint rbsize = 0;
03472     cxint nspectra = 0;
03473 
03474     cxdouble wlmin = 0.;
03475     cxdouble wlmax = 0.;
03476     cxdouble* _optical_model = NULL;
03477 
03478     cpl_matrix* wavelengths = NULL;
03479 
03480     cpl_image* _exspectra = NULL;
03481     cpl_image* _exerrors = NULL;
03482     cpl_image* _rbspectra = NULL;
03483     cpl_image* _rberrors = NULL;
03484     cpl_image* abscissa = NULL;
03485 
03486     cpl_propertylist* properties = NULL;
03487 
03488     GiImage* rbspectra = NULL;
03489     GiImage* rberrors = NULL;
03490 
03491     GiLocPosition locPos;
03492 
03493     GiRebinParams binPrms;
03494 
03495     GiRebinInfo setup;
03496 
03497 
03498     /*
03499      * default opt model is xoptmod2, python code
03500      * can not handle anything else anyway
03501      */
03502 
03503      lmrq_model_id opt_mod_id = LMRQ_XOPTMOD2;
03504 
03505 
03506     if (result == NULL || extraction == NULL || localization == NULL) {
03507         return 1;
03508     }
03509 
03510     if (result->spectra != NULL || result->errors != NULL) {
03511         return 1;
03512     }
03513 
03514     if (extraction->spectra == NULL) {
03515         return 1;
03516     }
03517 
03518     if (localization->locy == NULL || localization->locw == NULL) {
03519         return 1;
03520     }
03521 
03522     if (fiber_position == NULL) {
03523         return 1;
03524     }
03525 
03526     if (subslits == NULL) {
03527         return 1;
03528     }
03529 
03530     if (grating_data == NULL) {
03531         return 1;
03532     }
03533 
03534     if (optical_model == NULL) {
03535         return 1;
03536     }
03537 
03538 
03539     if (xres_coeff != NULL) {
03540         if (xres_limits == NULL || xres_order == NULL) {
03541             return 1;
03542         }
03543     }
03544 
03545 
03546     /*
03547      * FIXME: Should we set opt_mod_id to opt_mod_id used by wave
03548      *        calibration? Yes!!!
03549      */
03550 
03551     _exspectra = giraffe_image_get(extraction->spectra);
03552 
03553     if (extraction->error != NULL) {
03554         _exerrors = giraffe_image_get(extraction->error);
03555     }
03556 
03557     _optical_model = cpl_matrix_get_data(optical_model);
03558 
03559     nspectra = cpl_image_get_size_x(_exspectra);
03560 
03561     om_sign = (_optical_model[O_NX] >= 0) ? 1 : -1;
03562 
03563     if (scale == GIREBIN_SCALE_LOG) {
03564         log_scale = TRUE;
03565     }
03566 
03567 
03568     /*
03569      *  Find wavelength range
03570      */
03571 
03572      if (range == GIREBIN_RANGE_SETUP) {
03573 
03574         /*
03575          * Wavelength range taken from observed mode
03576          */
03577 
03578         wlmin = cpl_matrix_get(grating_data, 2, 0);
03579         wlmax = cpl_matrix_get(grating_data, 4, 0);
03580 
03581         if (log_scale == TRUE) {
03582             wlmin = log(wlmin);
03583             wlmax = log(wlmax);
03584         }
03585 
03586     }
03587     else {
03588 
03589         /*
03590          * Spectral range based on max/min wavelengths
03591          */
03592 
03593         status = giraffe_rebin_compute_lambda_range(fiber_position,
03594                                                     optical_model,
03595                                                     grating_data, log_scale,
03596                                                     TRUE, &wlmin, &wlmax);
03597 
03598     }
03599 
03600     rbsize = 1 + (cxint) ((wlmax - wlmin) / rbstep);
03601 
03602     if (rbsize < 0) {
03603 
03604         cpl_msg_debug(fctid, "Invalid dispersion direction [%d], changing "
03605                       "optical model orientation", om_sign);
03606 
03607         om_sign = -om_sign;
03608         _optical_model[O_NX] = -_optical_model[O_NX];
03609 
03610         status = giraffe_rebin_compute_lambda_range(fiber_position,
03611                                                     optical_model,
03612                                                     grating_data, log_scale,
03613                                                     TRUE, &wlmin, &wlmax);
03614 
03615         rbsize = 1 + (cxint) ((wlmax - wlmin) / rbstep);
03616 
03617     }
03618 
03619     if (rbsize < 1) {
03620         cpl_msg_error(fctid, "Invalid size %d of rebinned spectra, "
03621                       "aborting...", rbsize);
03622         return 2;
03623     }
03624 
03625 
03626     /*
03627      *  Calculate rebinned X positions...
03628      */
03629 
03630     locPos.type      = GILOCDATATYPE_FITTED_DATA;
03631     locPos.centroids = giraffe_image_get(localization->locy);
03632     locPos.widths    = giraffe_image_get(localization->locw);
03633 
03634     binPrms.min  = wlmin;
03635     binPrms.step = rbstep;
03636     binPrms.size = rbsize;
03637     binPrms.log  = log_scale;
03638 
03639     if (xres_coeff == NULL || (xres_order->xdeg == 0 &&
03640                                xres_order->ydeg == 0)) {
03641         binPrms.xres = FALSE;
03642     }
03643     else {
03644         binPrms.xres = TRUE;
03645     }
03646 
03647     abscissa = giraffe_rebin_compute_rebin_abcissa(fiber_position, &locPos,
03648                                                    subslits, xres_limits,
03649                                                    xres_coeff, grating_data,
03650                                                    optical_model, wlen_offsets,
03651                                                    lmrq_models[opt_mod_id],
03652                                                    binPrms);
03653 
03654 
03655     /*
03656      *  Perform rebinng of spectra and associated errors...
03657      */
03658 
03659     wavelengths = cpl_matrix_new(rbsize, 1);
03660 
03661     for (i = 0; i < rbsize; i++) {
03662         cpl_matrix_set(wavelengths, i, 0, wlmin + (cxdouble) i * rbstep);
03663     }
03664 
03665     rbspectra = giraffe_image_create(CPL_TYPE_DOUBLE, nspectra, rbsize);
03666     _rbspectra = giraffe_image_get(rbspectra);
03667 
03668     if (_exerrors != NULL) {
03669         rberrors = giraffe_image_create(CPL_TYPE_DOUBLE, nspectra, rbsize);
03670         _rberrors = giraffe_image_get(rberrors);
03671     }
03672 
03673     switch (method) {
03674     case GIREBIN_METHOD_LINEAR:
03675         status = _giraffe_resample_linear(_rbspectra, _rberrors, abscissa,
03676                                           _exspectra, _exerrors, om_sign);
03677         break;
03678 
03679     case GIREBIN_METHOD_SPLINE:
03680         status = _giraffe_resample_spline(_rbspectra, _rberrors, abscissa,
03681                                           _exspectra, _exerrors, om_sign);
03682         break;
03683 
03684     default:
03685 
03686         /* We should never get to this point! */
03687 
03688         gi_error("Invalid rebinning method!");
03689         break;
03690     }
03691 
03692     cpl_image_delete(abscissa);
03693     abscissa = NULL;
03694 
03695     if (status != 0) {
03696         cpl_msg_error(fctid, "Error during rebinning, aborting...");
03697 
03698         cpl_matrix_delete(wavelengths);
03699         wavelengths = NULL;
03700 
03701         giraffe_image_delete(rbspectra);
03702         rbspectra = NULL;
03703 
03704         if (rberrors != NULL) {
03705             giraffe_image_delete(rberrors);
03706             rberrors = NULL;
03707         }
03708 
03709         return 3;
03710     }
03711 
03712 
03713 
03714     /*
03715      *  Add calculated image, keywords etc. to rebinned spectrum frame...
03716      */
03717 
03718     switch (scale) {
03719     case GIREBIN_SCALE_LOG:
03720         {
03721             cxsize nw = cpl_matrix_get_nrow(wavelengths);
03722 
03723             cxdouble mm2nm = log(GI_MM_TO_NM);
03724 
03725             setup.wmin = mm2nm + cpl_matrix_get(wavelengths, 0, 0);
03726             setup.wcenter = mm2nm + cpl_matrix_get(wavelengths, nw / 2, 0);
03727             setup.wmax = mm2nm + cpl_matrix_get(wavelengths, nw - 1, 0);
03728             setup.wstep  = rbstep;
03729 
03730             setup.units = "log(nm)";
03731             setup.offset = 0;
03732         }
03733         break;
03734 
03735     case GIREBIN_SCALE_LINEAR:
03736         {
03737             cxsize nw = cpl_matrix_get_nrow(wavelengths);
03738 
03739             setup.wmin = GI_MM_TO_NM * cpl_matrix_get(wavelengths, 0, 0);
03740             setup.wcenter = GI_MM_TO_NM * cpl_matrix_get(wavelengths,
03741                                                          nw / 2, 0);
03742             setup.wmax = GI_MM_TO_NM * cpl_matrix_get(wavelengths,
03743                                                       nw - 1, 0);
03744             setup.wstep  = GI_MM_TO_NM * rbstep;
03745 
03746             setup.units = "nm";
03747             setup.offset = 0;
03748         }
03749         break;
03750 
03751     default:
03752 
03753         /* We should never get here */
03754 
03755         gi_error("Invalid scaling option!");
03756         break;
03757     }
03758 
03759     cpl_matrix_delete(wavelengths);
03760     wavelengths = NULL;
03761 
03762 
03763     switch (method) {
03764     case GIREBIN_METHOD_LINEAR:
03765         setup.method = "linear";
03766         break;
03767 
03768     case GIREBIN_METHOD_SPLINE:
03769         setup.method = "spline";
03770         break;
03771 
03772     default:
03773 
03774         /* We should never get here */
03775 
03776         gi_error("Invalid rebinning method!");
03777         break;
03778     }
03779 
03780 
03781     switch (scale) {
03782     case GIREBIN_SCALE_LINEAR:
03783         setup.scale = "linear";
03784         break;
03785 
03786     case GIREBIN_SCALE_LOG:
03787         setup.scale = "logarithmic";
03788         break;
03789 
03790     default:
03791 
03792         /* We should never get here */
03793 
03794         gi_error("Invalid scaling option!");
03795         break;
03796     }
03797 
03798     switch (range) {
03799     case GIREBIN_RANGE_SETUP:
03800         setup.range = "setup";
03801         break;
03802 
03803     case GIREBIN_RANGE_COMMON:
03804         setup.range = "common";
03805         break;
03806 
03807     default:
03808 
03809         /* We should never get here */
03810 
03811         gi_error("Invalid range option!");
03812         break;
03813     }
03814 
03815 
03816     /*
03817      * Finalize resampled spectra
03818      */
03819 
03820     giraffe_error_push();
03821 
03822     properties = giraffe_image_get_properties(extraction->spectra);
03823     giraffe_image_set_properties(rbspectra, properties);
03824 
03825     if (cpl_error_get_code() != CPL_ERROR_NONE) {
03826         giraffe_image_delete(rbspectra);
03827         rbspectra = NULL;
03828 
03829         if (rberrors != NULL) {
03830             giraffe_image_delete(rberrors);
03831             rberrors = NULL;
03832         }
03833 
03834         return 4;
03835     }
03836 
03837     giraffe_error_pop();
03838 
03839     status = _giraffe_resample_update_properties(rbspectra, &setup);
03840 
03841     if (status != 0) {
03842         giraffe_image_delete(rbspectra);
03843         rbspectra = NULL;
03844 
03845         if (rberrors != NULL) {
03846             giraffe_image_delete(rberrors);
03847             rberrors = NULL;
03848         }
03849 
03850         return 4;
03851     }
03852 
03853 
03854     /*
03855      * Finalize resampled spectra errors if they are available
03856      */
03857 
03858     if (_rberrors != NULL) {
03859 
03860         giraffe_error_push();
03861 
03862         properties =  giraffe_image_get_properties(extraction->error);
03863         giraffe_image_set_properties(rberrors, properties);
03864 
03865         if (cpl_error_get_code() != CPL_ERROR_NONE) {
03866             giraffe_image_delete(rbspectra);
03867             rbspectra = NULL;
03868 
03869             if (rberrors != NULL) {
03870                 giraffe_image_delete(rberrors);
03871                 rberrors = NULL;
03872             }
03873 
03874             return 5;
03875         }
03876 
03877         giraffe_error_pop();
03878 
03879         status = _giraffe_resample_update_properties(rberrors, &setup);
03880 
03881         if (status != 0) {
03882             giraffe_image_delete(rbspectra);
03883             rbspectra = NULL;
03884 
03885             if (rberrors != NULL) {
03886                 giraffe_image_delete(rberrors);
03887                 rberrors = NULL;
03888             }
03889 
03890             return 5;
03891         }
03892 
03893     }
03894 
03895     result->spectra = rbspectra;
03896     result->errors = rberrors;
03897 
03898     return 0;
03899 
03900 }
03901 
03902 
03910 GiRange *
03911 giraffe_rebin_get_wavelength_range(GiImage *spectra, GiTable *wlsolution,
03912                                    GiTable *grating, GiTable *slitgeometry,
03913                                    cxbool common)
03914 {
03915 
03916     cxint status = 0;
03917 
03918     cxdouble min = 0.;
03919     cxdouble max = 0.;
03920 
03921     cpl_matrix *optical_model = NULL;
03922     cpl_matrix *grating_data = NULL;
03923 
03924     GiFiberPosition *positions = NULL;
03925     GiSlitGeo *subslits = NULL;
03926 
03927     GiWcalSolution *wcal = NULL;
03928 
03929     GiRange *range = NULL;
03930 
03931 
03932     if (spectra == NULL) {
03933         return NULL;
03934     }
03935 
03936     if (grating == NULL) {
03937         return NULL;
03938     }
03939 
03940     if (slitgeometry == NULL) {
03941         return NULL;
03942     }
03943 
03944 
03945     wcal = _giraffe_wcalsolution_create(wlsolution);
03946 
03947     if (wcal == NULL) {
03948         return NULL;
03949     }
03950 
03951     optical_model = _giraffe_rebin_setup_model(spectra, wcal);
03952 
03953     if (optical_model == NULL) {
03954         _giraffe_wcalsolution_delete(wcal);
03955         return NULL;
03956     }
03957 
03958     _giraffe_wcalsolution_delete(wcal);
03959 
03960     grating_data = _giraffe_rebin_setup_grating(spectra, grating,
03961                                                 wlsolution);
03962 
03963     if (grating_data == NULL) {
03964 
03965         cpl_matrix_delete(grating_data);
03966         cpl_matrix_delete(optical_model);
03967 
03968         return NULL;
03969 
03970     }
03971 
03972     positions = _giraffe_fiberposition_new();
03973     subslits = _giraffe_slitgeo_new();
03974 
03975     status = _giraffe_slitgeo_setup(slitgeometry, positions, subslits,
03976                                     FALSE);
03977 
03978     if (status != 0) {
03979 
03980         _giraffe_slitgeo_delete(subslits);
03981         _giraffe_fiberposition_delete(positions);
03982 
03983         cpl_matrix_delete(grating_data);
03984         cpl_matrix_delete(optical_model);
03985 
03986         return NULL;
03987 
03988     }
03989 
03990     status = giraffe_rebin_compute_lambda_range(positions, optical_model,
03991                                                 grating_data,
03992                                                 GIREBIN_SCALE_LINEAR,
03993                                                 common, &min, &max);
03994 
03995     /*
03996      * Convert wavelength from millimeters to nanometers.
03997      */
03998 
03999     min *= GI_MM_TO_NM;
04000     max *= GI_MM_TO_NM;
04001 
04002     _giraffe_slitgeo_delete(subslits);
04003     _giraffe_fiberposition_delete(positions);
04004 
04005     cpl_matrix_delete(grating_data);
04006     cpl_matrix_delete(optical_model);
04007 
04008     range = giraffe_range_create(min, max);
04009 
04010     return range;
04011 
04012 }
04013 
04014 
04048 cxint
04049 giraffe_rebin_spectra(GiRebinning *rebinning,
04050                       const GiExtraction *extraction,
04051                       const GiTable *fibers,
04052                       const GiLocalization *localization,
04053                       const GiTable *grating,
04054                       const GiTable *slitgeo,
04055                       const GiTable *solution,
04056                       const GiRebinConfig *config)
04057 {
04058 
04059     const cxchar* const fctid = "giraffe_rebin_spectra";
04060 
04061 
04062     cxint status = 0;
04063     cxint ex_sp_extr_pixels = 0;
04064     cxint calc_rebinned_size = 0;
04065     cxint default_rebinned_size = GIREBIN_SIZE_Y_DEFAULT;
04066 
04067     cxdouble rbin_multiplier = 0.;
04068     cxdouble ex_sp_pixsize_x = 0.;
04069     cxdouble rbin_stepsize = 0.;
04070 
04071     cpl_matrix* grat_params    = NULL;
04072     cpl_matrix* opt_mod_params = NULL;
04073     cpl_matrix* wloffsets      = NULL;
04074 
04075     cpl_table* _fibers = NULL;
04076 
04077     cpl_propertylist* _pl_ext_sp = NULL;
04078     cpl_propertylist* _pl_wsol   = NULL;
04079 
04080     GiImage* ex_sp_frame = NULL;
04081     GiImage* ex_sp_err_frame = NULL;
04082     GiImage* loc_y_frame = NULL;
04083     GiImage* loc_w_frame = NULL;
04084 
04085     GiSlitGeo* subslit_fibers = NULL;
04086     GiSlitGeo* wav_coeffs = NULL;
04087     GiSlitGeo* wav_limits = NULL;
04088 
04089     GiGrat* grating_data = NULL;
04090 
04091     GiFiberPosition* fiber_slit_position  = NULL;
04092 
04093     GiWcalSolution* wcalib_solution = NULL;
04094 
04095     GiBinnParams xres_polynom_deg = {0, 0};
04096 
04097 
04098 
04099     /*
04100      * Preprocessing
04101      */
04102 
04103     if (extraction == NULL) {
04104         cpl_msg_error(fctid, "No extracted data, aborting...");
04105         return 1;
04106     }
04107 
04108     if (extraction->spectra == NULL) {
04109         cpl_msg_error(fctid, "No extracted spectra, aborting...");
04110         return 1;
04111     }
04112 
04113     if (fibers == NULL) {
04114         cpl_msg_error(fctid, "No fiber table, aborting ...");
04115         return 1;
04116     }
04117 
04118     if (localization == NULL) {
04119         cpl_msg_error(fctid, "No localization data, aborting...");
04120         return 1;
04121     }
04122 
04123     if (localization->locy == NULL) {
04124         cpl_msg_error(fctid, "No localization centroids, aborting...");
04125         return 1;
04126     }
04127 
04128     if (localization->locw == NULL) {
04129         cpl_msg_error(fctid, "No localization widths, aborting...");
04130         return 1;
04131     }
04132 
04133     if (grating == NULL) {
04134         cpl_msg_error(fctid, "No grating data, aborting...");
04135         return 1;
04136     }
04137 
04138     if (rebinning == NULL) {
04139         cpl_msg_error(fctid, "No rebinning results container, aborting...");
04140         return 1;
04141     }
04142 
04143     if (config == NULL) {
04144         cpl_msg_error(fctid, "No rebinning configuration data, aborting...");
04145         return 1;
04146     }
04147 
04148     if (solution == NULL) {
04149         cpl_msg_error(fctid, "No wavecalibration solution, aborting...");
04150         return 1;
04151     }
04152 
04153     ex_sp_frame          = extraction->spectra;
04154     ex_sp_err_frame      = extraction->error;
04155     loc_y_frame          = localization->locy;
04156     loc_w_frame          = localization->locw;
04157 
04158     _pl_ext_sp           = giraffe_image_get_properties(ex_sp_frame);
04159     _pl_wsol             = giraffe_table_get_properties(solution);
04160 
04161 
04162     _fibers = giraffe_table_get(fibers);
04163     cx_assert(_fibers != NULL);
04164 
04165 
04166 
04167     /*
04168      * Initialization
04169      */
04170 
04171     /*
04172      *  Retrieve necessary values from FITS keywords
04173      */
04174 
04175     if (cpl_propertylist_has(_pl_ext_sp, GIALIAS_PIXSIZX) == TRUE) {
04176         ex_sp_pixsize_x = cpl_propertylist_get_double(_pl_ext_sp,
04177                                                       GIALIAS_PIXSIZX);
04178 
04179     }
04180     else {
04181         cpl_msg_error(fctid, "%s Keyword missing in Extracted Spectra "
04182                       "Frame, aborting ...", GIALIAS_PIXSIZX);
04183         return 2;
04184     }
04185 
04186 
04187     /*
04188      * Convert pixel size to microns
04189      */
04190 
04191     if (ex_sp_pixsize_x > 1.) {
04192         ex_sp_pixsize_x /= 1000.;
04193     }
04194 
04195 
04196     /*
04197      * Determine rebinning step size multiplier
04198      */
04199 
04200     if (cpl_propertylist_has(_pl_ext_sp, GIALIAS_GRATNAME) == TRUE) {
04201 
04202         const cxchar* _string = NULL;
04203 
04204         _string = cpl_propertylist_get_string(_pl_ext_sp, GIALIAS_GRATNAME);
04205 
04206         if (strncmp(_string, "LR", 2) == 0) {
04207             rbin_multiplier = 4.;
04208         }
04209         else if (strncmp(_string, "HR", 2) == 0) {
04210             rbin_multiplier = 1.;
04211         }
04212         else {
04213             rbin_multiplier = 1.;
04214         }
04215 
04216     }
04217     else {
04218         cpl_msg_error(fctid, "%s Keyword missing in Extracted Spectra Frame, "
04219                       "aborting ...", GIALIAS_GRATNAME);
04220         return 2;
04221     }
04222 
04223 
04224     /*
04225      * find number of pixel per spectrum
04226      */
04227 
04228     if (cpl_propertylist_has(_pl_ext_sp, GIALIAS_EXT_NX) == TRUE) {
04229         ex_sp_extr_pixels = cpl_propertylist_get_int(_pl_ext_sp,
04230                                                      GIALIAS_EXT_NX);
04231 
04232     }
04233     else {
04234         cpl_msg_error(fctid, "%s Keyword missing in Extracted Spectra Frame, "
04235                       "aborting ...", GIALIAS_EXT_NX);
04236         return 2;
04237     }
04238 
04239 
04240     /*
04241      *  Retrieve Grating information
04242      */
04243 
04244     grating_data = _giraffe_grating_new();
04245 
04246     status = _giraffe_grating_setup(grating, ex_sp_frame, grating_data);
04247 
04248     if (status != 0) {
04249         cpl_msg_error(fctid, "Unable to retrieve grating information, "
04250                       "aborting...");
04251         _giraffe_grating_delete(grating_data);
04252         return 3;
04253     }
04254 
04255     /*
04256      *  Retrieve Slit Geometry Information
04257      */
04258 
04259     fiber_slit_position = _giraffe_fiberposition_new();
04260     subslit_fibers = _giraffe_slitgeo_new();
04261 
04262     status = _giraffe_slitgeo_setup(slitgeo, fiber_slit_position,
04263                                     subslit_fibers, FALSE);
04264 
04265     if (status != 0) {
04266         cpl_msg_error(fctid, "Unable to retrieve slit geometry information, "
04267                       "aborting...");
04268         _giraffe_grating_delete(grating_data);
04269         _giraffe_fiberposition_delete(fiber_slit_position);
04270         _giraffe_slitgeo_delete(subslit_fibers);
04271         return 7;
04272     }
04273 
04274 
04275     wcalib_solution = _giraffe_wcalsolution_create(solution);
04276 
04277     if (wcalib_solution == NULL) {
04278         cpl_msg_error(fctid, "Cannot create wavelength solution, "
04279                       "aborting ...");
04280         _giraffe_grating_delete(grating_data);
04281         _giraffe_fiberposition_delete(fiber_slit_position);
04282         _giraffe_slitgeo_delete(subslit_fibers);
04283         return 4;
04284     }
04285 
04286     if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMFCOLL) == TRUE) {
04287         grating_data->fcoll =
04288             cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMFCOLL);
04289     }
04290 
04291     if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMGCAM) == TRUE) {
04292         grating_data->gcam =
04293             cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMGCAM);
04294     }
04295 
04296     if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMGTHETA) == TRUE) {
04297         grating_data->theta =
04298             cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMGTHETA);
04299     }
04300 
04301     if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMSDX) == TRUE) {
04302         grating_data->slitdx =
04303             cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMSDX);
04304     }
04305 
04306     if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMSDY) == TRUE) {
04307         grating_data->slitdy =
04308             cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMSDY);
04309     }
04310 
04311     if (cpl_propertylist_has(_pl_wsol, GIALIAS_WSOL_OMSPHI) == TRUE) {
04312         grating_data->slitphi =
04313             cpl_propertylist_get_double(_pl_wsol, GIALIAS_WSOL_OMSPHI);
04314     }
04315 
04316 
04317     /*
04318      * If wavelength corrections were provided, convert the wavelength
04319      * offsets from nanometers to millimeters and store them as a
04320      * matrix (nfibers x 1).
04321      */
04322 
04323     if (cpl_table_has_column(_fibers, "WLRES") != 0) {
04324 
04325         cxint fiber = 0;
04326         cxint nfibers = cpl_table_get_nrow(_fibers);
04327 
04328 
04329         wloffsets  = cpl_matrix_new(nfibers, 1);
04330 
04331         for (fiber = 0; fiber < nfibers; ++fiber) {
04332 
04333             cxdouble wloffset = cpl_table_get_double(_fibers, "WLRES",
04334                 fiber, NULL);
04335 
04336 
04337             wloffset *= -GI_NM_TO_MM;
04338             cpl_matrix_set(wloffsets, fiber, 0, wloffset);
04339 
04340         }
04341 
04342         cpl_msg_info(fctid, "Applying SIMCAL wavelength corrections ...");
04343 
04344     }
04345 
04346 
04347 
04348     /*
04349      * Processing
04350      */
04351 
04352 
04353     /*
04354      *  Determine rebinning stepsize and size in y direction after rebinning
04355      */
04356 
04357     if (config->scmethod == GIREBIN_SCALE_LOG) {
04358 
04359         cxint rebin_size;
04360 
04361         cxdouble wlenmax;
04362         cxdouble wlenmin;
04363 
04364         rebin_size = default_rebinned_size;
04365 
04366         wlenmin = log(grating_data->wlenmin / GI_MM_TO_NM);
04367         wlenmax = log(grating_data->wlenmax / GI_MM_TO_NM);
04368 
04369         if ((config->size != rebin_size) && (config->size != 0)) {
04370             rebin_size = config->size;
04371         }
04372 
04373         rbin_stepsize = (wlenmax - wlenmin) / rebin_size;
04374 
04375         calc_rebinned_size = 1 + (cxint) ((wlenmax-wlenmin)/ rbin_stepsize);
04376 
04377     }
04378     else {
04379 
04380         cxint rebin_size;
04381 
04382         cxdouble wlenmax;
04383         cxdouble wlenmin;
04384 
04385         wlenmin = grating_data->wlenmin / GI_MM_TO_NM;
04386         wlenmax = grating_data->wlenmax / GI_MM_TO_NM;
04387 
04388         rbin_stepsize = (config->lstep / GI_MM_TO_NM) * rbin_multiplier;
04389         rebin_size    = (wlenmax - wlenmin) / rbin_stepsize;
04390 
04391         if ((config->size != rebin_size) && (config->size != 0)) {
04392             rebin_size = config->size;
04393             rbin_stepsize = (wlenmax - wlenmin) / rebin_size;
04394         }
04395 
04396         calc_rebinned_size = 1 + (cxint) ((wlenmax-wlenmin) / rbin_stepsize);
04397 
04398     }
04399 
04400     /*
04401      *  Retrieve Wavecalibration Solution Physical Optical Paramters
04402      */
04403 
04404     if (wcalib_solution!=NULL) {
04405 
04406         if (wcalib_solution->opt_mod==LMRQ_XOPTMOD) {
04407 
04408             cxint    nrow;
04409             cxdouble opt_direction, fcoll, cfact;
04410 
04411             nrow = cpl_matrix_get_nrow(wcalib_solution->opt_mod_params);
04412             if (nrow==4) {
04413                 opt_direction =
04414                     cpl_matrix_get(wcalib_solution->opt_mod_params, 0, 0);
04415                 fcoll =
04416                     cpl_matrix_get(wcalib_solution->opt_mod_params, 1, 0);
04417                 cfact =
04418                     cpl_matrix_get(wcalib_solution->opt_mod_params, 2, 0);
04419 
04420                 opt_mod_params = cpl_matrix_new(4,1);
04421                 cpl_matrix_set(opt_mod_params, 0, 0,
04422                                ex_sp_extr_pixels * opt_direction);
04423                 cpl_matrix_set(opt_mod_params, 1, 0, ex_sp_pixsize_x);
04424                 cpl_matrix_set(opt_mod_params, 2, 0, fcoll);
04425                 cpl_matrix_set(opt_mod_params, 3, 0, cfact);
04426             }
04427             else {
04428                 cpl_msg_error(fctid, "Invalid number of physical optical "
04429                               "parameters, aborting...");
04430 
04431                 if (wloffsets != NULL) {
04432                     cpl_matrix_delete(wloffsets);
04433                 }
04434 
04435                 _giraffe_wcalsolution_delete(wcalib_solution);
04436                 _giraffe_grating_delete(grating_data);
04437                 _giraffe_fiberposition_delete(fiber_slit_position);
04438                 _giraffe_slitgeo_delete(subslit_fibers);
04439                 return 6;
04440             }
04441 
04442         }
04443         else if (wcalib_solution->opt_mod==LMRQ_XOPTMOD2) {
04444 
04445             cxint nrow;
04446             cxdouble opt_direction, fcoll, cfact, gtheta, slitdx,
04447                 slitdy, slitphi;
04448 
04449             nrow = cpl_matrix_get_nrow(wcalib_solution->opt_mod_params);
04450             if (nrow==7) {
04451                 opt_direction =
04452                     cpl_matrix_get(wcalib_solution->opt_mod_params, 0, 0);
04453                 fcoll   =
04454                     cpl_matrix_get(wcalib_solution->opt_mod_params, 1, 0);
04455                 cfact   =
04456                     cpl_matrix_get(wcalib_solution->opt_mod_params, 2, 0);
04457                 gtheta  =
04458                     cpl_matrix_get(wcalib_solution->opt_mod_params, 3, 0);
04459                 slitdx  =
04460                     cpl_matrix_get(wcalib_solution->opt_mod_params, 4, 0);
04461                 slitdy  =
04462                     cpl_matrix_get(wcalib_solution->opt_mod_params, 5, 0);
04463                 slitphi =
04464                     cpl_matrix_get(wcalib_solution->opt_mod_params, 6, 0);
04465 
04466                 opt_mod_params = cpl_matrix_new(7,1);
04467                 cpl_matrix_set(opt_mod_params, 0, 0,
04468                                ex_sp_extr_pixels * opt_direction);
04469                 cpl_matrix_set(opt_mod_params, 1, 0, ex_sp_pixsize_x);
04470                 cpl_matrix_set(opt_mod_params, 2, 0, fcoll);
04471                 cpl_matrix_set(opt_mod_params, 3, 0, cfact);
04472                 cpl_matrix_set(opt_mod_params, 4, 0, slitdx);
04473                 cpl_matrix_set(opt_mod_params, 5, 0, slitdy);
04474                 cpl_matrix_set(opt_mod_params, 6, 0, slitphi);
04475 
04476             }
04477             else {
04478                 cpl_msg_error(fctid, "Invalid number of physical optical "
04479                               "parameters, aborting...");
04480 
04481                 if (wloffsets != NULL) {
04482                     cpl_matrix_delete(wloffsets);
04483                 }
04484 
04485                 _giraffe_wcalsolution_delete(wcalib_solution);
04486                 _giraffe_grating_delete(grating_data);
04487                 _giraffe_fiberposition_delete(fiber_slit_position);
04488                 _giraffe_slitgeo_delete(subslit_fibers);
04489                 return 6;
04490             }
04491 
04492         }
04493         else {
04494             cpl_msg_error(fctid, "Invalid optical model, aborting...");
04495 
04496             if (wloffsets != NULL) {
04497                 cpl_matrix_delete(wloffsets);
04498             }
04499 
04500             _giraffe_wcalsolution_delete(wcalib_solution);
04501             _giraffe_grating_delete(grating_data);
04502             _giraffe_fiberposition_delete(fiber_slit_position);
04503             _giraffe_slitgeo_delete(subslit_fibers);
04504             return 5;
04505         }
04506 
04507 
04508         if (wcalib_solution->wav_coeffs != NULL) {
04509 
04510             GiSlitGeo* coeffs = wcalib_solution->wav_coeffs;
04511 
04512             xres_polynom_deg.xdeg =
04513                 cpl_matrix_get_nrow(_giraffe_slitgeo_get(coeffs, 0));
04514             xres_polynom_deg.ydeg =
04515                 cpl_matrix_get_ncol(_giraffe_slitgeo_get(coeffs, 0));
04516         }
04517 
04518     }
04519     else {
04520         cpl_msg_error(fctid, "No Wavelength Calibration solution found, "
04521                       "aborting...");
04522 
04523         if (wloffsets != NULL) {
04524             cpl_matrix_delete(wloffsets);
04525         }
04526 
04527         _giraffe_wcalsolution_delete(wcalib_solution);
04528         _giraffe_grating_delete(grating_data);
04529         _giraffe_fiberposition_delete(fiber_slit_position);
04530         _giraffe_slitgeo_delete(subslit_fibers);
04531         return 4;
04532     }
04533 
04534     if (config->xresiduals==FALSE) {
04535         xres_polynom_deg.xdeg = 0;
04536         xres_polynom_deg.ydeg = 0;
04537     }
04538 
04539     if (wcalib_solution->wav_coeffs!=NULL) {
04540         wav_coeffs = wcalib_solution->wav_coeffs;
04541     }
04542 
04543     if (wcalib_solution->wav_limits!=NULL) {
04544         wav_limits = wcalib_solution->wav_limits;
04545     }
04546 
04547 
04548     /*
04549      *  Setup Rebinning grating parameters
04550      */
04551 
04552     grat_params = cpl_matrix_new(7,1);
04553 
04554     cpl_matrix_set(grat_params, 0, 0, grating_data->theta);
04555     cpl_matrix_set(grat_params, 1, 0, grating_data->order);
04556     cpl_matrix_set(grat_params, 2, 0, grating_data->wlenmin / GI_MM_TO_NM);
04557     cpl_matrix_set(grat_params, 3, 0, grating_data->wlen0   / GI_MM_TO_NM);
04558     cpl_matrix_set(grat_params, 4, 0, grating_data->wlenmax / GI_MM_TO_NM);
04559     cpl_matrix_set(grat_params, 5, 0, grating_data->resol);
04560     cpl_matrix_set(grat_params, 6, 0, grating_data->space );
04561 
04562 
04563     /*
04564      *  Give user some feedback...
04565      */
04566 
04567     cpl_msg_info(fctid, "Performing Rebinning of spectra, stepsize=%.4f "
04568                  "[nm], resulting image size=%d, using x residuals : %s",
04569                  rbin_stepsize * GI_MM_TO_NM, calc_rebinned_size,
04570                  config->xresiduals ? "Yes" : "No");
04571 
04572 
04573     switch (config->rmethod) {
04574         case GIREBIN_METHOD_LINEAR:
04575             cpl_msg_info(fctid, "Rebinning method    : linear");
04576             break;
04577 
04578         case GIREBIN_METHOD_SPLINE:
04579             cpl_msg_info(fctid, "Rebinning method    : spline");
04580             break;
04581 
04582         default:
04583             cpl_msg_info(fctid, "Rebinning method    : undefined");
04584             break;
04585     }
04586 
04587     switch (config->scmethod) {
04588         case GIREBIN_SCALE_LOG:
04589             cpl_msg_info(fctid, "Scaling method      : logarithmic, "
04590                          "log(wavelength [nm]): min,max,range = %.3f, %.3f, %.3f",
04591                          log(grating_data->wlenmin),
04592                          log(grating_data->wlenmax),
04593                          log(grating_data->wlenmax) -
04594                          log(grating_data->wlenmin));
04595             break;
04596 
04597         case GIREBIN_SCALE_LINEAR:
04598             cpl_msg_info(fctid, "Scaling method      : linear, wavelength [nm]: "
04599                          "min,max,range = %.3f, %.3f, %.3f",
04600                          grating_data->wlenmin,
04601                          grating_data->wlenmax,
04602                          grating_data->wlenmax - grating_data->wlenmin);
04603             break;
04604 
04605         default:
04606             cpl_msg_info(fctid, "Scaling method      : undefined");
04607             break;
04608     }
04609 
04610     switch (config->range) {
04611         case GIREBIN_RANGE_SETUP:
04612             cpl_msg_info(fctid, "Wavelength range    : Setup");
04613             break;
04614 
04615         case GIREBIN_RANGE_COMMON:
04616             cpl_msg_info(fctid, "Wavelength range    : Common");
04617             break;
04618 
04619         default:
04620             cpl_msg_info(fctid, "Wavelength range    : undefined");
04621             break;
04622     }
04623 
04624 
04625     /*
04626      * Resample the spectra to the wavelength grid
04627      */
04628 
04629     status = _giraffe_resample_spectra(rebinning, extraction,
04630                                        localization, fiber_slit_position,
04631                                        subslit_fibers, wav_limits,
04632                                        wav_coeffs, &xres_polynom_deg,
04633                                        grat_params, opt_mod_params,
04634                                        wloffsets, rbin_stepsize,
04635                                        config->rmethod, config->range,
04636                                        config->scmethod);
04637 
04638     if (status != 0) {
04639 
04640         if (wloffsets != NULL) {
04641             cpl_matrix_delete(wloffsets);
04642         }
04643 
04644         cpl_matrix_delete(opt_mod_params);
04645         cpl_matrix_delete(grat_params);
04646 
04647         _giraffe_wcalsolution_delete(wcalib_solution);
04648         _giraffe_grating_delete(grating_data);
04649         _giraffe_fiberposition_delete(fiber_slit_position);
04650         _giraffe_slitgeo_delete(subslit_fibers);
04651 
04652         return 8;
04653 
04654     }
04655 
04656 
04657     /*
04658      *  Cleanup...
04659      */
04660 
04661     if (wloffsets != NULL) {
04662         cpl_matrix_delete(wloffsets);
04663     }
04664 
04665     cpl_matrix_delete(opt_mod_params);
04666     cpl_matrix_delete(grat_params);
04667 
04668     _giraffe_wcalsolution_delete(wcalib_solution);
04669     _giraffe_grating_delete(grating_data);
04670     _giraffe_fiberposition_delete(fiber_slit_position);
04671     _giraffe_slitgeo_delete(subslit_fibers);
04672 
04673     return 0;
04674 
04675 } /* end giraffe_rebin_spectra() */
04676 
04677 
04690 GiRebinning*
04691 giraffe_rebinning_new(void)
04692 {
04693 
04694     GiRebinning *rebinn = cx_malloc(sizeof(GiRebinning));
04695 
04696     rebinn->spectra = NULL;
04697     rebinn->errors  = NULL;
04698 
04699     return rebinn;
04700 
04701 }
04702 
04719 GiRebinning*
04720 giraffe_rebinning_create(GiImage *spectra, GiImage *errors)
04721 {
04722 
04723     GiRebinning *rebin = giraffe_rebinning_new();
04724 
04725     if (spectra) {
04726         rebin->spectra = spectra;
04727     }
04728 
04729     if (errors) {
04730         rebin->errors = errors;
04731     }
04732 
04733     return rebin;
04734 
04735 }
04736 
04737 
04756 void
04757 giraffe_rebinning_delete(GiRebinning *rebinning)
04758 {
04759 
04760     if (rebinning) {
04761         cx_free(rebinning);
04762     }
04763 
04764     return;
04765 
04766 }
04767 
04768 
04784 void
04785 giraffe_rebinning_destroy(GiRebinning *rebinning)
04786 {
04787 
04788     if (rebinning) {
04789 
04790         if (rebinning->spectra) {
04791             giraffe_image_delete(rebinning->spectra);
04792             rebinning->spectra = NULL;
04793         }
04794 
04795         if (rebinning->errors) {
04796             giraffe_image_delete(rebinning->errors);
04797             rebinning->errors = NULL;
04798         }
04799 
04800         cx_free(rebinning);
04801     }
04802 
04803     return;
04804 
04805 }
04806 
04807 
04822 GiRebinConfig *
04823 giraffe_rebin_config_create(cpl_parameterlist *list)
04824 {
04825 
04826     const cxchar *fctid = "giraffe_rebin_config_create";
04827 
04828     const cxchar *s;
04829 
04830     cpl_parameter *p;
04831 
04832     GiRebinConfig *config = NULL;
04833 
04834 
04835     if (!list) {
04836         return NULL;
04837     }
04838 
04839     config = cx_calloc(1, sizeof *config);
04840 
04841 
04842     config->rmethod    = GIREBIN_METHOD_UNDEFINED;
04843     config->xresiduals = FALSE;
04844     config->lstep      = 0.0;
04845     config->scmethod   = GIREBIN_SCALE_UNDEFINED;
04846     config->size       = 0;
04847     config->range      = GIREBIN_RANGE_UNDEFINED;
04848 
04849 
04850     p = cpl_parameterlist_find(list, "giraffe.rebinning.method");
04851     s = cpl_parameter_get_string(p);
04852     if (strcmp(s, "linear")==0) {
04853         config->rmethod = GIREBIN_METHOD_LINEAR;
04854     } else if (strcmp(s, "spline")==0) {
04855         config->rmethod = GIREBIN_METHOD_SPLINE;
04856     }
04857 
04858     p = cpl_parameterlist_find(list, "giraffe.rebinning.xresiduals");
04859     config->xresiduals = cpl_parameter_get_bool(p);
04860 
04861     p = cpl_parameterlist_find(list, "giraffe.rebinning.lstep");
04862     config->lstep = cpl_parameter_get_double(p);
04863 
04864     p = cpl_parameterlist_find(list, "giraffe.rebinning.scalemethod");
04865     s = cpl_parameter_get_string(p);
04866     if (strcmp(s, "log")==0) {
04867         config->scmethod = GIREBIN_SCALE_LOG;
04868     } else if (strcmp(s, "linear")==0) {
04869         config->scmethod = GIREBIN_SCALE_LINEAR;
04870     }
04871 
04872     p = cpl_parameterlist_find(list, "giraffe.rebinning.size");
04873     config->size = cpl_parameter_get_int(p);
04874 
04875     p = cpl_parameterlist_find(list, "giraffe.rebinning.range");
04876     s = cpl_parameter_get_string(p);
04877     if (strcmp(s, "setup")==0) {
04878         config->range = GIREBIN_RANGE_SETUP;
04879     } else if (strcmp(s, "common")==0) {
04880         config->range = GIREBIN_RANGE_COMMON;
04881     }
04882 
04883     /* Validate */
04884 
04885     if (config->rmethod==GIREBIN_METHOD_UNDEFINED) {
04886         cpl_msg_info(fctid, "Invalid Rebinning method, aborting");
04887         cx_free(config);
04888         return NULL;
04889     }
04890 
04891     if (config->scmethod==GIREBIN_SCALE_UNDEFINED) {
04892         cpl_msg_info(fctid, "Invalid Rebinning scaling method, aborting");
04893         cx_free(config);
04894         return NULL;
04895     }
04896 
04897     if (config->range==GIREBIN_RANGE_UNDEFINED) {
04898         cpl_msg_info(fctid, "Invalid Rebinning range, aborting");
04899         cx_free(config);
04900         return NULL;
04901     }
04902 
04903     return config;
04904 
04905 }
04906 
04907 
04922 void
04923 giraffe_rebin_config_destroy(GiRebinConfig *config)
04924 {
04925 
04926     if (config) {
04927         cx_free(config);
04928     }
04929 
04930     return;
04931 
04932 }
04933 
04946 void
04947 giraffe_rebin_config_add(cpl_parameterlist *list)
04948 {
04949 
04950     cpl_parameter *p;
04951 
04952     if (!list) {
04953         return;
04954     }
04955 
04956     p = cpl_parameter_new_enum("giraffe.rebinning.method",
04957                                CPL_TYPE_STRING,
04958                                "Method to use : `linear' or `spline'",
04959                                "giraffe.rebinning.method",
04960                                "linear", 2, "linear", "spline");
04961     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-method");
04962     cpl_parameterlist_append(list, p);
04963 
04964     p = cpl_parameter_new_value("giraffe.rebinning.xresiduals",
04965                                 CPL_TYPE_BOOL,
04966                                 "Use x residuals during rebinning? `true'/"
04967                                 "`false'",
04968                                 "giraffe.rebinning.xresiduals",
04969                                 TRUE);
04970     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-xresid");
04971     cpl_parameterlist_append(list, p);
04972 
04973     p = cpl_parameter_new_value("giraffe.rebinning.lstep",
04974                                 CPL_TYPE_DOUBLE,
04975                                 "Lambda step size, only used if "
04976                                 "scaling method is 'linear'",
04977                                 "giraffe.rebinning.lstep",
04978                                 0.005);
04979     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-lstep");
04980     cpl_parameterlist_append(list, p);
04981 
04982     p = cpl_parameter_new_enum("giraffe.rebinning.scalemethod",
04983                                CPL_TYPE_STRING,
04984                                "Scaling method: `log' or `linear'",
04985                                "giraffe.rebinning.scalemethod",
04986                                "linear", 2, "linear", "log");
04987     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-scmethod");
04988     cpl_parameterlist_append(list, p);
04989 
04990     p = cpl_parameter_new_value("giraffe.rebinning.size",
04991                                 CPL_TYPE_INT,
04992                                 "Size of output rebinned spectra, 0 means "
04993                                 "calculate size based on wavelength range "
04994                                 "and lambda stepsize",
04995                                 "giraffe.rebinning.size",
04996                                 0);
04997     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-size");
04998     cpl_parameterlist_append(list, p);
04999 
05000     p = cpl_parameter_new_enum("giraffe.rebinning.range",
05001                                CPL_TYPE_STRING,
05002                                "Rebinning range: `setup' or `common'",
05003                                "giraffe.rebinning.scalemethod",
05004                                "setup", 2, "setup", "common");
05005     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "rbin-range");
05006     cpl_parameterlist_append(list, p);
05007 
05008     return;
05009 
05010 }

This file is part of the GIRAFFE Pipeline Reference Manual 2.8.8.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Fri Mar 4 10:50:27 2011 by doxygen 1.6.3 written by Dimitri van Heesch, © 1997-2004