sofi_spc_jitter.c

00001 /* $Id: sofi_spc_jitter.c,v 1.44 2012/01/12 13:37:28 llundin Exp $
00002  *
00003  * This file is part of the SOFI Pipeline
00004  * Copyright (C) 2002,2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: llundin $
00023  * $Date: 2012/01/12 13:37:28 $
00024  * $Revision: 1.44 $
00025  * $Name: sofi-1_5_5 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*-----------------------------------------------------------------------------
00033                                 Includes
00034  -----------------------------------------------------------------------------*/
00035 
00036 #include <string.h>
00037 #include <math.h>
00038 #include <cpl.h>
00039 
00040 #include "irplib_plugin.h"
00041 #include "irplib_utils.h"
00042 #include "irplib_spectrum.h"
00043 
00044 #include "sofi_utils.h"
00045 #include "sofi_wavelength.h"
00046 #include "sofi_pfits.h"
00047 #include "sofi_dfs.h"
00048 
00049 /*-----------------------------------------------------------------------------
00050                             Defines
00051  -----------------------------------------------------------------------------*/
00052 
00053 #define RECIPE_STRING "sofi_spc_jitter"
00054 
00055 #define SOFI_SPC_JITTER_OFFSET_ERR     10
00056 
00057 /*-----------------------------------------------------------------------------
00058                             Functions prototypes
00059  -----------------------------------------------------------------------------*/
00060 
00061 static cpl_image ** sofi_spc_jitter_combine(cpl_frameset *, const char *, 
00062         const char *, const char *);
00063 static cpl_vector * sofi_spc_jitter_get_offsets(cpl_frameset *);
00064 static int * sofi_spc_jitter_classif(cpl_vector *, int *);
00065 static int off_comp(double, double, double);
00066 static cpl_imagelist * sofi_spc_jitter_saa_groups(cpl_imagelist *,
00067         cpl_vector *, int *, int, cpl_vector **);
00068 static int sofi_spc_jitter_wavecal(const char *, const char *, cpl_image *, 
00069         cpl_frameset *);
00070 static cpl_imagelist * sofi_spc_jitter_nodded(cpl_imagelist *, cpl_vector *, 
00071         cpl_vector **);
00072 static cpl_imagelist * sofi_spc_jitter_distor(cpl_imagelist *, const char *);
00073 static double sofi_spc_jitter_refine_offset(cpl_image *, cpl_image *);
00074 static cpl_table * sofi_spc_jitter_extract(cpl_image *);
00075 static cpl_error_code sofi_spc_jitter_save(cpl_frameset *, const cpl_image *,
00076                                            const cpl_table *,
00077                                            const cpl_parameterlist *);
00078 
00079 cpl_recipe_define(sofi_spc_jitter, SOFI_BINARY_VERSION,
00080                   "Lars Lundin", PACKAGE_BUGREPORT, "2002,2003,2009", 
00081                   "SOFI Spectro jitter recipe",
00082                   RECIPE_STRING " -- SOFI Spectro jitter recipe"
00083                   "The files listed in the Set Of Frames (sof-file) " 
00084                   "must be tagged:\n"
00085                   "raw-file.fits "SOFI_SPC_JITTER_NODOBJ_RAW" or\n"
00086                   "raw-file.fits "SOFI_SPC_JITTER_NODSKY_RAW"\n"
00087                   "Calibration files:\n"
00088                   "oh-cat.fits "SOFI_CALPRO_OH_CAT" or\n"
00089                   "flat-file.fits "SOFI_CALIB_SPFLAT" or\n"
00090                   "arc-file.fits "SOFI_CALIB_ARC"\n");
00091 
00092 /*-----------------------------------------------------------------------------
00093                             Static variables
00094  -----------------------------------------------------------------------------*/
00095 
00096 static struct {
00097     /* Inputs */
00098     int             display;
00099     int             crosstalk;
00100     /* wavecal_in : 0 for physical model, 1 for sky, 2 for arc table */
00101     int             wavecal_in;
00102     int             wavecal_degree;
00103     double          wavecal_err;
00104     int             wavecal_nsamples;
00105     int             wavecal_ppm;
00106     int             saa_refine;
00107     double          saa_rej_high;
00108     double          saa_rej_low;
00109     int             extr_spec_pos;
00110     int             extr_spec_width;
00111     int             extr_sky_le_width;
00112     int             extr_sky_ri_width;
00113     int             extr_sky_le_dist;
00114     int             extr_sky_ri_dist;
00115     /* Outputs */
00116     /* wavecal_out : 0 for physical model, 1 for sky, 2 for arc table */
00117     cpl_vector  *   throws;
00118     cpl_vector  *   intensities;
00119     char            filter[512];
00120     int             wavecal_out;
00121     double          wavecal_cc;
00122     double          wavecal_a0;
00123     double          wavecal_a1;
00124     double          wavecal_a2;
00125     double          wavecal_a3;
00126     double          wavecal_a4;
00127 } sofi_spc_jitter_config;
00128 
00129 
00130 /*-----------------------------------------------------------------------------
00131                                 Functions code
00132  -----------------------------------------------------------------------------*/
00133 
00134 /*----------------------------------------------------------------------------*/
00142 /*----------------------------------------------------------------------------*/
00143 static
00144 cpl_error_code sofi_spc_jitter_fill_parameterlist(cpl_parameterlist * self)
00145 {
00146     const char * context = PACKAGE "." RECIPE_STRING;
00147     cpl_error_code err;
00148 
00149     cpl_ensure_code(self, CPL_ERROR_NULL_INPUT);
00150 
00151     /* Fill the parameters list */
00152 
00153 
00154     /* --crosstalk */
00155     err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
00156                                         "crosstalk", CPL_TRUE, NULL, context,
00157                                         "Enable removal of the crosstalk "
00158                                         "effect");
00159     cpl_ensure_code(!err, err);
00160 
00161     /* --wavecal */
00162     err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
00163                                           "wavecal", "sky", NULL, context,
00164                                           "Wavelength method: "
00165                                           "phy or sky or arc");
00166     cpl_ensure_code(!err, err);
00167 
00168     /* --wavecal_ppm */
00169     err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
00170                                         "wavecal_ppm", CPL_FALSE, NULL, context,
00171                                         "Enable Point Pattern Matching in the "
00172                                         "wavelength calibration");
00173     cpl_ensure_code(!err, err);
00174 
00175     /* --wavecal_degree */
00176     err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00177                                        "wavecal_degree", 2, NULL, context,
00178                                        "Degree of the wavelength dispersion "
00179                                        "polynomial");
00180     cpl_ensure_code(!err, err);
00181 
00182     /* --wavecal_nsamples */
00183     err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00184                                        "wavecal_nsamples", 100, NULL, context,
00185                                        "Number of samples for the wavelength "
00186                                        "calibration");
00187     cpl_ensure_code(!err, err);
00188 
00189     /* --wavecal_err */
00190     err = irplib_parameterlist_set_double(self, PACKAGE, RECIPE_STRING,
00191                                           "wavecal_err", 1000.0, NULL, context,
00192                                           "The wavelength error [Angstrom]");
00193     cpl_ensure_code(!err, err);
00194 
00195     /* --saa_refine */
00196     err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING,
00197                                         "saa_refine", CPL_TRUE, NULL, context,
00198                                         "Enable refinement of the offsets");
00199     cpl_ensure_code(!err, err);
00200 
00201     /* --saa_rej */
00202     err = irplib_parameterlist_set_string(self, PACKAGE, RECIPE_STRING,
00203                                           "saa_rej", "0.1,0.1", NULL, context,
00204                                           "Low, high SAA rejection [%,%]");
00205     cpl_ensure_code(!err, err);
00206 
00207     /* --spec_pos */
00208     err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00209                                        "spec_pos", -1, NULL, context,
00210                                        "Spectrum position");
00211     cpl_ensure_code(!err, err);
00212 
00213     /* --spec_width */
00214     err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00215                                        "spec_width", 10, NULL, context,
00216                                        "Spectrum width");
00217     cpl_ensure_code(!err, err);
00218 
00219     /* --sky_le_width */
00220     err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00221                                        "sky_le_width", 10, NULL, context,
00222                                        "Sky width left of the spectrum");
00223     cpl_ensure_code(!err, err);
00224 
00225     /* --sky_ri_width */
00226     err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00227                                        "sky_ri_width", 10, NULL, context,
00228                                        "Sky width right of the spectrum");
00229     cpl_ensure_code(!err, err);
00230 
00231     /* --sky_le_dist */
00232     err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00233                                        "sky_le_dist", -1, NULL, context,
00234                                        "Sky distance left of the spectrum");
00235     cpl_ensure_code(!err, err);
00236 
00237     /* --sky_ri_dist */
00238     err = irplib_parameterlist_set_int(self, PACKAGE, RECIPE_STRING,
00239                                        "sky_ri_dist", -1, NULL, context,
00240                                        "Sky distance right of the spectrum");
00241     cpl_ensure_code(!err, err);
00242 
00243     /* --display */ 
00244     err = irplib_parameterlist_set_bool(self, PACKAGE, RECIPE_STRING, "display",
00245                                         CPL_FALSE, NULL, context,
00246                                         "Enable plotting");
00247     cpl_ensure_code(!err, err);
00248 
00249     return CPL_ERROR_NONE;
00250 }
00251 
00252 /*----------------------------------------------------------------------------*/
00259 /*----------------------------------------------------------------------------*/
00260 static int sofi_spc_jitter(cpl_frameset            * framelist,
00261                            const cpl_parameterlist * parlist)
00262 {
00263     cpl_propertylist    *   plist;
00264     const char          *   sval;
00265     cpl_frameset        *   rawframes = NULL;
00266     const cpl_frame     *   cur_frame;
00267     const char          *   flat;
00268     const char          *   oh;
00269     const char          *   arc;
00270     cpl_image           **  combined = NULL;
00271     cpl_table           *   extracted = NULL;
00272     
00273     /* Initialise */
00274     sofi_spc_jitter_config.wavecal_out = -1;
00275     sofi_spc_jitter_config.wavecal_cc = -1.0;
00276     sofi_spc_jitter_config.throws = NULL;
00277     sofi_spc_jitter_config.intensities = NULL;
00278     sofi_spc_jitter_config.filter[0] = (char)0;
00279 
00280     /* Retrieve input parameters */
00281 
00282     /* Cross-talk */
00283     sofi_spc_jitter_config.crosstalk
00284         = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
00285                                         "crosstalk");
00286 
00287     /* --wavecal */
00288     sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
00289                                            "wavecal");
00290     bug_if(sval == NULL);
00291     if (!strcmp(sval, "phy")) sofi_spc_jitter_config.wavecal_in = 0;
00292     else if (!strcmp(sval, "sky")) sofi_spc_jitter_config.wavecal_in = 1;
00293     else if (!strcmp(sval, "arc")) sofi_spc_jitter_config.wavecal_in = 2;
00294     else {
00295         error_if(1, CPL_ERROR_UNSUPPORTED_MODE,
00296                  "Invalid value for wavecal option: %s", sval);
00297     }
00298 
00299     /* --wavecal_degree */
00300     sofi_spc_jitter_config.wavecal_degree
00301         = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00302                                        "wavecal_degree");
00303 
00304     /* --wavecal_nsamples */
00305     sofi_spc_jitter_config.wavecal_nsamples
00306         = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00307                                        "wavecal_nsamples");
00308 
00309     /* --wavecal_err */
00310     sofi_spc_jitter_config.wavecal_err
00311         = irplib_parameterlist_get_double(parlist, PACKAGE, RECIPE_STRING,
00312                                           "wavecal_err");
00313 
00314     /* --wavecal_ppm */
00315     sofi_spc_jitter_config.wavecal_ppm
00316         = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
00317                                         "wavecal_ppm");
00318 
00319     /* Refine of offsets */
00320     sofi_spc_jitter_config.saa_refine
00321         = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
00322                                         "saa_refine");
00323     
00324     /* Rejection parameters for SAA */
00325     sval = irplib_parameterlist_get_string(parlist, PACKAGE, RECIPE_STRING,
00326                                            "saa_rej");
00327     skip_if (sscanf(sval, "%lg,%lg",
00328                     &sofi_spc_jitter_config.saa_rej_low,
00329                     &sofi_spc_jitter_config.saa_rej_high) != 2);
00330 
00331     /* --spec_pos */
00332     sofi_spc_jitter_config.extr_spec_pos
00333         = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00334                                        "spec_pos");
00335 
00336     /* --spec_width */
00337     sofi_spc_jitter_config.extr_spec_width
00338         = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00339                                        "spec_width");
00340 
00341     /* --sky_le_width */
00342     sofi_spc_jitter_config.extr_sky_le_width
00343         = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00344                                        "sky_le_width");
00345     /* --sky_ri_width */
00346     sofi_spc_jitter_config.extr_sky_ri_width
00347         = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00348                                        "sky_ri_width");
00349 
00350     /* --sky_le_dist */
00351     sofi_spc_jitter_config.extr_sky_le_dist
00352         = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00353                                        "sky_le_dist");
00354 
00355     /* --sky_ri_dist */
00356     sofi_spc_jitter_config.extr_sky_ri_dist
00357         = irplib_parameterlist_get_int(parlist, PACKAGE, RECIPE_STRING,
00358                                        "sky_ri_dist");
00359     /* Display */
00360     sofi_spc_jitter_config.display
00361         = irplib_parameterlist_get_bool(parlist, PACKAGE, RECIPE_STRING,
00362                                         "display");
00363     
00364     /* Identify the RAW and CALIB frames in the input frameset */
00365     skip_if (sofi_dfs_set_groups(framelist));
00366 
00367     /* Get the filter */
00368     cur_frame = cpl_frameset_get_frame(framelist, 0);
00369     plist = cpl_propertylist_load(cpl_frame_get_filename(cur_frame), 0);
00370     skip_if(plist == NULL);
00371 
00372     if ((sval = sofi_pfits_get_filter(plist)) != NULL) {
00373         sprintf(sofi_spc_jitter_config.filter, sval);
00374     } else {
00375         cpl_error_reset();
00376     }
00377     cpl_propertylist_delete(plist);
00378 
00379     /* Retrieve calibration data */
00380     arc =  sofi_extract_filename(framelist, SOFI_CALIB_ARC);
00381     flat = sofi_extract_filename(framelist, SOFI_CALIB_SPFLAT);
00382     oh = sofi_extract_filename(framelist, SOFI_CALPRO_OH_CAT);
00383 
00384     /* Retrieve raw frames */
00385     rawframes = sofi_extract_frameset(framelist, SOFI_SPC_JITTER_NODOBJ_RAW);
00386     error_if (rawframes == NULL, CPL_ERROR_DATA_NOT_FOUND,
00387               "Cannot find the raw frames in the input list");
00388 
00389     /* If arc calibration requested, arc file must be provided */
00390     error_if (arc == NULL && sofi_spc_jitter_config.wavecal_in == 2,
00391               CPL_ERROR_ILLEGAL_INPUT,
00392               "You must provide an ARC file for the wl cal");
00393 
00394     /* Create the combined image */
00395     cpl_msg_info(cpl_func, "Create the combined image");
00396     cpl_msg_indent_more();
00397     combined = sofi_spc_jitter_combine(rawframes, oh, flat, arc);
00398     cpl_msg_indent_less();
00399 
00400     error_if (combined==NULL, CPL_ERROR_ILLEGAL_INPUT,
00401               "Cannot combine the images");
00402     
00403     /* Extract the spectrum */
00404     cpl_msg_info(cpl_func, "Extract the spectrum");
00405     cpl_msg_indent_more();
00406     extracted = sofi_spc_jitter_extract(combined[0]);
00407     cpl_msg_indent_less();
00408 
00409     error_if (extracted == NULL, CPL_ERROR_DATA_NOT_FOUND,
00410               "Cannot extract the spectrum");
00411 
00412     /* Write the products */
00413     cpl_msg_info(cpl_func, "Save the products");
00414     skip_if(sofi_spc_jitter_save(framelist, combined[0], extracted, parlist));
00415 
00416     end_skip;
00417 
00418     if (combined != NULL) {
00419         cpl_image_delete(combined[0]);
00420         cpl_image_delete(combined[1]);
00421         cpl_free(combined);
00422     }
00423 
00424     cpl_vector_delete(sofi_spc_jitter_config.intensities);
00425     cpl_vector_delete(sofi_spc_jitter_config.throws);
00426 
00427     cpl_frameset_delete(rawframes);
00428 
00429     cpl_table_delete(extracted);
00430  
00431     return cpl_error_get_code();
00432 }
00433 
00434 /*----------------------------------------------------------------------------*/
00443 /*----------------------------------------------------------------------------*/
00444 static cpl_image ** sofi_spc_jitter_combine(
00445         cpl_frameset        *   rawframes,
00446         const char          *   oh,
00447         const char          *   flat,
00448         const char          *   arc)
00449 {
00450     cpl_imagelist       *   ilist;
00451     cpl_image           *   tmp_im;
00452     cpl_vector          *   offsets;
00453     int                 *   groups;
00454     int                     ngroups;
00455     cpl_imagelist       *   abba;
00456     cpl_vector          *   abba_off;
00457     cpl_imagelist       *   nodded;
00458     cpl_vector          *   nodded_off_x;
00459     cpl_vector          *   nodded_off_y;
00460     double                  throw;
00461     cpl_table           *   extracted;
00462     double                  intensity;
00463     double              *   pnodded_off_x;
00464     cpl_imagelist       *   nodded_warped;
00465     cpl_bivector        *   nodded_offsets;
00466     cpl_image           **  combined;
00467     int                     nima;
00468     double                  new_offset;
00469     int                     i;
00470     
00471     /* Test entries */
00472     if (rawframes == NULL) return NULL;
00473 
00474     /* Load the images */
00475     cpl_msg_info(cpl_func, "Load the data");
00476     cpl_msg_indent_more();
00477     if ((ilist = cpl_imagelist_load_frameset(rawframes, CPL_TYPE_FLOAT, 1, 
00478                     0)) == NULL) {
00479         cpl_msg_error(cpl_func, "cannot load the data");
00480         cpl_msg_indent_less();
00481         return NULL;
00482     }
00483     cpl_msg_indent_less();
00484   
00485     /* Apply the cross-talk correction */
00486     if (sofi_spc_jitter_config.crosstalk) {
00487         cpl_msg_info(cpl_func, "Apply the cross-talk correction");
00488         cpl_msg_indent_more();
00489         if (sofi_correct_crosstalk_list(ilist) == -1) {
00490             cpl_msg_error(cpl_func, "Cannot correct for Cross-talk");
00491             cpl_imagelist_delete(ilist);
00492             cpl_msg_indent_less();
00493             return NULL;
00494         }
00495         cpl_msg_indent_less();
00496     }
00497     
00498     /* Apply the flafield */
00499     if (flat != NULL) {
00500         cpl_msg_info(cpl_func, "Apply the flatfield correction");
00501         if ((tmp_im = cpl_image_load(flat, CPL_TYPE_FLOAT, 0, 0)) == NULL) {
00502             cpl_msg_warning(cpl_func, "cannot load the flat field");
00503         } else {
00504             if (cpl_imagelist_divide_image(ilist, tmp_im) != CPL_ERROR_NONE) {
00505                 cpl_msg_warning(cpl_func, "cannot apply the flat field");
00506             }
00507             cpl_image_delete(tmp_im);
00508         }
00509     }
00510 
00511     /* Get the offsets */
00512     cpl_msg_info(cpl_func, "Get the offsets");
00513     if ((offsets = sofi_spc_jitter_get_offsets(rawframes)) == NULL) {
00514         cpl_msg_error(cpl_func, "cannot get the offsets");
00515         cpl_imagelist_delete(ilist);
00516         return NULL;
00517     }
00518 
00519     /* Classify in groups the a and b images sequence */
00520     cpl_msg_info(cpl_func, "Classify in groups");
00521     cpl_msg_indent_more();
00522     if ((groups = sofi_spc_jitter_classif(offsets, &ngroups)) == NULL) {
00523         cpl_msg_error(cpl_func, "cannot classify the data");
00524         cpl_imagelist_delete(ilist);
00525         cpl_vector_delete(offsets);
00526         cpl_msg_indent_less();
00527         return NULL;
00528     }
00529     cpl_msg_indent_less();
00530   
00531     /* Shift and add each group to one image */
00532     cpl_msg_info(cpl_func, "Shift and add each group to one image");
00533     cpl_msg_indent_more();
00534     if ((abba = sofi_spc_jitter_saa_groups(ilist, offsets, groups, 
00535                     ngroups, &abba_off)) == NULL) {
00536         cpl_msg_error(cpl_func, "cannot shift and add groups");
00537         cpl_imagelist_delete(ilist);
00538         cpl_vector_delete(offsets);
00539         cpl_free(groups);
00540         cpl_msg_indent_less();
00541         return NULL;
00542     }
00543     cpl_imagelist_delete(ilist);
00544     cpl_free(groups);
00545     cpl_vector_delete(offsets);
00546     cpl_msg_indent_less();
00547 
00548     /* Compute the wavelength calibration */
00549     cpl_msg_info(cpl_func, "Compute the wavelength calibration");
00550     cpl_msg_indent_more();
00551     if (sofi_spc_jitter_wavecal(arc, oh, cpl_imagelist_get(abba, 0),
00552                 rawframes) == -1) {
00553         cpl_msg_error(cpl_func, "cannot compute the wavelength");
00554         cpl_imagelist_delete(abba);
00555         cpl_vector_delete(abba_off);
00556         cpl_msg_indent_less();
00557         return NULL;
00558     }
00559     cpl_msg_indent_less();
00560    
00561    /* Create the nodded images */
00562     cpl_msg_info(cpl_func, "Create the nodded images");
00563     cpl_msg_indent_more();
00564     if ((nodded = sofi_spc_jitter_nodded(abba, abba_off, 
00565                     &nodded_off_x))==NULL) {
00566         cpl_msg_error(cpl_func, "cannot create the nodded images");
00567         cpl_imagelist_delete(abba);
00568         cpl_vector_delete(abba_off);
00569         cpl_msg_indent_less();
00570         return NULL;
00571     }
00572     cpl_imagelist_delete(abba);
00573     cpl_msg_indent_less();
00574 
00575     /* Get the throw offsets from abba_off */
00576     nima = cpl_imagelist_get_size(nodded);
00577     sofi_spc_jitter_config.throws = cpl_vector_new(nima);
00578     for (i=0; i<nima/2; i++) {
00579         throw = fabs(   (cpl_vector_get(abba_off, 2*i))-
00580                         (cpl_vector_get(abba_off, 2*i+1)));
00581         cpl_vector_set(sofi_spc_jitter_config.throws, 2*i, throw);
00582         cpl_vector_set(sofi_spc_jitter_config.throws, 2*i+1, throw);
00583     }
00584     cpl_vector_delete(abba_off);
00585     
00586     /* Get the spectra intensities in the nodded images */
00587     cpl_msg_info(cpl_func, "Compute the spectra intensities");
00588     cpl_msg_indent_more();
00589     nima = cpl_imagelist_get_size(nodded);
00590     sofi_spc_jitter_config.intensities = cpl_vector_new(nima);
00591     for (i=0; i<nima; i++) {
00592         if ((extracted = sofi_spc_jitter_extract(
00593                         cpl_imagelist_get(nodded, i))) == NULL) {
00594             cpl_msg_warning(cpl_func,"Cannot extract the spectrum from nodded %d", 
00595                     i+1);
00596             intensity = -1.0;
00597         } else {
00598             intensity = cpl_table_get_column_mean(extracted, 
00599                     "Extracted_spectrum_value");
00600             intensity *= cpl_table_get_nrow(extracted);
00601             cpl_table_delete(extracted);
00602         }
00603         cpl_msg_info(cpl_func, "Spectrum intensity nb %d: %g", i+1,
00604                 intensity);
00605         cpl_vector_set(sofi_spc_jitter_config.intensities, i, intensity);
00606     }
00607     cpl_msg_indent_less();
00608 
00609     /* Distortion correction */
00610     if (arc) {
00611         cpl_msg_info(cpl_func, "Correct the distortion on nodded images");
00612         cpl_msg_indent_more();
00613         if ((nodded_warped = sofi_spc_jitter_distor(nodded, arc)) == NULL) {
00614             cpl_msg_error(cpl_func, "cannot correct the distortion");
00615             cpl_imagelist_delete(nodded);
00616             cpl_vector_delete(nodded_off_x);
00617             cpl_msg_indent_less();
00618             return NULL;
00619         }
00620         cpl_imagelist_delete(nodded);
00621         nodded = nodded_warped;
00622         cpl_msg_indent_less();
00623     }
00624 
00625     /* Refine the offsets if requested */
00626     if (sofi_spc_jitter_config.saa_refine) {
00627         cpl_msg_info(cpl_func, "Refine the offsets");
00628         pnodded_off_x = cpl_vector_get_data(nodded_off_x);
00629         for (i=0; i<cpl_imagelist_get_size(nodded); i++) {
00630             new_offset = sofi_spc_jitter_refine_offset(
00631                     cpl_imagelist_get(nodded, 0),
00632                     cpl_imagelist_get(nodded, i));
00633             if (new_offset > 5000) {
00634                 cpl_msg_debug(cpl_func, "cannot refine the offset - keep %g", 
00635                         pnodded_off_x[i]);
00636             } else {
00637                 if (fabs(new_offset-pnodded_off_x[i]) < 
00638                         SOFI_SPC_JITTER_OFFSET_ERR) {
00639                     cpl_msg_debug(cpl_func, "refined offset : %g (old was %g)",
00640                             new_offset, pnodded_off_x[i]);
00641                     pnodded_off_x[i] = new_offset;
00642                 } else { 
00643                     cpl_msg_debug(cpl_func, 
00644                             "refined offset %g too different - keep %g",
00645                             new_offset, pnodded_off_x[i]);
00646                 }
00647             }
00648         }
00649     }
00650 
00651     /* Images combination */
00652     /* Get the offsets in a bivector */
00653     nodded_off_y = cpl_vector_duplicate(nodded_off_x);
00654     cpl_vector_fill(nodded_off_y, 0.0);
00655     nodded_offsets = cpl_bivector_wrap_vectors(nodded_off_x, nodded_off_y);
00656     /* Shift and add */
00657     cpl_msg_info(cpl_func, "Apply the shift and add on the nodded frames");
00658     nima = cpl_imagelist_get_size(nodded);
00659     if ((combined = cpl_geom_img_offset_saa(nodded, nodded_offsets,
00660                     CPL_KERNEL_DEFAULT, 
00661                     (int)(sofi_spc_jitter_config.saa_rej_low * nima), 
00662                     (int)(sofi_spc_jitter_config.saa_rej_high * nima), 
00663             CPL_GEOM_FIRST, NULL, NULL)) == NULL) {
00664         cpl_msg_error(cpl_func, "Cannot shift and add group");
00665         cpl_imagelist_delete(nodded);
00666         cpl_bivector_unwrap_vectors(nodded_offsets);
00667         cpl_vector_delete(nodded_off_x);
00668         cpl_vector_delete(nodded_off_y);
00669         return NULL;
00670     }
00671     cpl_imagelist_delete(nodded);
00672     cpl_bivector_unwrap_vectors(nodded_offsets);
00673     cpl_vector_delete(nodded_off_x);
00674     cpl_vector_delete(nodded_off_y);
00675     return combined;
00676 }
00677  
00678 /*----------------------------------------------------------------------------*/
00684 /*----------------------------------------------------------------------------*/
00685 static cpl_vector * sofi_spc_jitter_get_offsets(cpl_frameset * rawframes)
00686 {
00687     cpl_vector          *   offsets;
00688     double              *   pvect;
00689     int                     nraw;
00690     cpl_frame           *   cur_frame;
00691     cpl_propertylist    *   plist;
00692     int                     i;
00693 
00694     /* Test entries */
00695     if (rawframes == NULL) return NULL;
00696     
00697     /* Initialise */
00698     nraw = cpl_frameset_get_size(rawframes);
00699 
00700     /* Get the rawframes X offsets */
00701     offsets = cpl_vector_new(nraw);
00702     pvect = cpl_vector_get_data(offsets);
00703     for (i=0; i<nraw; i++) {
00704         cur_frame = cpl_frameset_get_frame(rawframes, i);
00705         if ((plist=cpl_propertylist_load(cpl_frame_get_filename(cur_frame),
00706                         0)) == NULL) {
00707             cpl_msg_error(cpl_func, "cannot get property list");
00708             cpl_vector_delete(offsets);
00709             return NULL;
00710         }
00711         pvect[i] = sofi_pfits_get_cumoffsetx(plist);
00712         if (cpl_error_get_code()) {
00713             cpl_msg_error(cpl_func, "cannot get the offset from the header");
00714             cpl_vector_delete(offsets);
00715             cpl_propertylist_delete(plist);
00716             return NULL;
00717         }
00718         cpl_propertylist_delete(plist);
00719         pvect[i] *= -1.0;
00720     }
00721     return offsets;
00722 }
00723     
00724 /*----------------------------------------------------------------------------*/
00762 /*----------------------------------------------------------------------------*/
00763 static int * sofi_spc_jitter_classif(
00764         cpl_vector      *   offsets,
00765         int             *   ngroups)
00766 {
00767     double              *   pvect;
00768     int                     nraw;
00769     double                  offset_thresh;
00770     cpl_vector          *   tmp_vec;
00771     int                 *   groups;
00772     int                     last_group;
00773     int                     i, j, k, l;
00774 
00775     /* Test entries */
00776     if (offsets == NULL) return NULL;
00777 
00778     /* Initialise */
00779     nraw = cpl_vector_get_size(offsets);
00780 
00781     /* Separate the offsets in 2 categories */
00782     tmp_vec = cpl_vector_duplicate(offsets);
00783     cpl_vector_sort(tmp_vec, 1);
00784     pvect = cpl_vector_get_data(tmp_vec);
00785     if (pvect[0] == pvect[nraw-1]) {
00786         cpl_msg_error(cpl_func, "Only one offset in the list - abort");
00787         cpl_vector_delete(tmp_vec);
00788         return NULL;
00789     }
00790     offset_thresh = (pvect[0] + pvect[nraw-1]) / 2.0;
00791     cpl_vector_delete(tmp_vec);
00792 
00793     /* Identify the different A and B groups */
00794     pvect = cpl_vector_get_data(offsets);
00795     *ngroups = 0;
00796     groups = cpl_calloc(nraw, sizeof(int));
00797 
00798     /* Create a look up table to associate the ith obj with the jth frame */
00799     i = 0;
00800     while (i < nraw) {
00801         j = 0;
00802         /* Count the number of successive '+' or '-' (j) */
00803         while ((i+j<nraw) &&
00804                 (!off_comp(pvect[i], pvect[i+j], offset_thresh))) j++;
00805 
00806         if (i+j >= nraw) i = nraw;
00807         else {
00808             k = 0;
00809             /* Check if there are j '-' or '+' (k) */
00810             while ((i+j+k < nraw)
00811                     && (!off_comp(pvect[i+j], pvect[i+j+k], offset_thresh))
00812                     && (k<j)) k++;
00813             last_group = 1;
00814             if (i+j+k < nraw) {
00815                 for (l=i+j+k; l<nraw; l++) {
00816                     if (off_comp(pvect[i+j], pvect[l], offset_thresh)) {
00817                         last_group = 0;
00818                         break;
00819                     }
00820                 }
00821             }
00822             if (last_group == 0) {
00823                 for (l=0; l<j; l++) groups[i+l]   = *ngroups + 1;
00824                 for (l=0; l<k; l++) groups[i+j+l] = *ngroups + 2;
00825                 *ngroups += 2;
00826                 i += j+k;
00827             } else {
00828                 for (l=0; l<j; l++)               groups[i+l] = *ngroups + 1;
00829                 for (l=0; l<nraw - (i+j); l++)    groups[i+j+l] =*ngroups + 2;
00830                 *ngroups += 2;
00831                 i = nraw;
00832             }
00833         }
00834     }
00835 
00836     /* Nb of groups found should be even */
00837     if (*ngroups % 2) {
00838         cpl_msg_error(cpl_func, "Odd number of groups found");
00839         cpl_free(groups);
00840         return NULL;
00841     }
00842 
00843     return groups;
00844 }
00845     
00846 /*----------------------------------------------------------------------------*/
00877 /*----------------------------------------------------------------------------*/
00878 static cpl_imagelist * sofi_spc_jitter_saa_groups(
00879         cpl_imagelist   *   ilist,
00880         cpl_vector      *   offsets,
00881         int             *   groups,
00882         int                 ngroups,
00883         cpl_vector      **  abba_off)
00884 {
00885     cpl_imagelist       *   abba;
00886     cpl_imagelist       *   group_list;
00887     cpl_image           *   tmp_ima;
00888     cpl_image           **  combined;
00889     cpl_bivector        *   group_off;
00890     double              *   pgroup_off;
00891     double              *   poffsets;
00892     double              *   pabba_off;
00893     int                     nima;
00894     int                     saa;
00895     int                     i, j, k;
00896 
00897     /* Test entries */
00898     if ((ilist == NULL) || (offsets == NULL) || (groups == NULL)) return NULL;
00899     
00900     /* Initialise */
00901     nima = cpl_imagelist_get_size(ilist);
00902     poffsets = cpl_vector_get_data(offsets);
00903 
00904     /* Create the output image list */
00905     abba = cpl_imagelist_new();
00906     *abba_off = cpl_vector_new(ngroups);
00907     pabba_off = cpl_vector_get_data(*abba_off);
00908     
00909     /* Loop on the groups */
00910     for (i=0; i<ngroups; i++) {
00911         /* Initialise */
00912         saa = 0;
00913         /* Create the group list of images */
00914         group_list = cpl_imagelist_new();
00915         k = 0;
00916         for (j=0; j<nima; j++) {
00917             if (i+1 == groups[j]) {
00918                 /* Get the first offset of the group in abba_off */
00919                 if (k==0) pabba_off[i] = poffsets[j];
00920                 /* To know if we need the saa (shift and add) */
00921                 if (fabs(pabba_off[i]-poffsets[j]) > 1e-3) saa = 1;
00922                 /* Copy the images of the group in group_list */
00923                 tmp_ima = cpl_image_duplicate(cpl_imagelist_get(ilist, j));
00924                 cpl_imagelist_set(group_list, tmp_ima, k);
00925                 tmp_ima = NULL;
00926                 k++;
00927             }
00928         }
00929 
00930         if (saa) {
00931             /* Get the offsets of the group in group_off */
00932             group_off = cpl_bivector_new(k);
00933             cpl_vector_fill(cpl_bivector_get_y(group_off), 0.0);
00934             pgroup_off = cpl_bivector_get_x_data(group_off);
00935             k = 0;
00936             for (j=0; j<nima; j++) {
00937                 if (i+1 == groups[j]) {
00938                     pgroup_off[k] = poffsets[j];
00939                     k++;
00940                 }
00941             }
00942             cpl_vector_subtract_scalar(cpl_bivector_get_x(group_off), 
00943                     pabba_off[i]);
00944             /* Shift and add */
00945             cpl_msg_debug(cpl_func, "Apply shift-and-add for group %d", i+1);
00946             if ((combined = cpl_geom_img_offset_saa(group_list,
00947                            group_off, CPL_KERNEL_DEFAULT, 0, 0,
00948                CPL_GEOM_FIRST, NULL, NULL)) == NULL) {
00949                 cpl_msg_error(cpl_func,"Cannot shift and add group nb %d", i+1);
00950                 cpl_imagelist_delete(group_list);
00951                 cpl_bivector_delete(group_off);
00952                 cpl_imagelist_delete(abba);
00953                 cpl_vector_delete(*abba_off);
00954                 return NULL;
00955             }
00956             cpl_bivector_delete(group_off);
00957             cpl_image_delete(combined[1]);
00958             cpl_imagelist_set(abba, combined[0], i);
00959             cpl_free(combined);
00960         } else {
00961             /* Averaging */
00962             cpl_msg_debug(cpl_func, "Apply averaging for group %d", i+1);
00963             if ((tmp_ima = cpl_imagelist_collapse_create(group_list)) == NULL) {
00964                 cpl_msg_error(cpl_func, "Cannot average group nb %d", i+1);
00965                 cpl_imagelist_delete(group_list);
00966                 cpl_imagelist_delete(abba);
00967                 cpl_vector_delete(*abba_off);
00968                 return NULL;
00969             }
00970             cpl_imagelist_set(abba, tmp_ima, i);
00971         }
00972         cpl_imagelist_delete(group_list);
00973     }
00974     return abba;
00975 }
00976 
00977 /*----------------------------------------------------------------------------*/
00986 /*----------------------------------------------------------------------------*/
00987 static int sofi_spc_jitter_wavecal(
00988         const char      *   arc,
00989         const char      *   oh,
00990         cpl_image       *   ima,
00991         cpl_frameset    *   raw)
00992 {
00993     cpl_table           *   arc_tab;
00994     cpl_polynomial      *   phdisprel;
00995     cpl_frame           *   cur_frame;
00996     const char          *   cur_fname;
00997     cpl_polynomial      *   disprel;
00998     double                  slit_width;
00999     cpl_size                p[5];
01000     double                  xc, a, b, c, d, e;
01001     int                     degree;
01002     
01003     /* Get the wavelength from the arc file */
01004     if (sofi_spc_jitter_config.wavecal_in == 2) {
01005         if (arc == NULL) {
01006             cpl_msg_error(cpl_func, "Missing arc for the wavelength calib");
01007             return -1;
01008         }
01009         cpl_msg_info(cpl_func, "Get the wavelength from the ARC file");
01010         if ((arc_tab = cpl_table_load(arc, 1, 0)) == NULL) {
01011             cpl_msg_error(cpl_func, "Cannot load the arc table");
01012             sofi_spc_jitter_config.wavecal_out = -1;
01013             return -1;
01014         }
01015         sofi_spc_jitter_config.wavecal_a0 =
01016             cpl_table_get_double(arc_tab, "WL_coefficients", 0, NULL);
01017         sofi_spc_jitter_config.wavecal_a1 = 
01018             cpl_table_get_double(arc_tab, "WL_coefficients", 1, NULL);
01019         sofi_spc_jitter_config.wavecal_a2 = 
01020             cpl_table_get_double(arc_tab, "WL_coefficients", 2, NULL);
01021         sofi_spc_jitter_config.wavecal_a3 = 
01022             cpl_table_get_double(arc_tab, "WL_coefficients", 3, NULL);
01023         sofi_spc_jitter_config.wavecal_a4 = 
01024             cpl_table_get_double(arc_tab, "WL_coefficients", 4, NULL);
01025         cpl_table_delete(arc_tab);
01026         sofi_spc_jitter_config.wavecal_out = 2;
01027         sofi_spc_jitter_config.wavecal_cc = -1.0;
01028         return 0;
01029     }
01030 
01031     /* Get the reference frame */
01032     cur_frame = cpl_frameset_get_frame(raw, 0);
01033     cur_fname = cpl_frame_get_filename(cur_frame);
01034     
01035     /* Get the physical model */
01036     cpl_msg_info(cpl_func, "Compute the physical model");
01037     cpl_msg_indent_more();
01038     if ((phdisprel = sofi_get_disprel_estimate(cur_fname, 1)) == NULL) {
01039         cpl_msg_error(cpl_func, "cannot compute the physical model");
01040         sofi_spc_jitter_config.wavecal_out = -1;
01041         cpl_msg_indent_less();
01042         return -1;
01043     }
01044     p[0] = 0; p[1] = 1;
01045     a = cpl_polynomial_get_coeff(phdisprel, p);
01046     b = cpl_polynomial_get_coeff(phdisprel, p + 1);
01047     cpl_msg_info(cpl_func, "f(x)=%g + %g*x", a, b);
01048     sofi_spc_jitter_config.wavecal_a0 = a;
01049     sofi_spc_jitter_config.wavecal_a1 = b;
01050     sofi_spc_jitter_config.wavecal_a2 = 0.0;
01051     sofi_spc_jitter_config.wavecal_a3 = 0.0;
01052     sofi_spc_jitter_config.wavecal_a4 = 0.0;
01053     sofi_spc_jitter_config.wavecal_cc = -1.0;
01054     sofi_spc_jitter_config.wavecal_out = 0;
01055     cpl_msg_indent_less();
01056 
01057     /* Compute the wavelength using the sky lines */
01058     if (sofi_spc_jitter_config.wavecal_in == 1) {
01059         /* Compute the slit_width */
01060         if ((slit_width = sofi_get_slitwidth(cur_fname)) == -1) {
01061             cpl_msg_warning(cpl_func, "cannot get the slit width");
01062             cpl_polynomial_delete(phdisprel);
01063             return 0;
01064         }
01065         /* Compute the wavelength */
01066         cpl_msg_info(cpl_func, "Compute the wavelength with the sky lines");
01067         cpl_msg_indent_more();
01068         if ((disprel = sofi_wavelength_engine(ima, "oh", oh, NULL, NULL, 
01069                         phdisprel, slit_width, 
01070                         sofi_spc_jitter_config.wavecal_degree, 
01071                         sofi_spc_jitter_config.wavecal_err, 
01072                         sofi_spc_jitter_config.wavecal_nsamples, 
01073                         sofi_spc_jitter_config.wavecal_ppm, 
01074                         sofi_spc_jitter_config.display, &xc)) == NULL) {
01075             cpl_msg_error(cpl_func, "cannot compute the dispersion relation");
01076             cpl_polynomial_delete(phdisprel);
01077             cpl_msg_indent_less();
01078             return 0;
01079         }
01080         cpl_msg_info(cpl_func, "Cross correlation factor: %g", xc);
01081         p[0] = 0; p[1] = 1; p[2] = 2; p[3] = 3; p[4] = 4;
01082         a = b = c = d = e = 0.0;
01083         degree = cpl_polynomial_get_degree(disprel);
01084         a = cpl_polynomial_get_coeff(disprel, p);
01085         if (degree > 0) b = cpl_polynomial_get_coeff(disprel, p + 1);
01086         if (degree > 1) c = cpl_polynomial_get_coeff(disprel, p + 2);
01087         if (degree > 2) d = cpl_polynomial_get_coeff(disprel, p + 3);
01088         if (degree > 3) e = cpl_polynomial_get_coeff(disprel, p + 4);
01089         if (degree == 0)
01090             cpl_msg_info(cpl_func, "f(x)=%g", a);
01091         if (degree == 1)
01092             cpl_msg_info(cpl_func, "f(x)=%g + %g*x", a, b);
01093         if (degree == 2)
01094             cpl_msg_info(cpl_func, "f(x)=%g + %g*x + %g*x^2", a, b, c);
01095         if (degree == 3)
01096             cpl_msg_info(cpl_func, "f(x)=%g + %g*x + %g*x^2 + %g*x^3", 
01097                     a, b, c, d);
01098         if (degree == 4)
01099             cpl_msg_info(cpl_func, "f(x)=%g + %g*x + %g*x^2 + %g*x^3 + %g*x^4", 
01100                     a, b, c, d, e);
01101         sofi_spc_jitter_config.wavecal_a0 = a;
01102         sofi_spc_jitter_config.wavecal_a1 = b;
01103         sofi_spc_jitter_config.wavecal_a2 = c;
01104         sofi_spc_jitter_config.wavecal_a3 = d;
01105         sofi_spc_jitter_config.wavecal_a4 = e;
01106         sofi_spc_jitter_config.wavecal_cc = xc;
01107         sofi_spc_jitter_config.wavecal_out = 1;
01108         cpl_polynomial_delete(disprel);
01109         cpl_msg_indent_less();
01110     }
01111     cpl_polynomial_delete(phdisprel);
01112     return 0;
01113 }
01114 
01115 /*----------------------------------------------------------------------------*/
01136 /*----------------------------------------------------------------------------*/
01137 static cpl_imagelist * sofi_spc_jitter_nodded(
01138         cpl_imagelist   *   abba,
01139         cpl_vector      *   abba_off,
01140         cpl_vector      **  nodded_off)
01141 {
01142     cpl_imagelist       *   nodded;
01143     cpl_image           *   tmp_ima;
01144     int                     nima;
01145     double                  ref_off;
01146     int                     i;
01147 
01148     /* Test entries */
01149     if ((abba == NULL) || (abba_off == NULL)) return NULL;
01150 
01151     /* Initialise */
01152     nima = cpl_imagelist_get_size(abba);
01153     if (nima % 2) {
01154         cpl_msg_error(cpl_func, "Number of images should be even");
01155         return NULL;
01156     }
01157    
01158     /* Create the offsets between the nodded images */
01159     *nodded_off = cpl_vector_duplicate(abba_off);
01160     /* The image list to contain the nodded images */
01161     nodded = cpl_imagelist_new();
01162     for (i=0; i<(nima/2); i++) {
01163         /* a-b */
01164         tmp_ima = cpl_image_duplicate(cpl_imagelist_get(abba, 2*i));
01165         cpl_image_subtract(tmp_ima, cpl_imagelist_get(abba, 2*i+1));
01166         cpl_imagelist_set(nodded, tmp_ima, 2*i);
01167         /* b-a */
01168         tmp_ima = cpl_image_duplicate(cpl_imagelist_get(abba, 2*i+1));
01169         cpl_image_subtract(tmp_ima, cpl_imagelist_get(abba, 2*i));
01170         cpl_imagelist_set(nodded, tmp_ima, 2*i+1);
01171     }
01172 
01173     /* Subtract the first offset to the others */
01174     ref_off = cpl_vector_get(*nodded_off, 0);
01175     cpl_vector_subtract_scalar(*nodded_off, ref_off);
01176     return nodded;
01177 }
01178 
01179 /*----------------------------------------------------------------------------*/
01186 /*----------------------------------------------------------------------------*/
01187 static cpl_imagelist * sofi_spc_jitter_distor(
01188         cpl_imagelist   *   ilist,
01189         const char      *   arc)
01190 {
01191     cpl_polynomial      *   arc_poly;
01192     cpl_polynomial      *   id_poly;
01193     cpl_table           *   tab;
01194     cpl_size                power[2];
01195     cpl_vector          *   profile;
01196     cpl_imagelist       *   warped_list;
01197     cpl_image           *   warped;
01198     int                     i;
01199     
01200     /* Test entries */
01201     if (ilist == NULL) return NULL;
01202     if (arc == NULL) return NULL;
01203 
01204     /* Get the arc polynomial */
01205     arc_poly = cpl_polynomial_new(2);
01206     cpl_msg_info(cpl_func, "Get the arc distortion from the file");
01207     if ((tab = cpl_table_load(arc, 1, 0)) == NULL) {
01208         cpl_msg_error(cpl_func, "cannot load the arc table");
01209         cpl_polynomial_delete(arc_poly);
01210         return NULL;
01211     }
01212     for (i=0; i<cpl_table_get_nrow(tab); i++) {
01213         power[0] = cpl_table_get_int(tab, "Degree_of_x", i, NULL);
01214         power[1] = cpl_table_get_int(tab, "Degree_of_y", i, NULL);
01215         cpl_polynomial_set_coeff(arc_poly, power,
01216                 cpl_table_get_double(tab, "poly2d_coef", i, NULL));
01217     }
01218     cpl_table_delete(tab);
01219 
01220     /* Create the ID polynomial for the other direction */
01221     id_poly = cpl_polynomial_new(2);
01222     power[0] = 1;
01223     power[1] = 0;
01224     cpl_polynomial_set_coeff(id_poly, power, 1.0);
01225    
01226     /* Create the kernel */
01227     profile = cpl_vector_new(CPL_KERNEL_DEF_SAMPLES);
01228     cpl_vector_fill_kernel_profile(profile, CPL_KERNEL_DEFAULT,
01229             CPL_KERNEL_DEF_WIDTH);
01230 
01231     /* Correct the images */
01232     warped_list = cpl_imagelist_new();
01233     for (i=0; i<cpl_imagelist_get_size(ilist); i++) {
01234         warped = cpl_image_duplicate(cpl_imagelist_get(ilist, i));
01235         if (cpl_image_warp_polynomial(warped, cpl_imagelist_get(ilist, i), 
01236                     id_poly, arc_poly, profile, CPL_KERNEL_DEF_WIDTH, profile,
01237                     CPL_KERNEL_DEF_WIDTH) != CPL_ERROR_NONE) {
01238             cpl_msg_error(cpl_func, "cannot correct the distortion");
01239             cpl_image_delete(warped);
01240             cpl_polynomial_delete(arc_poly);
01241             cpl_polynomial_delete(id_poly);
01242             cpl_vector_delete(profile);
01243             return NULL;
01244         }
01245         cpl_imagelist_set(warped_list, warped, i);
01246     }
01247     cpl_vector_delete(profile);
01248     cpl_polynomial_delete(arc_poly);
01249     cpl_polynomial_delete(id_poly);
01250     return warped_list;
01251 }
01252 
01253 /*----------------------------------------------------------------------------*/
01260 /*----------------------------------------------------------------------------*/
01261 static double sofi_spc_jitter_refine_offset(
01262         cpl_image   *   ima1,
01263         cpl_image   *   ima2)
01264 {
01265     double                  pos1, pos2;
01266 
01267     /* Test entries */
01268     if (ima1 == NULL) return 10000.0;
01269     if (ima2 == NULL) return 10000.0;
01270    
01271     /* Detect the spectra */
01272     if (irplib_spectrum_find_brightest(ima1, 0.0, NO_SHADOW, 0.0, 1, 
01273                 &pos1) == -1){
01274         return 10000.0;
01275     }
01276     if (irplib_spectrum_find_brightest(ima2, 0.0, NO_SHADOW, 0.0, 1,
01277                 &pos2) == -1){
01278         return 10000.0;
01279     }
01280     return pos1-pos2;
01281 }
01282 
01283 /*----------------------------------------------------------------------------*/
01289 /*----------------------------------------------------------------------------*/
01290 static cpl_table * sofi_spc_jitter_extract(cpl_image * combined)
01291 {
01292     int                     ri_dist, le_dist, ri_width, le_width, spec_pos;
01293     int                     nx, ny;
01294     double                  pos;
01295     int                     right_side, left_side;
01296     int                     sky_pos[4];
01297     cpl_vector          *   sky;
01298     cpl_vector          *   spec;
01299     cpl_vector          *   wl;
01300     double              *   pspec;
01301     double              *   psky;
01302     double              *   pwl;
01303     cpl_table           *   out;
01304     cpl_bivector        *   toplot;
01305     int                     throw;
01306     int                     res;
01307     int                     i;
01308 
01309     /* Test entries */
01310     if (combined == NULL) return NULL;
01311 
01312     /* Initialise */
01313     nx = cpl_image_get_size_x(combined);
01314     ny = cpl_image_get_size_y(combined);
01315     ri_dist = sofi_spc_jitter_config.extr_sky_ri_dist;
01316     le_dist = sofi_spc_jitter_config.extr_sky_le_dist;
01317     ri_width = sofi_spc_jitter_config.extr_sky_ri_width;
01318     le_width = sofi_spc_jitter_config.extr_sky_le_width;
01319     spec_pos = sofi_spc_jitter_config.extr_spec_pos;
01320     res = -1;
01321 
01322     /* Detect the spectrum position if not passed */
01323     if (spec_pos < 0) {
01324         if (sofi_spc_jitter_config.throws == NULL) {
01325             cpl_msg_error(cpl_func, 
01326                     "Need a throw value to detect the spectra !!");
01327             return NULL;
01328         }
01329         for (i=0; i<cpl_vector_get_size(sofi_spc_jitter_config.throws); i++){
01330             throw = (int)cpl_vector_get(sofi_spc_jitter_config.throws, i);
01331             if ((res = irplib_spectrum_find_brightest(combined, throw, 
01332                             TWO_SHADOWS, 0.0, 1, &pos)) == 0) break;
01333             if ((res = irplib_spectrum_find_brightest(combined, throw, 
01334                             ONE_SHADOW, 0.0, 1, &pos)) == 0) break;
01335         }
01336         if (res != 0) {
01337             cpl_msg_error(cpl_func, "Cannot detect the spectrum");
01338             return NULL;
01339         }
01340         spec_pos = (int)pos;
01341         cpl_msg_info(cpl_func, "Spectrum detected at x = %d", spec_pos);
01342     }
01343 
01344     /* Set the parameters for the extraction */
01345 
01346     /* Spectrum position */
01347     left_side = spec_pos - (int)(sofi_spc_jitter_config.extr_spec_width/2);
01348     right_side = left_side + sofi_spc_jitter_config.extr_spec_width;
01349     if ((left_side < 1) || (right_side > ny)) {
01350         cpl_msg_error(cpl_func, "Spectrum zone falls outside the image");
01351         return NULL;
01352     }
01353     /* Residual Sky position */
01354     if (ri_dist < 0) ri_dist = 2*sofi_spc_jitter_config.extr_spec_width;
01355     if (le_dist < 0) le_dist = 2*sofi_spc_jitter_config.extr_spec_width;
01356     sky_pos[1] = spec_pos - le_dist;
01357     sky_pos[0] = sky_pos[1] - le_width;
01358     sky_pos[2] = spec_pos + ri_dist;
01359     sky_pos[3] = sky_pos[2] + ri_width;
01360 
01361     /* Get the sky */
01362     sky = cpl_vector_new(ny);
01363     psky = cpl_vector_get_data(sky);
01364     if (((sky_pos[0] < 1) || (le_width == 0)) && 
01365             ((sky_pos[3] <= nx) && (ri_width > 0))) {
01366         for (i=0; i<ny; i++) {
01367             psky[i] = cpl_image_get_median_window(combined, sky_pos[2],
01368                     ny-i, sky_pos[3], ny-i);
01369         }
01370     } else if (((sky_pos[3] > nx) || (ri_width == 0))
01371             && ((sky_pos[0] > 0) && (le_width > 0))) {
01372         for (i=0; i<ny; i++) {
01373             psky[i] = cpl_image_get_median_window(combined, sky_pos[0],
01374                     ny-i, sky_pos[1], ny-i);
01375         }
01376     } else if ((ri_width != 0) && (le_width != 0)
01377             && (sky_pos[0] > 0) && (sky_pos[3] <= nx)) {
01378         for (i=0; i<ny; i++) {
01379             psky[i] = cpl_image_get_median_window(combined, sky_pos[2],
01380                     ny-i, sky_pos[3], ny-i);
01381             psky[i] += cpl_image_get_median_window(combined, sky_pos[0],
01382                     ny-i, sky_pos[1], ny-i);
01383             psky[i] /= 2.0;
01384         }
01385     } else {
01386         for (i=0; i<ny; i++) psky[i] = 0.0;
01387     }
01388 
01389     /* Estimate the spectrum */
01390     spec = cpl_vector_new(ny);
01391     pspec = cpl_vector_get_data(spec);
01392     for (i=0; i<ny; i++) {
01393         pspec[i] = cpl_image_get_flux_window(combined, left_side, ny-i,
01394                 right_side, ny-i);
01395         pspec[i] -= psky[i] * sofi_spc_jitter_config.extr_spec_width;
01396     } 
01397 
01398     /* Get the wavelength */
01399     wl = cpl_vector_new(ny);
01400     pwl = cpl_vector_get_data(wl);
01401     for (i=0; i<ny; i++) {
01402         pwl[i] = sofi_spc_jitter_config.wavecal_a0 +
01403             sofi_spc_jitter_config.wavecal_a1 * (i+1) +
01404             sofi_spc_jitter_config.wavecal_a2 * (i+1) * (i+1) +
01405             sofi_spc_jitter_config.wavecal_a3 * (i+1) * (i+1) * (i+1) +
01406             sofi_spc_jitter_config.wavecal_a4 * (i+1) * (i+1) * (i+1) + (i+1);
01407     }
01408 
01409     /* Plot the spectrum if requested */
01410     if (sofi_spc_jitter_config.display) {
01411         toplot = cpl_bivector_wrap_vectors(wl, spec);
01412         cpl_plot_bivector(NULL, "t 'Spectrum' w lines", NULL, toplot);
01413         cpl_bivector_unwrap_vectors(toplot);
01414         toplot = cpl_bivector_wrap_vectors(wl, sky);
01415         cpl_plot_bivector(NULL, "t 'Sky' w lines", NULL, toplot);
01416         cpl_bivector_unwrap_vectors(toplot);
01417     }
01418     
01419     /* Create and fill the output table */
01420     out = cpl_table_new(nx);
01421     cpl_table_new_column(out, "Y_coordinate", CPL_TYPE_DOUBLE);
01422     cpl_table_new_column(out, "Extracted_spectrum_value", CPL_TYPE_DOUBLE);
01423     cpl_table_new_column(out, "Sky_spectrum", CPL_TYPE_DOUBLE);
01424     for (i=0; i<nx; i++) {
01425         cpl_table_set_double(out, "Y_coordinate", i, pwl[i]);
01426         cpl_table_set_double(out, "Extracted_spectrum_value", i, pspec[i]);
01427         cpl_table_set_double(out, "Sky_spectrum", i, psky[i]);
01428     }
01429     cpl_vector_delete(wl);
01430     cpl_vector_delete(spec);
01431     cpl_vector_delete(sky);
01432     return out;
01433 }
01434 
01435 /*----------------------------------------------------------------------------*/
01444 /*----------------------------------------------------------------------------*/
01445 static cpl_error_code sofi_spc_jitter_save(cpl_frameset            * set,
01446                                            const cpl_image         * ima,
01447                                            const cpl_table         * tab,
01448                                            const cpl_parameterlist * parlist)
01449 {
01450     cpl_propertylist * plist;
01451     /* Get the QC params in qclist */
01452     cpl_propertylist * qclist = cpl_propertylist_new();
01453     cpl_propertylist * paflist;
01454     /* Get the reference frame */
01455     const cpl_frame  * ref_frame
01456         = irplib_frameset_get_first_from_group(set, CPL_FRAME_GROUP_RAW);
01457     char                    qc_str[128];
01458     int                     i;
01459 
01460 
01461     /* Add QC parameters */
01462     if (sofi_spc_jitter_config.filter[0] != (char)0)
01463         cpl_propertylist_append_string(qclist, "ESO QC FILTER OBS",
01464                 sofi_spc_jitter_config.filter);
01465     cpl_propertylist_append_double(qclist, "ESO QC DISPCO1",
01466             sofi_spc_jitter_config.wavecal_a0);
01467     cpl_propertylist_append_double(qclist, "ESO QC DISPCO2",
01468             sofi_spc_jitter_config.wavecal_a1);
01469     cpl_propertylist_append_double(qclist, "ESO QC DISPCO3",
01470             sofi_spc_jitter_config.wavecal_a2);
01471     cpl_propertylist_append_double(qclist, "ESO QC DISPCO4",
01472             sofi_spc_jitter_config.wavecal_a3);
01473     cpl_propertylist_append_double(qclist, "ESO QC DISPCO5",
01474             sofi_spc_jitter_config.wavecal_a4);
01475     cpl_propertylist_append_double(qclist, "ESO QC WLEN",
01476             sofi_spc_jitter_config.wavecal_a0 +
01477             sofi_spc_jitter_config.wavecal_a1 * 512 +
01478             sofi_spc_jitter_config.wavecal_a2 * 512 * 512 +
01479             sofi_spc_jitter_config.wavecal_a3 * 512 * 512 * 512 +
01480             sofi_spc_jitter_config.wavecal_a4 * 512 * 512 * 512 * 512);
01481     cpl_propertylist_append_double(qclist, "ESO QC DISP XCORR",
01482             sofi_spc_jitter_config.wavecal_cc);
01483     if (sofi_spc_jitter_config.wavecal_out == 0) {
01484         cpl_propertylist_append_string(qclist, "ESO QC WLMETHOD",
01485                 "physical model");
01486     } else if (sofi_spc_jitter_config.wavecal_out == 1) {
01487         cpl_propertylist_append_string(qclist, "ESO QC WLMETHOD",
01488                 "sky lines");
01489     } else if (sofi_spc_jitter_config.wavecal_out == 2) {
01490         cpl_propertylist_append_string(qclist, "ESO QC WLMETHOD",
01491                 "arc file");
01492     }
01493     for (i=0; i<cpl_vector_get_size(sofi_spc_jitter_config.intensities);i++) {
01494         sprintf(qc_str, "ESO QC SPEC INTENS%d", i+1);
01495         cpl_propertylist_append_double(qclist, qc_str,
01496                 cpl_vector_get(sofi_spc_jitter_config.intensities, i));
01497     }
01498 
01499     /* Change WCS keywords to the computed wavelength solution */
01500     cpl_propertylist_update_double(qclist, "CRVAL1",
01501             sofi_spc_jitter_config.wavecal_a0);
01502     cpl_propertylist_update_double(qclist, "CRVAL2", 1.0);
01503     cpl_propertylist_update_double(qclist, "CRPIX1", 1.0);
01504     cpl_propertylist_update_double(qclist, "CRPIX2", 1.0);
01505     cpl_propertylist_update_double(qclist, "CDELT1",
01506             sofi_spc_jitter_config.wavecal_a1);
01507     cpl_propertylist_update_double(qclist, "CDELT2", 1.0);
01508     cpl_propertylist_update_string(qclist, "CTYPE1", "LINEAR");
01509     cpl_propertylist_update_string(qclist, "CTYPE2", "LINEAR");
01510     if (cpl_propertylist_has(qclist, "CD1_1")) {
01511         cpl_propertylist_update_double(qclist, "CD1_1",
01512                 sofi_spc_jitter_config.wavecal_a1);
01513     } else {
01514         cpl_propertylist_insert_after_double(qclist, "CTYPE2", "CD1_1",
01515                 sofi_spc_jitter_config.wavecal_a1);
01516     }
01517     if (cpl_propertylist_has(qclist, "CD2_2")) {
01518         cpl_propertylist_update_double(qclist, "CD2_2", 1.0);
01519     } else {
01520         cpl_propertylist_insert_after_double(qclist, "CD1_1", "CD2_2", 1.0);
01521     }
01522 
01523     /* Write the image  */
01524     irplib_dfs_save_image(set, parlist, set, ima, CPL_BPP_IEEE_FLOAT,
01525                           RECIPE_STRING, SOFI_SPC_JITTER_COMB, qclist,
01526                           NULL, PACKAGE "/" PACKAGE_VERSION,
01527                           RECIPE_STRING "_combined" CPL_DFS_FITS);
01528 
01529     /* Write the table  */
01530     if (tab != NULL) {
01531         irplib_dfs_save_table(set, parlist, set, tab, NULL, RECIPE_STRING,
01532                 SOFI_SPC_JITTER_EXTR, qclist, NULL, PACKAGE "/" PACKAGE_VERSION,
01533                 RECIPE_STRING "_extracted" CPL_DFS_FITS);
01534     }
01535 
01536 
01537     /* Get FITS header from reference file */
01538     plist = cpl_propertylist_load(cpl_frame_get_filename(ref_frame), 0);
01539     if (plist == NULL) {
01540         cpl_propertylist_delete(qclist);
01541         return cpl_error_set_message(cpl_func, cpl_error_get_code(), "Could "
01542                                      "not read header from reference frame");
01543     }
01544 
01545     /* Get the keywords for the paf file */
01546     paflist = cpl_propertylist_new();
01547     cpl_propertylist_copy_property_regexp(paflist, plist,
01548         "^(ARCFILE|MJD-OBS|INSTRUME|ESO TPL ID|ESO TPL NEXP|ESO DPR CATG|"
01549         "ESO DPR TECH|ESO DPR TYPE|DATE-OBS|ESO INS GRAT NAME|"
01550         "ESO INS GRAT WLEN|ESO INS OPTI1 ID|ESO OBS ID|ESO OBS TARG NAME)$", 0);
01551     cpl_propertylist_delete(plist);
01552 
01553     /* Copy the QC in paflist */
01554     cpl_propertylist_copy_property_regexp(paflist, qclist, "", 0);
01555     cpl_propertylist_delete(qclist);
01556 
01557     /* Save the PAF file */
01558     cpl_dfs_save_paf("SOFI", RECIPE_STRING, paflist,
01559                      RECIPE_STRING CPL_DFS_PAF);
01560     cpl_propertylist_delete(paflist);
01561 
01562     return cpl_error_get_code();
01563 }
01564 
01565 /*----------------------------------------------------------------------------*/
01573 /*----------------------------------------------------------------------------*/
01574 static int off_comp(double off1, double off2, double thresh)
01575 {
01576     if (((off1>thresh) && (off2<thresh)) || ((off1<thresh) && (off2>thresh)))
01577         return 1;
01578     else return 0;
01579 }
01580 

Generated on Thu Mar 7 16:21:06 2013 for SOFI Pipeline Reference Manual by  doxygen 1.5.8