naco_spc_jitter.c

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

Generated on Fri Jul 3 11:23:58 2009 for NACO Pipeline Reference Manual by  doxygen 1.5.8