 /*                                                                            *
 *   This file is part of the ESO X-shooter Pipeline                          *
 *   Copyright (C) 2006 European Southern Observatory                         *
 *                                                                            *
 *   This library is free software; you can redistribute it and/or modify     *
 *   it under the terms of the GNU General Public License as published by     *
 *   the Free Software Foundation; either version 2 of the License, or        *
 *   (at your option) any later version.                                      *
 *                                                                            *
 *   This program is distributed in the hope that it will be useful,          *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of           *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
 *   GNU General Public License for more details.                             *
 *                                                                            *
 *   You should have received a copy of the GNU General Public License        *
 *   along with this program; if not, write to the Free Software              *
 *   Foundation, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA     *
 *                                                                           */

/*
 * $Author: amodigli $
 * $Date: 2012-12-18 14:12:51 $
 * $Revision: 1.25 $
 * $Name: not supported by cvs2svn $
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/*--------------------------------------------------------------------------*/
/**
 * @defgroup xsh_cfg_recover   xsh_cfg_recover
 * @ingroup recipes
 *
 * This recipe is used to startup the data reduction chain.
 * It requires an input frame where a single pinhole is illuminated by a ThAr
 * lamp, reference line list, a model configuration parameter file,
 * It calculates the geometry of the spectral format from a physical 
 * model corresponding to the given model configuration file and the line list,
 * and compares the predicted line positions to the ones on the calibration 
 * frame
 * See man-page for details.
 */
/*--------------------------------------------------------------------------*/
/**@{*/

/*---------------------------------------------------------------------------
  Includes
  ---------------------------------------------------------------------------*/


/* DRL steps */

/* Error handling */
#include <xsh_error.h>
/* Utility fonctions */
#include <xsh_utils.h>
#include <xsh_msg.h>

//#include <xsh_data_instrument.h> //Needed?
/* DFS functions */
#include <xsh_dfs.h>
/* DRL functions */
//#include <xsh_data_order.h> //Needed?
#include <xsh_drl.h>
#include <xsh_pfits.h>

//#include <xsh_data_the_map.h> //Needed?

/* Library */
#include <cpl.h>
#include <math.h>
//#include <xsh_data_the_map.h>
#include <xsh_data_resid_tab.h>
#include <xsh_utils_table.h>

#include <xsh_model_kernel.h>
#include <xsh_model_utils.h>
#include <xsh_model_io.h>
#include <xsh_spectrum.h>
#include<xsh_model_utils.h>
#include <xsh_fit.h>
//#include <xsh_pfits.h>
#include <stdlib.h>

/*---------------------------------------------------------------------------
  Defines
  ---------------------------------------------------------------------------*/

#define RECIPE_ID "xsh_cfg_recover"
#define RECIPE_AUTHOR "A. Modigliani, P. Bristow"
#define RECIPE_CONTACT "amodigli@eso.org"

#define XSH_THE_TAB_SUB_VIS "XSH_THE_TAB_VIS"
#define XSH_THE_TAB_SUB_UVB "XSH_THE_TAB_UVB"
#define XSH_THE_TAB_SUB_NIR "XSH_THE_TAB_NIR"

#define XSH_STARTUP_TABLE_COLNAME_X "X"


#define XSH_ORDPOS_POL_DIM_MAX 4
/*---------------------------------------------------------------------------
  Functions prototypes
  ---------------------------------------------------------------------------*/

/*
 *   Plugin initalization, execute and cleanup handlers
 */

static cpl_error_code
xsh_cfg_recover_prepare_pm_set(cpl_table* tab_pat,
			    cpl_table* tab_dat,
                            cpl_parameterlist* parameters,
			    cpl_matrix** mat_pat,
                            cpl_matrix** mat_dat,
                            int* use_pat, 
                            int* use_dat);



static cpl_error_code
xsh_cfg_recover_model_THE_create(cpl_frame* config_frame,
                             xsh_instrument* instrument,
                             cpl_frame* wave_list,
                             cpl_frame** THE1, cpl_frame** THE9);


static cpl_error_code
xsh_cfg_recover_pattern_match(cpl_parameterlist* parameters,
                          cpl_matrix* mat_gue,
                          cpl_matrix* mat_dat,
                          int use_pattern,
                          int use_data,
			  int debug_level);



static cpl_error_code 
xsh_cfg_recover_guess_tab_corr_by_user(cpl_parameterlist* parameters,
                                   cpl_frame** model_xy_gue);


static cpl_error_code
xsh_cfg_recover_measure_line_xy_fit(cpl_frame* raw_frm,
                                cpl_parameterlist* parameters,
                                cpl_frame** model_xy_gue, 
                                int debug_level);


static cpl_error_code
xsh_cfg_recover_add_peaks_xpos(cpl_frame* order_tab_centr,
                           xsh_instrument* instr,
                           cpl_table** tab_xy_peaks);



static cpl_table* 
xsh_cfg_recover_remove_blends(cpl_table* tab_xy_guess,
                          cpl_table* tab_xy_peaks_sel,
                          const int thresh_x,
                          const int thresh_y);


static cpl_table* 
xsh_cfg_recover_measure_tab_xy_peaks(cpl_image* ima_ext,
				 cpl_parameterlist* parameters);

static cpl_table*
xsh_cfg_recover_select_peaks(cpl_table* tab_xy_guess,
                         cpl_table* tab_xy_peaks,
                         const double factor);

static cpl_error_code
xsh_cfg_recover_extend_xy_pos_frm(cpl_frame** frm,xsh_instrument* instrument);

static cpl_error_code
xsh_cfg_recover_measure_line_xy(cpl_frame* frame,
                            xsh_instrument* inst,
                            cpl_frame* order_tab_centr,
                            cpl_parameterlist* parameters,
                            const char* method,
			    cpl_frame* model_config,
                            cpl_frame** guess,
                            int debug_level);

static cpl_error_code
xsh_cfg_recover_gen_xyg(
		    cpl_table  *   lines_tab,
		    struct xs_3* p_xs_3_config,
		    xsh_instrument* inst,int pre_scan,
		    cpl_table  **  lines_gue);


static cpl_frame* 
xsh_cfg_recover_gen_xyg_frame(
			  cpl_frame *   wave_list,
			  cpl_frame *  config_frame,
			  xsh_instrument* instr,int prescan);


static cpl_image* 
xsh_cfg_recover_linear_ext(cpl_frame* raw_frm, 
                       cpl_frame* order_tab_centr,
                       xsh_instrument* instr, 
                       const int slit,
                       const double thresh_min);

static cpl_error_code
xsh_cfg_recover_guess_tab_corr_by_ordpos(xsh_instrument* instr,
                                     cpl_frame* order_tab_centr,
                                     cpl_frame** model_xy_gue);




static int xsh_cfg_recover_create(cpl_plugin *);
static int xsh_cfg_recover_exec(cpl_plugin *);
static int xsh_cfg_recover_destroy(cpl_plugin *);

/* The actual executor function */
static int 
xsh_cfg_recover_last_step(cpl_parameterlist* parameters, 
                      cpl_frameset* frameset,
                      xsh_instrument* instrument,
                      cpl_frameset* raws,
                      cpl_frameset* calib);

static cpl_error_code 
xsh_cfg_recover_driver(cpl_parameterlist* parameters,
                   cpl_frameset* frameset);

/*---------------------------------------------------------------------------
  Static variables
  ---------------------------------------------------------------------------*/
static char xsh_cfg_recover_description_short[] =
  "Optimizes a model configuration to match data taken after a major format change";

/*
    - [UVB,OPTIONAL-required if trace-orders=TRUE] \n\
      Two RAW frames (Format = RAW, Tag = ORDERDEF_QTH_arm,ORDERDEF_D2_arm)\n\
    - [VIS,OPTIONAL-required if trace-orders=TRUE] \n\
      A RAW frame (Format = RAW, Tag = ORDERDEF_arm)\n\
    - [NIR,OPTIONAL-required if trace-orders=TRUE] \n\
      Two RAW frames (Format = RAW, Tag = ORDERDEF_arm_ON, ORDERDEF_arm_OFF)\n\
    - [OPTIONAL-Required if trace-orders=TRUE] \n\
     A spectral format table (Format = TABLE, Tag = SPECTRAL_FORMAT_TAB_arm)\n\
*/
static char xsh_cfg_recover_description[] =
  "This recipe creates a wavelength solution and an order table.\n\
  Input Frames :\n\
    - [UVB, VIS] A RAW frame (Format = RAW, Tag = FMTCHK_arm)\n\
    - [NIR] Two RAW frames (Format = RAW, Tag = FMTCHK_arm_ON,FMTCHK_arm_OFF)\n\
    - The old model cfg table (Format = TABLE, Tag = XSH_MOD_CFG_TAB_arm)\n\
    - A ref. line list. The model computes corresponding positions \n\
      (Format = TABLE, Tag = ARC_LINE_LIST_arm)\n\
    - [UVB,VIS,OPTIONAL] A master bias (Format = PRE, Tag = MASTER_BIAS_arm)\n\
    - [UVB,VIS,OPTIONAL] A master dark (Format = PRE, Tag = MASTER_DARK_arm)\n\
    - [OPTIONAL-Required if method=pm,peaks] \n\
     An order table (Format = TABLE, Tag = ORDER_TAB_CENTR_arm)\n\
    - [OPTIONAL-Required if first-anneal=TRUE] \n\
      A table with measured line positions (Format = TABLE, Tag = XSH_MEASCOORD_arm)\n\
  Products : \n\
    - if first-anneal=FALSE & last-step=FALSE\n\
      nothing\n\
    - if first-anneal=TRUE & last-step=FALSE\n\
      an optimized model configuration, PRO.CATG=XSH_MOD_CFG_arm\n\
    - if last-step=TRUE\n\
      an optimized model configuration, PRO.CATG=XSH_MOD_FAN_arm\n\
      an optimized model configuration, PRO.CATG=XSH_MOD_CFG_OPT_arm\n\
      an quality control table, PRO.CATG=MODEL_GUESS_XY_arm\n\
      the model theoretical map corresponding to the optimized model config,\n\
      PRO.CATG=THEO_TAB_MULT_arm, THEO_TAB_IFU_arm, and THEO_TAB_SING_arm\n\
      \n";



/*---------------------------------------------------------------------------
  Functions code
  ---------------------------------------------------------------------------*/


/*--------------------------------------------------------------------------*/
/**
   @brief    Build the list of available plugins, for this module.
   @param    list    the plugin list
   @return   0 if everything is ok, -1 otherwise

   Create the recipe instance and make it available to the application using 
   the interface. This function is exported.
*/
/*--------------------------------------------------------------------------*/

int cpl_plugin_get_info(cpl_pluginlist *list) {
  cpl_recipe *recipe = NULL;
  cpl_plugin *plugin = NULL;

  recipe = cpl_calloc(1, sizeof(*recipe));
  if ( recipe == NULL ){
    return -1;
  }

  plugin = &recipe->interface ;

  cpl_plugin_init(plugin,
		  CPL_PLUGIN_API,                   /* Plugin API */
		  XSH_BINARY_VERSION,            /* Plugin version */
		  CPL_PLUGIN_TYPE_RECIPE,           /* Plugin type */
		  RECIPE_ID,                        /* Plugin name */
		  xsh_cfg_recover_description_short,      /* Short help */
		  xsh_cfg_recover_description,            /* Detailed help */
		  RECIPE_AUTHOR,                    /* Author name */
		  RECIPE_CONTACT,                   /* Contact address */
		  xsh_get_license(),                /* Copyright */
		  xsh_cfg_recover_create,
		  xsh_cfg_recover_exec,
		  xsh_cfg_recover_destroy);

  cpl_pluginlist_append(list, plugin);

  return (cpl_error_get_code() != CPL_ERROR_NONE);
}



/*---------------------------------------------------------------------------*/
/**   p = cpl_parameter_new_enum("xsh.xsh_model_compute.arm",
                              CPL_TYPE_STRING,
                              "Arm setting: ",
                              "xsh.xsh_model_compute",
                              "vis",
                              3,"uvb","vis","nir");

   cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"arm");
   cpl_parameterlist_append(recipe->parameters, p);


   @brief    Setup the recipe options
   @param    plugin  the plugin
   @return   0 if everything is ok

   Create the recipe instance and make it available to the application using 
   the interface.

*/
/*--------------------------------------------------------------------------*/
static int xsh_cfg_recover_create(cpl_plugin * plugin)
{
  cpl_recipe      * recipe ;
  cpl_parameter   * p ;
/*
   xsh_detect_continuum_param param = { 10, 2, 5,
				       DETECT_CONTINUUM_POLYNOMIAL_DEGREE,
				       1, 0.,
				        20, 50, 140., 2., 0 } ;
*/
  /* Reset library state */
  xsh_init();


  /* Check that the plugin is part of a valid recipe */
  if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
    recipe = (cpl_recipe *)plugin ;
  else return -1 ;

  /* Create the parameters list in the cpl_recipe object */
  recipe->parameters = cpl_parameterlist_new() ; 

  assure( recipe->parameters != NULL,
	  CPL_ERROR_ILLEGAL_OUTPUT,
	  "Memory allocation failed!");

  /* Set generic parameters (common to all recipes) xsh_parameters_decode_bp(RECIPE_ID,recipe->parameters,-1);*/
  check( xsh_parameters_generic( RECIPE_ID, recipe->parameters ) ) ;
  xsh_parameters_decode_bp(RECIPE_ID,recipe->parameters,-1);

  // Set startup parameters
  /* Fill the parameters list */
  p = cpl_parameter_new_value("xsh.xsh_cfg_recover.first-anneal",
			      CPL_TYPE_BOOL,
			      "Run first annealing (TRUE) or not (FALSE)"
                              "See recipe man-page % Input frames",
			      "xsh.xsh_cfg_recover",CPL_FALSE);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"first-anneal");
  cpl_parameterlist_append(recipe->parameters,p);


  //Set first_anneal params

   p = cpl_parameter_new_enum("xsh.xsh_model_compute.arm",
                              CPL_TYPE_STRING,
                              "Arm setting: ",
                              "xsh.xsh_model_compute",
                              "vis",
                              3,"uvb","vis","nir");

   cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"arm");
   cpl_parameterlist_append(recipe->parameters, p);


   p = cpl_parameter_new_value("xsh.xsh_model_compute.name_i",
                              CPL_TYPE_STRING,
                              "Filename with wavelength,x,y,order: ",
                              "xsh.xsh_model_compute",
                              "line_xy_ord.txt");

   cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,"name_i");
   cpl_parameterlist_append(recipe->parameters, p);


   p = cpl_parameter_new_value("xsh.xsh_model_compute.niter",
			      CPL_TYPE_INT,"No of iterations for first anneal",
			      "xsh.xsh_model_compute", 100000);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"niter");
  cpl_parameterlist_append(recipe->parameters,p);

   p = cpl_parameter_new_value("xsh.xsh_model_compute.coord_frame",
			      CPL_TYPE_INT,"Co-ordinate frame for centroids (0=raw,1=pre)",
			      "xsh.xsh_model_compute", 1);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"coord_frame");
  cpl_parameterlist_append(recipe->parameters,p);

/*
  p = cpl_parameter_new_value("xsh.xsh_cfg_recover.trace-orders",
			      CPL_TYPE_BOOL,
			      "Run order trace (TRUE) or not (FALSE)"
                              "If FALSE you must provide ORDER_TAB_CENTRE_arm"
                              "See recipe man-page % Input frames",
			      "xsh.xsh_cfg_recover",CPL_FALSE);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"trace-orders");
  cpl_parameterlist_append(recipe->parameters,p);


  // Set orderpos parameters
  check(xsh_parameters_detect_continuum_create(RECIPE_ID,
					       recipe->parameters,
					       param));
  check( xsh_parameters_clipping_dcn_create( RECIPE_ID,
					     recipe->parameters ) ) ;

*/

  /* Fill the parameters list */
  p = cpl_parameter_new_value("xsh.xsh_cfg_recover.last-step",
			      CPL_TYPE_BOOL,
			      "Run last step (TRUE) or not (FALSE)"
                              "See recipe man-page % Input frames",
			      "xsh.xsh_cfg_recover",CPL_FALSE);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"last-step");
  cpl_parameterlist_append(recipe->parameters,p);

  /* Fill the parameters list */
  p = cpl_parameter_new_value("xsh.xsh_cfg_recover.plot",
			      CPL_TYPE_BOOL,
			      "Display plot (TRUE) or not (FALSE)",
			      "xsh.xsh_cfg_recover",CPL_FALSE);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"plot");
  cpl_parameterlist_append(recipe->parameters,p);

  p = cpl_parameter_new_value("xsh.xsh_cfg_recover.ima_thresh_min",
			      CPL_TYPE_DOUBLE,
			      "Min thresh raw image.",
			      "xsh.xsh_cfg_recover", 40.);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"ima_tresh_min");
  cpl_parameterlist_append(recipe->parameters,p);


  p = cpl_parameter_new_value("xsh.xsh_cfg_recover.cor_prescan",
			      CPL_TYPE_BOOL,"Correct for prescan",
			      "xsh.xsh_cfg_recover", FALSE);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"cor_prescan");
  cpl_parameterlist_append(recipe->parameters,p);


  p = cpl_parameter_new_enum("xsh.xsh_cfg_recover.method",
			     CPL_TYPE_STRING,
			     "Model predictions correction method. "
			     "safefit: safe fit"
			     "gfit: 2D Gaussian line fit"
			     "peaks: line peaks detection"
			     "pm: line peaks detection & pattern match",
			     "xsh.xsh_cfg_recover", 
			     "safefit", 4,
                             "safefit","gfit","peaks", "pm");
//                             "peaks", "gfit", "pbrfit", "safefit", "pm");
 //Temporarily suppressed methods 


  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"method");
  cpl_parameterlist_append(recipe->parameters,p);


  p = cpl_parameter_new_value("xsh.xsh_cfg_recover.offx",
			      CPL_TYPE_DOUBLE,"X offset to model predictions",
			      "xsh.xsh_cfg_recover", 0.);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"offx");
  cpl_parameterlist_append(recipe->parameters,p);


  p = cpl_parameter_new_value("xsh.xsh_cfg_recover.offy",
			      CPL_TYPE_DOUBLE,"Y offset to model predictions",
			      "xsh.xsh_cfg_recover", 0.);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"offy");
  cpl_parameterlist_append(recipe->parameters,p);



  p = cpl_parameter_new_value("xsh.xsh_cfg_recover.slit",
			      CPL_TYPE_INT,"Extraction slit",
			      "xsh.xsh_cfg_recover", 5);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"slit");
  cpl_parameterlist_append(recipe->parameters,p);


  /*
    p = cpl_parameter_new_value("xsh.xsh_cfg_recover.gfit_box_sx",
    CPL_TYPE_INT,"2D Gauss fit X search box size"
    "for lines on actual frame",
    "xsh.xsh_cfg_recover", 5);

    cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"gfit_box_sx");
    cpl_parameterlist_append(recipe->parameters,p);
  */


  p = cpl_parameter_new_value("xsh.xsh_cfg_recover.gfit_box_sy",
			      CPL_TYPE_INT,"Gauss fit Y search box size "
			      "for lines on actual frame",
			      "xsh.xsh_cfg_recover", 20);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"gfit_box_sy");
  cpl_parameterlist_append(recipe->parameters,p);


  p = cpl_parameter_new_value("xsh.xsh_cfg_recover.peak_line_fwhm",
			      CPL_TYPE_INT,
			      "The FWHM used in line convolution, "
			      "in pixel units",
			      "xsh.xsh_cfg_recover", 4);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"peak_line_fwhm");
  cpl_parameterlist_append(recipe->parameters,p);


  p = cpl_parameter_new_value("xsh.xsh_cfg_recover.peak_kappa",
			      CPL_TYPE_DOUBLE,
			      "The kappa value, used to identify line peaks "
			      "if max>kappa*stdev+median, max is a valid peak "
			      "where max, stdev,median are computed on the "
			      "extracted spectrum",  
			      "xsh.xsh_cfg_recover", 5.);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"peak_kappa");
  cpl_parameterlist_append(recipe->parameters,p);




  p = cpl_parameter_new_value("xsh.xsh_cfg_recover.peak_factor",
			      CPL_TYPE_DOUBLE,
			      "Relative Intensity threshold factor "
			      "for line peaks detection",
			      "xsh.xsh_cfg_recover", 10.);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"peak_factor");
  cpl_parameterlist_append(recipe->parameters,p);


  p = cpl_parameter_new_value("xsh.xsh_cfg_recover.peak_match_x",
			      CPL_TYPE_INT,"Radii for line peaks matches",
			      "xsh.xsh_cfg_recover", 10);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"peak_match_x");
  cpl_parameterlist_append(recipe->parameters,p);


  p = cpl_parameter_new_value("xsh.xsh_cfg_recover.peak_match_y",
			      CPL_TYPE_INT,"Radii for line peaks matches",
			      "xsh.xsh_cfg_recover", 20);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"peak_match_y");
  cpl_parameterlist_append(recipe->parameters,p);


  p = cpl_parameter_new_value("xsh.xsh_cfg_recover.pm_ord_sel",
			      CPL_TYPE_INT,
			      "From guess line and peaks positions "
			      "are extracted the ones in the range "
			      "[ord_min,ord_min+pm_ord_sel] ",
			      "xsh.xsh_cfg_recover", 1);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"pm_ord_sel");
  cpl_parameterlist_append(recipe->parameters,p);


  p = cpl_parameter_new_value("xsh.xsh_cfg_recover.pm_radius",
			      CPL_TYPE_DOUBLE,
			      "Search radius applied in final pattern "
			      "matching (data units).",
			      "xsh.xsh_cfg_recover", 20.);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"pm_radius");
  cpl_parameterlist_append(recipe->parameters,p);

  p = cpl_parameter_new_range("xsh.xsh_cfg_recover.pm_tolerance",
			      CPL_TYPE_DOUBLE,
			      "Max relative difference of angles and scales "
			      "from their median value for match acceptance.",
			      "xsh.xsh_cfg_recover", 0.1,0.001,0.5);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"pm_tolerance");
  cpl_parameterlist_append(recipe->parameters,p);



  p = cpl_parameter_new_value("xsh.xsh_cfg_recover.anneal_niter",
			      CPL_TYPE_INT,"Simulated annealing iterations",
			      "xsh.xsh_cfg_recover", 1000);

  cpl_parameter_set_alias(p,CPL_PARAMETER_MODE_CLI,"anneal_niter");
  cpl_parameterlist_append(recipe->parameters,p);
  


  /* Return */
 cleanup:
  return 0;
}



/*--------------------------------------------------------------------------*/
/**
   @brief    Execute the plugin instance given by the interface
   @param    plugin  the plugin
   @return   0 if everything is ok
*/
/*--------------------------------------------------------------------------*/

static int xsh_cfg_recover_exec(cpl_plugin *plugin) {
  cpl_recipe *recipe = NULL;
  int recipe_status=0;
  cpl_errorstate initial_errorstate = cpl_errorstate_get();   

  /* Check parameter */
  assure( plugin != NULL, CPL_ERROR_NULL_INPUT, "Null plugin" );

  /* Get the recipe out of the plugin */
  assure( cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE,
	  CPL_ERROR_TYPE_MISMATCH, "Plugin is not a recipe");

  recipe = (cpl_recipe *)plugin;

  /* Check recipe */
  check(xsh_cfg_recover_driver(recipe->parameters, recipe->frames));

  if (!cpl_errorstate_is_equal(initial_errorstate)) {                    
    /* Dump the error history since recipe execution start.            
       At this point the recipe cannot recover from the error */ 
     xsh_free_parameterlist(&recipe->parameters);
    cpl_errorstate_dump(initial_errorstate, CPL_FALSE, NULL);          
  }         

  cleanup:
  return recipe_status;    

}

/*--------------------------------------------------------------------------*/
/**
   @brief    Destroy what has been created by the 'create' function
   @param    plugin  the plugin
   @return   0 if everything is ok
*/
/*--------------------------------------------------------------------------*/
static int xsh_cfg_recover_destroy(cpl_plugin *plugin)
{
  cpl_recipe *recipe = NULL;

  /* Check parameter */
  assure( plugin != NULL, CPL_ERROR_NULL_INPUT, "Null plugin" );

  /* Get the recipe out of the plugin */
  assure( cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE,
	  CPL_ERROR_TYPE_MISMATCH, "Plugin is not a recipe");

  recipe = (cpl_recipe *)plugin;

  xsh_free_parameterlist(&recipe->parameters);

 cleanup:
  if (cpl_error_get_code() != CPL_ERROR_NONE)
    {
      return 1;
    }
  else
    {
      return 0;
    }
}

static cpl_error_code 
xsh_cfg_recover_driver(cpl_parameterlist* parameters,
			      cpl_frameset* frameset)
{

  const char* recipe_tags[1] = {XSH_FMTCHK};
  int recipe_tags_size = 1;

  cpl_parameter* p=NULL;
  int first_anneal=0;
  //int trace_order=0;
  int last_step=0;
  cpl_frameset* raws=NULL;
  cpl_frameset* calib=NULL;
  xsh_instrument* instrument=NULL;

/*
  check(p = cpl_parameterlist_find(parameters,
                                   "xsh.xsh_cfg_recover.trace-orders"));
  check(trace_order = cpl_parameter_get_bool(p));
*/

  check(p = cpl_parameterlist_find(parameters,
                                   "xsh.xsh_cfg_recover.first-anneal"));
  check(first_anneal = cpl_parameter_get_bool(p));


  check(p = cpl_parameterlist_find(parameters,
                                   "xsh.xsh_cfg_recover.last-step"));
  check(last_step = cpl_parameter_get_bool(p));

/*
  check( xsh_begin(frameset,parameters,&instrument, &raws, &calib,
                   "XSH_FAN",RECIPE_ID, XSH_BINARY_VERSION,
                    xsh_first_anneal_description_short ) ) ;
*/

  check( xsh_begin( frameset, parameters, &instrument, &raws, &calib,
		    recipe_tags, recipe_tags_size, RECIPE_ID, 
                    XSH_BINARY_VERSION,
		    xsh_cfg_recover_description_short ) ) ;

  if(first_anneal) {
     check_msg(xsh_model_first_anneal(parameters,frameset),
               "error_performing first anneal");
  }

/*
  if(trace_order) {
     check_msg(xsh_orderpos(recipe->parameters, recipe->frames),
               "Error performing order tracing");
  }
*/

  if(last_step) {
     check_msg(xsh_cfg_recover_last_step(parameters,frameset,
                                                     instrument,raws,calib),
            "error performing startup");
  }

  xsh_free_frameset(&raws);
  xsh_free_frameset(&calib);

 cleanup:
  xsh_free_frameset(&raws);
  xsh_free_frameset(&calib);
  xsh_instrument_free(&instrument);

  return cpl_error_get_code();

}


/*--------------------------------------------------------------------------*/
/**
   @brief    Interpret the command line options and execute the data processing
   @param    parameters     the parameters list
   @param    frameset   the frames list

   In case of failure the cpl_error_code is set.
*/
/*--------------------------------------------------------------------------*/
static int 
xsh_cfg_recover_last_step(cpl_parameterlist* parameters, 
                      cpl_frameset* frameset,
                      xsh_instrument* instrument,
                      cpl_frameset* raws,
                      cpl_frameset* calib)
{
 
  //const char          *   fctid = "xsh_cfg_recover" ;
  //xsh_instrument* instrument=NULL;

  /* allocated locally */

  //cpl_frameset* raws = NULL;
  //cpl_frameset* calib = NULL;

  cpl_frameset* on = NULL;
  cpl_frameset* off = NULL;
  cpl_frameset* on_off = NULL;


  cpl_frame* master_bias = NULL;
  cpl_frame* master_dark = NULL;
  cpl_frame* bpmap = NULL;
  cpl_frame* predict_rmbias = NULL;
  cpl_frame* predict_rmdark = NULL; 

  cpl_frame*   wave_list=NULL ;
  cpl_frame*   xsh_config_first_anneal=NULL ;
  cpl_frame*   xsh_config_input=NULL ;
  cpl_frame*   xsh_config_last_anneal=NULL ;
  cpl_frame * order_tab_centr = NULL ;
  cpl_frame * model_xy_gue=NULL;
  cpl_frame * measure_xy_pos_frm=NULL; 
  cpl_frame * model_THE1_frm=NULL;
  cpl_frame * model_THE9_frm=NULL;

  int anneal_niter=10000;
  cpl_parameter* p=NULL;
  const char* method=NULL;
  int prescan=false;
  int debug_level=0;
  cpl_frame* fmtchk = NULL; 
  const char* name=NULL;
  const char* tag=NULL;
  //cpl_frame* usr_lines_gue=NULL;
  //cpl_table* usr_lines_tab=NULL;
  const char* filename=NULL;
  cpl_propertylist* plist=NULL ;
  cpl_table* tab_xsh_config_first_anneal=NULL;
  cpl_table* tab_xsh_config_input=NULL;
  cpl_frame* first_anneal_frm=NULL;
  int found_temp=true;
  int first_anneal=true;

  int pre_overscan_corr=0;

  //double zeroK=-273.15;
  int nrows;
  /*Get the recipe options*/
  check(p = cpl_parameterlist_find(parameters,"xsh.xsh_cfg_recover.cor_prescan"));
  check(prescan = cpl_parameter_get_bool(p));

  check(p = cpl_parameterlist_find(parameters,"xsh.xsh_cfg_recover.anneal_niter"));
  check(anneal_niter = cpl_parameter_get_int(p));

  check(p = cpl_parameterlist_find(parameters,"xsh.xsh_cfg_recover.method"));
  check(method = cpl_parameter_get_string(p));

  check(p = cpl_parameterlist_find(parameters,"xsh.xsh_cfg_recover.first-anneal"));
  check(first_anneal = cpl_parameter_get_bool(p));

  check(debug_level=xsh_parameters_debug_level_get("xsh_cfg_recover",parameters));


/*
  check( xsh_begin( frameset, parameters, &instrument, &raws, &calib,
		    XSH_FMTCHK,RECIPE_ID, XSH_BINARY_VERSION,
		    xsh_cfg_recover_description_short ) ) ;
*/
  check( xsh_instrument_set_mode( instrument, XSH_MODE_SLIT));

  /* RETRIEVE INPUT DATA */
  if(first_anneal) {
     check(first_anneal_frm=xsh_find_frame_with_tag(frameset,
						    XSH_MOD_CFG_FAN,
						    instrument));
     check(xsh_config_first_anneal=cpl_frame_duplicate(first_anneal_frm));
  } else {
     check(first_anneal_frm=xsh_find_frame_with_tag(frameset,
						    XSH_MOD_CFG,
						    instrument));
     check(xsh_config_first_anneal=cpl_frame_duplicate(first_anneal_frm));
     check(name=cpl_frame_get_filename(xsh_config_first_anneal));
     check(tab_xsh_config_first_anneal=cpl_table_load(name,1,0));
     check(plist=cpl_propertylist_load(name,0));
     check(tag=xsh_get_tag_from_arm(XSH_MOD_CFG_FAN,instrument));
     check(filename=cpl_sprintf("%s%s",tag,".fits"));
     check(cpl_table_save(tab_xsh_config_first_anneal,plist, NULL,filename,
			  CPL_IO_DEFAULT));
     check(cpl_frame_set_filename(xsh_config_first_anneal,filename));
     check(cpl_frame_set_tag(xsh_config_first_anneal,tag));
     check(cpl_frame_set_group(xsh_config_first_anneal,CPL_FRAME_GROUP_PRODUCT));
     check(cpl_frame_set_level(xsh_config_first_anneal,CPL_FRAME_LEVEL_FINAL));
     
  }
  /* Read in the list of wavelengths*/
  check(wave_list = xsh_find_frame_with_tag( calib,XSH_ARC_LINE_LIST,
                                                   instrument));


  check(bpmap = xsh_find_master_bpmap( calib));
  /* Look for a order_tab file (this has the polynomial coefficients for already
     fitted orders*/
  if(strcmp(method,"safefit")!=0) {
     if((order_tab_centr = xsh_find_frame_with_tag(calib,XSH_ORDER_TAB_CENTR,
                                                   instrument)) == NULL ) {
        xsh_msg_warning("Frame %s not provided",
                        xsh_get_tag_from_arm(XSH_ORDER_TAB_CENTR,instrument));
        cpl_error_set(cpl_func,CPL_ERROR_DATA_NOT_FOUND);
        order_tab_centr=NULL;
        xsh_error_reset();
	if ((strcmp(method,"pm") == 0) || (strcmp(method,"peaks") == 0) ) {
	  xsh_msg_error("If method is 'pm' or 'peaks' you must provide");
	  xsh_msg_error("A valid frame taged as %s ",
			xsh_get_tag_from_arm(XSH_ORDER_TAB_CENTR,instrument));
	  goto cleanup;
      }
     }
  }
  /* In UVB and VIS mode */
  if ( xsh_instrument_get_arm(instrument) != XSH_ARM_NIR){
    /* RAWS frameset must have only one file */
    XSH_ASSURE_NOT_ILLEGAL(cpl_frameset_get_size(raws) == 1);
    if((master_bias = xsh_find_frame_with_tag(calib,XSH_MASTER_BIAS,
					      instrument)) == NULL) {
      xsh_msg_warning("Frame %s not provided",XSH_MASTER_BIAS);
      xsh_error_reset();
    }
    if((master_dark = xsh_find_frame_with_tag(calib,XSH_MASTER_DARK,
					      instrument)) == NULL) {
      xsh_msg_warning("Frame %s not provided",XSH_MASTER_DARK);
      xsh_error_reset();
    }
  }

  /* Reduce data */
  /* Prepare frames */
  /* In UVB and VIS mode */

  if ( xsh_instrument_get_arm(instrument) != XSH_ARM_NIR){
     /* prepare RAW frames in XSH format */
    check(xsh_prepare( raws, bpmap, master_bias, XSH_FMTCHK, instrument,
		       pre_overscan_corr,CPL_TRUE));
     check(fmtchk = cpl_frameset_get_frame(raws,0));
     /* subtract bias */
     if(master_bias != NULL) {
        check(predict_rmbias = xsh_subtract_bias(fmtchk,master_bias, 
                                                 instrument,"FMTCHK_",0,0));
     } else {
        predict_rmbias = cpl_frame_duplicate(fmtchk);
     }
     if(master_dark != NULL) {
        /* subtract dark */
        filename = xsh_stringcat_any( "FMTCHK_DARK_",
                                      xsh_instrument_arm_tostring( instrument ),
                                      ".fits", (void*)NULL ) ;
        check(predict_rmdark = xsh_subtract_dark(predict_rmbias, master_dark,
                                                 filename, instrument));
     } else {
        predict_rmdark = cpl_frame_duplicate(predict_rmbias);
     }
  }
  /* in NIR mode */
  else{
    check( on = xsh_frameset_extract( raws,XSH_FMTCHK_NIR ) ) ;
    check( off = xsh_frameset_extract ( raws,XSH_FMTCHK_OFF ) ) ;

    check(xsh_prepare(on,NULL, NULL, "ON", instrument,pre_overscan_corr,CPL_TRUE));
    /* prepare OFF frames in XSH format */
    check(xsh_prepare(off,bpmap, NULL, "OFF", instrument,pre_overscan_corr,CPL_TRUE));
    /* subtract dark */
    check(on_off = xsh_subtract_nir_on_off(on, off, instrument));
    check(predict_rmdark = cpl_frame_duplicate(cpl_frameset_get_frame(on_off,0)));
  }
 

  /* Compute guess table frame */
  check(model_xy_gue=xsh_cfg_recover_gen_xyg_frame(wave_list,
					       xsh_config_first_anneal,
                                               instrument,prescan));


  //Apply user defined offsets if any has been set
  check(xsh_cfg_recover_guess_tab_corr_by_user(parameters,&model_xy_gue));
 
  /* This creates extra columns that are needed later, even in the case that we
     use the barycentre measured in the data instead of the orderpos x-disp value*/

  check(xsh_cfg_recover_guess_tab_corr_by_ordpos(instrument,order_tab_centr,
                                             &model_xy_gue));

  /*If first anneal is skipped then we want to update the temperature of the old
    config that we are using to do the search. However, we should not update the
    temperature if first_anneal was run because the config produced by first_anneal
    will have been fit with the old temperature and won't find the lines if we put
    the new one in*/
  /*load the image, we just want the header here*/

  if (!first_anneal) {
    if(found_temp) {
      xsh_msg("update the prism temperatures before line matching");
      check(xsh_model_temperature_update_frame(&xsh_config_first_anneal,predict_rmdark,
                                               instrument,&found_temp));
    }
  }

  check(xsh_cfg_recover_measure_line_xy(predict_rmdark,
                                    instrument,
                                    order_tab_centr,
                                    parameters,
                                    method,
                                    xsh_config_first_anneal,
                                    &model_xy_gue,
                                    debug_level)); 
   
   xsh_msg(" REGDEBUG A generate %s", cpl_frame_get_filename(model_xy_gue));

   /*The first anneal config was only needed for locating the features, now we go back
     to the input config, the least known good soln*/
   if((xsh_config_input  = xsh_find_frame_with_tag(frameset,XSH_MOD_CFG,
					    instrument)) == NULL) {
     xsh_msg_error("Frame %s not found",
		   xsh_stringcat_any( XSH_MOD_CFG,
				      xsh_instrument_arm_tostring(instrument),
				      (void*)NULL ) ) ;
     cpl_error_set(cpl_func, CPL_ERROR_ILLEGAL_INPUT);
     goto cleanup;
   }


   /*Now that the matching has been done, we should update the temperature
     before the annealing, because we want the eventual solution to be valid
     for the correct temperature*/
  if(found_temp) {
    xsh_msg("update the prism temperatures before annealing");
    //get the model so that we can update the prism 
    //temperatures before annealing
    check(xsh_model_temperature_update_frame(&xsh_config_input,predict_rmdark,
                                             instrument,&found_temp));
  }


  //We need to set proper format in our best guess table in order to interface
  //with the anneal part of the physical model
  check(measure_xy_pos_frm=cpl_frame_duplicate(model_xy_gue));

  /*add extra columns needed for pipe_anneal function*/
  check(xsh_cfg_recover_extend_xy_pos_frm(&measure_xy_pos_frm,instrument));

    check(name=cpl_frame_get_filename(measure_xy_pos_frm));

  nrows=cpl_table_get_nrow(cpl_table_load(name,1,0));
  //printf("rows in tab %d \n",nrows);
  if ((xsh_instrument_get_arm(instrument)==XSH_ARM_UVB && nrows<70) ||
      (xsh_instrument_get_arm(instrument) == XSH_ARM_VIS && nrows<120) ||
      (xsh_instrument_get_arm(instrument) == XSH_ARM_NIR && nrows<80)) {
    xsh_msg_error("Not enough matches (%" CPL_SIZE_FORMAT "). Try running with more iterations for first_anneal (higher niter)",cpl_table_get_nrow(cpl_table_load(name,1,0)));
    return -1;
  }

  /*Call the annealing*/
  //The following generates leaks
  xsh_msg(" REGDEBUG B before annealing %s", cpl_frame_get_filename( measure_xy_pos_frm));
  check(xsh_config_last_anneal=xsh_model_pipe_anneal(xsh_config_input,
						     measure_xy_pos_frm,
						     anneal_niter,
						     1.0,
						     1,
                                                     0));
  /*Make a THE table with the new config*/
  check(xsh_cfg_recover_model_THE_create(xsh_config_last_anneal,
                                     instrument,
                                     wave_list,
                                     &model_THE1_frm,
                                     &model_THE9_frm));
 
  // xsh_cfg_recover_model_anneal();

  check(xsh_add_product_table(xsh_config_last_anneal,frameset,parameters,
                              RECIPE_ID,instrument,NULL));
  check(xsh_add_product_table(model_xy_gue,frameset,parameters, RECIPE_ID,
			      instrument,NULL));
  check(xsh_add_product_table(model_THE1_frm,frameset,parameters, RECIPE_ID,
			      instrument,NULL));
  check(xsh_add_product_table(model_THE9_frm,frameset,parameters, RECIPE_ID,
			      instrument,NULL));
   
 cleanup:
  xsh_free_table(&tab_xsh_config_first_anneal);
  xsh_free_table(&tab_xsh_config_input);
  xsh_end( RECIPE_ID, frameset, parameters );
  //xsh_free_frameset(&raws);
  //xsh_free_frameset(&calib);
  xsh_free_frame(&predict_rmbias );
  xsh_free_frame(&predict_rmdark );
  //xsh_instrument_free(&instrument );
  xsh_free_frame(&model_xy_gue);
  xsh_free_frame(&measure_xy_pos_frm);
  xsh_free_frame(&xsh_config_last_anneal);
  xsh_free_frame(&model_THE1_frm);
  xsh_free_frame(&model_THE9_frm);
  xsh_free_frameset(&on);
  xsh_free_frameset(&off);
  xsh_free_frameset(&on_off);


  /* Return */
  if (cpl_error_get_code() != CPL_ERROR_NONE) {
    xsh_print_rec_status(0);
    return -1 ;
  } else {
    return 0 ;
  }

}

/*--------------------------------------------------------------------------*/
/**
   @name xsh_cfg_recover_model_THE_create 
   @brief creates the model THE table corresponding to the best found model 
   configuration
   @param  config_frame frame of annealed model configuration parameters
   @param  xsh_instrument instrument instrument ARM setting
   @param  wave_list input frame wavelength list 
   @param  THE1_frm THE map for central pinhole
   @param  THE9_frm THE map for 9 pinholes

   @return model_THE_frm output model THE table corresponding to line list and 
   annealed model configuration or NULL if failure
   THIS IS ESSENTIALLY A WRAPPER FOR xsh_model_THE_create
*/
/*--------------------------------------------------------------------------*/

static cpl_error_code 
xsh_cfg_recover_model_THE_create(cpl_frame* config_frame,
                             xsh_instrument* instrument,
                             cpl_frame* wave_list,
                             cpl_frame** THE1_frm, 
                             cpl_frame** THE9_frm)
{
   struct xs_3* p_xs_3_config=NULL;
   struct xs_3 xs_3_config;
   const char* line_list=NULL;
   const char* THE1_filename="model_THE1.fits";
   const char* THE9_filename="model_THE9.fits";
   const char* pro_catg=NULL;

   //Load xsh model configuration
   p_xs_3_config=&xs_3_config;
   if (xsh_model_config_load_best(config_frame, p_xs_3_config) != 
       CPL_ERROR_NONE) {
      xsh_msg_error("Cannot load %s as a config", 
                    cpl_frame_get_filename(config_frame)) ;
      return CPL_ERROR_DATA_NOT_FOUND ;
   }

   check(line_list=cpl_frame_get_filename(wave_list));
   check(*THE1_frm=xsh_model_THE_create(p_xs_3_config,instrument,line_list,
                                       1,-1,THE1_filename));
   check(pro_catg=XSH_GET_TAG_FROM_ARM(XSH_THEO_TAB_SING,instrument));
   check(xsh_frame_config(THE1_filename,pro_catg,CPL_FRAME_TYPE_TABLE, 
                          CPL_FRAME_GROUP_PRODUCT,CPL_FRAME_LEVEL_FINAL,
                          THE1_frm));

   check(*THE9_frm=xsh_model_THE_create(p_xs_3_config,instrument,line_list,
                                       9,-1,THE9_filename));

   check(pro_catg=XSH_GET_TAG_FROM_ARM(XSH_THEO_TAB_MULT,instrument));
   check(xsh_frame_config(THE9_filename,pro_catg,CPL_FRAME_TYPE_TABLE, 
                          CPL_FRAME_GROUP_PRODUCT,CPL_FRAME_LEVEL_FINAL,
                          THE9_frm));


  cleanup:
   if(cpl_error_get_code() == CPL_ERROR_NONE) {
      return cpl_error_get_code();
   } else {
      xsh_print_rec_status(0);
      return cpl_error_get_code();
   }
}

/*--------------------------------------------------------------------------*/
/**
   @name xsh_cfg_recover_guess_tab_corr_by_user 
   @brief Applies user X-Y offset to guess
   @param  parameters recipe input parameters
   @param  model-xy_guess input/outup table frame 

   @return   error code status

*/
/*--------------------------------------------------------------------------*/

static cpl_error_code 
xsh_cfg_recover_guess_tab_corr_by_user(cpl_parameterlist* parameters,
                                   cpl_frame** model_xy_gue)
{
  const char* name=NULL;
  cpl_table* tab=NULL;
  double offx=0;
  double offy=0;
  cpl_parameter* p=NULL;

  check(name=cpl_frame_get_filename(*model_xy_gue));
  check(tab=cpl_table_load(name,1,0));

  check(p = cpl_parameterlist_find(parameters,"xsh.xsh_cfg_recover.offx"));
  check(offx = cpl_parameter_get_double(p));

  check(p = cpl_parameterlist_find(parameters,"xsh.xsh_cfg_recover.offy"));
  check(offy = cpl_parameter_get_double(p));

  check(cpl_table_add_scalar(tab,"XG",offx));
  check(cpl_table_add_scalar(tab,"YG",offy));

  check(cpl_table_save(tab, NULL, NULL,name, CPL_IO_DEFAULT));

 cleanup:
  xsh_free_table(&tab);

  /* Return */
  return cpl_error_get_code();
}


/*--------------------------------------------------------------------------*/
/**
   @name xsh_cfg_recover_extend_xy_pos_frm 
   @brief Add columns to properly match with outher functions used later
   @param    frm  the input table frame
   @return   error code status
*/
/*--------------------------------------------------------------------------*/

static cpl_error_code
xsh_cfg_recover_extend_xy_pos_frm(cpl_frame** frm,xsh_instrument* inst)
{
  const char * name=NULL;
  cpl_table* tbl=NULL;
  int nrows=0;
  cpl_propertylist* header = NULL;
  char name_o[256];
  const char* tag=XSH_GET_TAG_FROM_ARM(XSH_MEASURE_LINE_POS_XY,inst);

  sprintf(name_o,"%s%s",tag,".fits");

  check(name=cpl_frame_get_filename(*frm));

/* Commented because we have changed definition of the resid tab */

  check(tbl=cpl_table_load(name,1,0));
  check ( header = cpl_propertylist_load( name, 0));

  check(nrows=cpl_table_get_nrow(tbl));
  if(nrows==0) {
    xsh_msg_error("Table %s has 0 rows. Something wrong! Exit",name);
    goto cleanup;
  }

  /* Renaming to be similar with resid_tab */ 
  check(cpl_table_name_column(tbl,"WAVELENGTH",
			      XSH_RESID_TAB_TABLE_COLNAME_WAVELENGTH));
  check(cpl_table_name_column(tbl,"ABS_ORD",
			      XSH_RESID_TAB_TABLE_COLNAME_ORDER));
  check(cpl_table_new_column(tbl,XSH_RESID_TAB_TABLE_COLNAME_SLITPOSITION,
			     CPL_TYPE_DOUBLE));
  check(cpl_table_fill_column_window(tbl,
				     XSH_RESID_TAB_TABLE_COLNAME_SLITPOSITION,
				     0,nrows,0.));
  cpl_table_new_column(tbl,XSH_RESID_TAB_TABLE_COLNAME_SLITINDEX,CPL_TYPE_INT);
  cpl_table_fill_column_window(tbl,XSH_RESID_TAB_TABLE_COLNAME_SLITINDEX,0,
                               nrows,4);

  /* Input theoretical positions  Not used by model */
  check(cpl_table_duplicate_column(tbl,
    XSH_RESID_TAB_TABLE_COLNAME_XTHPRE,
    tbl,"XC"));
  check( cpl_table_duplicate_column(tbl,
    XSH_RESID_TAB_TABLE_COLNAME_YTHPRE,
    tbl, "YC"));

  /* Corrected input positions Not used by model */
  check(cpl_table_duplicate_column(tbl,
    XSH_RESID_TAB_TABLE_COLNAME_XTHCOR,
    tbl,"XC"));
  check( cpl_table_duplicate_column(tbl,
    XSH_RESID_TAB_TABLE_COLNAME_YTHCOR,
    tbl, "YC"));

  /* Only Important columns for model */
  check(cpl_table_duplicate_column(tbl,
    XSH_RESID_TAB_TABLE_COLNAME_XGAUSS,
    tbl,"XC"));
  check( cpl_table_duplicate_column(tbl,
    XSH_RESID_TAB_TABLE_COLNAME_YGAUSS,
    tbl, "YC"));

  cpl_table_new_column(tbl, XSH_RESID_TAB_TABLE_COLNAME_SIGMAXGAUSS,
    CPL_TYPE_DOUBLE);
  xsh_msg("create column %s", XSH_RESID_TAB_TABLE_COLNAME_SIGMAXGAUSS);

  cpl_table_fill_column_window(tbl, XSH_RESID_TAB_TABLE_COLNAME_SIGMAXGAUSS,
    0, nrows, 0.);
  cpl_table_new_column(tbl, XSH_RESID_TAB_TABLE_COLNAME_SIGMAYGAUSS,
    CPL_TYPE_DOUBLE);
  cpl_table_fill_column_window(tbl, XSH_RESID_TAB_TABLE_COLNAME_SIGMAYGAUSS,
    0, nrows, 0.);
  cpl_table_new_column(tbl, XSH_RESID_TAB_TABLE_COLNAME_XTHANNEAL,
    CPL_TYPE_DOUBLE);
  cpl_table_fill_column_window(tbl, XSH_RESID_TAB_TABLE_COLNAME_XTHANNEAL,
    0, nrows, 0.);
  cpl_table_new_column(tbl, XSH_RESID_TAB_TABLE_COLNAME_YTHANNEAL,
    CPL_TYPE_DOUBLE);
  cpl_table_fill_column_window(tbl, XSH_RESID_TAB_TABLE_COLNAME_YTHANNEAL,
    0, nrows, 0.);

  cpl_table_new_column(tbl, XSH_RESID_TAB_TABLE_COLNAME_RESIDXMODEL,
    CPL_TYPE_DOUBLE);
  cpl_table_fill_column_window(tbl, XSH_RESID_TAB_TABLE_COLNAME_RESIDXMODEL,
    0, nrows, 0.);
    cpl_table_new_column(tbl, XSH_RESID_TAB_TABLE_COLNAME_RESIDYMODEL,
    CPL_TYPE_DOUBLE);
  cpl_table_fill_column_window(tbl, XSH_RESID_TAB_TABLE_COLNAME_RESIDYMODEL,
    0, nrows, 0.);

  check( xsh_pfits_set_wavesoltype( header, XSH_WAVESOLTYPE_MODEL));

  cpl_table_erase_invalid_rows(tbl);
  check( xsh_pfits_set_pcatg(header,tag));
  check(cpl_table_save(tbl, header, NULL,name_o, CPL_IO_DEFAULT));
   
  cpl_frame_set_filename(*frm,name_o);
  cpl_frame_set_tag(*frm,tag);

  cleanup:
    xsh_free_table(&tbl);
    if(cpl_error_get_code() != CPL_ERROR_NONE) {
      xsh_print_rec_status(0);
    }
    return cpl_error_get_code() ;
}
/*--------------------------------------------------------------------------*/
/**
   @name  xsh_cfg_recover_measure_line_xy_fit 

   @brief Measure lines x,y positions with a Gaussian fit on the raw_frm

   @param raw_frm  the input raw formatcheck frame (pre-overscan removed)
   @param parameters  the recipe input parameters
   @param guess  the guess table frame to be corrected after line measurements
   @param debug_level debug level
   @return error code status
   ONLY USED BY GFIT METHOD
*/
/*--------------------------------------------------------------------------*/

static cpl_error_code
xsh_cfg_recover_measure_line_xy_fit(cpl_frame* raw_frm,
                                cpl_parameterlist* parameters,
                                cpl_frame** guess,
                                int debug_level)
{
  //int box_sx=0;
  int box_sy=0;
  cpl_parameter* p=NULL;
  int ngue=0;
  int i=0;

  double* pxg=NULL;
  double* pyg=NULL;
  double* pxf=NULL;
  double* pyf=NULL;

  int* ps=NULL;
  cpl_image* ima=NULL;
  const char* name=NULL;
  //int size=50;
  double norm=0;
  double xcen=0;
  double ycen=0;
  double sig_x=0;
  double sig_y=0;
  double fwhm_x=0;
  double fwhm_y=0;
  const char* name_g="tab_xy_corr_gauss.fits";
  cpl_table* tab=NULL;
  cpl_table* tmp=NULL;
  int nfit=0;
  /*
    check(p = cpl_parameterlist_find(parameters,"xsh.xsh_cfg_recover.gfit_box_sx"));
    check(box_sx = cpl_parameter_get_int(p));
  */
 
  check(p = cpl_parameterlist_find(parameters,"xsh.xsh_cfg_recover.gfit_box_sy"));
  check(box_sy = cpl_parameter_get_int(p));

  check(name=cpl_frame_get_filename(raw_frm));
  check(ima=cpl_image_load(name,CPL_TYPE_DOUBLE,0,0));

  check(name=cpl_frame_get_filename(*guess));
  check(tab=cpl_table_load(name,1,0));

  check(ngue=cpl_table_get_nrow(tab));
  check(cpl_table_new_column(tab,"SELECT",CPL_TYPE_INT));
  check(cpl_table_new_column(tab,"XF",CPL_TYPE_DOUBLE));
  check(cpl_table_new_column(tab,"YF",CPL_TYPE_DOUBLE));

  check(cpl_table_fill_column_window(tab,"SELECT",0,ngue,-1));
  check(cpl_table_fill_column_window(tab,"XF",0,ngue,0));
  check(cpl_table_fill_column_window(tab,"YF",0,ngue,0));

  check(pxg=cpl_table_get_data_double(tab,"XC"));
  check(pyg=cpl_table_get_data_double(tab,"YC"));
  check(pxf=cpl_table_get_data_double(tab,"XF"));
  check(pyf=cpl_table_get_data_double(tab,"YF"));
  check(ps=cpl_table_get_data_int(tab,"SELECT"));

  xsh_msg("ngue=%d",ngue);
  for(i=0;i<ngue;i++) {
    //xsh_msg("fit line %d",i);
    //one could also use xsh_image_find_barycenter but that is less accurate
    if(cpl_image_fit_gaussian(ima,(int)pxg[i],(int)pyg[i],box_sy,
			      &norm,
			      &xcen,&ycen,
			      &sig_x,&sig_y,
			      &fwhm_x,&fwhm_y) == CPL_ERROR_NONE) {
      pxf[i]=xcen;
      pyf[i]=ycen;
      ps[i]=1;

    } else {
      //xsh_print_rec_status(0);
      cpl_error_reset();
    }
  }
  check(nfit=cpl_table_and_selected_int(tab,"SELECT",CPL_GREATER_THAN,-1));

  xsh_msg("nfit=%d",nfit);
  check(tmp=cpl_table_extract_selected(tab));

  check(cpl_table_erase_column(tmp,"XC"));
  check(cpl_table_erase_column(tmp,"YC"));

  check(cpl_table_duplicate_column(tmp,"XC",tmp,"XF"));
  check(cpl_table_duplicate_column(tmp,"YC",tmp,"YF"));

  if(debug_level > XSH_DEBUG_LEVEL_NONE) {
    check(cpl_table_save(tmp, NULL, NULL, name_g, CPL_IO_DEFAULT));
    check(cpl_table_save(tmp, NULL, NULL, name, CPL_IO_DEFAULT));
  }

 cleanup:
  xsh_free_table(&tab);
  xsh_free_table(&tmp);
  xsh_free_image(&ima);

  if(nfit ==0 ) {
    xsh_msg_error("nfit = 0, something wrong in %s",cpl_func);
    return CPL_ERROR_UNSPECIFIED;
  } else {
    if( cpl_error_get_code() != CPL_ERROR_NONE) {
      xsh_print_rec_status(0);
    }
    return cpl_error_get_code() ;
  }
}
/*--------------------------------------------------------------------------*/
/**
   @name  xsh_cfg_recover_measure_line_xy 
   @brief    Measure lines x,y positions 
   @param    raw_frm  the input raw formatcheck frame (pre-overscan removed)
   @param    instr instrument setting
   @param    order_tab_centr input raw order-flat frame (pre-overscan removed)
   @param    parameters  the recipe input parameters
   @param    guess  guess table frame to be corrected after line measurements
   @return   error code status

*/
/*--------------------------------------------------------------------------*/


static cpl_error_code xsh_cfg_recover_measure_line_xy(cpl_frame* raw_frm,
    xsh_instrument* instr, cpl_frame* order_tab_centr,
    cpl_parameterlist* parameters, const char* method, cpl_frame* model_config,
    cpl_frame** guess, int debug_level) {
  cpl_image* ima = NULL;



  cpl_table* tab_tmp1 = NULL;
  cpl_table* tab_tmp2 = NULL;
  cpl_table* tab_xy_corr = NULL;
  cpl_image* ima_ext = NULL;
  cpl_image* ima_raw = NULL;
  double fct = 2.;
  int slit = 10;
  cpl_parameter* p = NULL;
  const char* name = NULL;
  const char* name_g = NULL;
  const char* name_t = "tab_xy_peaks.fits";
  int thresh_x = 0;
  int thresh_y = 0;
  cpl_table* tab_xy_guess=NULL;
  cpl_matrix* mat_gue = NULL;
  cpl_matrix* mat_msr = NULL;
  double thresh_min = 25;
  int use_data = 0;
  int use_pattern = 0;

  double* pxg = NULL;
  double* pyg = NULL;
  double yg_temp[20000];
  double xg_temp[20000];
  double* wave = NULL;
  int* ordg = NULL;
  int* psl = NULL;


  //int ord_num;
  int wmin = 0;

  int w = 0;


  cpl_vector* spectrum = NULL;
  cpl_vector* filtered = NULL;
  cpl_vector* spec_clean = NULL;
  cpl_vector* bright_lines = NULL;

  //FILE* ex1d_out=NULL;
  int kk = 0;
  double* pxc = NULL;
  double* pyc = NULL;
  //double* pwl = NULL;
  int nrow = 0;

  cpl_vector** trace = NULL;
  cpl_vector** extracted = NULL;
  int MAX_NO_ORD = 16;
  struct xs_3 xs_3_config;
  struct xs_3* p_xs_3 = NULL;
  int h = 4;
  cpl_table* spec_form_tab = NULL;
  int starti = 0;
  int absord = 0;
  double tot = 0.0;
  double total = 0.0;
  double dx = 0;
  double* detec = NULL;
  int size_x = 0;
  int size_y = 0;
  int size_y_use = 0;
  int status = 0;
  double x = 0, y = 0, offx = 0, offy = 0;
  cpl_frame* spec_form_frame = NULL;
  int pix = 0;
  int nb_match = 0;
  cpl_table* tab_tmp = NULL;
  cpl_table* tab_xy_peaks = NULL;
  cpl_table* tab_xy_peaks_sel = NULL;
  double wave_use = 0, zero_off = 0, match_lim = 0, startlam = 0, endlam = 0;
  //double    order_median = 0;
  p_xs_3 = &xs_3_config;

  /*Get a new spectral format table using the config in spectralformat_create function*/
  check(xsh_model_config_load_best(model_config, p_xs_3));
  xsh_msg("Calling spectral format create");
  /*When "spec_form.fits" is passed as the name then the extra orders are generated
   so that other parts of the pipeline do not complain about the number of orders*/
  check(
      spec_form_frame = xsh_model_spectralformat_create(p_xs_3,
          "not_spec_form.fits"));
  check(
      cpl_frame_set_tag(spec_form_frame,
          xsh_get_tag_from_arm(XSH_ORDER_TAB_CENTR, instr)));

  check(p = cpl_parameterlist_find(parameters, "xsh.xsh_cfg_recover.method"));
  check(method = cpl_parameter_get_string(p));

  int starty = 0;
  int endy = 0;
  int ii=0, jj=0;
  if (strcmp(method, "gfit") == 0) {
    check(
        xsh_cfg_recover_measure_line_xy_fit(raw_frm, parameters, guess,
            debug_level));

  } else if (strcmp(method, "pbrfit") == 0 || strcmp(method, "safefit") == 0) {

    if (strcmp(method, "safefit") == 0) {
      /* Get the command line offsets so that they can be applied in the xtraction
       and the matching */
      check(p = cpl_parameterlist_find(parameters, "xsh.xsh_cfg_recover.offx"));
      check(offx = cpl_parameter_get_double(p));
      check(p = cpl_parameterlist_find(parameters, "xsh.xsh_cfg_recover.offy"));
      check(offy = cpl_parameter_get_double(p));

      /*Get the loci of the orders defined by the current model (as opposed to using
       the orderpos polynomials*/
      trace = xsh_model_locus(p_xs_3, instr, 0.0);
      /*Get the order parameter table defined by the current model (for max min
       co-ords and wavelengths for each order) */
      spec_form_tab = cpl_table_load(cpl_frame_get_filename(spec_form_frame), 1,
          0);

      /*Put the raw data pixel array into a 1d array - detec*/
      check(name = cpl_frame_get_filename(raw_frm));
      check(ima_raw = cpl_image_load(name, CPL_TYPE_DOUBLE, 0, 0));
      check(size_y = cpl_image_get_size_y(ima_raw));
      check(size_x = cpl_image_get_size_x(ima_raw));
      xsh_msg("size_x=%d size_y=%d", size_x, size_y);
      check(detec = cpl_image_get_data_double(ima_raw));

      /*Allocate array of MAX_NO_ORD vectors for 1d extracted spectra and fill with zeros*/
      check(extracted = cpl_malloc(MAX_NO_ORD * sizeof(cpl_vector *)));
      for (ii = 0; ii < MAX_NO_ORD; ii++) {
        extracted[ii] = cpl_vector_new(size_y);
        cpl_vector_fill(extracted[ii], 0.0);
      }
      /*The order parameter table may contain extra orders (dev purposes), so find the
       index of the one corresponding to the standard minimum order for this arm and
       start the loop from there*/
      starti = 0;
      while (cpl_table_get_int(spec_form_tab, "ORDER", starti, &status)
          < p_xs_3->morder_min) {
        starti++;
      }
      ii = starti;
      /*loop over orders*/
      for (ii = starti; ii <= starti + p_xs_3->morder_max - p_xs_3->morder_min;
          ii++) {
        absord = cpl_table_get_int(spec_form_tab, "ORDER", ii, &status);
        if (p_xs_3->arm != 2) {
          starty = (int) (cpl_table_get_float(spec_form_tab, "DISP_MIN", ii,
              &status));
          endy = (int) (cpl_table_get_float(spec_form_tab, "DISP_MAX", ii,
              &status));
        } else {
          starty = (int) (cpl_table_get_float(spec_form_tab, "DISP_MAX", ii,
              &status));
          endy = (int) (cpl_table_get_float(spec_form_tab, "DISP_MIN", ii,
              &status));
        }
        /*now loop over dispersion coordinate:
         - Compute x-disp coord from model
         - extract flux from +/-h pix around x-disp posn
         NOTE: ds9(1,1) -> jj=0 int(dx+0.5)+kk=0
         */
        //xsh_msg("endy=%d",endy);
        /*correct the limits with the command line offsets*/
        if (offy < 0.0) {
          starty -= (int) (offy);
          size_y_use = size_y;
        } else {
          endy -= (int) (offy);
          size_y_use = size_y - offy;
        }
        int jj=0;
        for (jj = starty; ((jj < endy) && (jj < size_y_use)); jj++) {
          tot = 0.0;
          /*get dx as a function of jj, with the command line offsets applied*/
          dx = cpl_vector_get(trace[absord - p_xs_3->morder_min], jj + offy)
              - offx;
          for (kk = -h; kk <= h; kk++) {
            if (p_xs_3->arm == 2) {
              pix = size_x * jj + ((int) (dx + 0.5) + kk);
            } else {
              pix = size_x * jj + (int) (dx + 0.5) + kk;
            }
            if (pix < size_x * size_y) {
              tot += detec[pix];
            }
          }
          check(
              cpl_vector_set(extracted[absord - p_xs_3->morder_min], jj, tot));
        }
      }
    }

    else {
      //Get parameters for linear extraction
      check(p = cpl_parameterlist_find(parameters, "xsh.xsh_cfg_recover.slit"));
      check(slit = cpl_parameter_get_int(p));

      check(
          p = cpl_parameterlist_find(parameters,
              "xsh.xsh_cfg_recover.peak_factor"));
      check(fct = cpl_parameter_get_double(p));

      check(
          p = cpl_parameterlist_find(parameters,
              "xsh.xsh_cfg_recover.peak_match_x"));
      check(thresh_x = cpl_parameter_get_int(p));

      check(
          p = cpl_parameterlist_find(parameters,
              "xsh.xsh_cfg_recover.peak_match_y"));
      check(thresh_y = cpl_parameter_get_int(p));

      check(
          p = cpl_parameterlist_find(parameters,
              "xsh.xsh_cfg_recover.ima_thresh_min"));
      check(thresh_min = cpl_parameter_get_double(p));

      //Image (linear) extraction: sum pixels
      //to check the actual image we are going to fit vs the model guess

      cknull(
          ima_ext = xsh_cfg_recover_linear_ext(raw_frm, order_tab_centr, instr,
              slit, thresh_min));

    }
    cpl_table* tab_xy_guess = NULL;
    /*Get the table that will contain the measured centroids*/
    check(name_g = cpl_frame_get_filename(*guess));
    check(tab_xy_guess = cpl_table_load(name_g, 1, 0));
    xsh_msg("guess tablename=%s", name_g);
    int morder_min = 0;
    morder_min = p_xs_3->morder_min;
    nrow = cpl_table_get_nrow(tab_xy_guess);
    /*add some new columns that will be needed*/
    cpl_table_new_column(tab_xy_guess, "XF", CPL_TYPE_DOUBLE);
    cpl_table_new_column(tab_xy_guess, "YF", CPL_TYPE_DOUBLE);
    cpl_table_new_column(tab_xy_guess, "SELECT", CPL_TYPE_INT);
    cpl_table_fill_column_window(tab_xy_guess, "XF", 0, nrow, -1);
    cpl_table_fill_column_window(tab_xy_guess, "YF", 0, nrow, -1);
    cpl_table_fill_column_window(tab_xy_guess, "SELECT", 0, nrow, -1);
    /*set pointers to some table columns that we will want to update*/
    pxc = cpl_table_get_data_double(tab_xy_guess, "XF");
    pyc = cpl_table_get_data_double(tab_xy_guess, "YF");
    //pwl = cpl_table_get_data_double(tab_xy_guess, "WAVELENGTH");
    /*temporary variable for the newly calcuated yg so that we can continue to use the
     current value while we are stil in the loop below.
     Set to -1 so we know that =>1 means that a match was found*/
    for (kk = 0; kk < nrow; kk++) {
      yg_temp[kk] = -1.0;
    }
    for (kk = 0; kk < nrow; kk++) {
      xg_temp[kk] = -1.0;
    }

    kk = 0;
    /* loop over orders*/

    int ord=0;
    for (ord = 0; ord < p_xs_3->morder_max - morder_min + 1; ord++) {
      check(
          absord = cpl_table_get_int(spec_form_tab, "ORDER", ord + starti,
              &status));
      if (p_xs_3->arm != 2) {
        check(
            starty = (int) (cpl_table_get_float(spec_form_tab, "DISP_MIN",
                ord + starti, &status)));
        check(
            endy = (int) (cpl_table_get_float(spec_form_tab, "DISP_MAX",
                ord + starti, &status)));
      } else {
        check(
            starty = (int) (cpl_table_get_float(spec_form_tab, "DISP_MAX",
                ord + starti, &status)));
        check(
            endy = (int) (cpl_table_get_float(spec_form_tab, "DISP_MIN",
                ord + starti, &status)));
      }
      check(
          startlam = cpl_table_get_float(spec_form_tab, "LFSR", ord + starti,
              &status));
      check(
          endlam = cpl_table_get_float(spec_form_tab, "UFSR", ord + starti,
              &status));
      /*For safefit use the 1d sepc in extracted[ord]*/
      if (strcmp(method, "safefit") == 0) {
        spectrum = extracted[ord];
        /* Subrtract the low frequency part */
        //cpl_msg_info(__func__, "Low Frequency signal removal") ;
        if ((filtered = cpl_vector_filter_median_create(spectrum, 200))
            == NULL) {
          cpl_msg_error(__func__, "Cannot filter the spectrum");
          return CPL_ERROR_ILLEGAL_INPUT;
        }
        spec_clean = cpl_vector_duplicate(spectrum);
        cpl_vector_subtract(spec_clean, filtered);
        cpl_vector_delete(filtered);

        //order_median = cpl_vector_get_median_const(spec_clean);
      } else {
        /*otherwise from the ima_ext image array created by the
         xsh_cfg_recover_linear_ext function*/
        check(spectrum = cpl_vector_new_from_image_row(ima_ext, ord + 1));
        spec_clean = cpl_vector_duplicate(spectrum);
      }
      check(bright_lines = xsh_model_refining_detect(spec_clean, 3, 5.0, 0));

      /*set some more pointers to table colummns that we will want to update*/
      check(pxg = cpl_table_get_data_double(tab_xy_guess, "XC"));
      check(pyg = cpl_table_get_data_double(tab_xy_guess, "YC"));
      check(wave = cpl_table_get_data_double(tab_xy_guess, "WAVELENGTH"));
      check(ordg = cpl_table_get_data_int(tab_xy_guess, "ABS_ORD"));
      check(psl = cpl_table_get_data_int(tab_xy_guess, "SELECT"));

      /*loop over these peaks:
       - loop over w
       - get CofG for region containing core on left and window on right
       - get CofG for region containing window on left and core on right
       - check that both are within prec of listed peak centre
       - record the value of w to which the CofG is OK
       */
      double flux = 0;
      //double cent2_cor = 0; 
      //double flux_cor = 0; 
      double ex_cor = 0;
      double prec = 0, precfac = 0, precmin = 0;
      int min_iso=0;
      int lmax = 0, rmax = 0;
      int nbright_lines = 0;
      int cnt = 0;
      int lines_dev = 0;
      cpl_table* tab_xy_guess = NULL;


      if (bright_lines != NULL) {
        check(nbright_lines = cpl_vector_get_size(bright_lines));
        double cent = 0, cent2 = 0;
        for (ii = 0; ii < nbright_lines; ii++) {
          cent = cpl_vector_get(bright_lines, ii) + 0.5 - 1.0;
          //printf("%d %d %lf \n",ord,ii,cent);
          /*The -1.0 above is because Yves' function labels the first bin in the
           vector as 1, I label it 0*/

          /*lines_dev: 0=normal; 1=vis sim; 2=vis real; 3=uvb sim; 4=uvb real; 5 nir sim; 6 nir real*/
          /*Try with match lim small for sim data and large for real data*/
          lines_dev = 0;

          if (lines_dev == 1) {
            precmin = 0.25;
            precfac = 25.0;
            wmin = 3;
            min_iso = 5;
            zero_off = -0.5;
            match_lim = 0.2;
          } else if (lines_dev == 2) {
            precmin = 0.5;
            precfac = 25.0;
            wmin = 3;
            min_iso = 5;
            zero_off = -0.5;
            match_lim = 1.0;
          } else if (lines_dev == 3) {
            precmin = 0.25;
            precfac = 25.0;
            wmin = 3;
            min_iso = 5;
            zero_off = -0.5;
            match_lim = 0.25;
          } else if (lines_dev == 4) {
            precmin = 0.5;
            precfac = 25.0;
            wmin = 3;
            min_iso = 5;
            zero_off = -0.5;
            match_lim = 1.0;
          } else if (lines_dev == 5) {
            precmin = 0.4;
            precfac = 25.0;
            wmin = 3;
            min_iso = 5;
            zero_off = -0.5;
            match_lim = 0.5;
          } else if (lines_dev == 6) {
            precmin = 0.5;
            precfac = 15.0;
            wmin = 3;
            min_iso = 80;
            zero_off = -0.5;
            match_lim = 1.0; //check
          } else {
            precmin = 0.5;
            precfac = 20.0;
            wmin = 4;
            min_iso = 4;
            match_lim = 2.5;
            zero_off = 0.0;
          }
          rmax = 0;
          w = wmin;
          while (w < 200) {
            //prec=2.0;
            prec = (float) (w) / precfac;
            if (prec < precmin) {
              prec = precmin;
            }
            flux = 0.0;
            cent2 = 0.0;
            //flux_cor = 0.0;
            //cent2_cor = 0.0;
            for (jj = (int) (cent) - wmin; jj <= (int) (cent) + w; jj++) {
              //printf("%d %d %d %d \n",ord, ii, jj,endy);
              if (jj > 0 && jj < endy) {
                ex_cor = cpl_vector_get(spec_clean, jj);
                if (ex_cor > 0.0) {
                  flux += ex_cor;
                  cent2 += ex_cor * ((float) (jj) + 0.5 - cent);
                }
                //printf("%d %d %d %lf %lf %lf %lf \n",ord, ii, jj, flux, cent2, flux_cor, cent2_cor);
              }
            }
            cent2 /= flux;
            //printf("1 %d %d %lf %lf %lf %d %d %lf \n",ord, ii, cent2, flux, cent, w, (int)(cent)+w, prec);
            cent2 += cent;
            if (fabs(cent2 - cent) < prec) {
              rmax = w;
              //printf("%d %d %lf \n",ii, -w, cent2-cent);
            } else {
              w = 1000;
            }
            w += 1;
          }
          lmax = 0;
          w = wmin;
          while (w < 200) {
            //prec=2.0;
            prec = (float) (w) / precfac;
            if (prec < precmin) {
              prec = precmin;
            }
            flux = 0.0;
            cent2 = 0.0;
            //flux_cor = 0.0;
            //cent2_cor = 0.0;
            for (jj = (int) (cent) - w; jj <= (int) (cent) + wmin; jj++) {
              if (jj > 0 && jj < endy) {
                ex_cor = cpl_vector_get(spec_clean, jj);
                if (ex_cor > 0.0) {
                  flux += ex_cor;
                  cent2 += ex_cor * ((float) (jj) + 0.5 - cent);
                }
              }
            }
            cent2 /= flux;
            //printf("2 %d %d %lf %lf %lf %d %d %lf \n",ord, ii, cent2, flux, cent, w, (int)(cent)-w, prec);
            cent2 += cent;
            if (fabs(cent2 - cent) < prec) {
              lmax = w;
              //printf("%d %d %lf \n",ii, w, cent2-cent);
            } else {
              w = 1000;
            }
            w += 1;
          }
          //printf("%d %lf %d %d %d\n",ii, cent, ord, lmax, rmax);
          /*Check that isolation on both sides is above the minimum*/
          int ll=0;
          if (lmax >= min_iso && rmax >= min_iso) {
            /*For method safefit use model predictions to check against measured position,
             then determine x-disp co-ord*/
            if (strcmp(method, "safefit") == 0) {
              nb_match = 0;
              for (jj = 0; jj < cpl_table_get_nrow(tab_xy_guess); jj++) {
                if (ord == ordg[jj] - morder_min) {
                  /*Get x,y with model*/
                  check(
                      xsh_model_get_xy(p_xs_3, instr, wave[jj], absord, 0.0, &x,
                          &y));
                  x -= offx;
                  y -= offy;
                  if (lines_dev > 0 && fabs(y - cent + zero_off) < match_lim) {
                    nb_match++;
                    //printf("%lf %lf %lf %lf %lf %lf %d %d %d %d %lf %lf\n", wave[jj], x, pyg[jj], y, cent, y-cent, ord, lmax, rmax,nb_match,match_lim, fabs(y-cent+zero_off));
                    wave_use = wave[jj];
                  }
                  if (abs(y - cent) < (float) (min_iso) / 2.0) {
                    /*keep this measured disp centroid in a temporary vector while we still
                     need pyg (actually not necessary for the safefit method*/
                    yg_temp[jj] = cent;
                    psl[jj] = 1;
                    total = 0.0;
                    cent2 = 0.0;
                    /*Now get the barycenter in a rectagle 3 wide (centred on measured
                     disp co-ord) and +/-h around the model x-disp co-ord*/
                    for (ll = -h; ll <= h; ll++) {
                      tot = 0.0;
                      for (kk = -1; kk <= 1; kk++) {
                        /* 		    check(tot=cpl_image_get_median_window(ima_raw,(int)(x+0.5)+ll,(int)(cent+0.5)-1, */
                        /* 							  (int)(x+0.5)+ll,(int)(cent+0.5)+1)); */
                        /* 		    check(tot-=cpl_image_get_median_window(ima_raw,(int)(x+0.5)+14,(int)(cent+0.5)-1, */
                        /* 							     (int)(x+0.5)+16,(int)(cent+0.5)+1)); */
                        pix = size_x * ((int) (cent + 0.5) + kk)
                            + (int) (x + 0.5) + ll;
                        tot += detec[pix];
                        pix = size_x * ((int) (cent + 0.5) + kk)
                            + (int) (x + 0.5) + ll + 15;
                        tot -= detec[pix];
                        //printf("%d %d  %d %d  %lf \n",ll, kk,(int)(x+0.5)+ll,((int)(cent+0.5)+kk),tot);
                      }
                      total += tot;
                      cent2 += tot * ((float) (ll) + 0.5);
                    }
                    if (fabs(cent2 / total) < 3.0) {
                      cent2 = x + (cent2 / total);
                    } else {
                      cent2 = x;
                    }
                    /*keep this measured x-disp centroid in a temporary vector while we still
                     need pxg (actually not necessary for the safefit method)*/
                    xg_temp[jj] = cent2;
                  }
                }
              }
              if (nb_match == 1 && lines_dev > 0) {
                if (wave_use > startlam && wave_use < endlam) {
                  cnt++;
                  //printf("%lf 100.0 \n",wave_use);
                  printf("%lf 100.0 %d tot%d\n", wave_use, min_iso, cnt);
                }
              }
            } else {
              for (jj = 0; jj < cpl_table_get_nrow(tab_xy_guess); jj++) {
                if (ord == ordg[jj] - morder_min) {
                  //printf("-- %d %d %d %lf %lf %lf %lf %d %d \n", jj, lmax, rmax, pyg[jj],cent,pxg[jj],wave[jj],ord,ordg[jj]-morder_min);
                  if (abs(pyg[jj] - cent) < (float) (min_iso / 2)) {
                    //printf("%lf %lf %lf %lf %d \n", wave[jj], pxg[jj], pyg[jj], cent, ord);
                    /*keep this measured disp centroid in a temporary vector while we still
                     need pyg*/
                    yg_temp[jj] = cent;
                    psl[jj] = 1;
                  }
                }
              }
            }
          } //end of isolation margins check
        } //end for loop on ii (line peaks in data)
      } //end check on bright line vector
      else {
        xsh_msg_warning("bright_lines is NULL, order %d\n", ord);
      }
    } //end loop on orders
    /*copy the temporary vectors to the table (via the pointers set up earlier*/
    for (jj = 0; jj < cpl_table_get_nrow(tab_xy_guess); jj++) {
      if (yg_temp[jj] > 0.0) {
        pyg[jj] = yg_temp[jj];
        pxg[jj] = xg_temp[jj];
      }
      pyc[jj] = pyg[jj];
      pxc[jj] = pxg[jj];
    }
    //int nfit = 0;
    /*clear out table entries that were not matched to the real data*/
    check(cpl_table_and_selected_int(tab_xy_guess, "SELECT",
            CPL_GREATER_THAN, -1));
    check(tab_tmp = cpl_table_extract_selected(tab_xy_guess));
    xsh_free_table(&tab_xy_guess);
    check(cpl_table_erase_column(tab_tmp, "XC"));
    check(cpl_table_erase_column(tab_tmp, "YC"));

    check(cpl_table_duplicate_column(tab_tmp, "XC", tab_tmp, "XF"));
    check(cpl_table_duplicate_column(tab_tmp, "YC", tab_tmp, "YF"));

    check(cpl_table_save( tab_tmp, NULL, NULL, name_g, CPL_IO_DEFAULT));
    xsh_free_table(&tab_tmp);

  } else { //peaks or pm methods

    //Get parameters for linear extraction
    check(p = cpl_parameterlist_find(parameters, "xsh.xsh_cfg_recover.slit"));
    check(slit = cpl_parameter_get_int(p));

    check(
        p = cpl_parameterlist_find(parameters,
            "xsh.xsh_cfg_recover.peak_factor"));
    check(fct = cpl_parameter_get_double(p));

    check(
        p = cpl_parameterlist_find(parameters,
            "xsh.xsh_cfg_recover.peak_match_x"));
    check(thresh_x = cpl_parameter_get_int(p));

    check(
        p = cpl_parameterlist_find(parameters,
            "xsh.xsh_cfg_recover.peak_match_y"));
    check(thresh_y = cpl_parameter_get_int(p));

    check(
        p = cpl_parameterlist_find(parameters,
            "xsh.xsh_cfg_recover.ima_thresh_min"));
    check(thresh_min = cpl_parameter_get_double(p));

    //Image (linear) extraction: sum pixels
    //to check the actual image we are going to fit vs the model guess

    cknull(
        ima_ext = xsh_cfg_recover_linear_ext(raw_frm, order_tab_centr, instr,
            slit, thresh_min));


    cpl_table* tab_xy_trace=NULL;
    //Peaks image & table determination
    cknull(
        tab_xy_peaks = xsh_cfg_recover_measure_tab_xy_peaks(ima_ext,
            parameters));
    check(
        cpl_table_duplicate_column(tab_xy_peaks, "ABS_ORD", tab_xy_peaks,
            "REL_ORD"));

    check(name_g = cpl_frame_get_filename(*guess));
    check(tab_xy_guess = cpl_table_load(name_g, 1, 0));
    xsh_msg("guess table name=%s", name_g);

    check(name = cpl_frame_get_filename(order_tab_centr));
    check(tab_xy_trace = cpl_table_load(name, 1, 0));
    xsh_msg("Trace table name=%s", name);
    int ord_min = 0;
    check(ord_min = cpl_table_get_column_min(tab_xy_trace, "ABSORDER"));
    check(cpl_table_add_scalar(tab_xy_peaks, "ABS_ORD", ord_min));

    if (debug_level > XSH_DEBUG_LEVEL_NONE) {
      check(cpl_table_save( tab_xy_peaks, NULL, NULL, name_t, CPL_IO_DEFAULT));
    }

    check(
        xsh_cfg_recover_add_peaks_xpos(order_tab_centr, instr, &tab_xy_peaks));

    if (debug_level > XSH_DEBUG_LEVEL_NONE) {
      check(cpl_table_save( tab_xy_peaks, NULL, NULL, name_t, CPL_IO_DEFAULT));
    }


    if (fct > 0) {
      //Table peaks selection
      xsh_msg("Peaks selection fct=%g", fct);
      cknull(
          tab_xy_peaks_sel = xsh_cfg_recover_select_peaks(tab_xy_guess,
              tab_xy_peaks, fct));
    } else {
      xsh_msg("No peaks selection");
      tab_xy_peaks_sel = cpl_table_duplicate(tab_xy_peaks);
    }

    if (debug_level > XSH_DEBUG_LEVEL_NONE) {
      check(
          cpl_table_save(tab_xy_peaks_sel, NULL, NULL, "tab_xy_peaks_sel.fits",
              CPL_IO_DEFAULT));
    }
    //Line selection: pattern matching or simple box selection
    int ngue = 0;
    int npck = 0;
    if ((strcmp(method, "pm") == 0) || (strcmp(method, "manual") == 0)) {
      check(
          xsh_cfg_recover_prepare_pm_set(tab_xy_guess, tab_xy_peaks_sel,
              parameters, &mat_gue, &mat_msr, &use_pattern, &use_data));

      check(
          xsh_cfg_recover_pattern_match(parameters, mat_gue, mat_msr,
              use_pattern, use_data, debug_level));

    } else {

      //peaks table cleaning
      xsh_msg("Remove blended lines");
      //Identify and remove lines peaks which are either 
      //out of any box centered on
      //the line guess x-y position or that contain a neighboor 
      //within the same box
      ngue = cpl_table_get_nrow(tab_xy_guess);
      npck = cpl_table_get_nrow(tab_xy_peaks_sel);
      if (ngue <= npck) {
        cknull(
            tab_xy_corr = xsh_cfg_recover_remove_blends(tab_xy_guess,
                tab_xy_peaks_sel, thresh_x, thresh_y));

        if (debug_level > XSH_DEBUG_LEVEL_NONE) {
          check(
              cpl_table_save(tab_xy_corr, NULL, NULL, "tab_xy_corr.fits",
                  CPL_IO_DEFAULT));

        }
      } else {
        xsh_msg_error("Number og guess lines more than found peaks!");
        xsh_msg_error("Either increase factor ");
        xsh_msg_error("or choose a reference line table with less entries");
        return CPL_ERROR_ILLEGAL_INPUT;
      }
    }
  }

  cleanup: if (trace != NULL) {
    for (ii = 0; ii < MAX_NO_ORD; ii++) {
      xsh_free_vector(&(trace[ii]));
    }
    cpl_free(trace);
    trace = NULL;
  }

  if (extracted != NULL) {
    for (ii = 0; ii < MAX_NO_ORD; ii++) {
      xsh_free_vector(&(extracted[ii]));
    }
    cpl_free(extracted);
    extracted = NULL;
  }

  xsh_free_frame(&spec_form_frame);
  xsh_free_table(&spec_form_tab);
  xsh_free_image(&ima);
  xsh_free_image(&ima_ext);
  xsh_free_table(&tab_xy_guess);
  xsh_free_table(&tab_xy_peaks);
  xsh_free_table(&tab_xy_peaks_sel);
  xsh_free_table(&tab_tmp);
  xsh_free_table(&tab_tmp1);
  xsh_free_table(&tab_tmp2);
  xsh_free_table(&tab_xy_corr);
  cpl_vector_delete(spec_clean);
  if (cpl_error_get_code() != CPL_ERROR_NONE) {
    xsh_print_rec_status(0);
  }
  return cpl_error_get_code();

}


/*--------------------------------------------------------------------------*/
/**
   @name  xsh_cfg_recover_prepare_pm_set
   @brief Prepare  data for pattern matching
   @param tab_xy_guess table containing xy pattern
   @param tab_xy_peaks_sel table containing xy data
   @param parameters recipe parameters
   @param mat_gue matrix catalog (output)
   @param mat_msr matrix data (output)
   @return   error code status

*/
/*--------------------------------------------------------------------------*/

static cpl_error_code
xsh_cfg_recover_prepare_pm_set(cpl_table* tab_pat,
			    cpl_table* tab_dat,
                            cpl_parameterlist* parameters,
			    cpl_matrix** mat_pat,
                            cpl_matrix** mat_dat,
                            int* use_pat, 
                            int* use_dat)

{

  int npat=0;
  int ndat=0;
  int i=0; 
 
  double* pxd=NULL;
  double* pyd=NULL;
  double* pxg=NULL;
  double* pyg=NULL;

  int* pog=NULL;
  int* pod=NULL;
  int* ps=NULL;

  int ord_min=0;
  int ord_max=0;
  int ord_min_dat=0;
  int ord_max_dat=0;

  int ord=0;

  int ord_sel=5;
  cpl_parameter* p=NULL;
  cpl_table* pat=NULL;
  cpl_table* dat=NULL;
  cpl_table* tmp=NULL;

  int j=0;
  double rad=0;
  double xmin=0;
  double xmax=0;
  double ymin=0;
  double ymax=0;

  check(p = cpl_parameterlist_find(parameters,"xsh.xsh_cfg_recover.pm_ord_sel"));
  check(ord_sel = cpl_parameter_get_int(p));

  check(p = cpl_parameterlist_find(parameters,"xsh.xsh_cfg_recover.pm_radius"));
  check(rad = cpl_parameter_get_double(p));


  check(npat=cpl_table_get_nrow(tab_pat));
  check(ndat=cpl_table_get_nrow(tab_dat));


  check(xsh_sort_table_1(tab_pat,"ABS_ORD",CPL_TRUE));
  check(xsh_sort_table_1(tab_dat,"ABS_ORD",CPL_TRUE));

  check(pat=cpl_table_duplicate(tab_pat));
  check(cpl_table_new_column(pat,"SEL",CPL_TYPE_INT));
  check(cpl_table_fill_column_window(pat,"SEL",0,npat,-1));


  check(ps=cpl_table_get_data_int(pat,"SEL"));
  check(pog=cpl_table_get_data_int(pat,"ABS_ORD"));

  check(ord_min=cpl_table_get_column_min(pat,"ABS_ORD"));
  check(ord_max=cpl_table_get_column_max(pat,"ABS_ORD"));


  check(ord_min_dat=cpl_table_get_column_min(tab_dat,"ABS_ORD"));
  check(ord_max_dat=cpl_table_get_column_max(tab_dat,"ABS_ORD"));

  xsh_msg("pat min=%d max=%d",ord_min,ord_max);
  xsh_msg("dat min=%d max=%d",ord_min_dat,ord_max_dat);


  *use_pat=0;

  //select starting pattern points
  for(ord=ord_min;ord<=ord_max;ord++) {
    for(i=0;i<npat;i++) {
      if((pog[i]==ord) && (j< ord_sel)) {
	ps[i]=1;
	j++;
      }
    }
    j=0;
  }
  check(*use_pat=cpl_table_and_selected_int(pat,"SEL",CPL_GREATER_THAN,0));
  check(tmp=cpl_table_extract_selected(pat));
  //PIPPO
  check(cpl_table_save(pat,NULL,NULL,"pat.fits",CPL_IO_DEFAULT));


  check(dat=cpl_table_duplicate(tab_dat));
  check(cpl_table_new_column(dat,"SEL",CPL_TYPE_INT));
  check(cpl_table_fill_column_window(dat,"SEL",0,ndat,-1));
  check(ps=cpl_table_get_data_int(dat,"SEL"));

  check(pod=cpl_table_get_data_int(dat,"ABS_ORD"));
  check(pxd=cpl_table_get_data_double(dat,"XP"));
  check(pyd=cpl_table_get_data_double(dat,"YP"));

  check(pog=cpl_table_get_data_int(tmp,"ABS_ORD"));
  check(pxg=cpl_table_get_data_double(tmp,"XC"));
  check(pyg=cpl_table_get_data_double(tmp,"YC"));

  //select starting data points
  for(i=0;i<*use_pat;i++) {
    xmin=pxg[i]-rad;
    xmax=pxg[i]+rad;
    ymin=pyg[i]-rad;
    ymax=pyg[i]+rad;
    for(j=0;j<ndat;j++) {
      if( pog[i] == pod[j] ) {
	if(pxd[j] >= xmin  &&  pxd[j] <= xmax) {
	  if(pyd[j] >= ymin  &&  pyd[j] <= ymax  ) {
	    ps[j]=1;
	  }
	}
      }
    }
  }
  check(cpl_table_save(dat,NULL,NULL,"dat.fits",CPL_IO_DEFAULT));
  check(*use_dat=cpl_table_and_selected_int(dat,"SEL",CPL_GREATER_THAN,0));

  xsh_msg("use_pattern=%d use_data=%d",*use_pat,*use_dat);
  if(*use_pat > *use_dat) {
     xsh_msg_error("You try to find a matching pattern searching ");
     xsh_msg_error("more points than available data. Try to increase ");
     xsh_msg_error("pm_radius and or peaks_factor ");
     xsh_msg_error("and/or decrease pm_ord_sel parameter values");
     goto cleanup;
  }

  check(xsh_sort_table_1(dat,"SEL",CPL_TRUE));
  check(xsh_sort_table_1(pat,"SEL",CPL_TRUE));
  check(*mat_pat=cpl_matrix_new(2,npat));
  check(*mat_dat=cpl_matrix_new(2,ndat));

  check(pxg=cpl_table_get_data_double(pat,"XC"));
  check(pyg=cpl_table_get_data_double(pat,"YC"));
  for(i=0;i<npat;i++) {

    check(cpl_matrix_set(*mat_pat,0,i,pxg[i]));
    check(cpl_matrix_set(*mat_pat,1,i,pyg[i]));

  }

  check(pxd=cpl_table_get_data_double(dat,"XP"));
  check(pyd=cpl_table_get_data_double(dat,"YP"));
  for(i=0;i<ndat;i++) {

    check(cpl_matrix_set(*mat_dat,0,i,pxd[i]));
    check(cpl_matrix_set(*mat_dat,1,i,pyd[i]));

  }


 cleanup:
  xsh_free_table(&pat);
  xsh_free_table(&dat);
  xsh_free_table(&tmp);


  return cpl_error_get_code() ;

}


/*--------------------------------------------------------------------------*/
/**
   @name  xsh_cfg_recover_pattern_match 
   @brief Select lines using pattern matching technique  
   @param parameters recipe input parameters
   @param mat_cat matrix catalog
   @param mat_dat matrix data
   @param use_pattern starting number of searched pattern points
   @param use_data    starting number of searched data points
   @param debug_level debug level
   @return cpl_error_code

*/
/*--------------------------------------------------------------------------*/


static cpl_error_code
xsh_cfg_recover_pattern_match(cpl_parameterlist* parameters,
                          cpl_matrix* mat_gue,
                          cpl_matrix* mat_dat,
                          int use_pattern,
                          int use_data,
                          int debug_level)
{
  cpl_array  *matches  = NULL;

  double err_data=1;
  double err_pattern=0;
  double tolerance=0.1;
  double radius=1;
  cpl_matrix* mdata=NULL;
  cpl_matrix* mpattern=NULL;
  cpl_parameter* p=NULL;
  cpl_table* pm_tbl=NULL;
  cpl_table* dat_tbl=NULL;
  cpl_table*gue_tbl=NULL;

  int nmatch=0;
  double* pcatx=NULL;
  double* pcaty=NULL;    
  double* ppatx=NULL;
  double* ppaty=NULL;
  int i=0;
  int ndat=0;
  int ngue=0;
  double lin_scale=1.0;
  double lin_angle=0.0;


  check(p = cpl_parameterlist_find(parameters,"xsh.xsh_cfg_recover.pm_tolerance"));
  check(tolerance = cpl_parameter_get_double(p));

  check(p = cpl_parameterlist_find(parameters,"xsh.xsh_cfg_recover.pm_radius"));
  check(radius = cpl_parameter_get_double(p));

     
  //Monitor input data
  ndat=cpl_matrix_get_ncol(mat_dat);
  ngue=cpl_matrix_get_ncol(mat_gue);
  
  check(dat_tbl=cpl_table_new(ndat));
  check(gue_tbl=cpl_table_new(ngue));
  
  check(cpl_table_new_column(dat_tbl,"XD",CPL_TYPE_DOUBLE));
  check(cpl_table_new_column(dat_tbl,"YD",CPL_TYPE_DOUBLE));
  check(cpl_table_fill_column_window(dat_tbl,"XD",0,ndat,0));
  check(cpl_table_fill_column_window(dat_tbl,"YD",0,ndat,0));
  check(pcatx=cpl_table_get_data_double(dat_tbl,"XD"));
  check(pcaty=cpl_table_get_data_double(dat_tbl,"YD"));



  for(i=0;i<ndat;i++) {

    check(pcatx[i]=cpl_matrix_get(mat_dat,0,i));
    check(pcaty[i]=cpl_matrix_get(mat_dat,1,i));


  }

  if(debug_level > XSH_DEBUG_LEVEL_NONE) {
    check(cpl_table_save(dat_tbl,NULL,NULL,"pm_dat.fits",CPL_IO_DEFAULT));
  }

  check(cpl_table_new_column(gue_tbl,"XG",CPL_TYPE_DOUBLE));
  check(cpl_table_new_column(gue_tbl,"YG",CPL_TYPE_DOUBLE));
  check(cpl_table_fill_column_window(gue_tbl,"XG",0,ngue,0));
  check(cpl_table_fill_column_window(gue_tbl,"YG",0,ngue,0));
  check(ppatx=cpl_table_get_data_double(gue_tbl,"XG"));
  check(ppaty=cpl_table_get_data_double(gue_tbl,"YG"));


  for(i=0;i<ngue;i++) {

    check(ppatx[i]=cpl_matrix_get(mat_gue,0,i));
    check(ppaty[i]=cpl_matrix_get(mat_gue,1,i));


  }

  if(debug_level > XSH_DEBUG_LEVEL_NONE) {
    check(cpl_table_save(gue_tbl,NULL,NULL,"pm_gue.fits",CPL_IO_DEFAULT));
  }    
  check(matches = cpl_ppm_match_points(mat_dat,use_data,err_data, 
				       mat_gue,use_pattern,err_pattern,
				       tolerance,radius,&mdata, &mpattern,
				       &lin_scale,&lin_angle));
   
  check(nmatch=cpl_matrix_get_ncol(mpattern));
  xsh_msg("%d points matched linear scale factor=%f linear angle factor %f", 
	  nmatch,lin_scale,lin_angle);

  check(pm_tbl=cpl_table_new(nmatch));
  check(cpl_table_new_column(pm_tbl,"PM_CAT_X",CPL_TYPE_DOUBLE));
  check(cpl_table_new_column(pm_tbl,"PM_CAT_Y",CPL_TYPE_DOUBLE));
  check(cpl_table_new_column(pm_tbl,"PM_PAT_X",CPL_TYPE_DOUBLE));
  check(cpl_table_new_column(pm_tbl,"PM_PAT_Y",CPL_TYPE_DOUBLE));

  check(cpl_table_fill_column_window(pm_tbl,"PM_CAT_X",0,nmatch,0));
  check(cpl_table_fill_column_window(pm_tbl,"PM_CAT_Y",0,nmatch,0));
  check(cpl_table_fill_column_window(pm_tbl,"PM_PAT_X",0,nmatch,0));
  check(cpl_table_fill_column_window(pm_tbl,"PM_PAT_Y",0,nmatch,0));


  check(ppatx=cpl_table_get_data_double(pm_tbl,"PM_CAT_X"));
  check(ppaty=cpl_table_get_data_double(pm_tbl,"PM_CAT_Y"));

  check(pcatx=cpl_table_get_data_double(pm_tbl,"PM_PAT_X"));
  check(pcaty=cpl_table_get_data_double(pm_tbl,"PM_PAT_Y"));
    
  for(i=0;i<nmatch;i++) {

    check(pcatx[i]=cpl_matrix_get(mdata,0,i));
    check(pcaty[i]=cpl_matrix_get(mdata,1,i));

    check(ppatx[i]=cpl_matrix_get(mpattern,0,i));
    check(ppaty[i]=cpl_matrix_get(mpattern,1,i));


  }

  if(debug_level > XSH_DEBUG_LEVEL_NONE) {
    check(cpl_table_save(pm_tbl,NULL,NULL,
			 "pattern_match.fits",CPL_IO_DEFAULT));
  }
  xsh_free_table(&gue_tbl);
  xsh_free_table(&dat_tbl);
  xsh_free_table(&pm_tbl);
  xsh_free_array(&matches);
  xsh_free_matrix(&mpattern);
  xsh_free_matrix(&mdata);

 cleanup:
  if(cpl_error_get_code() != CPL_ERROR_NONE) {
    xsh_msg("Try to increase pm_radius and/or peak_factor");
  }
  return cpl_error_get_code() ;

}



/*--------------------------------------------------------------------------*/
/**
   @name  xsh_cfg_recover_add_peaks_xpos 
   @brief Add peaks x positions by taking into account of order polynomial  
   @param  order_tab_centr the input order table frame 
   @param  tab_xy_peaks  the input table with line IDs
   @return the input table with added x positions corresponding to y positions

*/
/*--------------------------------------------------------------------------*/
static cpl_error_code
xsh_cfg_recover_add_peaks_xpos(cpl_frame* order_tab_centr,
                           xsh_instrument* instr,
                           cpl_table** tab_xy_peaks)
{

  xsh_order_list* order_list = NULL;
  int size=0;
  double* px=NULL;
  double* py=NULL;
  int* po=NULL;
  int ord_min=0;
  int ord_rel=0;
  //double pre_scan=50;
  //double over_scan=50;
  int i=0;

  check(size=cpl_table_get_nrow(*tab_xy_peaks));
  check(cpl_table_new_column(*tab_xy_peaks,"XP",CPL_TYPE_DOUBLE));
  check(cpl_table_fill_column_window(*tab_xy_peaks,"XP",0,size,-1));

  check(px=cpl_table_get_data_double(*tab_xy_peaks,"XP"));
  check(py=cpl_table_get_data_double(*tab_xy_peaks,"YP"));
  check(po=cpl_table_get_data_int(*tab_xy_peaks,"ABS_ORD"));
  ord_min=cpl_table_get_column_min(*tab_xy_peaks,"ABS_ORD");

  check(order_list = xsh_order_list_load(order_tab_centr,instr));

  //xsh_msg("size=%d",size);
  for(i=0;i<size;i++) {
    //xsh_msg("abs order=%d",po[i]);
    check( ord_rel = xsh_order_list_get_order( order_list, po[i] ) ) ;
    //xsh_msg("rel order=%d",ord_rel);
    ord_rel=po[i]-ord_min;
    //xsh_msg("rel order=%d",ord_rel);

    //xsh_msg("size-1=%d",order_list->size-1);
    if(cpl_polynomial_get_dimension(order_list->list[ord_rel].cenpoly) <
       XSH_ORDPOS_POL_DIM_MAX) {

    check( px[i] = cpl_polynomial_eval_1d(
					  order_list->list[ord_rel].cenpoly,py[i],NULL));
    }
    //      order_list->list[order_list->size-1].cenpoly,py[i],NULL));
    //xsh_msg("y=%f xfit+prescan=%f",py[i], pxc[i]);
    //xsh_msg("y=%f x=%f",py[i], px[i]);
  }

 cleanup:
  xsh_order_list_free(&order_list);

  return cpl_error_get_code();


}

/*--------------------------------------------------------------------------*/
/**
   @name  xsh_cfg_recover_remove_blends 
   @brief    Remove blended lines from input line catalog  
   @param    tab_xy_guess  the input table with line IDs
   @param    tab_xy_peaks_sel the input table with line peaks
   @param    thresh_x x radii for peaks match search
   @param    thresh_y y radii for peaks match search
   @return   a cleaned table.

*/
/*--------------------------------------------------------------------------*/

static cpl_table* 
xsh_cfg_recover_remove_blends(cpl_table* tab_xy_guess,
                          cpl_table* tab_xy_peaks_sel,
                          const int thresh_x,
                          const int thresh_y)
{

  //double* pxg=NULL;
  //double* pyg=NULL;
  double* pyt=NULL;
  double* pyp=NULL;

  double* pxt=NULL;
  double* pxp=NULL;
  int* pwp=NULL;
  int* pap=NULL;
  int* prp=NULL;



  double* pxr=NULL;
  double* pyr=NULL;
  int* pwr=NULL;
  int* par=NULL;
  int* prr=NULL;

  double x=0;
  double y=0;
  int r=0;
  int a=0;
  int w=0;

 
  int ord=0;
  int ord_min=0;
  int ord_max=0;
  int nord=0;
  int npks=0;
  cpl_table* tab_tmp=NULL;
  cpl_table* tab_tmp1=NULL;
  cpl_table* tab_tmp2=NULL;

  cpl_table* result=NULL;
  int found=0;
  int i=0;
  int j=0;
 
  int k=0;
  int nrows=0;

  //pxg=cpl_table_get_data_double(tab_xy_guess,"XC");
  //pyg=cpl_table_get_data_double(tab_xy_guess,"YC");
  ord_min=cpl_table_get_column_min(tab_xy_guess,"ABS_ORD");
  ord_max=cpl_table_get_column_max(tab_xy_guess,"ABS_ORD");

  check(tab_tmp2=cpl_table_duplicate(tab_xy_peaks_sel));
  check(nrows=cpl_table_get_nrow(tab_tmp2));
  check(cpl_table_fill_column_window(tab_tmp2,"YP",0,nrows,-1));
  check(cpl_table_fill_column_window(tab_tmp2,"XP",0,nrows,-1));
  check(cpl_table_fill_column_window(tab_tmp2,"REL_ORD",0,nrows,-1));
  check(cpl_table_fill_column_window(tab_tmp2,"ABS_ORD",0,nrows,-1));
  check(cpl_table_fill_column_window(tab_tmp2,"WEIGHT",0,nrows,-1));
  
  check(pxr=cpl_table_get_data_double(tab_tmp2,"XP"));
  check(pyr=cpl_table_get_data_double(tab_tmp2,"YP"));
  check(prr=cpl_table_get_data_int(tab_tmp2,"REL_ORD"));
  check(pwr=cpl_table_get_data_int(tab_tmp2,"WEIGHT"));
  check(par=cpl_table_get_data_int(tab_tmp2,"ABS_ORD"));
  //xsh_msg("nrows=%d",nrows);
  for(ord=ord_min;ord<=ord_max;ord++) {
    check(nord=cpl_table_and_selected_int(tab_xy_guess,"ABS_ORD",
					  CPL_EQUAL_TO,ord));
    check(npks=cpl_table_and_selected_int(tab_xy_peaks_sel,"ABS_ORD",
					  CPL_EQUAL_TO,ord));
    xsh_free_table(&tab_tmp);
    check(tab_tmp=cpl_table_extract_selected(tab_xy_guess));
    xsh_free_table(&tab_tmp1);
    check(tab_tmp1=cpl_table_extract_selected(tab_xy_peaks_sel));

    pxt=cpl_table_get_data_double(tab_tmp,"XC");
    pyt=cpl_table_get_data_double(tab_tmp,"YC");

    pxp=cpl_table_get_data_double(tab_tmp1,"XP");
    pyp=cpl_table_get_data_double(tab_tmp1,"YP");
    prp=cpl_table_get_data_int(tab_tmp1,"REL_ORD");
    pwp=cpl_table_get_data_int(tab_tmp1,"WEIGHT");
    pap=cpl_table_get_data_int(tab_tmp1,"ABS_ORD");
    //xsh_msg("ord=%d nord=%d npks=%d",ord,nord,npks);

    for(i=0;i<nord;i++) {
      found=0;
      for(j=0;j<npks;j++) {
	//xsh_msg("dist=%f thresh=%d",fabs(pyp[j]-pyt[i]),thresh_y);
	if((fabs(pxp[j]-pxt[i]) < thresh_x) &&
	   (fabs(pyp[j]-pyt[i]) < thresh_y)) {
	  found++;
	  r=prp[j];
	  w=pwp[j];
	  a=pap[j];
	  x=pxp[j];
	  y=pyp[j];

	}
      }
      if(found==1) {
	pxr[k]=x;
	pyr[k]=y;
	prr[k]=r;
	pwr[k]=w;
	par[k]=a;
	k++;
	//xsh_msg("ord=%d found=%d k=%d",ord,found,k);
      }
    }
    check(cpl_table_select_all(tab_xy_peaks_sel));
    check(cpl_table_select_all(tab_xy_guess));
  }

  check(cpl_table_and_selected_int(tab_tmp2,"REL_ORD",CPL_GREATER_THAN,-1));
  check(result=cpl_table_extract_selected(tab_tmp2));
  check(cpl_table_name_column(result,"XP","XC"));
  check(cpl_table_name_column(result,"YP","YC"));

 cleanup:
  xsh_free_table(&tab_tmp);
  xsh_free_table(&tab_tmp1);
  xsh_free_table(&tab_tmp2);


  if (cpl_error_get_code() != CPL_ERROR_NONE) {
    return NULL;
  } else {
    return result;
  }

}

/*--------------------------------------------------------------------------*/
/**
   @name  xsh_cfg_recover_select_peaks 
   @brief Select lines from input line catalog whose Y interdistance is 
   greater than a threshold  
   @param tab_xy_guess  the input table with line IDs
   @param tab_xy_peaks_sel the input table with line peaks
   @return a cleaned table.

*/
/*--------------------------------------------------------------------------*/

static cpl_table*
xsh_cfg_recover_select_peaks(cpl_table* tab_xy_guess,
                         cpl_table* tab_xy_peaks, 
                         const double factor)
{


  int ord=0;
  int nord=0;
  int ord_min=0;
  int ord_max=0;
  int ord_min_peaks=0;
  int ord_max_peaks=0;
  int ord_min_guess=0;
  int ord_max_guess=0;

  int npks=0;
  cpl_table* tab_tmp=NULL;
  cpl_table* tab_tmp1=NULL;
  cpl_table* result=NULL;
  int weight_min=0;
  int nrows=0;

  check(ord_min_guess=cpl_table_get_column_min(tab_xy_guess,"ABS_ORD"));
  check(ord_max_guess=cpl_table_get_column_max(tab_xy_guess,"ABS_ORD"));

  check(ord_min_peaks=cpl_table_get_column_min(tab_xy_peaks,"ABS_ORD"));
  check(ord_max_peaks=cpl_table_get_column_max(tab_xy_peaks,"ABS_ORD"));
  ord_min=(ord_min_guess<=ord_min_peaks) ? ord_min_guess : ord_min_peaks;
  ord_max=(ord_max_guess>=ord_max_peaks) ? ord_max_guess : ord_max_peaks;

  cpl_table_select_all(tab_xy_peaks);

  xsh_msg("select lines in order range=[%d,%d]",ord_min,ord_max);
  //select the line peak sub table having for each order as many entries
  //as in the input table line list. Those are the brighest lines
  for(ord=ord_min;ord<=ord_max;ord++) {
  
    nord=cpl_table_and_selected_int(tab_xy_guess,"ABS_ORD",CPL_EQUAL_TO,ord);
    npks=cpl_table_and_selected_int(tab_xy_peaks,"ABS_ORD",CPL_EQUAL_TO,ord);
    check(tab_tmp=cpl_table_extract_selected(tab_xy_peaks));
    //xsh_msg("ord=%d nord=%d npks=%d",ord,nord,npks);
    if(npks>nord) {
      weight_min=cpl_table_get_column_min(tab_tmp,"WEIGHT");
      check(npks=cpl_table_and_selected_int(tab_tmp,"WEIGHT",
					    CPL_NOT_GREATER_THAN,
					    (int)(weight_min+factor*nord)));
      tab_tmp1=cpl_table_extract_selected(tab_tmp);
      //xsh_msg("ord=%d nord=%d weight_min=%d thresh=%d npks=%d",
      //      ord,nord,weight_min,(int)(weight_min+factor*nord),npks);

    } else {
      tab_tmp1=cpl_table_duplicate(tab_tmp);
    }
    if(ord == ord_min) {
      result=cpl_table_duplicate(tab_tmp1);
    } else {
      nrows=cpl_table_get_nrow(tab_xy_peaks);
      cpl_table_insert(result,tab_tmp1,nrows);
    }

    xsh_free_table(&tab_tmp1);
    xsh_free_table(&tab_tmp);
    cpl_table_select_all(tab_xy_peaks);
    cpl_table_select_all(tab_xy_guess);
  }
   
 cleanup:
  xsh_free_table(&tab_tmp1);
  xsh_free_table(&tab_tmp);

  if (cpl_error_get_code() != CPL_ERROR_NONE) {
    return NULL;
  } else {
    return result;
  }


}


/*--------------------------------------------------------------------------*/
/**
   @name  xsh_cfg_recover_measure_tab_xy_peaks
   @brief Determines line peaks in an input image frame  
   @param ima_ext  the input image (with spectra describing extracted orders)
   @param parameters the recipe input parameters
   @return table containing line peaks positions

*/
/*--------------------------------------------------------------------------*/
static cpl_table* 
xsh_cfg_recover_measure_tab_xy_peaks(cpl_image* ima_ext,
				 cpl_parameterlist* parameters)
{

  const char* name_p="ima_peaks.fits";
  const int size=5000;
  cpl_table* result=NULL;
  cpl_propertylist* plist=NULL; 
  double* pp=NULL;
  int* po=NULL;
  int row=0;
  int ord=0;
  int ord_num=0;

  double* pv=NULL;
  int sv=0;
  int* pw=NULL;
  int nrows=0;
  cpl_vector* spectrum=NULL;
  cpl_vector* peaks=NULL;
  int display=0;
  int line_fwhm=4;
  double kappa=5;
  cpl_parameter* p=NULL;
  int i=0;
  cpl_table* tab_tmp=NULL;
  int debug_level=0;
  char ext_val[10];

  check(p=cpl_parameterlist_find(parameters,"xsh.xsh_cfg_recover.plot"));
  check(display = cpl_parameter_get_bool(p));

  check(p=cpl_parameterlist_find(parameters,"xsh.xsh_cfg_recover.peak_line_fwhm"));
  check(line_fwhm = cpl_parameter_get_int(p));

  check(p=cpl_parameterlist_find(parameters,"xsh.xsh_cfg_recover.peak_kappa"));
  check(kappa = cpl_parameter_get_double(p));
  check(debug_level=xsh_parameters_debug_level_get("xsh_cfg_recover",parameters));
  ord_num=cpl_image_get_size_y(ima_ext);

  result=cpl_table_new(size);
  cpl_table_new_column(result,"YP",CPL_TYPE_DOUBLE);
  cpl_table_new_column(result,"REL_ORD",CPL_TYPE_INT);
  check(cpl_table_fill_column_window(result,"YP",0,size,-1));
  check(cpl_table_fill_column_window(result,"REL_ORD",0,size,-1));

  pp=cpl_table_get_data_double(result,"YP");
  po=cpl_table_get_data_int(result,"REL_ORD");

  row=0;
  for(ord=0;ord<ord_num;ord++) {
    check(spectrum=cpl_vector_new_from_image_row(ima_ext,ord+1));
    check(peaks=xsh_spectrum_detect_peaks(spectrum,line_fwhm,kappa,display));
    if(debug_level>XSH_DEBUG_LEVEL_NONE) {
      plist=cpl_propertylist_new();
      sprintf(ext_val,"%s%d","ext",ord);
      cpl_propertylist_append_string(plist,"EXTNAME",ext_val);
      if(ord==0) {
	cpl_vector_save(spectrum,name_p,CPL_BPP_IEEE_FLOAT,plist,
			CPL_IO_DEFAULT);
      } else {
	cpl_vector_save(spectrum,name_p,CPL_BPP_IEEE_FLOAT,
			plist,CPL_IO_EXTEND);
      }
      xsh_free_propertylist(&plist);
    }
    if(peaks!=NULL) {
    check(sv=cpl_vector_get_size(peaks));
    if (sv>0) {
      check(pv=cpl_vector_get_data(peaks));
      for(i=0;i<sv;i++) {
	po[row]=ord;
	pp[row]=pv[i];
	row++;
      }
    }
    }
    xsh_free_vector(&spectrum);
    xsh_free_vector(&peaks);
  }
  check(cpl_table_and_selected_double(result,"YP",CPL_GREATER_THAN,-1));
  check(tab_tmp=cpl_table_extract_selected(result));
  xsh_free_table(&result);
  result=cpl_table_duplicate(tab_tmp);   
  xsh_free_table(&tab_tmp);

  check(cpl_table_erase_invalid_rows(result));

  cpl_table_new_column(result,"WEIGHT",CPL_TYPE_INT);
  nrows=cpl_table_get_nrow(result);
  xsh_msg("size=%d",size);
  check(cpl_table_fill_column_window(result,"WEIGHT",0,size,-1));
  check(pw=cpl_table_get_data_int(result,"WEIGHT"));

  for(i=0;i<nrows;i++) {
    pw[i]=i;
  }

 cleanup:
  xsh_free_table(&tab_tmp);
  xsh_free_vector(&spectrum);
  xsh_free_vector(&peaks);

  if (cpl_error_get_code() != CPL_ERROR_NONE) {
    return NULL;
  } else {
    return result;
  }

}


/*--------------------------------------------------------------------------*/
/**
   @name  xsh_cfg_recover_linear_ext
   @brief Determines extracted spectra  
   @param raw_frm  the input image frame to be extracted 
   @param order_tab_centr the order table frame tracing the frame order
   @param instr the instrument setting
   @param slit the extraction slit
   @param parameters the recipe input parameters
   @return table containing line peaks positions
   This function allocates an image
*/
/*--------------------------------------------------------------------------*/
static cpl_image* 
xsh_cfg_recover_linear_ext(cpl_frame* raw_frm, 
                       cpl_frame* order_tab_centr,
                       xsh_instrument* instr,
                       const int slit,
                       const double min)

{
  const char* name=NULL;
  cpl_image* input=NULL;

  const char* name_o="ima_raw.fits";
  const char* name_e="ima_ext.fits";
  int sx=0;
  int sy=0;
  int ord_num=0;
  int ord_min_tra=0;
  int ord_max_tra=0;

  int ord=0;

  cpl_image* result=NULL;
  double* pou=NULL;
  double* pin=NULL;
  int i=0;
  int j=0;
  double x=0;
  int s=0;
  double flux=0;
  int pix=0;
  xsh_order_list* order_list = NULL;
  cpl_table* tab_centr=NULL;

  check(name=cpl_frame_get_filename(raw_frm));
  check(input=cpl_image_load(name,CPL_TYPE_DOUBLE,0,0));
  check(cpl_image_threshold(input,min,FLT_MAX,0,FLT_MAX));
  check(cpl_image_save(input,name_o,CPL_BPP_IEEE_FLOAT,NULL,
		       CPL_IO_DEFAULT));

  xsh_msg("extracting image %s",name_o);

  check(sx=cpl_image_get_size_x(input));
  check(sy=cpl_image_get_size_y(input));
  check(name=cpl_frame_get_filename( order_tab_centr));
  check(tab_centr=cpl_table_load(name,1,0));

  ord_min_tra=cpl_table_get_column_min(tab_centr,"ABSORDER");
  ord_max_tra=cpl_table_get_column_max(tab_centr,"ABSORDER");
  xsh_free_table(&tab_centr);

  ord_num=ord_max_tra-ord_min_tra+1;

  // allocates output image
  check(result=cpl_image_new(sy,ord_num,CPL_TYPE_DOUBLE));
  check(pou=cpl_image_get_data_double(result));
  check(pin=cpl_image_get_data_double(input));

  // we get the polynomials to follow the order traces during extraction
  check(order_list = xsh_order_list_load(order_tab_centr,instr));
  // average extraction

  //xsh_msg("ord_num=%d sx=%d sy=%d",ord_num,sx,sy);
  // do the linear extraction
  for(ord=0;ord<ord_num;ord++) {
    for(j=0;j<sy;j++) {
      flux=0;
      if(cpl_polynomial_get_dimension(order_list->list[ord].cenpoly) <
       XSH_ORDPOS_POL_DIM_MAX) {
	check(x=cpl_polynomial_eval_1d(order_list->list[ord].cenpoly,j,NULL));
      //xsh_msg("%d %ld",j,x);
      }
      i=(int)(x+0.5);
      for(s=-slit;s<=slit;s++) {
	pix=j*sx+i+s;
	if ( (pix>0) && (pix<sx*sy) ) {
	  flux+=pin[pix];
	  //xsh_msg("i=%d j=%d flux=%f",i,j,flux);
	}
      }
      pou[ord*sy+j]=flux;
    }
  }


    check(cpl_image_save(result,name_e,CPL_BPP_IEEE_FLOAT,NULL,
			 CPL_IO_DEFAULT));

 cleanup:
  xsh_free_image(&input);
  xsh_free_table(&tab_centr);
  xsh_order_list_free( &order_list ) ;

  if (cpl_error_get_code() != CPL_ERROR_NONE) {
    return NULL;
  } else {
    return result;
  }

}

/*--------------------------------------------------------------------------*/
/**
   @name  xsh_cfg_recover_guess_tab_corr_by_ordpos
   @brief Correct model guess X positions taking into account of order traces
   @param instr the instrument setting
   @param order_tab_centr the order table frame tracing the frame order
   @param model_xy_gue the guess table whose X positions are being corrected 
   @param debug_level debug level
   @return cpl_error_code

*/
/*--------------------------------------------------------------------------*/
static cpl_error_code
xsh_cfg_recover_guess_tab_corr_by_ordpos(xsh_instrument* instr,
                                     cpl_frame* order_tab_centr,
                                     cpl_frame** model_xy_gue) {

  cpl_table* tab_xy_guess=NULL;
  xsh_order_list* order_list = NULL;
  int size=0;
  double* pxc=NULL;
  double* pyc=NULL;
  double* px=NULL;
  double* py=NULL;
  int* pog=NULL;
  int* por=NULL;
  int* poa=NULL;
  int ord_min_tra=0;
  int ord_max_tra=0;

  int ord_min_gue=0;
  int ord_max_gue=0;
  int ord_min_off=0;
  int ord_max_off=0;

  int ord_rel=0;
  //double pre_scan=50;
  //double over_scan=50;

  const char* name_c=NULL;
  const char* name_g=NULL;
  int i=0;
  cpl_table * tab_centr=NULL;
  int sizey=4096;
  int j=0;
  int ord=0;
  int nord=0;

  check(name_g=cpl_frame_get_filename(*model_xy_gue));
  //xsh_msg("model guesses file=%s",name_g);
  check(tab_xy_guess=cpl_table_load(name_g,1,0));

  check(size=cpl_table_get_nrow(tab_xy_guess));
  check(cpl_table_new_column(tab_xy_guess,"XC",CPL_TYPE_DOUBLE));
  check(cpl_table_new_column(tab_xy_guess,"YC",CPL_TYPE_DOUBLE));
  check(cpl_table_fill_column_window(tab_xy_guess,"XC",0,size,-1));
  check(cpl_table_fill_column_window(tab_xy_guess,"YC",0,size,-1));

  check(pxc=cpl_table_get_data_double(tab_xy_guess,"XC"));
  check(pyc=cpl_table_get_data_double(tab_xy_guess,"YC"));
  check(px=cpl_table_get_data_double(tab_xy_guess,"XG"));
  check(py=cpl_table_get_data_double(tab_xy_guess,"YG"));
  check(pog=cpl_table_get_data_int(tab_xy_guess,"ABS_ORD"));
  check(ord_min_gue=cpl_table_get_column_min(tab_xy_guess,"ABS_ORD"));
  check(ord_max_gue=cpl_table_get_column_max(tab_xy_guess,"ABS_ORD"));

  if (order_tab_centr!=NULL) {
    name_c=cpl_frame_get_filename(order_tab_centr);
    xsh_msg("tab centre file=%s",name_c);
    check(tab_centr=cpl_table_load(name_c,1,0));
    check(ord_min_tra=cpl_table_get_column_min(tab_centr,"ABSORDER"));
    check(ord_max_tra=cpl_table_get_column_max(tab_centr,"ABSORDER"));
    xsh_free_table(&tab_centr);
  

    xsh_msg("Trace tab order min=%d max=%d",ord_min_tra,ord_max_tra);
    check(order_list = xsh_order_list_load(order_tab_centr,instr));
    xsh_msg("Guess tab order min=%d max=%d",ord_min_gue,ord_max_gue);
    ord_min_off=ord_min_gue-ord_min_tra;
    ord_max_off=ord_max_gue-ord_max_tra;
    xsh_msg_debug("offset ord min=%d",ord_min_off);
    xsh_msg_debug("offset ord max=%d",ord_max_off);
  
    if(ord_min_off!=0) {
      xsh_msg_error("The guess line table has lines in an order not traced");
      xsh_msg_error("Remove lines from guess at order %d",ord_min_gue);
      xsh_msg_error("Or allow xsh_orderpos to trace order %d",ord_min_gue);
      xsh_msg_error("(For example changing XSH_SPECTRALFORMAT_TABLE_arm");
      cpl_error_set(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT);
      goto cleanup;
    }

    xsh_msg_debug("size=%d ord_min_gue=%d ord_max_gue=%d",
		  size,ord_min_gue,ord_max_gue);

    for(i=0;i<size;i++) {
      pyc[i]=py[i];
      //xsh_msg("pyc=%f",pyc[i]);
      //xsh_msg("abs order=%d",pog[i]);
      check( ord_rel = xsh_order_list_get_order( order_list, pog[i] ) ) ;
      //xsh_msg("rel order=%d",ord_rel);
      ord_rel=pog[i]-ord_min_gue+ord_min_off;
      //xsh_msg("rel order=%d",ord_rel);

      //xsh_msg("size-1=%d",order_list->size-1);
      if(ord_rel>-1) {
	if(cpl_polynomial_get_dimension(order_list->list[ord_rel].cenpoly) <
	   XSH_ORDPOS_POL_DIM_MAX) {
	  check( pxc[i] = cpl_polynomial_eval_1d(order_list->list[ord_rel].cenpoly,py[i],NULL));
	}
      }
      //      order_list->list[order_list->size-1].cenpoly,py[i],NULL));
      //xsh_msg("y=%f xfit+prescan=%f",py[i], pxc[i]);
      //xsh_msg("y=%f x=%f",py[i], px[i]);
    }
  

    //For quality control we also generate ORDER, X and Y columns 
    //in order tab centres to be compared with the ones of the guess table
    nord=ord_max_tra-ord_min_tra+1;
    size=nord*sizey;
    check(tab_centr=cpl_table_new(nord*sizey));
    check(cpl_table_new_column(tab_centr,"X",CPL_TYPE_DOUBLE));
    check(cpl_table_new_column(tab_centr,"Y",CPL_TYPE_DOUBLE));
    check(cpl_table_new_column(tab_centr,"ORDER",CPL_TYPE_INT));
    check(cpl_table_new_column(tab_centr,"ABSORDER",CPL_TYPE_INT));
    check(cpl_table_fill_column_window(tab_centr,"X",0,size,-1));
    check(cpl_table_fill_column_window(tab_centr,"Y",0,size,-1));
    check(cpl_table_fill_column_window(tab_centr,"ORDER",0,size,-1));
    check(cpl_table_fill_column_window(tab_centr,"ABSORDER",0,size,-1));
    check(px=cpl_table_get_data_double(tab_centr,"X"));
    check(py=cpl_table_get_data_double(tab_centr,"Y"));
    check(por=cpl_table_get_data_int(tab_centr,"ORDER"));
    check(poa=cpl_table_get_data_int(tab_centr,"ABSORDER"));
  

    i=0;
    for(ord=0;ord<nord;ord++) {
      for(j=0;j<sizey;j++) {

	poa[i]=ord+ord_min_tra;
	por[i]=ord+1;
	py[i]=(double)j;
	check(px[i]=cpl_polynomial_eval_1d(order_list->list[ord].cenpoly,py[i],
					   NULL));
	i++;
      }
    }
    check(cpl_table_save(tab_centr,NULL,NULL,"tab_centr.fits",CPL_IO_DEFAULT));

  }
  check(cpl_table_save(tab_xy_guess, NULL, NULL, name_g, CPL_IO_DEFAULT));

 cleanup:

  xsh_free_table(&tab_centr);
  xsh_free_table(&tab_xy_guess);
  xsh_order_list_free( &order_list);
  if(cpl_error_get_code() != CPL_ERROR_NONE) {
    xsh_print_rec_status(0);
  }
  return cpl_error_get_code();

}

/*--------------------------------------------------------------------------*/
/**
   @name xsh_cfg_recover_gen_xyg_frame
   @brief generates a table frame with x-y guess predictions
   @param wave_list the input reference line list
   @param config_frame the XSH model configuration frame
   @param inst the XSH instrument setting
   @return   0 if everything is ok, -1 in error case
*/
/*--------------------------------------------------------------------------*/
static cpl_frame* 
xsh_cfg_recover_gen_xyg_frame(cpl_frame  *   wave_list,
			  cpl_frame  *   config_frame,
			  xsh_instrument* inst, int prescan)
{

  cpl_table*   lines_tab=NULL ;
  cpl_frame* result=NULL;
  struct xs_3* p_xs_3_config=NULL;
  struct xs_3 xs_3_config;
  cpl_table* lines_xyg=NULL;
  cpl_propertylist* header=NULL;
  char name_o[256];
  const char* tag=XSH_GET_TAG_FROM_ARM(XSH_MODEL_GUESS_XY,inst);

  sprintf(name_o,"%s%s",tag,".fits");

  //Load xsh model configuration

  p_xs_3_config=&xs_3_config;
  if (xsh_model_config_load_best(config_frame, p_xs_3_config) != 
      CPL_ERROR_NONE) {
    xsh_msg_error("Cannot load %s as a config", 
		  cpl_frame_get_filename(config_frame)) ;
    return NULL ;
  }

  /* Read the input FITS lines list */
  check(lines_tab = cpl_table_load(cpl_frame_get_filename(wave_list), 1, 0)) ;
 
  //Generate x-y model guess
  check(xsh_cfg_recover_gen_xyg(lines_tab,p_xs_3_config,inst,prescan,&lines_xyg));
  //int i;

  // saves the table for debug purposes
  header=cpl_propertylist_new();
  check( xsh_pfits_set_pcatg(header,tag));
  cpl_table_save(lines_xyg, header, NULL,name_o, CPL_IO_DEFAULT);

  //Saves the frame as a final product.
 result=xsh_frame_product(name_o,tag,CPL_FRAME_TYPE_TABLE,
				CPL_FRAME_GROUP_PRODUCT,
				CPL_FRAME_LEVEL_FINAL);
  cpl_error_reset();

 cleanup:
  xsh_free_propertylist(&header);
  xsh_free_table(&lines_tab);
  xsh_free_table(&lines_xyg);


  if (cpl_error_get_code() != CPL_ERROR_NONE) {
    return NULL;
  } else {
    return result;
  }

}

/*--------------------------------------------------------------------------*/
/**
   @name xsh_cfg_recover_gen_xyg
   @brief generates a table frame with x-y guess predictions
   @param lines_tab the input reference line table
   @param  p_xs_3_config a pouinter to the XSH model configuration structure
   @param inst the XSH instrument setting
   @param lines_xyg the output table with the model x-y guess positions
   @return   0 if everything is ok, -1 in error case
   This recipe return an allocated table.
*/
/*--------------------------------------------------------------------------*/

static cpl_error_code 
xsh_cfg_recover_gen_xyg(
		    cpl_table  *   lines_tab,
		    struct xs_3* p_xs_3_config,
		    xsh_instrument* inst,int pre_scan,
		    cpl_table  **  lines_xyg)
{
  double x,y;
  float* pw=NULL;
  int row=0;

  int i=0;
  double blaze_wav=0;
  double lambda_min=0;
  double lambda_max=0;
  int morder_cnt=0;
  double m_to_mu=1.e6; //conversion meter to microns
  int lines_tot;
  int prescan=0; //50
  if(pre_scan) {
    prescan=-50;
  }
  lines_tot = cpl_table_get_nrow(lines_tab) ;
  xsh_msg("lines_tot=%d",lines_tot);
  *lines_xyg = cpl_table_new(lines_tot*3);
  cpl_table_new_column(*lines_xyg,"WAVELENGTH",CPL_TYPE_DOUBLE);
  cpl_table_new_column(*lines_xyg,"XG",CPL_TYPE_DOUBLE);
  cpl_table_new_column(*lines_xyg,"YG",CPL_TYPE_DOUBLE);
  cpl_table_new_column(*lines_xyg,"ABS_ORD",CPL_TYPE_INT);
 
  pw=cpl_table_get_data_float(lines_tab,"WAVELENGTH");
  xsh_msg("order min:%d max: %d",
	  p_xs_3_config->morder_min,p_xs_3_config->morder_max);

  for(i=0;i<lines_tot;i++) {
    for (morder_cnt= p_xs_3_config->morder_min;
	 morder_cnt<=p_xs_3_config->morder_max;
	 morder_cnt++) {
      blaze_wav=2*(sin(-p_xs_3_config->nug))/(morder_cnt*p_xs_3_config->sg);
      lambda_max=blaze_wav*((double)(morder_cnt)/((double)(morder_cnt)-0.5));
      lambda_min=blaze_wav*((double)(morder_cnt)/(0.5+(double)(morder_cnt)));
      lambda_min *=m_to_mu;
      lambda_max *=m_to_mu;

      //xsh_msg("wave= %f range=[%f,%f]",pw[i],lambda_min,lambda_max);
      if(pw[i]> lambda_min*0.98 && pw[i]<1.02*lambda_max) {
	check(xsh_model_get_xy(p_xs_3_config,inst,pw[i],
			       morder_cnt,0.0,&x,&y));
	//xsh_msg("At wave %lf nm in order %d  on arm %d : x=%lf y=%lf \n",
	//    pw[i],morder_cnt,xsh_instrument_get_arm(inst),x,y);
	cpl_table_set_double(*lines_xyg,"WAVELENGTH",row,pw[i]);
	cpl_table_set_int(*lines_xyg,"ABS_ORD",row,morder_cnt);
	cpl_table_set_double(*lines_xyg,"XG",row,x-prescan);
	cpl_table_set_double(*lines_xyg,"YG",row,y);
	row++;
      }
    }
  }
/*   cpl_table_unselect_all(*lines_xyg); */
/*   for (i=0;i<lines_tot*3;i++) { */
/*     if (cpl_table_get_int(*lines_xyg,"ABS_ORD",i,NULL)==0) { */
/*       cpl_table_select_row(*lines_xyg,i); */
/*     } */
/*     else { */
/*       cpl_table_unselect_row(*lines_xyg,i); */
/*     } */
/*   } */
/*   cpl_table_erase_selected(*lines_xyg); */

  cpl_table_erase_invalid(*lines_xyg);

  xsh_msg("lines inc. overlap: %" CPL_SIZE_FORMAT "\n",cpl_table_get_nrow(*lines_xyg));

 cleanup:
  return cpl_error_get_code();

}



/**@}*/

