naco_spc_jitter.c

00001 /* $Id: naco_spc_jitter.c,v 1.16 2009/05/12 12:43:43 llundin Exp $
00002  *
00003  * This file is part of the NACO 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., 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: llundin $
00023  * $Date: 2009/05/12 12:43:43 $
00024  * $Revision: 1.16 $
00025  * $Name: HEAD $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /* FIXME */
00033 /*
00034    - Physical model missing
00035    - Wavelength calibration missing
00036    - Spectrum detection fails because spectrum not on the whole detector
00037 */
00038 
00039 /*-----------------------------------------------------------------------------
00040                                 Includes
00041  -----------------------------------------------------------------------------*/
00042 
00043 #include <math.h>
00044 #include <cpl.h>
00045 
00046 #include "irplib_utils.h"
00047 #include "irplib_std.h"
00048 #include "irplib_spectrum.h"
00049 
00050 #include "naco_utils.h"
00051 #include "naco_physicalmodel.h"
00052 #include "naco_wavelength.h"
00053 #include "naco_pfits.h"
00054 #include "naco_dfs.h"
00055 
00056 /*-----------------------------------------------------------------------------
00057                                 Define
00058  -----------------------------------------------------------------------------*/
00059 
00060 #define NACO_SPC_JITTER_OFFSET_ERR      10
00061 
00062 /*-----------------------------------------------------------------------------
00063                             Functions prototypes
00064  -----------------------------------------------------------------------------*/
00065 
00066 static int naco_spc_jitter_create(cpl_plugin *);
00067 static int naco_spc_jitter_exec(cpl_plugin *);
00068 static int naco_spc_jitter_destroy(cpl_plugin *);
00069 static int naco_spc_jitter(cpl_parameterlist *, cpl_frameset *);
00070 static cpl_image ** naco_spc_jitter_combine(cpl_frameset *, char *, char *, 
00071         char *);
00072 static cpl_vector * naco_spc_jitter_get_offsets(cpl_frameset *);
00073 static int * naco_spc_jitter_classif(cpl_vector *, int *);
00074 static int off_comp(double, double, double);
00075 static cpl_imagelist * naco_spc_jitter_saa_groups(cpl_imagelist *,
00076         cpl_vector *, int *, int, cpl_vector **);
00077 static int naco_spc_jitter_wavecal(char *, cpl_image *, cpl_frameset *);
00078 static cpl_imagelist * naco_spc_jitter_nodded(cpl_imagelist *, cpl_vector *, 
00079         cpl_vector **);
00080 static cpl_imagelist * naco_spc_jitter_distor(cpl_imagelist *, char *);
00081 static double naco_spc_jitter_refine_offset(cpl_image *, cpl_image *);
00082 static cpl_table * naco_spc_jitter_extract(cpl_image *);
00083 static int naco_spc_jitter_save(const cpl_image *, const cpl_table *, 
00084         cpl_parameterlist *, cpl_frameset *);
00085 
00086 /*-----------------------------------------------------------------------------
00087                             Static variables
00088  -----------------------------------------------------------------------------*/
00089 
00090 static struct {
00091     /* Inputs */
00092     int             display;
00093     /* wavecal_in : 0 for physical model, 1 for sky, 2 for arc table */
00094     int             wavecal_in;
00095     int             wavecal_rej_bottom;
00096     int             wavecal_rej_top;
00097     int             wavecal_rej_left;
00098     int             wavecal_rej_right;
00099     int             saa_refine;
00100     double          saa_rej_high;
00101     double          saa_rej_low;
00102     int             extr_spec_pos;
00103     int             extr_spec_width;
00104     int             extr_sky_ri_width;
00105     int             extr_sky_le_width;
00106     int             extr_sky_ri_dist;
00107     int             extr_sky_le_dist;
00108     /* Outputs */
00109     /* wavecal_out : 0 for physical model, 1 for sky, 2 for arc table */
00110     cpl_vector  *   throws;
00111     int             wavecal_out;
00112     double          wavecal_cc;
00113     double          wavecal_a0;
00114     double          wavecal_a1;
00115     double          wavecal_a2;
00116     double          wavecal_a3;
00117 } naco_spc_jitter_config;
00118 
00119 static char naco_spc_jitter_description[] = 
00120 "naco_spc_jitter -- NACO spectro jitter recipe\n"
00121 "The files listed in the Set Of Frames (sof-file) must be tagged:\n"
00122 "raw-file.fits "NACO_SPC_JITTER_RAW" or\n"
00123 "flat-file.fits "NACO_CALIB_SPFLAT" or\n"
00124 "arc-file.fits "NACO_CALIB_ARC" or\n"
00125 "arc_wl-file.fits "NACO_CALIB_ARC_WL"\n";
00126 
00127 /*----------------------------------------------------------------------------*/
00131 /*----------------------------------------------------------------------------*/
00132 
00133 /*-----------------------------------------------------------------------------
00134                                 Functions code
00135  -----------------------------------------------------------------------------*/
00136 
00137 /*----------------------------------------------------------------------------*/
00145 /*----------------------------------------------------------------------------*/
00146 int cpl_plugin_get_info(cpl_pluginlist * list)
00147 {
00148     cpl_recipe  *   recipe = cpl_calloc(1, sizeof(*recipe));
00149     cpl_plugin  *   plugin = &recipe->interface;
00150 
00151     cpl_plugin_init(plugin,
00152                     CPL_PLUGIN_API,
00153                     NACO_BINARY_VERSION,
00154                     CPL_PLUGIN_TYPE_RECIPE,
00155                     "naco_spc_jitter",
00156                     "Spectro jitter recipe",
00157                     naco_spc_jitter_description,
00158                     "Yves Jung",
00159                     "yjung@eso.org",
00160                     cpl_get_license(PACKAGE_NAME, "2002, 2003, 2005"),
00161                     naco_spc_jitter_create,
00162                     naco_spc_jitter_exec,
00163                     naco_spc_jitter_destroy);
00164 
00165     cpl_pluginlist_append(list, plugin);
00166     
00167     return 0;
00168 }
00169 
00170 /*----------------------------------------------------------------------------*/
00179 /*----------------------------------------------------------------------------*/
00180 static int naco_spc_jitter_create(cpl_plugin * plugin)
00181 {
00182     cpl_recipe      * recipe;
00183     cpl_parameter   * p;
00184 
00185     /* Get the recipe out of the plugin */
00186     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00187         recipe = (cpl_recipe *)plugin;
00188     else return -1;
00189 
00190     /* Create the parameters list in the cpl_recipe object */
00191     recipe->parameters = cpl_parameterlist_new();
00192 
00193     /* Fill the parameters list */
00194     /* --wavecal */
00195     p = cpl_parameter_new_value("naco.naco_spc_jitter.wavecal",
00196             CPL_TYPE_STRING, "Wavelength method: phy or sky", 
00197             "naco.naco_spc_jitter", "sky");
00198     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wavecal");
00199     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00200     cpl_parameterlist_append(recipe->parameters, p);
00201     /* --wavecal_rej */
00202     p = cpl_parameter_new_value("naco.naco_spc_jitter.wavecal_rej",
00203             CPL_TYPE_STRING, "left right bottom top rejections",
00204             "naco.naco_spc_jitter", "-1 -1 50 50");
00205     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "wc_rej");
00206     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00207     cpl_parameterlist_append(recipe->parameters, p);
00208     /* --saa_refine */
00209     p = cpl_parameter_new_value("naco.naco_spc_jitter.saa_refine", 
00210             CPL_TYPE_BOOL, "flag to refine the offsets",
00211             "naco.naco_spc_jitter", TRUE);
00212     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "saa_refine");
00213     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00214     cpl_parameterlist_append(recipe->parameters, p);
00215     /* --saa_rej */
00216     p = cpl_parameter_new_value("naco.naco_spc_jitter.saa_rej",
00217             CPL_TYPE_STRING, "low and high rejections in percent",
00218             "naco.naco_spc_jitter", "0.1 0.1");
00219     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "saa_rej");
00220     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00221     cpl_parameterlist_append(recipe->parameters, p);
00222     /* --spec_pos */
00223     p = cpl_parameter_new_value("naco.naco_spc_jitter.spec_pos",
00224             CPL_TYPE_INT, "spectrum position", "naco.naco_spc_jitter", -1);
00225     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "spec_pos");
00226     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00227     cpl_parameterlist_append(recipe->parameters, p);
00228     /* --spec_width */
00229     p = cpl_parameter_new_value("naco.naco_spc_jitter.spec_width",
00230             CPL_TYPE_INT, "spectrum width", "naco.naco_spc_jitter", 10);
00231     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "spec_width");
00232     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00233     cpl_parameterlist_append(recipe->parameters, p);
00234     /* --sky_ri_width */
00235     p = cpl_parameter_new_value("naco.naco_spc_jitter.sky_ri_width",
00236             CPL_TYPE_INT, "sky width right to the spectrum", 
00237             "naco.naco_spc_jitter", 10);
00238     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sky_ri_width");
00239     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00240     cpl_parameterlist_append(recipe->parameters, p);
00241     /* --sky_le_width */
00242     p = cpl_parameter_new_value("naco.naco_spc_jitter.sky_le_width",
00243             CPL_TYPE_INT, "sky width left to the spectrum", 
00244             "naco.naco_spc_jitter", 10);
00245     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sky_le_width");
00246     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00247     cpl_parameterlist_append(recipe->parameters, p);
00248     /* --sky_ri_dist */
00249     p = cpl_parameter_new_value("naco.naco_spc_jitter.sky_ri_dist",
00250             CPL_TYPE_INT, "sky distance right to the spectrum", 
00251             "naco.naco_spc_jitter", -1);
00252     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sky_ri_dist");
00253     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00254     cpl_parameterlist_append(recipe->parameters, p);
00255     /* --sky_le_dist */
00256     p = cpl_parameter_new_value("naco.naco_spc_jitter.sky_le_dist",
00257             CPL_TYPE_INT, "sky distance left to the spectrum", 
00258             "naco.naco_spc_jitter", -1);
00259     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "sky_le_dist");
00260     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00261     cpl_parameterlist_append(recipe->parameters, p);
00262     /* --display */ 
00263     p = cpl_parameter_new_value("naco.naco_spc_jitter.display",
00264             CPL_TYPE_BOOL, "flag to make plots", "naco.naco_spc_jitter",
00265             FALSE);
00266     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "display");
00267     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00268     cpl_parameterlist_append(recipe->parameters, p);
00269     return 0;
00270 }
00271 
00272 /*----------------------------------------------------------------------------*/
00278 /*----------------------------------------------------------------------------*/
00279 static int naco_spc_jitter_exec(cpl_plugin * plugin)
00280 {
00281     cpl_recipe  *   recipe;
00282 
00283     /* Get the recipe out of the plugin */
00284     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00285         recipe = (cpl_recipe *)plugin;
00286     else return -1;
00287 
00288     return naco_spc_jitter(recipe->parameters, recipe->frames);
00289 }
00290 
00291 /*----------------------------------------------------------------------------*/
00297 /*----------------------------------------------------------------------------*/
00298 static int naco_spc_jitter_destroy(cpl_plugin * plugin)
00299 {
00300     cpl_recipe  *   recipe;
00301 
00302     /* Get the recipe out of the plugin */
00303     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
00304         recipe = (cpl_recipe *)plugin;
00305     else return -1;
00306 
00307     cpl_parameterlist_delete(recipe->parameters);
00308     return 0;
00309 }
00310 
00311 /*----------------------------------------------------------------------------*/
00318 /*----------------------------------------------------------------------------*/
00319 static int naco_spc_jitter(
00320         cpl_parameterlist   *   parlist, 
00321         cpl_frameset        *   framelist)
00322 {
00323     const char          *   fctid = "naco_spc_jitter";
00324     cpl_parameter       *   par;
00325     cpl_propertylist    *   plist;
00326     const char          *   sval;
00327     int                 *   labels;
00328     int                     nlabels;
00329     cpl_frameset        *   rawframes;
00330     char                *   flat;
00331     char                *   arc;
00332     char                *   arc_wl;
00333     cpl_frame           *   cur_frame;
00334     char                *   tag;
00335     cpl_frameset        *   cur_set;
00336     cpl_image           **  combined;
00337     cpl_table           *   extracted;
00338     int                     i;
00339     
00340     /* Initialise */
00341     par = NULL;
00342     rawframes = NULL;
00343     arc = NULL;
00344     arc_wl = NULL;
00345     flat = NULL;
00346     naco_spc_jitter_config.wavecal_out = -1;
00347     naco_spc_jitter_config.wavecal_cc = -1.0;
00348     naco_spc_jitter_config.throws = NULL;
00349 
00350     /* Retrieve input parameters */
00351     /* --wavecal */
00352     par = cpl_parameterlist_find(parlist, "naco.naco_spc_jitter.wavecal");
00353     sval = cpl_parameter_get_string(par);
00354     if (!strcmp(sval, "phy")) naco_spc_jitter_config.wavecal_in = 0;
00355     else if (!strcmp(sval, "sky")) naco_spc_jitter_config.wavecal_in = 1;
00356     else {
00357         cpl_msg_error(fctid, "Invalid value for wavecal option");
00358         return -1;
00359     }
00360     /* Rejection parameters for wavelength calibration*/
00361     par = cpl_parameterlist_find(parlist, "naco.naco_spc_jitter.wavecal_rej");
00362     sval = cpl_parameter_get_string(par);
00363     if (sscanf(sval, "%d %d %d %d",
00364                     &naco_spc_jitter_config.wavecal_rej_left,
00365                     &naco_spc_jitter_config.wavecal_rej_right,
00366                     &naco_spc_jitter_config.wavecal_rej_bottom,
00367                     &naco_spc_jitter_config.wavecal_rej_top) != 4) {
00368         return -1;
00369     }
00370     /* Refine of offsets */
00371     par = cpl_parameterlist_find(parlist, "naco.naco_spc_jitter.saa_refine");
00372     naco_spc_jitter_config.saa_refine = cpl_parameter_get_bool(par);
00373     
00374     /* Rejection parameters for SAA */
00375     par = cpl_parameterlist_find(parlist, "naco.naco_spc_jitter.saa_rej");
00376     sval = cpl_parameter_get_string(par);
00377     if (sscanf(sval, "%lg %lg",
00378                     &naco_spc_jitter_config.saa_rej_low,
00379                     &naco_spc_jitter_config.saa_rej_high) != 2) {
00380         return -1;
00381     }
00382 
00383     /* --spec_pos */
00384     par=cpl_parameterlist_find(parlist,"naco.naco_spc_jitter.spec_pos");
00385     naco_spc_jitter_config.extr_spec_pos = cpl_parameter_get_int(par);
00386     /* --spec_width */
00387     par=cpl_parameterlist_find(parlist,"naco.naco_spc_jitter.spec_width");
00388     naco_spc_jitter_config.extr_spec_width = cpl_parameter_get_int(par);
00389     /* --sky_ri_width */
00390     par=cpl_parameterlist_find(parlist,"naco.naco_spc_jitter.sky_ri_width");
00391     naco_spc_jitter_config.extr_sky_ri_width = cpl_parameter_get_int(par);
00392     /* --sky_le_width */
00393     par=cpl_parameterlist_find(parlist,"naco.naco_spc_jitter.sky_le_width");
00394     naco_spc_jitter_config.extr_sky_le_width = cpl_parameter_get_int(par);
00395     /* --sky_ri_dist */
00396     par=cpl_parameterlist_find(parlist,"naco.naco_spc_jitter.sky_ri_dist");
00397     naco_spc_jitter_config.extr_sky_ri_dist = cpl_parameter_get_int(par);
00398     /* --sky_le_dist */
00399     par=cpl_parameterlist_find(parlist,"naco.naco_spc_jitter.sky_le_dist");
00400     naco_spc_jitter_config.extr_sky_le_dist = cpl_parameter_get_int(par);
00401     /* Display */
00402     par = cpl_parameterlist_find(parlist, "naco.naco_spc_jitter.display");
00403     naco_spc_jitter_config.display = cpl_parameter_get_bool(par);
00404     
00405     /* Identify the RAW and CALIB frames in the input frameset */
00406     if (naco_dfs_set_groups(framelist)) {
00407         cpl_msg_error(fctid, "Cannot identify RAW and CALIB frames");
00408         return -1;
00409     }
00410 
00411     /* Labelise the input frames according to their tags */
00412     if ((labels = cpl_frameset_labelise(framelist, irplib_compare_tags,
00413                     &nlabels)) == NULL) {
00414         cpl_msg_error(fctid, "Cannot labelise the input frames");
00415         return -1;
00416     }
00417     
00418     /* For each label */
00419     for (i=0 ; i<nlabels ; i++) {
00420         cur_set = cpl_frameset_extract(framelist, labels, i);
00421         cur_frame = cpl_frameset_get_frame(cur_set, 0);
00422         tag = (char*)cpl_frame_get_tag(cur_frame);
00423         if (!strcmp(tag, NACO_SPC_JITTER_RAW)) {
00424             /* Raw frames */
00425             rawframes = cpl_frameset_duplicate(cur_set);
00426         } else if (!strcmp(tag, NACO_CALIB_SPFLAT)) {
00427             /* Flat */
00428             if (flat == NULL) 
00429                 flat = cpl_strdup(cpl_frame_get_filename(cur_frame));
00430         } else if (!strcmp(tag, NACO_CALIB_ARC)) {
00431             /* Arc */
00432             if (arc == NULL) 
00433                 arc = cpl_strdup(cpl_frame_get_filename(cur_frame));
00434         } else if (!strcmp(tag, NACO_CALIB_ARC_WL)) {
00435             /* Arc for wl */
00436             naco_spc_jitter_config.wavecal_in = 2;
00437             if (arc_wl == NULL) 
00438                 arc_wl = cpl_strdup(cpl_frame_get_filename(cur_frame));
00439         }
00440         cpl_frameset_delete(cur_set);
00441     }
00442     cpl_free(labels);
00443 
00444     /* The raw frames must be there */
00445     if (rawframes == NULL) {
00446         cpl_msg_error(fctid, "Cannot find the raw frames in the input list");
00447         if (flat) cpl_free(flat);
00448         if (arc) cpl_free(arc);
00449         if (arc_wl) cpl_free(arc_wl);
00450         return -1;
00451     }
00452 
00453     /* Create the combined image */
00454     cpl_msg_info(fctid, "Create the combined image");
00455     cpl_msg_indent_more();
00456     if ((combined = naco_spc_jitter_combine(rawframes, flat, arc, 
00457                     arc_wl)) == NULL) {
00458         cpl_msg_error(fctid, "Cannot combine the images");
00459         if (flat) cpl_free(flat);
00460         if (arc) cpl_free(arc);
00461         if (arc_wl) cpl_free(arc_wl);
00462         cpl_frameset_delete(rawframes);
00463         if (naco_spc_jitter_config.throws)
00464             cpl_vector_delete(naco_spc_jitter_config.throws);
00465         cpl_msg_indent_less();
00466         return -1;
00467     }
00468     cpl_frameset_delete(rawframes);
00469     if (flat) cpl_free(flat);
00470     if (arc) cpl_free(arc);
00471     if (arc_wl) cpl_free(arc_wl);
00472     cpl_msg_indent_less();
00473     
00474     /* Extract the spectrum */
00475     cpl_msg_info(fctid, "Extract the spectrum");
00476     cpl_msg_indent_more();
00477     if ((extracted = naco_spc_jitter_extract(combined[0])) == NULL) {
00478         cpl_msg_error(fctid, "Cannot extract the spectrum");
00479     }
00480     if (naco_spc_jitter_config.throws)
00481         cpl_vector_delete(naco_spc_jitter_config.throws);
00482     cpl_msg_indent_less();
00483 
00484     /* Write the products */
00485     cpl_msg_info(fctid, "Save the products");
00486     cpl_msg_indent_more();
00487     if (naco_spc_jitter_save(combined[0], extracted, parlist, 
00488                 framelist) == -1) {
00489         cpl_msg_error(fctid, "Cannot save the products");
00490         cpl_image_delete(combined[0]);
00491         cpl_image_delete(combined[1]);
00492         cpl_free(combined);
00493         cpl_table_delete(extracted);
00494         cpl_msg_indent_less();
00495         return -1;
00496     }
00497     cpl_table_delete(extracted);
00498     cpl_image_delete(combined[0]);
00499     cpl_image_delete(combined[1]);
00500     cpl_free(combined);
00501     cpl_msg_indent_less();
00502  
00503     return 0;
00504 }
00505 
00506 /*----------------------------------------------------------------------------*/
00515 /*----------------------------------------------------------------------------*/
00516 static cpl_image ** naco_spc_jitter_combine(
00517         cpl_frameset        *   rawframes,
00518         char                *   flat,
00519         char                *   arc,
00520         char                *   arc_wl)
00521 {
00522     const char          *   fctid = "naco_spc_jitter_combine";
00523     cpl_imagelist       *   ilist;
00524     cpl_imagelist       *   corrected;
00525     cpl_image           *   cur_im;
00526     cpl_image           *   tmp_im;
00527     cpl_vector          *   offsets;
00528     int                 *   groups;
00529     int                     ngroups;
00530     cpl_imagelist       *   abba;
00531     cpl_vector          *   abba_off;
00532     cpl_imagelist       *   nodded;
00533     cpl_vector          *   nodded_off_x;
00534     cpl_vector          *   nodded_off_y;
00535     double                  throw;
00536     cpl_table           *   extracted;
00537     double                  intensity;
00538     double              *   pnodded_off_x;
00539     cpl_imagelist       *   nodded_warped;
00540     cpl_bivector        *   nodded_offsets;
00541     cpl_image           **  combined;
00542     int                     nima;
00543     double                  new_offset;
00544     int                     i;
00545     
00546     /* Test entries */
00547     if (rawframes == NULL) return NULL;
00548 
00549     /* Load the images */
00550     cpl_msg_info(fctid, "Load the data");
00551     cpl_msg_indent_more();
00552     if ((ilist = cpl_imagelist_load_frameset(rawframes, CPL_TYPE_FLOAT,
00553                     1, 0)) == NULL) {
00554         cpl_msg_error(fctid, "cannot load the data");
00555         cpl_msg_indent_less();
00556         return NULL;
00557     }
00558     cpl_msg_indent_less();
00559    
00560     /* Apply the flafield */
00561     if (flat != NULL) {
00562         cpl_msg_info(fctid, "Apply the flatfield correction");
00563         if ((tmp_im = cpl_image_load(flat, CPL_TYPE_FLOAT, 0, 0)) == NULL) {
00564             cpl_msg_warning(fctid, "cannot load the flat field");
00565         } else {
00566             if (cpl_imagelist_divide_image(ilist, tmp_im) != CPL_ERROR_NONE) {
00567                 cpl_msg_warning(fctid, "cannot apply the flat field");
00568             }
00569             cpl_image_delete(tmp_im);
00570         }
00571     }
00572 
00573     /* Get the offsets */
00574     cpl_msg_info(fctid, "Get the offsets");
00575     if ((offsets = naco_spc_jitter_get_offsets(rawframes)) == NULL) {
00576         cpl_msg_error(fctid, "cannot get the offsets");
00577         cpl_imagelist_delete(ilist);
00578         return NULL;
00579     }
00580 
00581     /* Classify in groups the a and b images sequence */
00582     cpl_msg_info(fctid, "Classify in groups");
00583     cpl_msg_indent_more();
00584     if ((groups = naco_spc_jitter_classif(offsets, &ngroups)) == NULL) {
00585         cpl_msg_error(fctid, "cannot classify the data");
00586         cpl_imagelist_delete(ilist);
00587         cpl_vector_delete(offsets);
00588         cpl_msg_indent_less();
00589         return NULL;
00590     }
00591     cpl_msg_indent_less();
00592   
00593     /* Shift and add each group to one image */
00594     cpl_msg_info(fctid, "Shift and add each group to one image");
00595     cpl_msg_indent_more();
00596     if ((abba = naco_spc_jitter_saa_groups(ilist, offsets, groups, 
00597                     ngroups, &abba_off)) == NULL) {
00598         cpl_msg_error(fctid, "cannot shift and add groups");
00599         cpl_imagelist_delete(ilist);
00600         cpl_vector_delete(offsets);
00601         cpl_free(groups);
00602         cpl_msg_indent_less();
00603         return NULL;
00604     }
00605     cpl_imagelist_delete(ilist);
00606     cpl_free(groups);
00607     cpl_vector_delete(offsets);
00608     cpl_msg_indent_less();
00609 
00610     /* Compute the wavelength calibration */
00611     /*
00612     cpl_msg_info(fctid, "Compute the wavelength calibration");
00613     cpl_msg_indent_more();
00614     if (naco_spc_jitter_wavecal(arc_wl, cpl_imagelist_get(abba, 0),
00615                 rawframes) == -1) {
00616         cpl_msg_error(fctid, "cannot compute the wavelength");
00617         cpl_imagelist_delete(abba);
00618         cpl_vector_delete(abba_off);
00619         cpl_msg_indent_less();
00620         return NULL;
00621     }
00622     cpl_msg_indent_less();
00623    */
00624 
00625    /* Create the nodded images */
00626     cpl_msg_info(fctid, "Create the nodded images");
00627     cpl_msg_indent_more();
00628     if ((nodded = naco_spc_jitter_nodded(abba, abba_off, 
00629                     &nodded_off_x))==NULL) {
00630         cpl_msg_error(fctid, "cannot create the nodded images");
00631         cpl_imagelist_delete(abba);
00632         cpl_vector_delete(abba_off);
00633         cpl_msg_indent_less();
00634         return NULL;
00635     }
00636     cpl_imagelist_delete(abba);
00637     cpl_msg_indent_less();
00638 
00639     /* Get the throw offsets from abba_off */
00640     nima = cpl_imagelist_get_size(nodded);
00641     naco_spc_jitter_config.throws = cpl_vector_new(nima);
00642     for (i=0 ; i<nima/2 ; i++) {
00643         throw = fabs(   (cpl_vector_get(abba_off, 2*i))-
00644                         (cpl_vector_get(abba_off, 2*i+1)));
00645         cpl_vector_set(naco_spc_jitter_config.throws, 2*i, throw);
00646         cpl_vector_set(naco_spc_jitter_config.throws, 2*i+1, throw);
00647     }
00648     cpl_vector_delete(abba_off);
00649     
00650     /* Distortion correction */
00651     if (arc) {
00652         cpl_msg_info(fctid, "Correct the distortion on nodded images");
00653         cpl_msg_indent_more();
00654         if ((nodded_warped = naco_spc_jitter_distor(nodded, arc)) == NULL) {
00655             cpl_msg_error(fctid, "cannot correct the distortion");
00656             cpl_imagelist_delete(nodded);
00657             cpl_vector_delete(nodded_off_x);
00658             cpl_msg_indent_less();
00659             return NULL;
00660         }
00661         cpl_imagelist_delete(nodded);
00662         nodded = nodded_warped;
00663         cpl_msg_indent_less();
00664     }
00665 
00666     /* Refine the offsets if requested */
00667     if (naco_spc_jitter_config.saa_refine) {
00668         cpl_msg_info(fctid, "Refine the offsets");
00669         pnodded_off_x = cpl_vector_get_data(nodded_off_x);
00670         for (i=0 ; i<cpl_imagelist_get_size(nodded) ; i++) {
00671             new_offset = naco_spc_jitter_refine_offset(
00672                     cpl_imagelist_get(nodded, 0),
00673                     cpl_imagelist_get(nodded, i));
00674             if (new_offset > 5000) {
00675                 cpl_msg_debug(fctid, "cannot refine the offset - keep %g", 
00676                         pnodded_off_x[i]);
00677             } else {
00678                 if (fabs(new_offset-pnodded_off_x[i]) < 
00679                         NACO_SPC_JITTER_OFFSET_ERR) {
00680                     cpl_msg_debug(fctid, "refined offset : %g (old was %g)",
00681                             new_offset, pnodded_off_x[i]);
00682                     pnodded_off_x[i] = new_offset;
00683                 } else { 
00684                     cpl_msg_debug(fctid, 
00685                             "refined offset %g too different - keep %g",
00686                             new_offset, pnodded_off_x[i]);
00687                 }
00688             }
00689         }
00690     }
00691 
00692     /* Images combination */
00693     /* Get the offsets in a bivector */
00694     nodded_off_y = cpl_vector_duplicate(nodded_off_x);
00695     cpl_vector_fill(nodded_off_y, 0.0);
00696     nodded_offsets = cpl_bivector_wrap_vectors(nodded_off_x, nodded_off_y);
00697     /* Shift and add */
00698     cpl_msg_info(fctid, "Apply the shift and add on the nodded frames");
00699     nima = cpl_imagelist_get_size(nodded);
00700     if ((combined = cpl_geom_img_offset_saa(nodded, nodded_offsets,
00701                     CPL_KERNEL_DEFAULT, 
00702                     (int)(naco_spc_jitter_config.saa_rej_low * nima), 
00703                     (int)(naco_spc_jitter_config.saa_rej_high * nima), 
00704                     CPL_GEOM_FIRST, NULL, NULL)) == NULL) {
00705         cpl_msg_error(fctid, "Cannot shift and add group");
00706         cpl_imagelist_delete(nodded);
00707         cpl_bivector_unwrap_vectors(nodded_offsets);
00708         cpl_vector_delete(nodded_off_x);
00709         cpl_vector_delete(nodded_off_y);
00710         return NULL;
00711     }
00712     cpl_imagelist_delete(nodded);
00713     cpl_bivector_unwrap_vectors(nodded_offsets);
00714     cpl_vector_delete(nodded_off_x);
00715     cpl_vector_delete(nodded_off_y);
00716     return combined;
00717 }
00718  
00719 /*----------------------------------------------------------------------------*/
00725 /*----------------------------------------------------------------------------*/
00726 static cpl_vector * naco_spc_jitter_get_offsets(cpl_frameset * rawframes)
00727 {
00728     const char          *   fctid = "naco_spc_jitter_get_offsets";
00729     cpl_vector          *   offsets;
00730     double              *   pvect;
00731     int                     nraw;
00732     cpl_frame           *   cur_frame;
00733     cpl_propertylist    *   plist;
00734     int                     i;
00735 
00736     /* Test entries */
00737     if (rawframes == NULL) return NULL;
00738     
00739     /* Initialise */
00740     nraw = cpl_frameset_get_size(rawframes);
00741 
00742     /* Get the rawframes X offsets */
00743     offsets = cpl_vector_new(nraw);
00744     pvect = cpl_vector_get_data(offsets);
00745     for (i=0 ; i<nraw ; i++) {
00746         cur_frame = cpl_frameset_get_frame(rawframes, i);
00747         if ((plist=cpl_propertylist_load(cpl_frame_get_filename(cur_frame),
00748                         0)) == NULL) {
00749             cpl_msg_error(fctid, "cannot get property list");
00750             cpl_vector_delete(offsets);
00751             return NULL;
00752         }
00753         pvect[i] = -1 * naco_pfits_get_cumoffsetx(plist);
00754         if (cpl_error_get_code()) {
00755             cpl_msg_error(fctid, "cannot get the offset from the header");
00756             cpl_vector_delete(offsets);
00757             cpl_propertylist_delete(plist);
00758             return NULL;
00759         }
00760         cpl_propertylist_delete(plist);
00761     }
00762     return offsets;
00763 }
00764     
00765 /*----------------------------------------------------------------------------*/
00803 /*----------------------------------------------------------------------------*/
00804 static int * naco_spc_jitter_classif(
00805         cpl_vector      *   offsets,
00806         int             *   ngroups)
00807 {
00808     const char          *   fctid = "naco_spc_jitter_classif";
00809     double              *   pvect;
00810     int                     nraw;
00811     double                  offset_thresh;
00812     cpl_vector          *   tmp_vec;
00813     int                 *   groups;
00814     int                     last_group;
00815     int                     i, j, k, l;
00816 
00817     /* Test entries */
00818     if (offsets == NULL) return NULL;
00819 
00820     /* Initialise */
00821     nraw = cpl_vector_get_size(offsets);
00822 
00823     /* Separate the offsets in 2 categories */
00824     tmp_vec = cpl_vector_duplicate(offsets);
00825     cpl_vector_sort(tmp_vec, 1);
00826     pvect = cpl_vector_get_data(tmp_vec);
00827     if (pvect[0] == pvect[nraw-1]) {
00828         cpl_msg_error(fctid, "Only one offset in the list - abort");
00829         cpl_vector_delete(tmp_vec);
00830         return NULL;
00831     }
00832     offset_thresh = (pvect[0] + pvect[nraw-1]) / 2.0;
00833     cpl_vector_delete(tmp_vec);
00834 
00835     /* Identify the different A and B groups */
00836     pvect = cpl_vector_get_data(offsets);
00837     *ngroups = 0;
00838     groups = cpl_calloc(nraw, sizeof(int));
00839 
00840     /* Create a look up table to associate the ith obj with the jth frame */
00841     i = 0;
00842     while (i < nraw) {
00843         j = 0;
00844         /* Count the number of successive '+' or '-' (j) */
00845         while ((i+j<nraw) &&
00846                 (!off_comp(pvect[i], pvect[i+j], offset_thresh))) j++;
00847 
00848         if (i+j >= nraw) i = nraw;
00849         else {
00850             k = 0;
00851             /* Check if there are j '-' or '+' (k) */
00852             while ((i+j+k < nraw)
00853                     && (!off_comp(pvect[i+j], pvect[i+j+k], offset_thresh))
00854                     && (k<j)) k++;
00855             last_group = 1;
00856             if (i+j+k < nraw) {
00857                 for (l=i+j+k ; l<nraw ; l++) {
00858                     if (off_comp(pvect[i+j], pvect[l], offset_thresh)) {
00859                         last_group = 0;
00860                         break;
00861                     }
00862                 }
00863             }
00864             if (last_group == 0) {
00865                 for (l=0 ; l<j ; l++) groups[i+l]   = *ngroups + 1;
00866                 for (l=0 ; l<k ; l++) groups[i+j+l] = *ngroups + 2;
00867                 *ngroups += 2;
00868                 i += j+k;
00869             } else {
00870                 for (l=0 ; l<j ; l++)               groups[i+l] = *ngroups + 1;
00871                 for (l=0 ; l<nraw - (i+j) ; l++)    groups[i+j+l] =*ngroups + 2;
00872                 *ngroups += 2;
00873                 i = nraw;
00874             }
00875         }
00876     }
00877 
00878     /* Nb of groups found should be even */
00879     if (*ngroups % 2) {
00880         cpl_msg_error(fctid, "Odd number of groups found");
00881         cpl_free(groups);
00882         return NULL;
00883     }
00884 
00885     return groups;
00886 }
00887     
00888 /*----------------------------------------------------------------------------*/
00919 /*----------------------------------------------------------------------------*/
00920 static cpl_imagelist * naco_spc_jitter_saa_groups(
00921         cpl_imagelist   *   ilist,
00922         cpl_vector      *   offsets,
00923         int             *   groups,
00924         int                 ngroups,
00925         cpl_vector      **  abba_off)
00926 {
00927     const char          *   fctid = "naco_spc_jitter_saa_groups";
00928     cpl_imagelist       *   abba;
00929     cpl_imagelist       *   group_list;
00930     cpl_image           *   tmp_ima;
00931     cpl_image           **  combined;
00932     cpl_bivector        *   group_off;
00933     double              *   pgroup_off;
00934     double              *   poffsets;
00935     double              *   pabba_off;
00936     int                     nima;
00937     int                     saa;
00938     int                     i, j, k;
00939 
00940     /* Test entries */
00941     if ((ilist == NULL) || (offsets == NULL) || (groups == NULL)) return NULL;
00942     
00943     /* Initialise */
00944     nima = cpl_imagelist_get_size(ilist);
00945     poffsets = cpl_vector_get_data(offsets);
00946 
00947     /* Create the output image list */
00948     abba = cpl_imagelist_new();
00949     *abba_off = cpl_vector_new(ngroups);
00950     pabba_off = cpl_vector_get_data(*abba_off);
00951     
00952     /* Loop on the groups */
00953     for (i=0 ; i<ngroups ; i++) {
00954         /* Initialise */
00955         saa = 0;
00956         /* Create the group list of images */
00957         group_list = cpl_imagelist_new();
00958         k = 0;
00959         for (j=0 ; j<nima ; j++) {
00960             if (i+1 == groups[j]) {
00961                 /* Get the first offset of the group in abba_off */
00962                 if (k==0) pabba_off[i] = poffsets[j];
00963                 /* To know if we need the saa (shift and add) */
00964                 if (fabs(pabba_off[i]-poffsets[j]) > 1e-3) saa = 1;
00965                 /* Copy the images of the group in group_list */
00966                 tmp_ima = cpl_image_duplicate(cpl_imagelist_get(ilist, j));
00967                 cpl_imagelist_set(group_list, tmp_ima, k);
00968                 tmp_ima = NULL;
00969                 k++;
00970             }
00971         }
00972 
00973         if (saa) {
00974             /* Get the offsets of the group in group_off */
00975             group_off = cpl_bivector_new(k);
00976             cpl_vector_fill(cpl_bivector_get_y(group_off), 0.0);
00977             pgroup_off = cpl_bivector_get_x_data(group_off);
00978             k = 0;
00979             for (j=0 ; j<nima ; j++) {
00980                 if (i+1 == groups[j]) {
00981                     pgroup_off[k] = poffsets[j];
00982                     k++;
00983                 }
00984             }
00985             cpl_vector_subtract_scalar(cpl_bivector_get_x(group_off), 
00986                     pabba_off[i]);
00987             /* Shift and add */
00988             cpl_msg_debug(fctid, "Apply shift-and-add for group %d", i+1);
00989             if ((combined = cpl_geom_img_offset_saa(group_list,
00990                            group_off, CPL_KERNEL_DEFAULT, 0, 0,
00991                            CPL_GEOM_FIRST)) == NULL) {
00992                 cpl_msg_error(fctid, "Cannot shift and add group nb %d", i+1);
00993                 cpl_imagelist_delete(group_list);
00994                 cpl_bivector_delete(group_off);
00995                 cpl_imagelist_delete(abba);
00996                 cpl_vector_delete(*abba_off);
00997                 return NULL;
00998             }
00999             cpl_bivector_delete(group_off);
01000             cpl_image_delete(combined[1]);
01001             cpl_imagelist_set(abba, combined[0], i);
01002             cpl_free(combined);
01003         } else {
01004             /* Averaging */
01005             cpl_msg_debug(fctid, "Apply averaging for group %d", i+1);
01006             if ((tmp_ima = cpl_imagelist_collapse_create(group_list)) == NULL) {
01007                 cpl_msg_error(fctid, "Cannot average group nb %d", i+1);
01008                 cpl_imagelist_delete(group_list);
01009                 cpl_imagelist_delete(abba);
01010                 cpl_vector_delete(*abba_off);
01011                 return NULL;
01012             }
01013             cpl_imagelist_set(abba, tmp_ima, i);
01014         }
01015         cpl_imagelist_delete(group_list);
01016     }
01017     return abba;
01018 }
01019 
01020 /*----------------------------------------------------------------------------*/
01028 /*----------------------------------------------------------------------------*/
01029 static int naco_spc_jitter_wavecal(
01030         char            *   arc,
01031         cpl_image       *   ima,
01032         cpl_frameset    *   raw)
01033 {
01034     const char          *   fctid = "naco_spc_jitter_wavecal";
01035     cpl_table           *   arc_tab;
01036     double              *   phdisprel;
01037     cpl_frame           *   cur_frame;
01038     const char          *   cur_fname;
01039     computed_disprel    *   disprel;
01040     int                     order;
01041     double                  slit_width;
01042 
01043     /* Get the wavelength from the arc file */
01044     if (arc) {
01045         cpl_msg_info(fctid, "Get the wavelength from the ARC file");
01046         if ((arc_tab = cpl_table_load(arc, 1, 0)) == NULL) {
01047             cpl_msg_error(fctid, "Cannot load the arc table");
01048             naco_spc_jitter_config.wavecal_out = -1;
01049             return -1;
01050         }
01051         naco_spc_jitter_config.wavecal_a0 =
01052             cpl_table_get_double(arc_tab, "WL_coefficients", 0, NULL);
01053         naco_spc_jitter_config.wavecal_a1 = 
01054             cpl_table_get_double(arc_tab, "WL_coefficients", 1, NULL);
01055         naco_spc_jitter_config.wavecal_a2 = 
01056             cpl_table_get_double(arc_tab, "WL_coefficients", 2, NULL);
01057         naco_spc_jitter_config.wavecal_a3 = 
01058             cpl_table_get_double(arc_tab, "WL_coefficients", 3, NULL);
01059         cpl_table_delete(arc_tab);
01060         naco_spc_jitter_config.wavecal_out = 2;
01061         naco_spc_jitter_config.wavecal_cc = -1.0;
01062         return 0;
01063     }
01064 
01065     /* Get the reference frame */
01066     cur_frame = cpl_frameset_get_frame(raw, 0);
01067     cur_fname = cpl_frame_get_filename(cur_frame);
01068     
01069     /* Get the physical model */
01070     cpl_msg_info(fctid, "Compute the physical model");
01071     cpl_msg_indent_more();
01072     if ((phdisprel = naco_get_disprel_estimate(cur_fname, 3)) == NULL) {
01073         cpl_msg_error(fctid, "cannot compute the physical model");
01074         naco_spc_jitter_config.wavecal_out = -1;
01075         cpl_msg_indent_less();
01076         return -1;
01077     }
01078     cpl_msg_info(fctid, "f(x)=%g + %g*x + %g*x^2 + %g*x^3",
01079             phdisprel[0], phdisprel[1], phdisprel[2], phdisprel[3]);
01080     naco_spc_jitter_config.wavecal_a0 = phdisprel[0];
01081     naco_spc_jitter_config.wavecal_a1 = phdisprel[1];
01082     naco_spc_jitter_config.wavecal_a2 = phdisprel[2];
01083     naco_spc_jitter_config.wavecal_a3 = phdisprel[3];
01084     naco_spc_jitter_config.wavecal_cc = -1.0;
01085     naco_spc_jitter_config.wavecal_out = 0;
01086     cpl_msg_indent_less();
01087 
01088     /* Compute the wavelength using the sky lines */
01089     if (naco_spc_jitter_config.wavecal_in == 1) {
01090         /* Compute the slit_width */
01091         if ((slit_width = naco_get_slitwidth(cur_fname)) == -1) {
01092             cpl_msg_warning(fctid, "cannot get the slit width");
01093             cpl_free(phdisprel);
01094             return 0;
01095         }
01096         /* Get the order */
01097         if ((order = naco_find_order(cur_fname)) == -1) {
01098             cpl_msg_warning(fctid, "cannot get the order");
01099             cpl_free(phdisprel);
01100             return 0;
01101         }
01102         /* Compute the wavelength */
01103         cpl_msg_info(fctid, "Compute the wavelength with the sky lines");
01104         cpl_msg_indent_more();
01105         if ((disprel = naco_spectro_compute_disprel(ima,
01106                         naco_spc_jitter_config.wavecal_rej_bottom,
01107                         naco_spc_jitter_config.wavecal_rej_top,
01108                         naco_spc_jitter_config.wavecal_rej_left,
01109                         naco_spc_jitter_config.wavecal_rej_right,
01110                         naco_has_thermal(cur_fname) > 0,
01111                         "oh", slit_width, order, 
01112                         (int)(cpl_msg_get_level() == CPL_MSG_DEBUG), 
01113                         phdisprel)) == NULL) {
01114             cpl_msg_error(fctid, "cannot compute the dispersion relation");
01115             cpl_free(phdisprel);
01116             cpl_msg_indent_less();
01117             return 0;
01118         }
01119         cpl_msg_info(fctid, "Cross correlation factor: %g", disprel->cc);
01120         cpl_msg_info(fctid, "f(x)=%g + %g*x + %g*x^2 + %g*x^3",
01121                 disprel->poly[0], disprel->poly[1], disprel->poly[2],
01122                 disprel->poly[3]);
01123         naco_spc_jitter_config.wavecal_a0 = disprel->poly[0];
01124         naco_spc_jitter_config.wavecal_a1 = disprel->poly[1];
01125         naco_spc_jitter_config.wavecal_a2 = disprel->poly[2];
01126         naco_spc_jitter_config.wavecal_a3 = disprel->poly[3];
01127         naco_spc_jitter_config.wavecal_cc = disprel->cc;
01128         naco_spc_jitter_config.wavecal_out = 1;
01129         if (disprel->poly != NULL) cpl_free(disprel->poly);
01130         cpl_free(disprel);
01131         cpl_msg_indent_less();
01132     }
01133     cpl_free(phdisprel);
01134     return 0;
01135 }
01136 
01137 /*----------------------------------------------------------------------------*/
01169 /*----------------------------------------------------------------------------*/
01170 static cpl_imagelist * naco_spc_jitter_nodded(
01171         cpl_imagelist   *   abba,
01172         cpl_vector      *   abba_off,
01173         cpl_vector      **  nodded_off)
01174 {
01175     const char          *   fctid = "naco_spc_jitter_nodded";
01176     cpl_imagelist       *   nodded;
01177     cpl_image           *   tmp_ima;
01178     int                     nima;
01179     double              *   pabba_off;
01180     double              *   pnodded_off;
01181     double                  ref_off;
01182     int                     i;
01183 
01184     /* Test entries */
01185     if ((abba == NULL) || (abba_off == NULL)) return NULL;
01186 
01187     /* Initialise */
01188     nima = cpl_imagelist_get_size(abba);
01189     if (nima % 2) {
01190         cpl_msg_error(fctid, "Number of images should be even");
01191         return NULL;
01192     }
01193 
01194     /* Create the offsets between the nodded images */
01195     *nodded_off = cpl_vector_duplicate(abba_off);
01196     /* The image list to contain the nodded images */
01197     nodded = cpl_imagelist_new();
01198     for (i=0 ; i<(nima/2) ; i++) {
01199         /* a-b */
01200         tmp_ima = cpl_image_duplicate(cpl_imagelist_get(abba, 2*i));
01201         cpl_image_subtract(tmp_ima, cpl_imagelist_get(abba, 2*i+1));
01202         cpl_imagelist_set(nodded, tmp_ima, 2*i);
01203         /* b-a */
01204         tmp_ima = cpl_image_duplicate(cpl_imagelist_get(abba, 2*i+1));
01205         cpl_image_subtract(tmp_ima, cpl_imagelist_get(abba, 2*i));
01206         cpl_imagelist_set(nodded, tmp_ima, 2*i+1);
01207     }
01208 
01209     /* Subtract the first offset to the others */
01210     ref_off = cpl_vector_get(*nodded_off, 0);
01211     cpl_vector_subtract_scalar(*nodded_off, ref_off);
01212     return nodded;
01213 }
01214 
01215 /*----------------------------------------------------------------------------*/
01222 /*----------------------------------------------------------------------------*/
01223 static cpl_imagelist * naco_spc_jitter_distor(
01224         cpl_imagelist   *   ilist,
01225         char            *   arc)
01226 {
01227     const char          *   fctid = "naco_spc_jitter_distor";
01228     cpl_polynomial      *   arc_poly;
01229     cpl_polynomial      *   sttr_poly;
01230     cpl_table           *   tab;
01231     int                     pow[2];
01232     cpl_vector          *   profile;
01233     cpl_imagelist       *   warped_list;
01234     cpl_image           *   warped;
01235     int                     i;
01236     
01237     /* Test entries */
01238     if (ilist == NULL) return NULL;
01239     if (arc == NULL) return NULL;
01240 
01241     /* Get the arc polynomial */
01242     arc_poly = cpl_polynomial_new(2);
01243     if (arc != NULL) {
01244         cpl_msg_info(fctid, "Get the arc distortion from the file");
01245         if ((tab = cpl_table_load(arc, 1, 0)) == NULL) {
01246             cpl_msg_error(fctid, "cannot load the arc table");
01247             cpl_polynomial_delete(arc_poly);
01248             return NULL;
01249         }
01250         for (i=0 ; i<cpl_table_get_nrow(tab) ; i++) {
01251             pow[0] = cpl_table_get_int(tab, "Degree_of_x", i, NULL);
01252             pow[1] = cpl_table_get_int(tab, "Degree_of_y", i, NULL);
01253             cpl_polynomial_set_coeff(arc_poly, pow,
01254                     cpl_table_get_double(tab, "poly2d_coef", i, NULL));
01255         }
01256         cpl_table_delete(tab);
01257     } else {
01258         cpl_msg_info(fctid, "Use the ID polynomial for the arc dist");
01259         pow[0] = 1;
01260         pow[1] = 0;
01261         cpl_polynomial_set_coeff(arc_poly, pow, 1.0);
01262     }
01263  
01264     /* Get the startrace polynomial */
01265     sttr_poly = cpl_polynomial_new(2);
01266     cpl_msg_info(fctid, "Use the ID polynomial for the startrace dist");
01267     pow[0] = 0;
01268     pow[1] = 1;
01269     cpl_polynomial_set_coeff(sttr_poly, pow, 1.0);
01270    
01271     /* Create the kernel */
01272     profile = cpl_vector_new(CPL_KERNEL_DEF_SAMPLES);
01273     cpl_vector_fill_kernel_profile(profile, CPL_KERNEL_DEFAULT,
01274             CPL_KERNEL_DEF_WIDTH);
01275 
01276     /* Correct the images */
01277     warped_list = cpl_imagelist_new();
01278     for (i=0 ; i<cpl_imagelist_get_size(ilist) ; i++) {
01279         warped = cpl_image_duplicate(cpl_imagelist_get(ilist, i));
01280         if (cpl_image_warp_polynomial(warped, cpl_imagelist_get(ilist, i), 
01281                     arc_poly, sttr_poly, profile, CPL_KERNEL_DEF_WIDTH, profile,
01282                     CPL_KERNEL_DEF_WIDTH) != CPL_ERROR_NONE) {
01283             cpl_msg_error(fctid, "cannot correct the distortion");
01284             cpl_image_delete(warped);
01285             cpl_polynomial_delete(arc_poly);
01286             cpl_polynomial_delete(sttr_poly);
01287             cpl_vector_delete(profile);
01288             return NULL;
01289         }
01290         cpl_imagelist_set(warped_list, warped, i);
01291     }
01292     cpl_vector_delete(profile);
01293     cpl_polynomial_delete(arc_poly);
01294     cpl_polynomial_delete(sttr_poly);
01295     return warped_list;
01296 }
01297 
01298 /*----------------------------------------------------------------------------*/
01305 /*----------------------------------------------------------------------------*/
01306 static double naco_spc_jitter_refine_offset(
01307         cpl_image   *   ima1,
01308         cpl_image   *   ima2)
01309 {
01310     double                  pos1, pos2;
01311 
01312     /* Test entries */
01313     if (ima1 == NULL) return 10000.0;
01314     if (ima2 == NULL) return 10000.0;
01315     
01316     /* Detect the spectra */
01317     if (irplib_spectrum_find_brightest(ima1, 0.0, NO_SHADOW, 0.0, 1,
01318                 &pos1) == -1){
01319         return 10000.0;
01320     }
01321     if (irplib_spectrum_find_brightest(ima2, 0.0, NO_SHADOW, 0.0, 1,
01322                 &pos2) == -1){
01323         return 10000.0;
01324     }
01325     return pos1-pos2;
01326 }
01327 
01328 /*----------------------------------------------------------------------------*/
01334 /*----------------------------------------------------------------------------*/
01335 static cpl_table * naco_spc_jitter_extract(cpl_image * combined)
01336 {
01337     const char          *   fctid = "naco_spc_jitter_extract";
01338     int                     le_dist, ri_dist, le_width, ri_width, spec_pos;
01339     int                     nx, ny;
01340     double                  pos;
01341     int                     le_side, ri_side;
01342     int                     sky_pos[4];
01343     cpl_vector          *   sky;
01344     cpl_vector          *   spec;
01345     cpl_vector          *   wl;
01346     double              *   pspec;
01347     double              *   psky;
01348     double              *   pwl;
01349     cpl_table           *   out;
01350     cpl_bivector        *   toplot;
01351     int                     throw;
01352     int                     res;
01353     int                     i;
01354 
01355     /* Test entries */
01356     if (combined == NULL) return NULL;
01357 
01358     /* Initialise */
01359     nx = cpl_image_get_size_x(combined);
01360     ny = cpl_image_get_size_y(combined);
01361     le_dist = naco_spc_jitter_config.extr_sky_le_dist;
01362     ri_dist = naco_spc_jitter_config.extr_sky_ri_dist;
01363     le_width = naco_spc_jitter_config.extr_sky_le_width;
01364     ri_width = naco_spc_jitter_config.extr_sky_ri_width;
01365     spec_pos = naco_spc_jitter_config.extr_spec_pos;
01366 
01367     /* Detect the spectrum position if not passed */
01368     if (spec_pos < 0) {
01369         if (naco_spc_jitter_config.throws == NULL) {
01370             cpl_msg_error(fctid, "Need a throw value to detect the spectra !!");
01371             return NULL;
01372         }
01373         
01374         for (i=0 ; i<cpl_vector_get_size(naco_spc_jitter_config.throws) ; i++){
01375             throw = (int)cpl_vector_get(naco_spc_jitter_config.throws, i);
01376             if ((res = irplib_spectrum_find_brightest(combined, throw, 
01377                             TWO_SHADOWS, 0.0, 1, &pos)) == 0) break;
01378             if ((res = irplib_spectrum_find_brightest(combined, throw, 
01379                             ONE_SHADOW, 0.0, 1, &pos)) == 0) break;
01380         }
01381         if (res != 0) {
01382             cpl_msg_error(fctid, "Cannot detect the spectrum");
01383             return NULL;
01384         }
01385         spec_pos = (int)pos;
01386         cpl_msg_info(fctid, "Spectrum detected at x = %d", spec_pos);
01387     }
01388 
01389     /* Set the parameters for the extraction */
01390 
01391     /* Spectrum position */
01392     le_side = spec_pos - (int)(naco_spc_jitter_config.extr_spec_width/2);
01393     ri_side = le_side + naco_spc_jitter_config.extr_spec_width;
01394     if ((le_side < 1) || (ri_side > nx)) {
01395         cpl_msg_error(fctid, "Spectrum zone falls outside the image");
01396         return NULL;
01397     }
01398     /* Residual Sky position */
01399     if (le_dist < 0) le_dist = 2 * naco_spc_jitter_config.extr_spec_width;
01400     if (ri_dist < 0) ri_dist = 2 * naco_spc_jitter_config.extr_spec_width;
01401     sky_pos[1] = spec_pos - le_dist;
01402     sky_pos[0] = sky_pos[1] - le_width;
01403     sky_pos[2] = spec_pos + ri_dist;
01404     sky_pos[3] = sky_pos[2] + ri_width;
01405 
01406     /* Get the sky */
01407     sky = cpl_vector_new(nx);
01408     psky = cpl_vector_get_data(sky);
01409     if (((sky_pos[0] < 1) || (le_width == 0)) && 
01410             ((sky_pos[3] <= nx) && (ri_width > 0))) {
01411         for (i=0 ; i<ny ; i++) {
01412             psky[i] = cpl_image_get_median_window(combined, sky_pos[2], i+1,
01413                     sky_pos[3], i+1);
01414         }
01415     } else if (((sky_pos[3] > nx) || (ri_width == 0))
01416             && ((sky_pos[0] > 0) && (le_width > 0))) {
01417         for (i=0 ; i<ny ; i++) {
01418             psky[i] = cpl_image_get_median_window(combined, sky_pos[0], i+1,
01419                     sky_pos[1], i+1);
01420         }
01421     } else if ((le_width != 0) && (ri_width != 0)
01422             && (sky_pos[0] > 0) && (sky_pos[3] <= nx)) {
01423         for (i=0 ; i<ny ; i++) {
01424             psky[i] = cpl_image_get_median_window(combined, sky_pos[2], i+1,
01425                     sky_pos[3], i+1);
01426             psky[i] += cpl_image_get_median_window(combined, sky_pos[0], i+1,
01427                     sky_pos[1], i+1);
01428             psky[i] /= 2.0;
01429         }
01430     } else {
01431         psky[i] = 0.0;
01432     }
01433 
01434     /* Estimate the spectrum */
01435     spec = cpl_vector_new(ny);
01436     pspec = cpl_vector_get_data(spec);
01437     for (i=0 ; i<ny ; i++) {
01438         pspec[i] = cpl_image_get_flux_window(combined, le_side, i+1, ri_side,
01439                 i+1);
01440         pspec[i] -= psky[i] * naco_spc_jitter_config.extr_spec_width;
01441     } 
01442 
01443     /* Get the wavelength */
01444     wl = cpl_vector_new(ny);
01445     pwl = cpl_vector_get_data(wl);
01446     for (i=0 ; i<ny ; i++) {
01447         pwl[i] = i+1;
01448             /*
01449         pwl[i] = naco_spc_jitter_config.wavecal_a0 +
01450             naco_spc_jitter_config.wavecal_a1 * (i+1) +
01451             naco_spc_jitter_config.wavecal_a2 * (i+1) * (i+1) +
01452             naco_spc_jitter_config.wavecal_a3 * (i+1) * (i+1) * (i+1);
01453             */
01454     }
01455 
01456     /* Plot the spectrum if requested */
01457     if (naco_spc_jitter_config.display) {
01458         toplot = cpl_bivector_wrap_vectors(wl, spec);
01459         cpl_plot_bivector(NULL, "t 'Spectrum' w lines", NULL, toplot);
01460         cpl_bivector_unwrap_vectors(toplot);
01461         toplot = cpl_bivector_wrap_vectors(wl, sky);
01462         cpl_plot_bivector(NULL, "t 'Sky' w lines", NULL, toplot);
01463         cpl_bivector_unwrap_vectors(toplot);
01464     }
01465     
01466     /* Create and fill the output table */
01467     out = cpl_table_new(nx);
01468     cpl_table_new_column(out, "Y_coordinate", CPL_TYPE_DOUBLE);
01469     cpl_table_new_column(out, "Extracted_spectrum_value", CPL_TYPE_DOUBLE);
01470     cpl_table_new_column(out, "Sky_spectrum", CPL_TYPE_DOUBLE);
01471     for (i=0 ; i<nx ; i++) {
01472         cpl_table_set_double(out, "Y_coordinate", i, pwl[i]);
01473         cpl_table_set_double(out, "Extracted_spectrum_value", i, pspec[i]);
01474         cpl_table_set_double(out, "Sky_spectrum", i, psky[i]);
01475     }
01476     cpl_vector_delete(wl);
01477     cpl_vector_delete(spec);
01478     cpl_vector_delete(sky);
01479     return out;
01480 }
01481 
01482 /*----------------------------------------------------------------------------*/
01491 /*----------------------------------------------------------------------------*/
01492 static int naco_spc_jitter_save(
01493         const cpl_image     *   ima,
01494         const cpl_table     *   tab,
01495         cpl_parameterlist   *   parlist,
01496         cpl_frameset        *   set)
01497 {
01498     const char          *   fctid = "naco_spc_jitter_save";
01499     char                    name_o[512];
01500     FILE                *   paf;
01501     cpl_propertylist    *   plist;
01502     cpl_propertylist    *   qclist;
01503     cpl_propertylist    *   paflist;
01504     cpl_frame           *   ref_frame;
01505     cpl_frame           *   product_frame;
01506     char                    qc_str[128];
01507     int                     i;
01508 
01509     /* Get the reference frame */
01510     ref_frame = cpl_frameset_get_frame(set, 0);
01511 
01512     /********************/
01513     /* Write the image  */
01514     /********************/
01515     /* Set the file name */
01516     sprintf(name_o, "naco_spc_jitter_combined.fits");
01517     cpl_msg_info(fctid, "Writing %s" , name_o);
01518 
01519     /* Get FITS header from reference file */
01520     if ((plist=cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
01521                     0)) == NULL) {
01522         cpl_msg_error(fctid, "getting header from reference frame");
01523         return -1;
01524     }
01525     
01526     /* Get the keywords for the paf file */
01527     paflist = cpl_propertylist_new();
01528     cpl_propertylist_copy_property_regexp(paflist, plist, 
01529         "^(ARCFILE|MJD-OBS|INSTRUME|ESO TPL ID|ESO TPL NEXP|ESO DPR CATG|"
01530         "ESO DPR TECH|ESO DPR TYPE|DATE-OBS|ESO INS GRAT NAME|"
01531         "ESO INS GRAT WLEN|ESO INS OPTI1 ID|ESO OBS ID|ESO OBS TARG NAME)$", 0);
01532     
01533     /* Create product frame */
01534     product_frame = cpl_frame_new();
01535     cpl_frame_set_filename(product_frame, name_o);
01536     cpl_frame_set_tag(product_frame, NACO_SPC_JITTER_COMB);
01537     cpl_frame_set_type(product_frame, CPL_FRAME_TYPE_IMAGE);
01538     cpl_frame_set_group(product_frame, CPL_FRAME_GROUP_PRODUCT);
01539     cpl_frame_set_level(product_frame, CPL_FRAME_LEVEL_FINAL);
01540 
01541     /* Add DataFlow keywords */
01542     if (cpl_dfs_setup_product_header(plist, product_frame, set, parlist,
01543             "naco_spc_jitter", PACKAGE "/" PACKAGE_VERSION,
01544             "PRO-1.15") != CPL_ERROR_NONE) {
01545         cpl_msg_warning(fctid, "Problem in the product DFS-compliance");
01546         cpl_error_reset();
01547     }
01548 
01549     /* Add QC parameters */
01550     cpl_propertylist_append_double(plist, "ESO QC DISPCO1",
01551             naco_spc_jitter_config.wavecal_a0);
01552     cpl_propertylist_append_double(plist, "ESO QC DISPCO2",
01553             naco_spc_jitter_config.wavecal_a1);
01554     cpl_propertylist_append_double(plist, "ESO QC DISPCO3",
01555             naco_spc_jitter_config.wavecal_a2);
01556     cpl_propertylist_append_double(plist, "ESO QC DISPCO4",
01557             naco_spc_jitter_config.wavecal_a3);
01558     cpl_propertylist_append_double(plist, "ESO QC WLEN",
01559             naco_spc_jitter_config.wavecal_a0 +
01560             naco_spc_jitter_config.wavecal_a1 * 512 +
01561             naco_spc_jitter_config.wavecal_a2 * 512 * 512 +
01562             naco_spc_jitter_config.wavecal_a3 * 512 * 512 * 512);
01563     cpl_propertylist_append_double(plist, "ESO QC DISP XCORR",
01564             naco_spc_jitter_config.wavecal_cc);
01565     if (naco_spc_jitter_config.wavecal_out == 0) {
01566         cpl_propertylist_append_string(plist, "ESO QC WLMETHOD",
01567                 "physical model");
01568     } else if (naco_spc_jitter_config.wavecal_out == 1) {
01569         cpl_propertylist_append_string(plist, "ESO QC WLMETHOD",
01570                 "sky lines");
01571     } else if (naco_spc_jitter_config.wavecal_out == 2) {
01572         cpl_propertylist_append_string(plist, "ESO QC WLMETHOD",
01573                 "arc file");
01574     }
01575     
01576     /* Get the QC params in qclist and keys for paf in paflist */
01577     qclist = cpl_propertylist_new();
01578     cpl_propertylist_copy_property_regexp(qclist, plist, "ESO QC", 0);
01579    
01580     /* Change WCS keywords to the computed wavelength solution */
01581     cpl_propertylist_update_double(plist, "CRVAL1",
01582             naco_spc_jitter_config.wavecal_a0);
01583     cpl_propertylist_update_double(plist, "CRVAL2", 1.0);
01584     cpl_propertylist_update_double(plist, "CRPIX1", 1.0);
01585     cpl_propertylist_update_double(plist, "CRPIX2", 1.0);
01586     cpl_propertylist_update_double(plist, "CDELT1", 
01587             naco_spc_jitter_config.wavecal_a1);
01588     cpl_propertylist_update_double(plist, "CDELT2", 1.0);
01589     cpl_propertylist_update_string(plist, "CTYPE1", "LINEAR");
01590     cpl_propertylist_update_string(plist, "CTYPE2", "LINEAR");
01591     cpl_propertylist_insert_after_double(plist, "CTYPE2", "CD1_1",
01592             naco_spc_jitter_config.wavecal_a1);
01593     cpl_propertylist_insert_after_double(plist, "CD1_1", "CD1_2", 1.0);
01594 
01595     /* Save the file */
01596     cpl_image_save(ima, name_o, CPL_BPP_DEFAULT, plist, CPL_IO_DEFAULT);
01597     cpl_propertylist_delete(plist);
01598 
01599     /* Log the saved file in the input frameset */
01600     cpl_frameset_insert(set, product_frame);
01601 
01602     if (tab != NULL) {
01603         /********************/
01604         /* Write the table  */
01605         /********************/
01606         /* Set the file name */
01607         sprintf(name_o, "naco_spc_jitter_extracted.tfits");
01608         cpl_msg_info(fctid, "Writing %s" , name_o);
01609 
01610         /* Get FITS header from reference file */
01611         if ((plist=cpl_propertylist_load(cpl_frame_get_filename(ref_frame),
01612                         0)) == NULL) {
01613             cpl_msg_error(fctid, "getting header from reference frame");
01614             cpl_propertylist_delete(paflist);
01615             cpl_propertylist_delete(qclist);
01616             return -1;
01617         }
01618         
01619         /* Create product frame */
01620         product_frame = cpl_frame_new();
01621         cpl_frame_set_filename(product_frame, name_o);
01622         cpl_frame_set_tag(product_frame, NACO_SPC_JITTER_EXTR);
01623         cpl_frame_set_type(product_frame, CPL_FRAME_TYPE_TABLE);
01624         cpl_frame_set_group(product_frame, CPL_FRAME_GROUP_PRODUCT);
01625         cpl_frame_set_level(product_frame, CPL_FRAME_LEVEL_FINAL);
01626 
01627         /* Add DataFlow keywords */
01628         if (cpl_dfs_setup_product_header(plist, product_frame, set, parlist,
01629                 "naco_spc_jitter", PACKAGE "/" PACKAGE_VERSION,
01630                 "PRO-1.15") != CPL_ERROR_NONE){
01631             cpl_msg_warning(fctid, "Problem in the product DFS-compliance");
01632             cpl_error_reset();
01633         }
01634 
01635         /* Save the file */
01636         cpl_table_save(tab, plist, NULL, name_o, CPL_IO_DEFAULT);
01637         cpl_propertylist_delete(plist);
01638 
01639         /* Log the saved file in the input frameset */
01640         cpl_frameset_insert(set, product_frame);
01641     }
01642 
01643     /**********************************/
01644     /* THE PAF FILE FOR QC PARAMETERS */
01645     /**********************************/
01646 
01647     /* Set the file name */
01648     sprintf(name_o, "naco_spc_jitter.paf");
01649     cpl_msg_info(fctid, "Writing %s" , name_o);
01650 
01651     /* Create the default PAF header */
01652     if ((paf = irplib_paf_print_header(name_o,
01653                     "NACO/naco_spc_jitter",
01654                     "QC file")) == NULL) {
01655         cpl_msg_error(fctid, "cannot open file [%s] for output", name_o);
01656         cpl_propertylist_delete(paflist);
01657         cpl_propertylist_delete(qclist);
01658         return -1;
01659     }
01660 
01661     /* Dump the keywords in PAF  */
01662     if (irplib_propertylist_dump_paf(paflist, paf) != CPL_ERROR_NONE) {
01663         cpl_msg_error(fctid, "cannot dump the keys in PAF file");
01664         cpl_propertylist_delete(paflist);
01665         cpl_propertylist_delete(qclist);
01666         fclose(paf);
01667         return -1;
01668     }
01669     cpl_propertylist_delete(paflist);
01670 
01671     /* Dump the QC keywords in PAF  */
01672     if (irplib_propertylist_dump_paf(qclist, paf) != CPL_ERROR_NONE) {
01673         cpl_msg_error(fctid, "cannot dump the QC keys in PAF file");
01674         cpl_propertylist_delete(qclist);
01675         fclose(paf);
01676         return -1;
01677     }
01678     cpl_propertylist_delete(qclist);
01679     fclose(paf);
01680 
01681     /* Return */
01682     return  0;
01683 }
01684 
01685 /*----------------------------------------------------------------------------*/
01693 /*----------------------------------------------------------------------------*/
01694 static int off_comp(double off1, double off2, double thresh)
01695 {
01696     if (((off1>thresh) && (off2<thresh)) || ((off1<thresh) && (off2>thresh)))
01697         return 1;
01698     else return 0;
01699 }

Generated on Wed Mar 9 15:46:17 2011 for NACO Pipeline Reference Manual by  doxygen 1.5.8