/*                                                                            *
 *   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 16:09:08 $
 * $Revision: 1.201 $

 */




#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <xsh_cpl_size.h>
//dummy edit
/*-----------------------------------------------------------------------------
   								Includes
 -----------------------------------------------------------------------------*/
#include <math.h>

#include <xsh_data_the_map.h>
#include <xsh_drl.h>
#include <xsh_data_pre.h>
#include <xsh_dfs.h>
#include <xsh_pfits.h>
#include <xsh_error.h>
#include <xsh_msg.h>
#include <xsh_data_instrument.h>
#include <xsh_data_spectralformat.h>
#include <xsh_badpixelmap.h>
#include <xsh_model_io.h>
#include <cpl.h>
#include <xsh_model_ref_ind.h>
#include <xsh_data_resid_tab.h>
#include <xsh_data_arclist.h>
#include <xsh_model_kernel.h>
#include <xsh_model_metric.h>
#include <xsh_model_arm_constants.h>
#include <xsh_utils_wrappers.h>
//#include <gen_physmod.h>

/*----------------------------------------------------------------------------*/
/**
 * @defgroup xsh_model_kernel Functions for the wl model computation
 */
/*----------------------------------------------------------------------------*/

#define VERBOSE  0
#define mm2nm 1000000.0
#define mm2um 1000.0 

#if defined VERBOSE && VERBOSE > 0
#define XSH_TRACE_MSG(array) \
xsh_msg("array: %g, %g, %g, %g",array[0],array[1],array[2],array[3]);
#else 
#define XSH_TRACE_MSG(array)
#endif


/* for conversion from degree to radians */
//static const DOUBLE DEG2RAD=0.017453292519943295;

typedef struct {
  int order ;			/**< Absolute order */
  int pos_x ;
  int pos_y ;
  double flux ;
} CENTER_ORDER ;

static const int vectordim=4;


/**@{*/

static void xsh_nullmatrix(mat A)
{
  
  register int i,j;
   for(i=0; i<vectordim; i++) { 
    for(j=0; j<vectordim; j++) {
      A[i][j]=0.0; 
    }
   }
  
  //memset(A,0,vectordim*vectordim);

}
/* Not used
static void xsh_copymatrix(mat A, mat B)
{
  
  int i,j;
   for(i=0; i<vectordim; i++) { 
    for(j=0; j<vectordim; j++) {
      A[i][j]=B[i][j]; 
    }
   }
  
   //memcpy(A,B,vectordim*vectordim);
}
*/
static void xsh_nullvector(vec a)
{
  
  int i;
  for(i=0; i<vectordim; i++) a[i]=0.0;
 
  //memset(vec,0,vectordim);
}

static void xsh_copyvector(vec a, vec b)
{
  int i;
  for(i=0; i<vectordim; i++) a[i]=b[i];
  //memcpy(a,b,vectordim);
}

static const char* 
xsh_get_tag_opt_mod_cfg(xsh_xs_3* p_xs_3,int rec_id)
{

   const char* tag=NULL;

   if(rec_id==0) {
      /* if input recipe was xsh_startup */
      if (p_xs_3->arm == XSH_ARM_UVB) {
         tag=XSH_MOD_CFG_OPT_REC_UVB;
      }
      else if (p_xs_3->arm == XSH_ARM_VIS) {
         tag=XSH_MOD_CFG_OPT_REC_VIS;
      }
      else if (p_xs_3->arm == XSH_ARM_NIR) {
         tag=XSH_MOD_CFG_OPT_REC_NIR;
      }
   } else if(rec_id==1) {
      /* if input recipe was xsh_predict */
      if (p_xs_3->arm == XSH_ARM_UVB) {
         tag=XSH_MOD_CFG_OPT_FMT_UVB;
      }
      else if (p_xs_3->arm == XSH_ARM_VIS) {
         tag=XSH_MOD_CFG_OPT_FMT_VIS;
      }
      else if (p_xs_3->arm == XSH_ARM_NIR) {
         tag=XSH_MOD_CFG_OPT_FMT_NIR;
      }
   } else if (rec_id ==2 ) {

      /* if input recipe was xsh_2dmap */
      if (p_xs_3->arm == XSH_ARM_UVB) {
         tag=XSH_MOD_CFG_OPT_2D_UVB;
      }
      else if (p_xs_3->arm == XSH_ARM_VIS) {
         tag=XSH_MOD_CFG_OPT_2D_VIS;
      }
      else if (p_xs_3->arm == XSH_ARM_NIR) {
         tag=XSH_MOD_CFG_OPT_2D_NIR;
      }

   } else if (rec_id ==3 ) {

      /* if input recipe was xsh_wavecal slit */
      if (p_xs_3->arm == XSH_ARM_UVB) {
         tag=XSH_MOD_CFG_OPT_WAV_SLIT_UVB;
      }
      else if (p_xs_3->arm == XSH_ARM_VIS) {
         tag=XSH_MOD_CFG_OPT_WAV_SLIT_VIS;
      }
      else if (p_xs_3->arm == XSH_ARM_NIR) {
         tag=XSH_MOD_CFG_OPT_WAV_SLIT_NIR;
      }


   } else if (rec_id ==4 ) {

      /* if input recipe was xsh_wavecal ifu */
      if (p_xs_3->arm == XSH_ARM_UVB) {
         tag=XSH_MOD_CFG_OPT_WAV_IFU_UVB;
      }
      else if (p_xs_3->arm == XSH_ARM_VIS) {
         tag=XSH_MOD_CFG_OPT_WAV_IFU_VIS;
      }
      else if (p_xs_3->arm == XSH_ARM_NIR) {
         tag=XSH_MOD_CFG_OPT_WAV_IFU_NIR;
      }

   } else if (rec_id ==5 ) {

      /* if input recipe was xsh_flexcor */
      if (p_xs_3->arm == XSH_ARM_UVB) {
         tag=XSH_MOD_CFG_OPT_AFC_UVB;
      }
      else if (p_xs_3->arm == XSH_ARM_VIS) {
         tag=XSH_MOD_CFG_OPT_AFC_VIS;
      }
      else if (p_xs_3->arm == XSH_ARM_NIR) {
         tag=XSH_MOD_CFG_OPT_AFC_NIR;
      }
   }
   return tag;
}



static cpl_error_code  
xsh_model_compute_residuals(xsh_xs_3* p_xs_3,coord* msp_coord,  
                            DOUBLE* p_wlarray,DOUBLE** ref_ind, 
                            const int size, const int annealed,
                            cpl_propertylist* resid_header, 
                            cpl_frame* resid_frame,
                            cpl_propertylist** result)
{

 
   double resx_min=0;
   double resx_max=0;
   double resy_min=0;
   double resy_max=0;

   double resx_med=0;
   double resy_med=0;

   double resx_avg=0;
   double resy_avg=0;

   double resx_rms=0;
   double resy_rms=0;

   int ndat=0;
   int morder_cnt=0;
   const char* resid_tbl_name=NULL;
   cpl_table* resid_tbl=NULL;
 
   int jj=0;
   double* pxm=NULL;
   double* pym=NULL;

 check(resid_tbl_name=cpl_frame_get_filename(resid_frame));
 
  check(resid_tbl=cpl_table_load(resid_tbl_name,1,0));
  check(cpl_table_fill_column_window(resid_tbl,
    XSH_RESID_TAB_TABLE_COLNAME_XTHANNEAL ,0,size,0.));
  check(cpl_table_fill_column_window(resid_tbl,
    XSH_RESID_TAB_TABLE_COLNAME_YTHANNEAL ,0,size,0.));

  check(pxm=cpl_table_get_data_double(resid_tbl,
    XSH_RESID_TAB_TABLE_COLNAME_XTHANNEAL));
  check(pym=cpl_table_get_data_double(resid_tbl,
    XSH_RESID_TAB_TABLE_COLNAME_YTHANNEAL));


  for (jj=0;jj<size;jj++) {
    p_xs_3->es_y_tot=p_xs_3->es_y+p_xs_3->slit[msp_coord[jj].slit_pos]*p_xs_3->slit_scale;
    morder_cnt=msp_coord[jj].order;
    xsh_3_init(p_xs_3);
    xsh_3_eval(p_wlarray[jj],morder_cnt,ref_ind,p_xs_3);
    xsh_3_detpix(p_xs_3);
    pxm[jj]=p_xs_3->xpospix;
    pym[jj]=p_xs_3->ypospix;
/*
    printf("check %d %lf %lf %d %d %lf %lf %lf %lf %d\n",
	   jj,p_wlarray[jj],p_xs_3->es_y,p_xs_3->chippix[0],
	   msp_coord[jj].arm,p_xs_3->xpospix,p_xs_3->ypospix,
	   msp_coord[jj].x-p_xs_3->xpospix,msp_coord[jj].y-p_xs_3->ypospix,
	   msp_coord[jj].order);
*/
  }
  check( cpl_table_copy_data_double( resid_tbl, XSH_RESID_TAB_TABLE_COLNAME_RESIDXMODEL,
    cpl_table_get_data_double ( resid_tbl, XSH_RESID_TAB_TABLE_COLNAME_XGAUSS)));
  check( cpl_table_copy_data_double( resid_tbl, XSH_RESID_TAB_TABLE_COLNAME_RESIDYMODEL,
    cpl_table_get_data_double ( resid_tbl, XSH_RESID_TAB_TABLE_COLNAME_YGAUSS)));

  check(cpl_table_subtract_columns(resid_tbl, XSH_RESID_TAB_TABLE_COLNAME_RESIDXMODEL, 
    XSH_RESID_TAB_TABLE_COLNAME_XTHANNEAL));
  check(cpl_table_subtract_columns(resid_tbl, XSH_RESID_TAB_TABLE_COLNAME_RESIDYMODEL,
    XSH_RESID_TAB_TABLE_COLNAME_YTHANNEAL));

  check(cpl_table_save(resid_tbl, resid_header, NULL,resid_tbl_name, CPL_IO_DEFAULT));


  check(resx_min=cpl_table_get_column_min(resid_tbl,
    XSH_RESID_TAB_TABLE_COLNAME_RESIDXMODEL));
  check(resx_max=cpl_table_get_column_max(resid_tbl,
    XSH_RESID_TAB_TABLE_COLNAME_RESIDXMODEL));
  check(resx_avg=cpl_table_get_column_mean(resid_tbl,
    XSH_RESID_TAB_TABLE_COLNAME_RESIDXMODEL));
  check(resx_med=cpl_table_get_column_median(resid_tbl,
    XSH_RESID_TAB_TABLE_COLNAME_RESIDXMODEL));
  check(resx_rms=cpl_table_get_column_stdev(resid_tbl,
    XSH_RESID_TAB_TABLE_COLNAME_RESIDXMODEL));


  check(resy_min=cpl_table_get_column_min(resid_tbl,
    XSH_RESID_TAB_TABLE_COLNAME_RESIDYMODEL));
  check(resy_max=cpl_table_get_column_max(resid_tbl,
    XSH_RESID_TAB_TABLE_COLNAME_RESIDYMODEL));
  check(resy_avg=cpl_table_get_column_mean(resid_tbl,
    XSH_RESID_TAB_TABLE_COLNAME_RESIDYMODEL));
  check(resy_med=cpl_table_get_column_median(resid_tbl,
    XSH_RESID_TAB_TABLE_COLNAME_RESIDYMODEL));
  check(resy_rms=cpl_table_get_column_stdev(resid_tbl,
    XSH_RESID_TAB_TABLE_COLNAME_RESIDYMODEL));
  check(ndat=cpl_table_get_nrow(resid_tbl));
  xsh_free_table(&resid_tbl);

  /*  printf ("After Anneal: \n");
  for (ii=0;ii<adim;ii++) {
    printf("%d %s %lf \n", aname[ii], (p_all_par+aname[ii])->name, abest[ii]);
    }*/
 
  //cpl_propertylist_append_string(*result, "INSTRUME", "XSHOOTER") ;

  cpl_propertylist_append_int(*result,"ESO QC MODEL NDAT",ndat) ;

  if(annealed==0) {
     cpl_propertylist_append_double(*result,XSH_QC_MODEL_PREDICT_RESX_MIN,resx_min) ;
     cpl_propertylist_append_double(*result,XSH_QC_MODEL_PREDICT_RESY_MIN,resy_min) ;
     cpl_propertylist_append_double(*result,XSH_QC_MODEL_PREDICT_RESX_MAX,resx_max) ;
     cpl_propertylist_append_double(*result,XSH_QC_MODEL_PREDICT_RESY_MAX,resy_max) ;
     cpl_propertylist_append_double(*result,XSH_QC_MODEL_PREDICT_RESX_AVG,resx_avg) ;
     cpl_propertylist_append_double(*result,XSH_QC_MODEL_PREDICT_RESY_AVG,resy_avg) ;
     cpl_propertylist_append_double(*result,XSH_QC_MODEL_PREDICT_RESX_MED,resx_med) ;
     cpl_propertylist_append_double(*result,XSH_QC_MODEL_PREDICT_RESY_MED,resy_med) ;
     cpl_propertylist_append_double(*result,XSH_QC_MODEL_PREDICT_RESX_RMS,resx_rms) ;
     cpl_propertylist_append_double(*result,XSH_QC_MODEL_PREDICT_RESY_RMS,resy_rms) ;
  } else {

     cpl_propertylist_append_double(*result,XSH_QC_MODEL_ANNEAL_RESX_MIN,resx_min) ;
     cpl_propertylist_append_double(*result,XSH_QC_MODEL_ANNEAL_RESY_MIN,resy_min) ;
     cpl_propertylist_append_double(*result,XSH_QC_MODEL_ANNEAL_RESX_MAX,resx_max) ;
     cpl_propertylist_append_double(*result,XSH_QC_MODEL_ANNEAL_RESY_MAX,resy_max) ;
     cpl_propertylist_append_double(*result,XSH_QC_MODEL_ANNEAL_RESX_AVG,resx_avg) ;
     cpl_propertylist_append_double(*result,XSH_QC_MODEL_ANNEAL_RESY_AVG,resy_avg) ;
     cpl_propertylist_append_double(*result,XSH_QC_MODEL_ANNEAL_RESX_MED,resx_med) ;
     cpl_propertylist_append_double(*result,XSH_QC_MODEL_ANNEAL_RESY_MED,resy_med) ;
     cpl_propertylist_append_double(*result,XSH_QC_MODEL_ANNEAL_RESX_RMS,resx_rms) ;
     cpl_propertylist_append_double(*result,XSH_QC_MODEL_ANNEAL_RESY_RMS,resy_rms) ;

  }
  cleanup:
  xsh_free_table(&resid_tbl);
  return cpl_error_get_code();


}

/*----------------------------------------------------------------------------*/
/**
  @brief    Pre-compute a number of non-wavelength dependent secondary
            parameters required by the model.
  @param    p_xs_3  the model parameter structure

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

void xsh_3_init(struct xs_3 * p_xs_3)
{
  /*int ii,jj;
  mat tras_toprism1,tras_toprism2,tras_toprism3;
  mat tras_toprism4,tras_toprism5,tras_toprism6;
  mat unity_mat={ {1,0,0,0},
		{0,1,0,0}, 
		{0,0,1,0},
		{0,0,0,1}};*/
#ifdef FCCDD_FLAG
  xsh_rotin(p_xs_3->todetector,-0.062,0.01,0.0);
#endif 

 /*******************  Rotation of entrance slit********************/
 //xsh_showmatrix(p_xs_3->e_slit);
 xsh_rotin(p_xs_3->e_slit,p_xs_3->mues,p_xs_3->nues,p_xs_3->taues);
 //xsh_showmatrix(p_xs_3->e_slit);
 /*******************  Rotation into Prism********************/
 xsh_rotin(p_xs_3->mup_ir_cor,p_xs_3->cmup1,0.0,0.0);
 xsh_rotin(p_xs_3->mup_ir_cor_out,-p_xs_3->cmup1,0.0,0.0);
 xsh_rotin(p_xs_3->toprism1,p_xs_3->mup1,p_xs_3->nup1,p_xs_3->taup1);
 xsh_rotin(p_xs_3->toprism2,p_xs_3->mup2,p_xs_3->nup2,p_xs_3->taup2);

 /*******************  Rotation out of Prism********************/
 /*******************  Rotation back to ref********************
 xsh_transpose(tras_toprism1,p_xs_3->toprism1);
 xsh_transpose(tras_toprism2,p_xs_3->toprism2);
 xsh_multiplymatrix(p_xs_3->prism_out,tras_toprism2,tras_toprism1);*/
 /*Above is not used, instead toprism1 is used when exiting the prism the first time, following the ZEMAX prescription*/
 /*IR only correction to 1st prism exit*/
 
 /*******************  Rotation into 2nd IR Prism********************/
 xsh_rotin(p_xs_3->toprism3,p_xs_3->mup3,p_xs_3->nup3,p_xs_3->taup3);
 xsh_rotin(p_xs_3->toprism4,p_xs_3->mup4,p_xs_3->nup4,p_xs_3->taup4);

 /*******************  Rotation out of 2nd IR Prism********************/
 /*******************  Rotation back to ref********************
 xsh_transpose(tras_toprism3,p_xs_3->toprism3);
 xsh_transpose(tras_toprism4,p_xs_3->toprism4);
 xsh_multiplymatrix(p_xs_3->prism_out2,tras_toprism4,tras_toprism3);*/
 /*Above is not used, instead toprism3 is used when exiting the prism the first time, following the ZEMAX prescription*/
 
/*******************  Rotation into 3rd IR Prism********************/
 xsh_rotin(p_xs_3->toprism5,p_xs_3->mup5,p_xs_3->nup5,p_xs_3->taup5);
 xsh_rotin(p_xs_3->toprism6,p_xs_3->mup6,p_xs_3->nup6,p_xs_3->taup6);

 /*******************  Rotation out of 3rd IR Prism********************/
 /*******************  Rotation back to ref********************
 xsh_transpose(tras_toprism5,p_xs_3->toprism5);
 xsh_transpose(tras_toprism6,p_xs_3->toprism6);
 xsh_multiplymatrix(p_xs_3->prism_out3,tras_toprism6,tras_toprism5);*/
 /*Above is not used, instead toprism5 is used when exiting the prism the first time, following the ZEMAX prescription*/
 
 /*******************  Rotation into and out of Grating ********************/
 xsh_rotin(p_xs_3->tograt,p_xs_3->mug,p_xs_3->nug,p_xs_3->taug);
 xsh_transpose(p_xs_3->grat_out,p_xs_3->tograt);

 /*******************  Rotation back into Prism********************/

 // xsh_transpose(p_xs_3->ret_prism2,p_xs_3->prism_out);
 /*intuitive version above is replaced with inverse of toprism1 which is actually used when exiting the prism the first time follwing the ZEMAX prescription*/
 xsh_transpose(p_xs_3->ret_prism2,p_xs_3->toprism1);
 xsh_transpose(p_xs_3->ret_prism1,p_xs_3->toprism2);
 xsh_multiplymatrix(p_xs_3->ret_prism_out1,p_xs_3->toprism2,p_xs_3->toprism1);
 xsh_transpose(p_xs_3->ret_prism4,p_xs_3->toprism3);
 xsh_transpose(p_xs_3->ret_prism3,p_xs_3->toprism4);
 xsh_multiplymatrix(p_xs_3->ret_prism_out2,p_xs_3->toprism4,p_xs_3->toprism3);
 xsh_transpose(p_xs_3->ret_prism6,p_xs_3->toprism5);
 xsh_transpose(p_xs_3->ret_prism5,p_xs_3->toprism6);
 xsh_multiplymatrix(p_xs_3->ret_prism_out3,p_xs_3->toprism6,p_xs_3->toprism5);

 /*Chip limits */
 if (p_xs_3->arm!=2) {
   p_xs_3->chipxup=p_xs_3->chipx+p_xs_3->pix_Y*(0.5*p_xs_3->chipypix);
   p_xs_3->chipxdown=p_xs_3->chipx-p_xs_3->pix_Y*(0.5*p_xs_3->chipypix);
   p_xs_3->chipyup=p_xs_3->chipy+p_xs_3->pix_X*(0.5*p_xs_3->chipxpix);
   p_xs_3->chipydown=p_xs_3->chipy-p_xs_3->pix_X*(0.5*p_xs_3->chipxpix);
 }
 else {
   p_xs_3->chipxup=p_xs_3->chipx+p_xs_3->pix_X*(0.5*p_xs_3->chipxpix+NIR_FIX);
   p_xs_3->chipxdown=p_xs_3->chipx-p_xs_3->pix_X*(0.5*p_xs_3->chipxpix);
   p_xs_3->chipyup=p_xs_3->chipy+p_xs_3->pix_Y*(+0.5*p_xs_3->chipypix);
   p_xs_3->chipydown=p_xs_3->chipy-p_xs_3->pix_Y*(0.5*p_xs_3->chipypix);
 }
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Compute the physical x,y position at the detector array for a given
            wavelength, order and parameter configuration
  @param    lambda    Wavelength in um (double)
  @param    morder    Spectral order (int)
  @param    ref_ind   pre-loaded refractive index array
  @param    p_xs_3    model parameter structure
 */
/*----------------------------------------------------------------------------*/

void xsh_3_eval(DOUBLE  lambda,
	       int morder,
	       DOUBLE** ref_ind,
	       struct xs_3* p_xs_3)
{
  DOUBLE lambda_um,lamf,rind_up,rind_down,xx,yy,dndT;
  vec vres,slitpos2,slitpos,detproj;

  mat mech={ {1,0,0,0},
	     {morder*(p_xs_3->sg),1,0,0},
	     {0,0,1,0},
	     {0,0,0,-1}};
  mat chrom_corr={ {1,0,0,0},
		   {0,1,0,0},
		   {0,0,1,0},
		   {0,0,0,1}};
  /*  mat mech={ {1,0,0,0},
	     {0,1,0,0},
	     {-morder*(p_xs_3->sg),0,1,0},
	     {0,0,0,-1}}; */

  /* init start vector */
  vec vres1={lambda,
	      0,
	      0,
	      -p_xs_3->fcol};


  XSH_TRACE_MSG(vres1)

  /*----------------------------------------------------------------------*/
  slitpos[0]=0.0;
  slitpos[1]=1.0*p_xs_3->es_x;
  /* config_mjd paramter is used below to check which version of uvb/vis
     chromatic aberration correction to use, before august 2010 it should
     be the old version. This doesn't affect NIR*/
  if (/*p_xs_3->arm!=2 && */p_xs_3->config_mjd>2455409.0) {
    //    printf("new %lf\n",p_xs_3->config_mjd);
    if (p_xs_3->arm==0) {
      if (lambda>0.000425) {
	slitpos[2]=-1.0*p_xs_3->es_y_tot*(1.0+(lambda-0.000425)*p_xs_3->offx);
      }
      else{
	slitpos[2]=-1.0*p_xs_3->es_y_tot*(1.0+(lambda-0.000425)*p_xs_3->offy);
      }
    }
    else if (p_xs_3->arm==1) {
      if (lambda>0.000650) {
	slitpos[2]=1.0*(p_xs_3->es_y_tot)*(1.0+(lambda-0.000900)*p_xs_3->offx);
      }
      else{
	slitpos[2]=1.0*(p_xs_3->es_y_tot)*(1.0+(lambda-0.000018)*p_xs_3->offy);
      }
    }
    else if (p_xs_3->arm==2) {
      if (lambda>0.001400) {
	slitpos[2]=1.0*(p_xs_3->es_y_tot-p_xs_3->es_y)*(1.0+(lambda-0.001600)*p_xs_3->offx)+p_xs_3->es_y;
      }
      else{
	slitpos[2]=1.0*(p_xs_3->es_y_tot)*(1.0+(lambda-0.000990)*p_xs_3->offy);
      }
    }
  }
  else {
    if (p_xs_3->arm==0) {
      slitpos[2]=-1.0*p_xs_3->es_y_tot;//*(1.0+(lambda-0.000413)*p_xs_3->offx);
    }
    else {
      slitpos[2]=1.0*p_xs_3->es_y_tot;//*(1.0+(lambda-0.000413)*p_xs_3->offx);
    }
  }
  slitpos[3]=0.0;
  xsh_matrixforvector(slitpos2,p_xs_3->e_slit,slitpos);
  xsh_subtractvectors(vres1,slitpos2);
  xsh_copyvector(vres,vres1);
  xsh_normall(vres);
  if (p_xs_3->arm!=2 && p_xs_3->config_mjd<2455409.0) {
    //    printf("old %lf \n",p_xs_3->config_mjd);
    xsh_rotin(chrom_corr,vres[2]*(lambda-p_xs_3->offy)*p_xs_3->offx,0.0,0.0);
    xsh_matrixforvector(vres,chrom_corr,vres);
  }

  XSH_TRACE_MSG(vres) 

  /***********************Rotation into Prism *******************/
  //printf("qwerty 00 %lf %lf %lf \n", vres[1], vres[2], vres[3]);
  if (p_xs_3->arm==2) xsh_matrixforvector(vres,p_xs_3->mup_ir_cor,vres);
  //printf("qwerty 01 %lf %lf %lf \n", vres[1], vres[2], vres[3]);
  xsh_matrixforvector(vres,p_xs_3->toprism1,vres);
  //printf("qwerty 02 %lf %lf %lf \n", vres[1], vres[2], vres[3]);

  lambda_um=lambda* mm2um;
  lamf=lambda_um*lambda_um;

  if (p_xs_3->arm==1) {
  /*NOTE: THE EQN BELOW IS FOR THE MANUFACTURER'S DATA,THE 4th, 5th AND 6th COEFFS ARE THE SQUARES OF THE NORMAL COEFFS (SUCH AS USED IN THE ZnSe DATA, hence the different eqn for NIS prisms 2 and 3 below)*/

    p_xs_3->rind=sqrt(ref_ind[0][0]*lamf/(lamf-ref_ind[0][3])+ref_ind[0][1]*lamf/(lamf-ref_ind[0][4])+ref_ind[0][2]*lamf/(lamf-ref_ind[0][5])+1.0);

    /*fit from Ghosh 97, APPLIED OPTICS y Vol. 36, No. 7 y 1 March 1997*/
    double lam_ig2=0.04963984;
    double H=71.0867E-06;
    double G=-50.2451E-06;
    double R;

    R=lamf/(lamf-lam_ig2);
    dndT=(G*R+H*R*R)/(2.0*p_xs_3->rind);

    /*approximate fit to dn/dT(lambda) from figure in Schott TIE-29 doc, p7, fig 3-2*/
    //dndT=(0.5/lambda_um)*0.000010+0.0000005;
    /*XSH ODR p93 fig4.10 would imply dn/dT=(0.55/lambda_um)*0.000009*/ 
    p_xs_3->rind+=dndT*(p_xs_3->temper-293.15);
    //    printf("ref_ind, lambda  %lf %lf \n",p_xs_3->rind=rind_down,lambda);
  } 
  else { 
    //printf("%lf %lf %lf\n",lambda_um, xsh_model_sellmeier_ext(p_xs_3->arm,p_xs_3->temper,lamf),p_xs_3->rind);
    p_xs_3->rind=xsh_model_sellmeier_ext(p_xs_3->arm,p_xs_3->temper,lamf);
  }

  /* Adjust refractive index to account for air (as opposed to vaccum) in the
     UVB and NIR spectrographs - CURRENTLY NOT USED */
/*   if (p_xs_3->arm!=2) { */
/*     p_xs_3->rind=p_xs_3->rind/xsh_model_ref_ind_air(p_xs_3->temper,lamf); */
/*   } */

  /* Refract */
  xsh_refract(vres,p_xs_3->rind,vres);
  //printf("qwerty 0 %lf %lf %lf \n", vres[1], vres[2], vres[3]);

  /* Rotate to exit surface */
  xsh_matrixforvector(vres,p_xs_3->toprism2,vres);
  //printf("qwerty 1 %lf %lf %lf \n", vres[1], vres[2], vres[3]);

  /* refract */
  xsh_refract(vres,1.0/(p_xs_3->rind),vres);
  //printf("qwerty 2 %lf %lf %lf \n", vres[1], vres[2], vres[3]);

  /* Rotate back into referential */
  /*NOTE: We follow the ZEMAX prescription and use toprism1 here instead of prism_out */
  xsh_matrixforvector(vres,p_xs_3->toprism1,vres);
  //printf("qwerty 3 %lf %lf %lf \n", vres[1], vres[2], vres[3]);


 
 XSH_TRACE_MSG(vres) 
  if (p_xs_3->arm==2) {
 XSH_TRACE_MSG(vres) 

    /***********************Rotation into 2nd Prism *******************/
    xsh_matrixforvector(vres,p_xs_3->toprism3,vres);
    //printf("qwerty 3.1 %lf %lf %lf \n", vres[1], vres[2], vres[3]);

    //ref_ind for ir 2nd prism (ref_ind applies to 2 and 3)
    /* Calculate ref ind at temperature above using Sellmeier equation */
    rind_up=sqrt(ref_ind[1][0]*lamf/(lamf-ref_ind[1][3]*ref_ind[1][3])+ref_ind[1][1]*lamf/(lamf-ref_ind[1][4]*ref_ind[1][4])+ref_ind[1][2]*lamf/(lamf-ref_ind[1][5]*ref_ind[1][5])+1.0);

    /* Calculate ref ind at temperature below using Sellmeier equation */
    rind_down=sqrt(ref_ind[0][0]*lamf/(lamf-ref_ind[0][3]*ref_ind[0][3])+ref_ind[0][1]*lamf/(lamf-ref_ind[0][4]*ref_ind[0][4])+ref_ind[0][2]*lamf/(lamf-ref_ind[0][5]*ref_ind[0][5])+1.0);

    /* Linear interpolation to get ref ind at actual temperature */
    p_xs_3->rind2=rind_down+((p_xs_3->t_ir_p2-ref_ind[0][6])/(ref_ind[1][6]-ref_ind[0][6]))*(rind_up-rind_down);

    /* Refract */
    xsh_refract(vres,p_xs_3->rind2,vres);
    //printf("qwerty 0b %lf %lf %lf \n", vres[1], vres[2], vres[3]);

    /* Rotate to exit surface */
    xsh_matrixforvector(vres,p_xs_3->toprism4,vres);
    //printf("qwerty 1b %lf %lf %lf \n", vres[1], vres[2], vres[3]);

    /* refract */
    xsh_refract(vres,1.0/(p_xs_3->rind2),vres);
    //printf("qwerty 2b %lf %lf %lf \n", vres[1], vres[2], vres[3]);

    /* Rotate back into referential */
    /*NOTE: We follow the ZEMAX prescription and use toprism1 here instead of prism_out */
    xsh_matrixforvector(vres,p_xs_3->toprism3,vres);
    //printf("qwerty 3b %lf %lf %lf \n", vres[1], vres[2], vres[3]);

 XSH_TRACE_MSG(vres) 

    /***********************Rotation into 3rd Prism *******************/
    xsh_matrixforvector(vres,p_xs_3->toprism5,vres);
 XSH_TRACE_MSG(vres) 

    //rind3 for ir 3rd prism (ref_ind applies to 2 and 3)
    /* Calculate ref ind at temperature above using Sellmeier equation */
    rind_up=sqrt(ref_ind[1][0]*lamf/(lamf-ref_ind[1][3]*ref_ind[1][3])+ref_ind[1][1]*lamf/(lamf-ref_ind[1][4]*ref_ind[1][4])+ref_ind[1][2]*lamf/(lamf-ref_ind[1][5]*ref_ind[1][5])+1.0);

    /* Calculate ref ind at temperature below using Sellmeier equation */
    rind_down=sqrt(ref_ind[0][0]*lamf/(lamf-ref_ind[0][3]*ref_ind[0][3])+ref_ind[0][1]*lamf/(lamf-ref_ind[0][4]*ref_ind[0][4])+ref_ind[0][2]*lamf/(lamf-ref_ind[0][5]*ref_ind[0][5])+1.0);

    /* Linear interpolation to get ref ind at actual temperature */
    p_xs_3->rind3=rind_down+((p_xs_3->t_ir_p3-ref_ind[0][6])/(ref_ind[1][6]-ref_ind[0][6]))*(rind_up-rind_down);

    /* Refract */
    xsh_refract(vres,p_xs_3->rind3,vres);
 XSH_TRACE_MSG(vres) 

    //printf("qwerty 0c %lf %lf %lf \n", vres[1], vres[2], vres[3]);

    /* Rotate to exit surface */
    xsh_matrixforvector(vres,p_xs_3->toprism6,vres);
 XSH_TRACE_MSG(vres) 

    //printf("qwerty 1c %lf %lf %lf \n", vres[1], vres[2], vres[3]);

    /* refract */
    xsh_refract(vres,1.0/(p_xs_3->rind3),vres);
 XSH_TRACE_MSG(vres) 


    //printf("qwerty 2c %lf %lf %lf \n", vres[1], vres[2], vres[3]);

    /* Rotate back into referential */
    /*NOTE: We follow the ZEMAX prescription and use toprism1 here instead of prism_out */
    xsh_matrixforvector(vres,p_xs_3->toprism5,vres);
 XSH_TRACE_MSG(vres) 


    //printf("qwerty 3c %lf %lf %lf \n", vres[1], vres[2], vres[3]);
  }

/*   p_xs_3->grat_alpha=xsh_physmod_grating(vres, */
/* 					 morder, */
/* 					 p_xs_3->sg, */
/* 					 p_xs_3->tograt, */
/* 					 p_xs_3->grat_out, */
/* 					 vres); */

  /* Rotate into grating */
  xsh_matrixforvector(vres,p_xs_3->tograt,vres);
 XSH_TRACE_MSG(vres) 


  p_xs_3->grat_alpha=atan(vres[1]/vres[3]);
  //printf("qwerty 4 %lf %lf %lf \n", vres[1], vres[2], vres[3]);

  /* Difraction */
  xsh_matrixforvector(vres,mech,vres);
 XSH_TRACE_MSG(vres) 


  //printf("qwerty 5 %lf %lf %lf \n", vres[1], vres[2], vres[3]);

  xsh_normz(vres);
 XSH_TRACE_MSG(vres) 


  p_xs_3->grat_beta=atan(vres[1]/vres[3]);
  //printf("qwerty 6 %lf %lf %lf \n", vres[1], vres[2], vres[3]);

  /*Rotate out of grating*/
  xsh_matrixforvector(vres,p_xs_3->grat_out,vres);
 XSH_TRACE_MSG(vres) 


  //printf("qwerty 7 %lf %lf %lf \n", vres[1], vres[2], vres[3]);

  if (p_xs_3->arm==2) {
    /* Rotate back into Prism 3*/
    xsh_matrixforvector(vres,p_xs_3->ret_prism6,vres);
 XSH_TRACE_MSG(vres) 


    //printf("qwerty 8c %lf %lf %lf \n", vres[1], vres[2], vres[3]);

    /* refract */
    xsh_refract(vres,p_xs_3->rind3,vres);
 XSH_TRACE_MSG(vres) 


    //printf("qwerty 9c %lf %lf %lf \n", vres[1], vres[2], vres[3]);

    /* Rotate to exit surface */
    xsh_matrixforvector(vres,p_xs_3->ret_prism5,vres);
 XSH_TRACE_MSG(vres) 


    //printf("qwerty 10c %lf %lf %lf \n", vres[1], vres[2], vres[3]);

    /* Refract */
    xsh_refract(vres,1.0/(p_xs_3->rind3),vres);
 XSH_TRACE_MSG(vres) 

    //printf("qwerty 11c %lf %lf %lf \n", vres[1], vres[2], vres[3]);

    /* Rotate back into referential */
    xsh_matrixforvector(vres,p_xs_3->ret_prism6,vres);
 XSH_TRACE_MSG(vres) 

    //printf("qwerty 12c %lf %lf %lf \n", vres[1], vres[2], vres[3]);


    /* Rotate back into Prism 2*/
    xsh_matrixforvector(vres,p_xs_3->ret_prism4,vres);
 XSH_TRACE_MSG(vres) 

    //printf("qwerty 8b %lf %lf %lf \n", vres[1], vres[2], vres[3]);

    /* refract */
    xsh_refract(vres,p_xs_3->rind2,vres);
 XSH_TRACE_MSG(vres) 

    //printf("qwerty 9b %lf %lf %lf \n", vres[1], vres[2], vres[3]);

    /* Rotate to exit surface */
    xsh_matrixforvector(vres,p_xs_3->ret_prism3,vres);
 XSH_TRACE_MSG(vres) 

    //printf("qwerty 10b %lf %lf %lf \n", vres[1], vres[2], vres[3]);

    /* Refract */
    xsh_refract(vres,1.0/(p_xs_3->rind2),vres);
 XSH_TRACE_MSG(vres) 

    //printf("qwerty 11b %lf %lf %lf \n", vres[1], vres[2], vres[3]);

    /* Rotate back into referential */
    xsh_matrixforvector(vres,p_xs_3->ret_prism4,vres);
 XSH_TRACE_MSG(vres) 

    //printf("qwerty 12b %lf %lf %lf \n", vres[1], vres[2], vres[3]);
  }

  /* Rotate back into Prism 1*/
  xsh_matrixforvector(vres,p_xs_3->ret_prism2,vres);
 XSH_TRACE_MSG(vres) 

  //printf("qwerty 8 %lf %lf %lf \n", vres[1], vres[2], vres[3]);

  /* refract */
  xsh_refract(vres,p_xs_3->rind,vres);
 XSH_TRACE_MSG(vres) 

  //printf("qwerty 9 %lf %lf %lf \n", vres[1], vres[2], vres[3]);

  /* Rotate to exit surface */
  xsh_matrixforvector(vres,p_xs_3->ret_prism1,vres);
 XSH_TRACE_MSG(vres) 

  //printf("qwerty 10 %lf %lf %lf \n", vres[1], vres[2], vres[3]);

  /* Refract */
  xsh_refract(vres,1.0/(p_xs_3->rind),vres);
 XSH_TRACE_MSG(vres) 

  //printf("qwerty 11 %lf %lf %lf \n", vres[1], vres[2], vres[3]);

  /* Rotate back into referential */
  xsh_matrixforvector(vres,p_xs_3->ret_prism2,vres);
 XSH_TRACE_MSG(vres) 

  //printf("qwerty 12 %lf %lf %lf \n", vres[1], vres[2], vres[3]);
  if (p_xs_3->arm==2) xsh_matrixforvector(vres,p_xs_3->mup_ir_cor_out,vres);
 XSH_TRACE_MSG(vres) 


#ifdef FCCDD_FLAG
  xsh_matrixforvector(vres,p_xs_3->todetector,vres);
 XSH_TRACE_MSG(vres) 

#endif

  /* Projection onto the detector (to begin with just a
     mm pixel grid, later we'll deal with individual chips) */
  xx=(p_xs_3->flipx)*(p_xs_3->fdet)/((vres[3]/vres[1])*cos(p_xs_3->nud)-sin(p_xs_3->nud));
  yy=(p_xs_3->flipy)*(p_xs_3->fdet)/((vres[3]/vres[2])*cos(p_xs_3->mud)-sin(p_xs_3->mud));




#ifdef CCCDD_FLAG
  /*Alternative projection onto a curved detector of radius fdet*/
    xx=(p_xs_3->flipx)*(p_xs_3->fdet)*vres[1];
    yy=(p_xs_3->flipy)*(p_xs_3->fdet)*vres[2];
#endif

#ifdef XCCCDD_FLAG
  /*Alternative projection onto a curved detector of radius fdet*/
    xx=(p_xs_3->flipx)*(p_xs_3->fdet)*2.0*vres[1];
    yy=(p_xs_3->flipy)*(p_xs_3->fdet)*2.0*vres[2];
#endif


  detproj[0]=0.0;
  detproj[1]=xx*cos(-p_xs_3->taud)+yy*sin(-p_xs_3->taud);
  detproj[2]=-xx*sin(-p_xs_3->taud)+yy*cos(-p_xs_3->taud);
  detproj[3]=0.0; 
  xsh_copyvector(vres,detproj);
 XSH_TRACE_MSG(vres) 


  p_xs_3->morder=(float)(morder);

  p_xs_3->xdet=vres[1];
  p_xs_3->ydet=vres[2];
}


/*----------------------------------------------------------------------------*/
/**
  @brief    Takes the physical x,y position at the detector array and converts
            this to a pixel position
  @param    p_xs_3    model parameter structure
 */
/*----------------------------------------------------------------------------*/

void xsh_3_detpix(struct xs_3 *p_xs_3)
{

  double xdet2, xdet3, ydet2, ydet3;
  double xdet_c, xdet_c2, xdet_c3, ydet_c, ydet_c2, ydet_c3;
  double d2_y1=0.0;
  double d2_y2=0.0;
  double d2_y3=0.0;
  double pc_x, pc_y, dstn_x, dstn_y;
  double xdet_c4, ydet_c4;
  //double h_det;
  int array_size_fix=0;

  //double mm_c3,mm_c,mm_c2;

  /* Find if on chip */
  p_xs_3->xpospix=0.0;
  p_xs_3->ypospix=0.0;
  p_xs_3->chippix[0]=-1;
  p_xs_3->chippix[1]=0;
  p_xs_3->chippix[2]=0;

#ifndef FCCDD_FLAG 
  //mm_c=p_xs_3->morder-(float)(p_xs_3->morder_min+((p_xs_3->morder_max-p_xs_3->morder_min)/2));
  //mm_c2=mm_c*mm_c;
  //mm_c3=mm_c*mm_c2;
  ydet2=p_xs_3->ydet*p_xs_3->ydet;
  ydet3=ydet2*p_xs_3->ydet;
  xdet2=p_xs_3->xdet*p_xs_3->xdet;
  xdet3=xdet2*p_xs_3->xdet;
  xdet_c=p_xs_3->xdet-p_xs_3->chipx;
  //xdet_c=p_xs_3->xdet-p_xs_3->d2_x1;
  xdet_c2=xdet_c*xdet_c;
  xdet_c3=xdet_c2*xdet_c;
  xdet_c4=xdet_c3*xdet_c;
  ydet_c=p_xs_3->ydet-p_xs_3->chipy;
  //ydet_c=p_xs_3->ydet-p_xs_3->d2_x2;
  ydet_c2=ydet_c*ydet_c;
  ydet_c3=ydet_c2*ydet_c;
  ydet_c4=ydet_c3*ydet_c;

  /**********PIN CUSHION DISTORTION************/
  pc_x=p_xs_3->chipx+
    (p_xs_3->pc_x_xx*xdet_c2)+
    (p_xs_3->pc_x_x1*xdet_c)+
    (p_xs_3->pc_x_yy*ydet_c2)+
    (p_xs_3->pc_x_y1*ydet_c)+
    (p_xs_3->pc_x_xy*xdet_c*ydet_c)+
    (p_xs_3->pc_x_x3*xdet_c3)+
    (p_xs_3->pc_x_x2y*xdet_c2*ydet_c)+
    (p_xs_3->pc_x_y2x*xdet_c*ydet_c2)+
    (p_xs_3->pc_x_y3*ydet_c3)+
    (p_xs_3->pc4_x_xy3*xdet_c*ydet_c3)+
    (p_xs_3->pc4_x_x3y*xdet_c3*ydet_c)+
    (p_xs_3->pc4_x_x2y2*xdet_c2*ydet_c2)+
    (p_xs_3->pc4_x_x4*xdet_c4)+
    (p_xs_3->pc4_x_y4*ydet_c4);
  pc_y=p_xs_3->chipy+
    (p_xs_3->pc_y_xx*xdet_c2)+
    (p_xs_3->pc_y_x1*xdet_c)+
    (p_xs_3->pc_y_yy*ydet_c2)+
    (p_xs_3->pc_y_y1*ydet_c)+
    (p_xs_3->pc_y_xy*xdet_c*ydet_c)+
    (p_xs_3->pc_y_x3*xdet_c3)+
    (p_xs_3->pc_y_x2y*xdet_c2*ydet_c)+
    (p_xs_3->pc_y_y2x*xdet_c*ydet_c2)+
    (p_xs_3->pc_y_y3*ydet_c3)+
    (p_xs_3->pc4_y_xy3*xdet_c*ydet_c3)+
    (p_xs_3->pc4_y_x3y*xdet_c3*ydet_c)+
    (p_xs_3->pc4_y_x2y2*xdet_c2*ydet_c2)+
    (p_xs_3->pc4_y_x4*xdet_c4)+
    (p_xs_3->pc4_y_y4*ydet_c4);
  /*note: pc4 coeffs will be zero for UVB/VIS and old format NIR configs*/

/*   else { */
/*   pc_x=(p_xs_3->pc_x_xx*xdet2)+ */
/*     (p_xs_3->pc_x_x1*p_xs_3->xdet)+ */
/*     (p_xs_3->pc_x_yy*ydet2)+ */
/*     (p_xs_3->pc_x_y1*p_xs_3->ydet)+ */
/*     (p_xs_3->pc_x_xy*p_xs_3->xdet*p_xs_3->ydet)+ */
/*     (p_xs_3->pc_x_x3*xdet3)+ */
/*     (p_xs_3->pc_x_x2y*xdet2*p_xs_3->ydet)+ */
/*     (p_xs_3->pc_x_y2x*p_xs_3->xdet*ydet2)+ */
/*     (p_xs_3->pc_x_y3*ydet3); */
/*   pc_y=(p_xs_3->pc_y_xx*xdet2)+ */
/*     (p_xs_3->pc_y_x1*p_xs_3->xdet)+ */
/*     (p_xs_3->pc_y_yy*ydet2)+ */
/*     (p_xs_3->pc_y_y1*p_xs_3->ydet)+ */
/*     (p_xs_3->pc_y_xy*p_xs_3->xdet*p_xs_3->ydet)+ */
/*     (p_xs_3->pc_y_x3*xdet3)+ */
/*     (p_xs_3->pc_y_x2y*xdet2*p_xs_3->ydet)+ */
/*     (p_xs_3->pc_y_y2x*p_xs_3->xdet*ydet2)+ */
/*     (p_xs_3->pc_y_y3*ydet3); */
/*   } */
  p_xs_3->xdet=pc_x;
  p_xs_3->ydet=pc_y;

  /*distortion extra*/
  if (p_xs_3->arm<2) {
    dstn_y=(p_xs_3->d2_x3*ydet_c3)+(p_xs_3->d2_x2*ydet_c2)+(p_xs_3->d2_x1*ydet_c);
    //dstn_y=(p_xs_3->d2_x3*mm_c3)+(p_xs_3->d2_x2*mm_c2)+(p_xs_3->d2_x1*mm_c);
    p_xs_3->ydet=p_xs_3->ydet+dstn_y;
/*     if (p_xs_3->arm==0) { */
/*       d2_y3=(p_xs_3->d2_y3x3*ydet_c3)+(p_xs_3->d2_y3x2*ydet_c2)+(p_xs_3->d2_y3x1*ydet_c)+p_xs_3->d2_y3x0; */
/*       d2_y2=(p_xs_3->d2_y2x3*ydet_c3)+(p_xs_3->d2_y2x2*ydet_c2)+(p_xs_3->d2_y2x1*ydet_c)+p_xs_3->d2_y2x0; */
/*       d2_y1=(p_xs_3->d2_y1x3*ydet_c3)+(p_xs_3->d2_y1x2*ydet_c2)+(p_xs_3->d2_y1x1*ydet_c)+p_xs_3->d2_y1x0; */
/*       dstn_y=(d2_y3*ydet_c3)+(d2_y2*ydet_c2)+(d2_y1*ydet_c); */
/*       p_xs_3->ydet=p_xs_3->ydet+dstn_y; */
/*     } */
  }
  else if (p_xs_3->arm==2) {
    /*Check what sort of coeffs (old or new) are present in the input config,
      this can be inferred from the d2_ values. Since the old configs were
      usually used with fixed (i.e. not annealed) non-zero d2_ coeffs, it is
      sufficient to check one of these.*/
    if (p_xs_3->d2_x3!=0.0) {
      dstn_x=(p_xs_3->d2_x3*xdet_c3)+(p_xs_3->d2_x2*xdet_c2)+(p_xs_3->d2_x1*xdet_c);
      //dstn_x=(p_xs_3->d2_x3*mm_c3)+(p_xs_3->d2_x2*mm_c2)+(p_xs_3->d2_x1*mm_c);
      p_xs_3->xdet=p_xs_3->xdet+dstn_x;
      d2_y3=(p_xs_3->d2_y3x3*xdet_c3)+(p_xs_3->d2_y3x2*xdet_c2)+(p_xs_3->d2_y3x1*xdet_c)+p_xs_3->d2_y3x0;
      d2_y2=(p_xs_3->d2_y2x3*xdet_c3)+(p_xs_3->d2_y2x2*xdet_c2)+(p_xs_3->d2_y2x1*xdet_c)+p_xs_3->d2_y2x0;
      d2_y1=(p_xs_3->d2_y1x3*xdet_c3)+(p_xs_3->d2_y1x2*xdet_c2)+(p_xs_3->d2_y1x1*xdet_c)+p_xs_3->d2_y1x0;
      
/*     d2_y3=(p_xs_3->d2_y3x1*p_xs_3->morder)+p_xs_3->d2_y3x0; */
/*     d2_y2=(p_xs_3->d2_y2x1*p_xs_3->morder)+p_xs_3->d2_y2x0; */
/*     d2_y1=(p_xs_3->d2_y1x3*p_xs_3->morder)+p_xs_3->d2_y1x0; */
      dstn_y=(d2_y3*ydet_c3)+(d2_y2*ydet_c2)+(d2_y1*ydet_c);
      p_xs_3->ydet=p_xs_3->ydet+dstn_y;
    }
    /* If d2_x3 is zero we can assume that the new coeffs are present*/
    else {
      dstn_y=(p_xs_3->ca_x1*(xdet_c-p_xs_3->ca_x0)+p_xs_3->ca_y1*(ydet_c-p_xs_3->ca_y0))*p_xs_3->es_y_tot;
      p_xs_3->ydet=p_xs_3->ydet+dstn_y;
    }
  }
#endif
#ifdef CCCDD_FLAG
    /*mapping onto deformed spherical (radius fdet) pixel grid*/
  h_det=sqrt(p_xs_3->xdet*p_xs_3->xdet+p_xs_3->xdet*p_xs_3->xdet);
  //h_det=sqrt(p_xs_3->xdet*p_xs_3->xdet+p_xs_3->ydet*p_xs_3->ydet);
  p_xs_3->xdet=(p_xs_3->fdet*p_xs_3->xdet/h_det)*sin(h_det/p_xs_3->fdet);
  p_xs_3->ydet=(p_xs_3->fdet*p_xs_3->ydet/h_det)*sin(h_det/p_xs_3->fdet);
#endif
  //  printf("%lf %lf %lf %lf %lf %lf \n",p_xs_3->chipxup,p_xs_3->chipxdown,p_xs_3->chipyup,p_xs_3->chipydown, p_xs_3->xdet,p_xs_3->ydet);
/*   if (p_xs_3->xdet<p_xs_3->chipxdown) */
/*   { */
/*     p_xs_3->chippix[0]=5; */
/*   } */
/*   else if (p_xs_3->xdet>p_xs_3->chipxup) */
/*   { */
/*     p_xs_3->chippix[0]=6; */
/*   } */
/*   else if (p_xs_3->ydet>p_xs_3->chipyup) */
/*   { */
/*     p_xs_3->chippix[0]=7; */
/*   } */
/*   else if (p_xs_3->ydet<p_xs_3->chipydown) */
/*   { */
/*     p_xs_3->chippix[0]=8; */
/*   } */

/*   /\*still need to allow for the possibility that xdet or ydet are NaN*\/ */
/*   else if (p_xs_3->xdet>p_xs_3->chipxdown && p_xs_3->xdet<p_xs_3->chipxup && p_xs_3->ydet<p_xs_3->chipyup && p_xs_3->ydet>p_xs_3->chipydown) { */
    p_xs_3->chippix[0]=1;
    /* xpospix=0.5,ypospix=0.5 would be the middle of the bottom left pixel */

    if(p_xs_3->arm!=2) {
      p_xs_3->xpospix=0.5*(p_xs_3->chipxpix+p_xs_3->xsize_corr)-(p_xs_3->ydet-p_xs_3->chipy)/p_xs_3->pix_X;
      p_xs_3->ypospix=0.5*(p_xs_3->chipypix+p_xs_3->ysize_corr)-(p_xs_3->xdet-p_xs_3->chipx)/p_xs_3->pix_Y;
    }
    else {
      p_xs_3->xpospix=0.5*(p_xs_3->chipxpix+p_xs_3->xsize_corr)+(p_xs_3->xdet-p_xs_3->chipx)/p_xs_3->pix_X;
      p_xs_3->ypospix=0.5*(p_xs_3->chipypix+p_xs_3->ysize_corr)+(p_xs_3->ydet-p_xs_3->chipy)/p_xs_3->pix_Y;
      array_size_fix=NIR_FIX; /*correction for wrong xsh_data_instrument default*/
    }
    //printf("qwerty %lf %lf \n", p_xs_3->xpospix,p_xs_3->ypospix);

    if (p_xs_3->pix_X>0.029) { /*binx=2 */
      p_xs_3->xpospix=p_xs_3->xpospix+0.25;
    }
    if (p_xs_3->pix_Y>0.029) { /*binx=2 */
      p_xs_3->ypospix=p_xs_3->ypospix+0.25;
    }
    /*The limits in chipxup...chipydown are not correct away from the axis of the chip. A pixel could fall within these limits but not actually fall on the chip. So: */
    if (p_xs_3->xpospix>p_xs_3->chipxpix-1+array_size_fix) {
      p_xs_3->xpospix=-1.0;
      p_xs_3->ypospix=-1.0;
      p_xs_3->chippix[0]=6;//Above (with orders horizontal)
    }
    if (p_xs_3->xpospix<0) {
      p_xs_3->xpospix=-1.0;
      p_xs_3->ypospix=-1.0;
      p_xs_3->chippix[0]=5;//Below
    }
    if (p_xs_3->ypospix<0) {
      p_xs_3->xpospix=-1.0;
      p_xs_3->ypospix=-1.0;
      p_xs_3->chippix[0]=8;//Left (i.e. below disp co-ord)
    }
    if (p_xs_3->ypospix>p_xs_3->chipypix-1) {
      p_xs_3->xpospix=-1.0;
      p_xs_3->ypospix=-1.0;
      p_xs_3->chippix[0]=7;//Right
    }

      p_xs_3->chippix[1]=(int)(p_xs_3->xpospix-0.5)+1;
      p_xs_3->chippix[2]=(int)(p_xs_3->ypospix-0.5)+1;

/*     /\*use pix size to determine binning*\/ */
/*     if (p_xs_3->pix_X>0.029) { /\*binx=2*\/ */
/*     /\*N-0.75<xpospix<N+0.25 => chippix[1]=N*\/ */
/*       p_xs_3->chippix[1]=(int)(p_xs_3->xpospix-0.25)+1; */
/*     } */
/*     else { */
/*     /\*N-0.5<xpospix<N+0.5 => chippix[1]=N*\/ */
/*       p_xs_3->chippix[1]=(int)(p_xs_3->xpospix-0.5)+1; */
/*     } */
/*     if (p_xs_3->pix_Y>0.029) { /\*biny=2*\/ */
/*     /\*N-0.75<ypospix<N+0.25 => chippix[2]=N*\/ */
/*       p_xs_3->chippix[2]=(int)(p_xs_3->ypospix-0.25)+1; */
/*     } */
/*     else { */
/*     /\*N-0.5<ypospix<N+0.5 => chippix[2]=N*\/ */
/*       p_xs_3->chippix[2]=(int)(p_xs_3->ypospix-0.5)+1; */
/*     } */

/*   } */
/*   else { */
/*     p_xs_3->chippix[0]=-2; */
/*   } */
  return;
} 

/*----------------------------------------------------------------------------*/
/**
  @brief    Load the refractive index array for a given arm and temperature.
            This old routine is only retained to allow easy testing of new
	    refractive index data.
  @param    ref_ind_file Filename for file conatining refractive index data
  @param    ref_ind    Refractive index coefficients
  @param    temper       Temperature in K
 */
/*----------------------------------------------------------------------------*/

/* Note that this function is not used !!*/
void 
xsh_ref_ind_read_old(const char* ref_ind_file, 
		     DOUBLE** ref_ind,
		     DOUBLE temper)
{
  int ii,jj,flag;
  FILE *p_ref_ind_file;  /*pointer to input file */
  //printf("temper %lf \n",temper);
  /*open refractive index data file */
  p_ref_ind_file=fopen(ref_ind_file,"r");
  if(p_ref_ind_file==NULL) {
    printf("couldn't find ref_ind file\n");
    cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT);
    return;
  }
  ii=2; /*start filling from row [2][*] */
  flag=0;
  while (fscanf(p_ref_ind_file,"%64lf %64lf %64lf %64lf %64lf %64lf %64lf\n",
                &ref_ind[ii][6],&ref_ind[ii][0],&ref_ind[ii][1],&ref_ind[ii][2],
                &ref_ind[ii][3],&ref_ind[ii][4],&ref_ind[ii][5]) !=EOF)
    /*      ref_ind[*][6] holds the temperature of the fit */
  {
    if (temper>=ref_ind[ii][6])
    {
      /*fill row [0][*] with the current values, the last time that this will be
        overwritten is the last time that temper is below the temperature value read in */
      flag=1;
      for (jj=0; jj<7; jj++)
      {
	ref_ind[0][jj]=ref_ind[ii][jj];
      }
    }
    else if (temper<ref_ind[ii][6] && flag==1)
    {
      /*fill row [1][*] with the current values, this will only be written once */
      flag=2;
      for (jj=0; jj<7; jj++)
      {
	ref_ind[1][jj]=ref_ind[ii][jj];
      }
    }
    ii++;
  }
  /*if the conditions are never met so that flag=2 then the temperature is out of range */
  if (flag!=2) printf("******* Temperature out of range! ******* %lf \n", temper);
  fclose(p_ref_ind_file);
  return;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Load the refractive index coeffs for a given arm and temperature
  @param    arm       Instrument arm
  @param    ref_ind_T Refractive index coefficients
  @param    temper    Temperature in K
 */
/*----------------------------------------------------------------------------*/

void xsh_ref_ind_read(int arm, DOUBLE** ref_ind_T,DOUBLE temper)
{
  int ii,jj,flag;

  //printf("temper %lf \n",temper);

  ii=2; /*start filling from row [2][*] */
  flag=0;
  for (ii=2; ii<8; ii+=1) {
    for (jj=0;jj<7;jj+=1){
      if (arm==0) {
	ref_ind_T[ii][jj]=silica_zemax[ii-2][jj];
      }
      else if (arm==1) {
	ref_ind_T[ii][jj]=schott_sf6_manu[ii-2][jj];
      }
      else {
	ref_ind_T[ii][jj]=znse[ii-2][jj];
      }
    }
    /*      ref_ind[*][6] holds the temperature of the fit */
    if (temper>=ref_ind_T[ii][6])
    {
      /*fill row [0][*] with the current values, the last time that this will be
        overwritten is the last time that temper is below the temperature value read in */
      flag=1;
      for (jj=0; jj<7; jj++) {
	ref_ind_T[0][jj]=ref_ind_T[ii][jj];
      }
    }
    else if (temper<ref_ind_T[ii][6] && flag==1)
    {
      /*fill row [1][*] with the current values, this will only be written once */
      flag=2;
      for (jj=0; jj<7; jj++) {
	ref_ind_T[1][jj]=ref_ind_T[ii][jj];
      }
    }      
  }
  /*if the conditions are never met so that flag=2 then the temperature is out of range */
  if (flag!=2) {
    printf("******* Temperature out of range! ******* %lf \n", temper);
    for (jj=0; jj<7; jj++) {
      ref_ind_T[1][jj]=ref_ind_T[7][jj];
    }
  }
  return;
}

#define ERROR 1
#define OK 0
/**
@brief allocates memory for an array of integers
@param asize size of array
@return allocated array (remember to de-allocate)
 */
int* xsh_alloc1Darray_INT(int asize)
{  
  int* array;
  /* get memory for the 1D array */
  if ((array=(int *)cpl_malloc(asize*sizeof(int))) == NULL)
    {
      printf("ERROR allocation  memory for array1D int\n");
      return NULL;
    }  
  return array;   
}
/**
@brief allocates memory for an array of doubles
@param asize size of array
@return allocated array (remember to de-allocate)
 */
DOUBLE* xsh_alloc1Darray(int asize)
{  
  DOUBLE* array;
  /* get memory for the 1D array */
  if ((array=(DOUBLE *)cpl_malloc(asize*sizeof(DOUBLE))) == NULL)
    {
      printf("ERROR allocation  memory for array1D double\n");
      return NULL;
    }  
  return array;   
}

/**
@brief allocates memory for a 2D array of doubles
@param asize size1 of array
@param bsize size2 of array
@return allocated array (remember to de-allocate)
 */
double** xsh_alloc2Darray(int asize, int bsize)
{  
     int ii;
     double** ccdtemp;
     /* get memory for all the 2D arrays */
     if ((ccdtemp=(double **)cpl_malloc(asize*sizeof(double *))) == NULL)
     {
       printf("ERROR allocating memory for ccdtemp at the initial pointer\n");
       return NULL;
     }

     for (ii = 0; ii < asize; ii++)
     {
       if ( (ccdtemp[ii]=(double *)cpl_malloc(bsize*sizeof(double))) == NULL)
       {
        printf("ERROR allocating doublle memory for ccdtemp at row=%d\n",ii);
        return NULL;
       }
     }
  return ccdtemp;   
}

/**
@brief allocates memory for a 2D array of floats
@param asize size1 of array
@param bsize size2 of array
@return allocated array (remember to de-allocate)
 */
float** xsh_alloc2Darray_f(int asize, int bsize)
{  
     int ii;
     float **ccdtemp;
     /* get memory for all the 2D arrays */
     if ((ccdtemp=(float **)cpl_malloc(asize*sizeof(float *))) == NULL)
     {
       printf("ERROR allocating memory for ccdtemp at the initial pointer\n");
       return NULL;
     }

     for (ii = 0; ii < asize; ii++)
     {
       if ( (ccdtemp[ii]=(float *)cpl_malloc(bsize*sizeof(float))) == NULL)
       {
        printf("ERROR allocating float memory for ccdtemp at row=%d\n",ii);
        return NULL;
       }
     }
  return ccdtemp;   
}

/**
@brief allocates memory for a 2D array of integers
@param asize size1 of array
@param bsize size2 of array
@return allocated array (remember to de-allocate)
 */

int** xsh_alloc2Darray_i(int asize, int bsize)
{  
     int ii;
     int **ccdtemp;
     /* get memory for all the 2D arrays */
     if ((ccdtemp=(int **)cpl_malloc(asize*sizeof(int *))) == NULL)
     {
       printf("ERROR allocating memory for ccdtemp at the initial pointer\n");
       return NULL;
     }

     for (ii = 0; ii < asize; ii++)
     {
       if ( (ccdtemp[ii]=(int *)cpl_malloc(bsize*sizeof(int))) == NULL)
       {
        printf("ERROR allocating int memory for ccdtemp at row=%d\n",ii);
        return NULL;
       }
     }
  return ccdtemp;   
}

/**
@brief free memory for a 2D array of doubles
@param ccdtemp array
@param asize size of array
@return 0 if no error or 1 if error
 */

int xsh_free2Darray(double ** ccdtemp, int asize)
{
  int i;
  const int my_asize=asize;
  for (i=my_asize-1; i >=0; i--) 
    {
     if (ccdtemp[i] !=NULL) cpl_free(ccdtemp[i]);   
     else 
       {
         printf("Error freeing memory at row= %d\n", i);
         return 1; 
       }      
    }
  if( ccdtemp !=NULL) cpl_free(ccdtemp); 
  else 
  { 
   printf("Error freeing memory at the initial pointer");
   return 1; 
  }
  return 0;   
}

/**
@brief free memory for a 2D array of integers
@param ccdtemp array
@param asize size of array
@return 0 if no error or 1 if error
 */

int xsh_free2Darray_i(int ** ccdtemp, int asize)
{
  int i;
  for (i=asize-1; i >=0; i--) 
    {
     if (ccdtemp[i] !=NULL) cpl_free(ccdtemp[i]);   
     else 
       {
         printf("Error freeing memory at row= %d\n", i);
         return 1; 
       }      
    }
  if( ccdtemp !=NULL) cpl_free(ccdtemp); 
  else 
  {
   printf("Error freeing memory at the initial pointer");
   return 1; 
  }
  return 0;   
}

/**
@brief free memory for a 2D array of floats
@param ccdtemp array
@param asize size of array
@return 0 if no error or 1 if error
 */

int xsh_free2Darray_f(float ** ccdtemp, int asize)
{
  int i;
  for (i=asize-1; i >=0; i--) 
    {
     if (ccdtemp[i] !=NULL) cpl_free(ccdtemp[i]);   
     else 
       {
         printf("Error freeing memory at row= %d\n", i);
         return 1; 
       }      
    }
  if( ccdtemp !=NULL) cpl_free(ccdtemp); 
  else 
  {
   printf("Error freeing memory at the initial pointer");
   return 1; 
  }
  return 0;   
}
/**
@brief copy 2D to 1D array
@param ccdtemp 2D array
@param asize size1
@param bsize size2
@return 1D array of doubles (remember to deallocate memory)
 */
double * xsh_copy2D_to_1D(double ** ccdtemp,int asize, int bsize)
{
  int ii;
  int jj;
  int kk;
  double *oneDccdtemp=NULL; 
  if ( (oneDccdtemp=(double *)cpl_malloc(asize*bsize*sizeof(double))) == NULL)
  {
        printf("ERROR allocating memory for oneDccdtemp\n");
        return NULL;
  }
  kk=0;
  for (ii = 0; ii < asize; ii++)
  { 
    for (jj = 0; jj < bsize; jj++)
    {
      oneDccdtemp[kk]=ccdtemp[ii][jj];
      kk +=1;
    }
  }  
  return oneDccdtemp;
}

/**
@brief copy 1D to 2D array
@param oneDccdtemp 1D array
@param asize size1
@param bsize size2
@return 2D array of doubles (remember to deallocate memory)
 */
double ** xsh_copy1D_to_2D(double * oneDccdtemp, int asize, int bsize)
{
  int ii;
  int jj;
  int kk;
  double **ccdtemp=NULL;
  ccdtemp=xsh_alloc2Darray(asize,bsize);
  kk=0;
  for (ii = 0; ii < asize; ii++)
  { 
    for (jj = 0; jj < bsize; jj++)
    {
      ccdtemp[ii][jj]=oneDccdtemp[kk];
      kk +=1;
    }
  }  
  return ccdtemp;
}

/**
@brief allocate 3D array
@param asize size1
@param bsize size2
@param csize size3
@return 3D array of doubles (remember to deallocate memory)
 */
double *** xsh_alloc3Darray2(int asize, int bsize, int csize)
{  
     int ii;
     double ***ccdtemp;

     /* get memory for the 3D array */
     if ((ccdtemp=(double ***)cpl_malloc(asize*sizeof(double **))) == NULL)
     {
       printf("ERROR allocating memory for ccdtemp at the initial pointer\n");
       return NULL ;
     }
     for (ii = 0; ii < asize; ii++) ccdtemp[ii]=xsh_alloc2Darray(bsize,csize);
     return ccdtemp;   
}


/**
@brief allocate 3D array
@param asize size1
@param bsize size2
@param csize size3
@return 3D array of doubles (remember to deallocate memory)
 */
double *** xsh_alloc3Darray(int asize, int bsize, int csize)
{  
     int ii,jj;
     double ***ccdtemp;

     /* get memory for all the 3D arrays */
     if ((ccdtemp=(double ***)cpl_malloc(asize*sizeof(double **))) == NULL)
     {
       printf("ERROR allocating memory for ccdtemp at the initial pointer\n");
       return NULL ;
     }

     for (ii = 0; ii < asize; ii++)
     {       
       if ( (ccdtemp[ii]=(double **)cpl_malloc(bsize*sizeof(double*))) == NULL)
       {
        printf("ERROR allocating memory for ccdtemp at row=%d\n",ii);
        return NULL;
       }
       else
      {
       for (jj = 0; jj < bsize; jj++)
       {
        if ( (ccdtemp[ii][jj]=(double *)cpl_malloc(csize*sizeof(double))) == NULL)
         {
          printf("ERROR allocating memory for ccdtemp at row=%d\n",ii);
          return NULL;
         }
        }
       }
     }
  return ccdtemp;   
}

/**
@brief free 3D array
@param ccdtemp free 3D array
@param asize size1
@param bsize size2
@return 0 if no error 1 if error
 */

int xsh_free3Darray(double ***ccdtemp, int asize, int bsize)
{
  int i;
  for (i=asize-1; i >=0; i--) 
    {
     if (ccdtemp[i] !=NULL) xsh_free2Darray(ccdtemp[i],bsize);   
     else 
       {
         printf("Error freeing memory at slide= %d\n", i);
         return ERROR; 
       }      
    }
  if( ccdtemp !=NULL) cpl_free(ccdtemp); 
  else 
  {
   printf("Error freeing memory at the 3D initial pointer");
   return ERROR; 
  }
  return OK;      
}

/**
@brief add 2 vectors a+=b
@param a vector1
@param b vector2
@return void
 */
void xsh_addvectors(vec a, vec b)
{
  int i;
  for(i=0; i<vectordim; i++) a[i]+=b[i];
}

/**
@brief add 2 vectors a+=b
@param a vector1
@param b vector2
@return void
 */
void xsh_addvectors3D(vec a, vec b)
{
  int i;
  for(i=0; i<vectordim-1; i++) a[i]+=b[i+1];
}

/**
@brief subtract 2 vectors a-=b
@param a vector1
@param b vector2
@return void
 */

void xsh_subtractvectors(vec a, vec b)
{
  int i;
  for(i=0; i<vectordim; i++) a[i]-=b[i];
}

/**
@brief implements scalar product
@param a vector1
@param b vector2
@return a*b
 */
DOUBLE xsh_scalarproduct(vec a, vec b)
{
  int i;
  DOUBLE scalar;
  scalar=0.0;
  for(i=0; i<vectordim; i++) scalar += a[i]*b[i];
  return scalar; 
}
/**
@brief applies scalar product to vector
@param a vector
@param k scalar
 */
void xsh_multiply(vec a, DOUBLE k)
{
  register int i;
  for(i=0; i<vectordim; i++) a[i] *=k;
}

/**
@brief show vector content
@param a vector
 */
void xsh_showvector(vec a)
{
 int i;
 for(i=0; i<vectordim; i++) printf("%lf ", a[i]*1000.0); 
 printf("          \n"); 
}


/**
@brief normalize vector
@param a vector
@note normalize by z^2 = 1- (x^2 + y^2)
 */


void xsh_normz(vec a)
{
  double x2_sqr = a[2]*a[2];
  if (x2_sqr > 1.0) {
    a[1]=0.0;
    a[2]=1.0;
    a[3]=0.0;
    return;
  }
  double x1_sqr = a[1]*a[1];
  if (x1_sqr > 1.0) {
    a[1]=1.0;
    a[2]=0.0;
    a[3]=0.0;
    return;
  }
  double sum_sqrs = x1_sqr + x2_sqr;
  if (sum_sqrs > 1.0) {
    double norm = 1./sqrt (sum_sqrs);
    a[1] *=norm;
    a[2] *=norm;
    a[3]=0.0;
  }
  else{
    if (a[3]>=0) a[3]=sqrt(1.0- sum_sqrs);
    else a[3]=-sqrt(1.0-sum_sqrs);
  }

  return;
}





/**
@brief normalize vector
@param a vector
@note normalize by  1/sqrt(x^2 + y^2 + z^2)
 */
void xsh_normall(vec a)
{
   DOUBLE mag;
   mag=1./sqrt(a[1]*a[1]+a[2]*a[2]+a[3]*a[3]);
   a[1]=a[1]*mag;
   a[2]=a[2]*mag;
   a[3]=a[3]*mag;
}

/**
@brief multiply three matrixes A=B*C
@param A matrix result
@param B matrix factor
@param C matrix factor
 */
void xsh_multiplymatrix(mat A, mat B, mat C)
{
  register int i,j,k; 
  xsh_nullmatrix(A);
  for(i=0; i<vectordim; i++) { 
    for(j=0; j<vectordim; j++) {
      for(k=0; k<vectordim; k++){
	  A[i][j] +=B[i][k]*C[k][j];
	}
    }
  }
}
/**
@brief multiply three matrixes A=B*C*D
@param A matrix result
@param B matrix factor
@param C matrix factor
@param D matrix factor
 */
void xsh_multiplythreematrix(mat A, mat B, mat C,mat D)
{
 mat temp;
 xsh_nullmatrix(temp);
 xsh_multiplymatrix(temp,C,D); /* multiply C*D and store the result in temp  */
 xsh_multiplymatrix(A,B,temp); /* multiply B*temp=B*C*D and store the result in A */
} 

/**
@brief Show matrix
@param A matrix to be shown
 */
void xsh_showmatrix(mat A)
{
 int i;
 for(i=0; i<vectordim; i++) {
   printf("%lf  %lf  %lf  %lf\n", A[i][0],A[i][1],A[i][2],A[i][3]);  
 }
  printf("          \n");
}

/**
@brief initialize matrix A
@param A matrix to be initialized
 */
void xsh_initializematrix(mat A)
{
  int i,j;
   for(i=0; i<vectordim; i++) { 
    for(j=0; j<vectordim; j++) {
      A[i][j]=i+j; 
    }
   }
}

/**
@brief Realize a*B*c
@param a vector
@param B matrix
@param c vector
@return void
 */
/*
void xsh_matrixforvector(vec a,mat B,vec c)
{
  register int i,j;
  vec temp;
  xsh_nullvector(temp);
  for(i=0; i<vectordim; i++) { 
    for(j=0; j<vectordim; j++) {
        temp[i] +=B[i][j]*c[j];
    }
  }
  xsh_copyvector(a,temp);  
}
*/

void xsh_matrixforvector(vec a,mat B,vec c)
{
  register int i,j;
  vec temp;
  xsh_nullvector(temp);
  for(j=0; j<vectordim; j++) {
    double c_j = c[j];
    for(i=0; i<vectordim; i++) {
        temp[i] +=B[i][j]*c_j;
    }
  }
  xsh_copyvector(a,temp);
}

/**
@brief matrix transposal
@param A transposed matrix
@param B matrix to be transposed
 */
void xsh_transpose(mat A ,mat B)
{
   register int i,j;
   for(i=0; i<vectordim; i++) { 
    for(j=0; j<vectordim; j++) {
      A[i][j]=B[j][i]; 
    }
   }
}

/**
@brief matrix rotation
@param A matrix to be rotated
@param axis axis around which rotation occurs
@param angle rotation angle
 */	
void 
xsh_rotationmatrix(mat A, const char axis, const DOUBLE angle)
{  
  xsh_nullmatrix(A); /*all element to zero */
  double sin_a=sin(angle);
  double cos_a=cos(angle);

  /*change only the element involved in the x rotation  */
  switch(axis){

  case 'x':{
    /*  1 0 0 0 , 0 1 0 0, 0 0 c s , 0 0 -s c   (left handed) */
  A[0][0]=A[1][1]=1;
  A[2][2]=A[3][3]=cos_a;
  A[2][3]=sin_a; 
  A[3][2]= -A[2][3]; 
  break;
  }

  /*change only the element involved in the y rotation  */
  case 'y':{
    /*  1 0 0 0 , 0 c 0 -s, 0 0 1 0 , 0 s 0 c   (left handed) */
  A[0][0]=A[2][2]=1;
  A[1][1]=A[3][3]=cos_a;
  A[1][3]=-sin_a; 
  A[3][1]=-A[1][3]; 
  break;
  }

  /*change only the element involved in the z rotation  */
  case 'z':{
  A[0][0]=A[3][3]=1;
  A[1][1]=A[2][2]=cos_a;
  A[1][2]=sin_a; 
  A[2][1]=-A[1][2]; 
  break;
  }
  printf("Error on creating rotation matrix\n");
 }
 
}

/**
@brief matrix rotation
@param A matrix to be rotated
@param x_angle rotation angle around X axis
@param y_angle rotation angle around Y axis
@param z_angle rotation angle around Z axis
 */	
void 
xsh_rotin(mat A,const DOUBLE x_angle, const DOUBLE y_angle,const DOUBLE z_angle)
{
  mat temp;
  mat X,Y,Z;
  xsh_rotationmatrix(X,'x',x_angle);
  xsh_rotationmatrix(Y,'y',y_angle); 
  xsh_rotationmatrix(Z,'z',z_angle);

  xsh_multiplymatrix(temp,Y,X);  /* multiply Y*X and store the result in temp */
  xsh_multiplymatrix(A,Z,temp);  /* multiply Z*temp=Z*Y*X and store the result in A */
}      

/*----------------------------------------------------------------------------*/
/**
  @brief    Calculate the new vector after a given incident vector is reflected
            in a prism (i.e. exits from the same surface than it entered through)
  @param    in       incident vector
  @param    m        spectral order
  @param    sg       grating constant
  @param    in_rot   matrix describing the rotation in to the entrance surface
  @param    exit_rot matrix describing the rotation out of the exit surface
  @param    out      output vector
  return    alpha    useful parameter for calculating blaze later...
 */
/*----------------------------------------------------------------------------*/
double xsh_physmod_grating(vec in,
			   int m,
			   double sg,
			   mat in_rot,
			   mat exit_rot,
			   vec out) {
  vec in2, out2;
  double alpha,beta;
  mat mech={ {1,0,0,0},
	     {m*(sg),1,0,0},
	     {0,0,1,0},
	     {0,0,0,-1}   };

  xsh_matrixforvector(in2,in_rot,in);
  alpha=atan(in2[1]/in2[3]);
  xsh_matrixforvector(out2,mech,in2);
  xsh_normz(out2);
  beta=atan(out2[1]/out2[3]);
  // NEED TO PASS BACK beta!!!!
  xsh_matrixforvector(out,exit_rot,out2);
  return alpha;
}


/*----------------------------------------------------------------------------*/
/**
  @brief    Calculate the new vector after a given incident vector passes a
            boundary between two materials
  @param    b    exit vector
  @param    rind refractive index
  @param    a    incident vector
  @return void
 */
/*----------------------------------------------------------------------------*/


void xsh_refract(vec b, DOUBLE rind, vec a)
{
  DOUBLE phi, pheta, y_signflag, z_signflag, sin_refrangle;
  y_signflag=1.0;
  z_signflag=1.0;
  phi=atan(sqrt(a[1]*a[1]+a[2]*a[2])/a[3]);
  pheta=atan(a[1]/a[2]);
  if (a[2]<0.0) y_signflag=-1.0;
  if (a[3]<0.0) z_signflag=-1.0;

  sin_refrangle = sin(phi)/rind;
  b[0]=a[0]; //preserve wavelength
  b[1]=z_signflag*y_signflag*sin(pheta)*sin_refrangle;
  b[2]=z_signflag*y_signflag*cos(pheta)*sin_refrangle;
  b[3]=z_signflag*cos(asin(sin_refrangle));
  return;
}

/*
void xsh_refract(vec b, DOUBLE rind, vec a)
{
  DOUBLE phi, pheta, sin_refrangle;

  phi=atan(sqrt(a[1]*a[1]+a[2]*a[2])/a[3]);
  pheta=atan(a[1]/a[2]);
  sin_refrangle = sin(phi)/rind;

  b[0]=a[0]; //preserve wavelength
  if (a[2]<0.0) {
    if (a[3]<0.0) {
      b[1] = sin(pheta)*sin_refrangle;
      b[2] = cos(pheta)*sin_refrangle;
      b[3] = -1.0*cos(asin(sin_refrangle));
    } else {
      b[1] = -1.0*sin(pheta)*sin_refrangle;
      b[2] = -1.0*cos(pheta)*sin_refrangle;
      b[3] = cos(asin(sin_refrangle));
    }
  } else {
    if (a[3]<0.0) {
      b[1] = -1.0*sin(pheta)*sin_refrangle;
      b[2] = -1.0*cos(pheta)*sin_refrangle;
      b[3] = -1.0*cos(asin(sin_refrangle));
    } else {
      b[1] = sin(pheta)*sin_refrangle;
      b[2] = cos(pheta)*sin_refrangle;
      b[3] = cos(asin(sin_refrangle));
    }
  }

  return;
}

*/


#define ERROR 1
#define OK 0





static cpl_error_code
xsh_model_compute_slitmap_kw(const double slit_min,
                             const double slit_max,
                             xsh_xs_3* p_xs_3,
                             xsh_instrument* instr,
                             cpl_propertylist** plist)
{

   int morder=0;
   double med_slit_cen=0;
   double med_slit_up=0;
   double med_slit_lo=0;
   double med_slit_slicup=0;
   double med_slit_sliclo=0;


   /* compute and write specific slitmap KW */
   med_slit_cen = (slit_min+slit_max)/2.0;

   med_slit_up = med_slit_cen+p_xs_3->es_s/2.0/p_xs_3->slit_scale;
   med_slit_lo = med_slit_cen-p_xs_3->es_s/2.0/p_xs_3->slit_scale;
   med_slit_slicup = IFU_HI+med_slit_cen;
   med_slit_sliclo = IFU_LOW+med_slit_cen;

   check( xsh_pfits_set_slitmap_median_cen( *plist, med_slit_cen));
   check( xsh_pfits_set_slitmap_median_edgup( *plist, med_slit_up));
   check( xsh_pfits_set_slitmap_median_edglo( *plist, med_slit_lo));

   for( morder = p_xs_3->morder_min; morder <= p_xs_3->morder_max; morder++){
      check( xsh_pfits_set_slitmap_order_cen( *plist, morder, med_slit_cen));
      check( xsh_pfits_set_slitmap_order_edgup( *plist, morder, med_slit_up));
      check( xsh_pfits_set_slitmap_order_edglo( *plist, morder, med_slit_lo));
   }
   if ( xsh_instrument_get_mode( instr) == XSH_MODE_IFU){
      check( xsh_pfits_set_slitmap_median_slicup( *plist, med_slit_slicup));
      check( xsh_pfits_set_slitmap_median_sliclo( *plist, med_slit_sliclo));
      for( morder = p_xs_3->morder_min; morder <= p_xs_3->morder_max; morder++){
         check( xsh_pfits_set_slitmap_order_slicup( *plist, morder, med_slit_slicup));
         check( xsh_pfits_set_slitmap_order_sliclo( *plist, morder, med_slit_sliclo));
      }
   }

  cleanup:

   return cpl_error_get_code();
}



/*----------------------------------------------------------------------------*/
/**
  @brief    Compute the wavelength and slit maps
  @param    p_xs_3       Model configuration data structure
  @param    instr        the xshooter arm
  @param    wtag         wavemap pro catg
  @param    stag         slitmap pro catg
  @param[out] wmap_frame wavemap pro catg
  @param[out] smap_frame slitmap pro catg

  @return cpl error code

 */
/*----------------------------------------------------------------------------*/
cpl_error_code xsh_model_maps_create(xsh_xs_3* p_xs_3, xsh_instrument* instr,
    const char * wtag, const char * stag, cpl_frame** wmap_frame,
    cpl_frame** smap_frame, const int save_tmp)

{
  int morder_cnt = 0; /* grating spectral order */
  DOUBLE lambda; /*wavelength in mm */
  DOUBLE lambda_nm; /* wavelength in nm */
  DOUBLE blaze_wav, lam_min, lam_max, lam_inc;
  XSH_ARM arm = XSH_ARM_UNDEFINED;
  XSH_MODE mode = XSH_MODE_UNDEFINED;
  long naxes[2];
  int ii, jj, binx, biny;
  int slitlet, slitlet_min, slitlet_max;
  double es_x_config;
  double slit_min, slit_max, slit_inc, slit_x, slit_y;
  double* ccd_wav; /*detector wavelengths array */
  double* ccd_slit; /*detector wavelengths array */
  int* ccd_mask; /*detector mask array */
  int* ccd_imap; /*detector ifu map array */
  cpl_image* ccd_wave_ima = NULL;
  cpl_image* ccd_slit_ima = NULL;
  cpl_image* ccd_mask_ima = NULL;
  cpl_image* ccd_imap_ima = NULL;

  cpl_polynomial * fit_wave_2d = NULL;
  cpl_polynomial * fit_slit_2d = NULL;
  cpl_matrix * mat_xy_sampling_points = NULL;
  cpl_vector * vec_w_sampling_points = NULL;
  cpl_vector * vec_s_sampling_points = NULL;

  cpl_vector* val = NULL;
  double* pval = NULL;

  DOUBLE** ref_ind = NULL;
  double* oneD_AB = NULL; /* 1D array to take contents of ccd */
  cpl_propertylist* plist = NULL;
  char filename[256];
  int array_size_fix = 0; /*in NIR case, this variable corrects for wrong
   xsh_data_instrument default*/
  int sx = 0;
  int sy = 0;
  int i = 0;
  int j = 0;
  double s_val = 0;
  double w_val = 0;
  int i_val = 0;
  cpl_table* tab_xy = NULL;
  int size_x = 0;
  int size_y = 0;

  XSH_ASSURE_NOT_NULL( p_xs_3);
  XSH_ASSURE_NOT_NULL( instr);
  XSH_ASSURE_NOT_NULL( wtag);
  XSH_ASSURE_NOT_NULL( stag);

  /* get instrument setting */
  check(arm=xsh_instrument_get_arm(instr));
  check(mode=xsh_instrument_get_mode(instr));
  check(binx=xsh_instrument_get_binx(instr));
  /* x-disp bin */
  check(biny=xsh_instrument_get_biny(instr));
  /* disp bin */

  xsh_msg("Generate physical model based wave and slit maps");

  /*For IFU mode needs to iterate over 3 slitlets. We define here relevant varable used later to step
   * through the slitlets, define their min/max value, and the incremental step to be applied to
   * generate the map*/
  if (mode == XSH_MODE_IFU) {
    slitlet_min = -1;
    slitlet_max = 1;
    slit_min = IFU_LOW + 0.000001;
    slit_max = IFU_HI - 0.000001;
    slit_inc = 0.05 * (slit_max - slit_min) * binx;
  } else {
    slitlet_min = 0;
    slitlet_max = 0;
    slit_min = (-0.5*p_xs_3->es_s) / p_xs_3->slit_scale;
    slit_max = (0.5*p_xs_3->es_s) / p_xs_3->slit_scale;
    slit_inc = 0.02 * (slit_max - slit_min) * binx;
  }

  /*znse_ref is the array holding Sellmeier coefs for ZnSe refractive index
   at each temp. Currently hard coded to take 6 temperatures in [2][*] to
   [7][*], can be extended. First two rows ([0][*] to [1][*]) take the entries
   for the temperature bracketing the operation.
   Column [*][0] takes the temperature, the other columns, [*][1] to [*][6]
   take the Sellmeier coeffs */
  ref_ind = xsh_alloc2Darray(8, 7);

  p_xs_3->arm = arm;

  /* here we need to define a constant to take care of the NIR arm special case, and
   * we load the refractive index coeffs for a given arm and temperature */
  if (arm == XSH_ARM_UVB) {
    xsh_ref_ind_read(0, ref_ind, p_xs_3->temper);
    array_size_fix = 0;
  } else if (arm == XSH_ARM_VIS) {
    xsh_ref_ind_read(1, ref_ind, p_xs_3->temper);
    array_size_fix = 0;
  } else {
    xsh_ref_ind_read(2, ref_ind, p_xs_3->t_ir_p2);
    array_size_fix = NIR_FIX;
  }

  /*initalize the model. Inside the echelle_init the cfg file is
   read and the variables assigned to the xsh structure
   initialisation. Sets up those matrices that are not dependent upon
   wavelength */

  xsh_3_init(p_xs_3);
  es_x_config = p_xs_3->es_x;

  size_x = p_xs_3->ASIZE + array_size_fix;
  size_y = p_xs_3->BSIZE;

  /* initialize array to hold wavelength results */
  ccd_wave_ima = cpl_image_new(size_x, size_y, CPL_TYPE_DOUBLE);
  ccd_slit_ima = cpl_image_new(size_x, size_y, CPL_TYPE_DOUBLE);
  ccd_mask_ima = cpl_image_new(size_x, size_y, CPL_TYPE_INT);
  ccd_imap_ima = cpl_image_new(size_x, size_y, CPL_TYPE_INT);

  ccd_wav = cpl_image_get_data_double(ccd_wave_ima);  /* wave map */
  ccd_slit = cpl_image_get_data_double(ccd_slit_ima); /* slit map */
  ccd_imap = cpl_image_get_data_int(ccd_imap_ima);    /* ifu map */
  ccd_mask = cpl_image_get_data_int(ccd_mask_ima);    /* mask (useful to speed-up code later)*/

  int fit_size = 0;
  const cpl_size max_deg_2d_w = 5;
  const cpl_size max_deg_2d_s = 5;

  double x_ord_min = 9999;
  double x_ord_max = -1;
  double y_ord_min = 9999;
  double y_ord_max = -1;
  cpl_error_code error2d;
  double x_val = 0;
  double y_val = 0;
  int x_det = 0;
  int y_det = 0;
  int x_min = 0;
  int y_min = 0;
  int fit_index = 0;
  int x_max = 0;
  int y_max = 0;
  int ord = 0;


  double two_sin_times_minus_nug=2 * (sin(-p_xs_3->nug));
  /* vectors we use inside the loop to get fit values from polynomials */
  val = cpl_vector_new(2);
  pval = cpl_vector_get_data(val);

  /* we loop over orders, wavelength,  to create the wave map */
  for (morder_cnt = p_xs_3->morder_min; morder_cnt <= p_xs_3->morder_max;
      morder_cnt += 1) {
    /*
     xsh_msg("order=%d",morder_cnt);
     */
    blaze_wav = two_sin_times_minus_nug / (morder_cnt * p_xs_3->sg);
    lam_max = blaze_wav
        * ((double) (morder_cnt) / ((double) (morder_cnt) - 0.5));
    lam_min = blaze_wav
        * ((double) (morder_cnt) / (0.5 + (double) (morder_cnt)));
    lam_inc = (lam_max - lam_min) / (0.5 * size_y);

    xsh_free_table(&tab_xy);
    xsh_free_matrix(&mat_xy_sampling_points);
    xsh_free_vector(&vec_w_sampling_points);
    xsh_free_vector(&vec_s_sampling_points);

    for (slitlet = slitlet_min; slitlet < slitlet_max + 1; slitlet++) {

      /* reset values */
      /* variable counting how many points we are going to fit */
      fit_index = 0;
      x_ord_min = 9999;
      x_ord_max = -1;
      y_ord_min = 9999;
      y_ord_max = -1;
      /* compute slit centres (IFU case) */
      if (slitlet == -1) {
        slit_x = 0.5 * (IFU_LEFT_MIN + IFU_LEFT_MAX);
        i_val = 1;
      } else if (slitlet == 1) {
        slit_x = 0.5 * (IFU_RIGHT_MIN + IFU_RIGHT_MAX);
        i_val = 3;
      } else {
        slit_x = 0.5 * (IFU_CEN_MIN + IFU_CEN_MAX);
        i_val = 2;
      }

      for (slit_y = slit_min; slit_y <= slit_max; slit_y += slit_inc) {
        /* check we do not go out of IFU slice */
        if (mode == XSH_MODE_IFU) {
          if (xsh_model_map_ifu(slit_x, slit_y, p_xs_3) != 0) {
            cpl_msg_error(__func__, "Outside slitlet array");
            return CPL_ERROR_UNSPECIFIED;
          }
        } else {
          /* computes actual slit positions in mm for the model */
          p_xs_3->es_y_tot = slit_y * p_xs_3->slit_scale + p_xs_3->es_y;
        }

        /* loop over dispersion (wavelength) direction (here we make an interpolation) */
        for (lambda = lam_min - p_xs_3->blaze_pad;
            lambda <= lam_max + p_xs_3->blaze_pad; lambda += lam_inc) {
          /* lambda is in mm */
          lambda_nm = lambda * mm2nm;
          /* computes x,y position at a given lambda,order for a given model configuration */
          xsh_3_eval(lambda, morder_cnt, ref_ind, p_xs_3);
          /* Takes the physical x,y position at the detector array and converts this to a pixel position */
          xsh_3_detpix(p_xs_3);
          x_val = p_xs_3->xpospix;
          y_val = p_xs_3->ypospix;

          /* check we are on the detector */
          if (p_xs_3->chippix[0] == 1) {
            /* check that we are on the detector after distortion correction */
            if (p_xs_3->chippix[1] >= 1 && p_xs_3->chippix[1] < size_x + 1
                && p_xs_3->chippix[2] >= 1 && p_xs_3->chippix[2] < size_y + 1) {
              /* we fill the grid points */

              fit_index += 1;

            } /* end check that we are on the detector
             after distortion correction */

          } /* end check we are on the detector */

        } /* end loop over lambda */

      } /* end loop over slit */

      fit_size = fit_index;

      xsh_free_matrix(&mat_xy_sampling_points);
      xsh_free_vector(&vec_w_sampling_points);
      xsh_free_vector(&vec_s_sampling_points);
      xsh_free_table(&tab_xy);

      mat_xy_sampling_points = cpl_matrix_new(2, fit_size);
      vec_w_sampling_points = cpl_vector_new(fit_size);
      vec_s_sampling_points = cpl_vector_new(fit_size);

      /* define a table to store sampling grid points:x,y positions, corresponding values of lambda,s,order
       * Note that this table is used only for debugging purposes !!
       * */
      tab_xy = cpl_table_new(fit_size);
      cpl_table_new_column(tab_xy, "X", CPL_TYPE_DOUBLE);
      cpl_table_new_column(tab_xy, "Y", CPL_TYPE_DOUBLE);
      cpl_table_new_column(tab_xy, "W", CPL_TYPE_DOUBLE);
      cpl_table_new_column(tab_xy, "S", CPL_TYPE_DOUBLE);
      cpl_table_new_column(tab_xy, "ord", CPL_TYPE_INT);

      cpl_table_fill_column_window_int(tab_xy, "ord", 0, fit_size, 0);
      cpl_table_fill_column_window_double(tab_xy, "X", 0, fit_size, 0);
      cpl_table_fill_column_window_double(tab_xy, "Y", 0, fit_size, 0);
      cpl_table_fill_column_window_double(tab_xy, "W", 0, fit_size, 0);
      cpl_table_fill_column_window_double(tab_xy, "S", 0, fit_size, 0);

      ord += 1;

      double* pxy = NULL;
      double* pw = NULL;
      double* ps = NULL;
      int* pto = NULL;
      double* ptx = NULL;
      double* pty = NULL;
      double* pts = NULL;
      double* ptw = NULL;

      pxy = cpl_matrix_get_data(mat_xy_sampling_points);
      pw = cpl_vector_get_data(vec_w_sampling_points);
      ps = cpl_vector_get_data(vec_s_sampling_points);

      ptx = cpl_table_get_data_double(tab_xy, "X");
      pty = cpl_table_get_data_double(tab_xy, "Y");
      pts = cpl_table_get_data_double(tab_xy, "S");
      ptw = cpl_table_get_data_double(tab_xy, "W");
      pto = cpl_table_get_data_int(tab_xy, "ord");
      int fit_index = 0;

      /* reset values */
      x_ord_min = 9999;
      x_ord_max = -1;
      y_ord_min = 9999;
      y_ord_max = -1;

      /* compute slit centres (IFU case) */
      for (slit_y = slit_min; slit_y <= slit_max; slit_y += slit_inc) {
        /* check we do not go out of IFU slice */
        if (mode == XSH_MODE_IFU) {
          if (xsh_model_map_ifu(slit_x, slit_y, p_xs_3) != 0) {
            cpl_msg_error(__func__, "Outside slitlet array");
            return CPL_ERROR_UNSPECIFIED;
          }
        } else {
          /* computes actual slit positions in mm for the model */
          p_xs_3->es_y_tot = slit_y * p_xs_3->slit_scale + p_xs_3->es_y;
        }

        /* loop over dispersion (wavelength) direction (here we make an interpolation) */
        for (lambda = lam_min - p_xs_3->blaze_pad;
            lambda <= lam_max + p_xs_3->blaze_pad; lambda += lam_inc) {
          /* lambda is in mm */
          lambda_nm = lambda * mm2nm;
          /* computes x,y position at a given lambda,order for a given model configuration */
          xsh_3_eval(lambda, morder_cnt, ref_ind, p_xs_3);
          /* Takes the physical x,y position at the detector array and converts this to a pixel position */
          xsh_3_detpix(p_xs_3);

          x_val = p_xs_3->xpospix;
          y_val = p_xs_3->ypospix;

          /* check we are on the detector */
          if (p_xs_3->chippix[0] == 1) {
            /* check that we are on the detector after distortion correction */
            if (p_xs_3->chippix[1] >= 1 && p_xs_3->chippix[1] < size_x + 1 &&
                p_xs_3->chippix[2] >= 1 && p_xs_3->chippix[2] < size_y + 1) {

              /* we fill the grid points: lambda, slit, x, y in corresponding table columns,
               * and vector/matrix positions
               *  */
              pw[fit_index] = lambda_nm;
              ps[fit_index] = slit_y;
              check(cpl_matrix_set(mat_xy_sampling_points,0,fit_index,x_val));
              check(cpl_matrix_set(mat_xy_sampling_points,1,fit_index,y_val));
              pto[fit_index] = morder_cnt;
              ptx[fit_index] = x_val;
              pty[fit_index] = y_val;
              pts[fit_index] = slit_y;
              ptw[fit_index] = lambda_nm;

              /* determine min/max of x and y values at the given order:
               * these values are used to fill a mask with 1/0 values where the
               * order is illuminated or not. Later we compute lambda
               */
              x_ord_min = (x_ord_min < x_val) ? x_ord_min : x_val;
              x_ord_max = (x_ord_max > x_val) ? x_ord_max : x_val;

              y_ord_min = (y_ord_min < y_val) ? y_ord_min : y_val;
              y_ord_max = (y_ord_max > y_val) ? y_ord_max : y_val;

              fit_index += 1;

            } /* end check that we are on the detector
             after distortion correction */

          } /* end check we are on the detector */

        } /* end loop over lambda */

      } /* end loop over slit */

      xsh_free_polynomial(&fit_wave_2d);
      xsh_free_polynomial(&fit_slit_2d);
      fit_wave_2d = cpl_polynomial_new(2);
      fit_slit_2d = cpl_polynomial_new(2);
      sprintf(filename, "tab_xy_%2.2d.fits", morder_cnt);
      //check(cpl_table_save(tab_xy,NULL,NULL,filename,CPL_IO_DEFAULT));

      xsh_msg_dbg_low(
          "SIZES vec=%" CPL_SIZE_FORMAT " ncol=%" CPL_SIZE_FORMAT " nrow=%" CPL_SIZE_FORMAT " pol size=%" CPL_SIZE_FORMAT "", cpl_vector_get_size(vec_w_sampling_points), cpl_matrix_get_ncol(mat_xy_sampling_points), cpl_matrix_get_nrow(mat_xy_sampling_points), cpl_polynomial_get_dimension(fit_wave_2d));
      /* Here we have to use a polynomial solution to pass from x,y to lambda,s
       *
       * The physical model works in one direction: we input a photon of a given
       * lambda and then we compute where it lands on the detector. This means we
       * make the direct transformation:
       *
       * x=phys(w,s,m,cfg)
       * y=phys(w,s,m,cfg)
       *
       * To compute a wave and a slit map instead we need the inverse transformation. In this case it is simpler
       * and sufficiently accurate to fit a 2D polynomial to a grid of sufficiently dense
       * x(w,s,m,cfg) and y(w,s,m,cfg) points sampling points and then use the solution to invert the
       * transformation and determine at each x,y detector points the corresponding lambda,s
       */
      /* Performs a polynomial fit to the grid of x,y points each with value lambda: ==>
       * determines a wave solution */
      check(
          error2d=cpl_polynomial_fit(fit_wave_2d,mat_xy_sampling_points, NULL,vec_w_sampling_points, NULL, CPL_FALSE,NULL, &max_deg_2d_w));
      /* Performs a polynomial fit to the grid of x,y points each with value lambda: ==>
             * determines a slit solution */
      check(
          error2d=cpl_polynomial_fit(fit_slit_2d,mat_xy_sampling_points, NULL,vec_s_sampling_points, NULL, CPL_FALSE,NULL, &max_deg_2d_s));

      sx = (int) (x_ord_max - x_ord_min + 0.5);
      sy = size_y; //(int)(y_ord_max-y_ord_min+0.5);

      x_min = (int) (x_ord_min + 0.5);
      y_min = (int) (y_ord_min + 0.5);
      x_max = (int) (x_ord_max + 0.5);
      y_max = (int) (y_ord_max + 0.5);

      /* initializes the mask to 0, then fill up by 1 only the region covered by the current order */
      memset(ccd_mask,0,sizeof(int)*size_x*size_y);
      int jj_times_size_x=0;
      for (jj = y_min; jj <= y_max; jj++) {
        jj_times_size_x=jj * size_x;
        for (ii = x_min; ii <= x_max; ii++) {
          ccd_mask[jj_times_size_x + ii] = 1;
        }
      }

      /* then finally fill up the given order by the lambda,s values
       * computed via the 2D polynomial solutions */
      x_det = x_min;
      y_det = 0;
      int y_det_times_size_x=0;
      for (j = 0; j < sy; j++) {

        /* TO BE CHECKED IF OFF BY 1 PIX */
        /* (if start from 0, j + 1) y position for poly evaluation */
        pval[1] = y_det + 1;
        x_det = x_min;

        y_det_times_size_x=y_det*size_x;
        for (i = 0; i < sx; i++) {
          /* (if start from 0, i + 1) y position for poly evaluation */
          pval[0] = x_det + 1;


          int pix_pos=y_det_times_size_x + x_det;
          if (ccd_mask[pix_pos] == 1) {
            s_val = cpl_polynomial_eval(fit_slit_2d, val);
            if (s_val > slit_min) {
              if (s_val < slit_max) {

                w_val = cpl_polynomial_eval(fit_wave_2d, val);

                ccd_wav[pix_pos] = w_val;
                ccd_slit[pix_pos] = s_val;
                ccd_imap[pix_pos] = i_val;

              }
            }
          } /* end of check over mask */
          x_det += 1;
        } /* end loop over s */
        y_det += 1;
      } /* here we have completed to fill up the given order with lambda,s values */


    } /* end loop over IFU slices */

  } /* end loop over order */

  if ((xsh_free2Darray(ref_ind, 8)) != 0) {
    cpl_msg_error(__func__, "Cannot free 2D array ref_ind");
    return CPL_ERROR_UNSPECIFIED;
  }

  naxes[0] = size_x;
  naxes[1] = size_y;

  /* wave map saving */
  check(plist=cpl_propertylist_new());
  sprintf(filename, "%s.fits", wtag);
  check(xsh_pfits_set_pcatg(plist, wtag ) );
  double crpix1=1.;
  double crval1=1.;
  double cdelt1=binx;
  double crpix2=1.;
  double crval2=1.;
  double cdelt2=biny;
  check(xsh_pfits_set_wcs(plist, crpix1,crval1,cdelt1,crpix2,crval2,cdelt2 ) );
  check(
      cpl_image_save(ccd_wave_ima,filename,CPL_BPP_IEEE_FLOAT,plist,CPL_IO_DEFAULT));
  xsh_free_propertylist(&plist);

  if (save_tmp) {
    xsh_add_temporary_file(filename);
  }
  *wmap_frame = xsh_frame_product(filename, wtag, CPL_FRAME_TYPE_IMAGE,
      CPL_FRAME_GROUP_PRODUCT, CPL_FRAME_LEVEL_FINAL);

  xsh_msg(
      " wave map frame %s %s", cpl_frame_get_filename(*wmap_frame), cpl_frame_get_tag(*wmap_frame));

  naxes[0] = size_x;
  naxes[1] = size_y;

  /*memory allocation for 1D representation of CCD array for cfitsio*/
  check(plist=cpl_propertylist_new());
  sprintf(filename, "%s.fits", stag);
  check(xsh_pfits_set_pcatg(plist, stag ) );

  xsh_model_compute_slitmap_kw(slit_min, slit_max, p_xs_3, instr, &plist);
  check(xsh_pfits_set_wcs(plist, crpix1,crval1,cdelt1,crpix2,crval2,cdelt2 ) );
  check(
      cpl_image_save(ccd_slit_ima,filename,CPL_BPP_IEEE_FLOAT,plist,CPL_IO_DEFAULT));

  if (mode == XSH_MODE_IFU) {
    check(
        cpl_image_save(ccd_imap_ima,filename,CPL_BPP_32_SIGNED,NULL,CPL_IO_EXTEND));
  }
  xsh_free_propertylist(&plist);

  if (save_tmp) {
    xsh_add_temporary_file(filename);
  }
  *smap_frame = xsh_frame_product(filename, stag, CPL_FRAME_TYPE_IMAGE,
      CPL_FRAME_GROUP_PRODUCT, CPL_FRAME_LEVEL_FINAL);
  xsh_msg(
      " slit map frame %s %s", cpl_frame_get_filename(*smap_frame), cpl_frame_get_tag(*smap_frame));

  cpl_free(oneD_AB);

  //If this is freed here then when ima is returned it is
  // corrupted. On the other hand after return there is no way to free oneD_AB
  //To me this seems to be a problem with returning cpl_images. I am leaving
  //it as it is for the moment (i.e. with a memory leak)
  cleanup: xsh_free_matrix(&mat_xy_sampling_points);
  xsh_free_vector(&vec_w_sampling_points);
  xsh_free_vector(&vec_s_sampling_points);
  xsh_free_vector(&val);
  xsh_free_polynomial(&fit_wave_2d);
  xsh_free_polynomial(&fit_slit_2d);
  xsh_free_table(&tab_xy);
  xsh_free_image(&ccd_wave_ima);
  xsh_free_image(&ccd_slit_ima);
  xsh_free_image(&ccd_mask_ima);
  xsh_free_image(&ccd_imap_ima);
  xsh_free_propertylist(&plist);

  return cpl_error_get_code();
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Map the IFU position to spectrograph slit position using
            transformation provided by Ana for IFU2
  @param    xifu         dispersion axis co-ordinate in arcsec on IFU slitlet
  @param    yifu         X-dispersion axis co-ordinate in arcsec on IFU slitlet
  @param    p_xs_3       Model configuration data structure
  @return   0 for success, -1 for error, 1 in the case that the incident ray
            does not pass through the IFU

  (The es_x and es_y_tot parameters are updated inside p_xs_3)
 */
/*----------------------------------------------------------------------------*/
int 
xsh_model_map_ifu(double xifu,
		  double yifu,
		  xsh_xs_3* p_xs_3)
{
  double xifu_mm, yifu_mm,es_x_tot;
  xifu_mm=xifu*IFU_SCALE;
  yifu_mm=yifu*IFU_SCALE;
  /*check which slitlet (if any) ray passes through*/
  if (xifu>IFU_LEFT_MIN && xifu<IFU_LEFT_MAX && yifu>IFU_LOW && yifu<IFU_HI) {
    p_xs_3->es_y_tot=(IFU_MAP_LEFT_C0Y+
		      IFU_MAP_LEFT_C1Y*yifu_mm+
		      IFU_MAP_LEFT_C2Y*yifu_mm*yifu_mm);
    es_x_tot=(IFU_MAP_LEFT_C0X+
	      IFU_MAP_LEFT_C1X*xifu_mm+
	      IFU_MAP_LEFT_C2X*xifu_mm*xifu_mm);
  }
  else if (xifu>IFU_CEN_MIN && xifu<IFU_CEN_MAX && yifu>IFU_LOW && yifu<IFU_HI) {
    p_xs_3->es_y_tot=(IFU_MAP_CEN_C0Y+
		      IFU_MAP_CEN_C1Y*yifu_mm+
		      IFU_MAP_CEN_C2Y*yifu_mm*yifu_mm);
    es_x_tot=(IFU_MAP_CEN_C0X+
	      IFU_MAP_CEN_C1X*xifu_mm+
	      IFU_MAP_CEN_C2X*xifu_mm*xifu_mm);
  }
  else if (xifu>IFU_RIGHT_MIN && xifu<IFU_RIGHT_MAX && yifu>IFU_LOW && yifu<IFU_HI) {
    p_xs_3->es_y_tot=(IFU_MAP_RIGHT_C0Y+
		      IFU_MAP_RIGHT_C1Y*yifu_mm+
		      IFU_MAP_RIGHT_C2Y*yifu_mm*yifu_mm);
    es_x_tot=(IFU_MAP_RIGHT_C0X+
	      IFU_MAP_RIGHT_C1X*xifu_mm
	      +IFU_MAP_RIGHT_C2X*xifu_mm*xifu_mm);
  }
  else {
    p_xs_3->es_x=-999;
    p_xs_3->es_y=-999;
    return 1;
  }
  /*Correct back to scale of spectrograph entrance slit*/
  p_xs_3->es_y_tot= p_xs_3->es_y+p_xs_3->es_y_tot*p_xs_3->slit_scale/IFU_SCALE;
  p_xs_3->es_x    = p_xs_3->es_x+es_x_tot*p_xs_3->slit_scale/IFU_SCALE;

  return 0;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Compute the locus of the spectrum 
  @param    p_xs_3         Model configuration data structure
  @param    instr          The XSH arm
  @param    ent_slit_pos   Position on the slit (double)
  @return   loci           cpl_vectors for the x-dispersion positions

  The returned pointer must be deallocated with
  for (i=0 ; i<n_orders ; i++) cpl_vector_delete(returned_ptr[i]) ;
  cpl_free(returned_ptr) ;
  here n_orders=16 for all 3 arms
 */
/*----------------------------------------------------------------------------*/
cpl_vector** 
xsh_model_locus(struct xs_3* p_xs_3,
		xsh_instrument* instr,
		double          ent_slit_pos)
{
  int n_order,  morder_cnt; /* grating spectral order*/
  DOUBLE lambda; /*wavelength in mm */
  DOUBLE lambda_nm; /* wavelength in nm */
  DOUBLE blaze_wav, lam_min, lam_max;
  DOUBLE pixwavlast, pixylast, pixxlast;
  int chipdist_current;
  double* trace_lam=NULL; /*trace array */
  double* trace_xdisp=NULL; /*trace array */
  int* trace_mm=NULL; /*trace array */
  cpl_vector**      loci=NULL ;
  FILE* trace_out;
  int ii;
  DOUBLE** ref_ind=NULL;
  XSH_ARM arm = XSH_ARM_UNDEFINED;
 
  XSH_ASSURE_NOT_NULL( p_xs_3);
  XSH_ASSURE_NOT_NULL( instr);

/*znse_ref is the array holding Sellmeier coefs for ZnSe refractive index at
  each temp. Currently hard coded to take 6 temperatures in [2][*] to [7][*],
  can be extended. First two rows ([0][*] to [1][*]) take the entries for the
  temperature bracketing the operation.
  Column [*][0] takes the temperature, the other columns, [*][1] to [*][6]
  take the Sellmeier coeffs */
  ref_ind=xsh_alloc2Darray(8,7);

  check( arm =  xsh_instrument_get_arm( instr));
  p_xs_3->arm=arm;
  if (arm==XSH_ARM_UVB) {
    xsh_ref_ind_read(0,ref_ind,290.0);
  }
  else if (arm==XSH_ARM_VIS) {
    xsh_ref_ind_read(1,ref_ind,p_xs_3->temper);
  }
  else {
    xsh_ref_ind_read(2,ref_ind,p_xs_3->t_ir_p2);
  }
  n_order=16; /*maximum value for all 3 orders used to make sure
		that the trace array created is always big enough,
		this is the value that should be used when freeing
		the memory in the code that calls this function */

  /*initalize the model. Inside the echelle_init the cfg file is
    read and the variables assigned to the xsh structure
    initialisation. Sets up those matrices that are not dependent upon
    wavelength */
  xsh_3_init(p_xs_3);

  trace_out=fopen("trace.dat","w");
  if ((trace_lam=xsh_alloc1Darray(p_xs_3->SIZE))==NULL){
    cpl_msg_error(__func__, "Cannot allocate 2D array");
    fclose(trace_out);
    return NULL;
  }
  if ((trace_xdisp=xsh_alloc1Darray(p_xs_3->SIZE))==NULL){
    cpl_msg_error(__func__, "Cannot allocate 2D array");
    fclose(trace_out);
    return NULL;
  }
  if ((trace_mm=xsh_alloc1Darray_INT(p_xs_3->SIZE))==NULL){
    cpl_msg_error(__func__, "Cannot allocate 2D array");
    fclose(trace_out);
    return NULL;
  }

  //  p_xs_3->es_x=0.0;
  p_xs_3->es_y_tot=p_xs_3->es_y+p_xs_3->slit_scale*ent_slit_pos;

  /* Create output vectors */
  if ((loci=cpl_malloc(n_order*sizeof(cpl_vector *)))==NULL) {
    cpl_msg_error(__func__, "Cannot allocate loci array");
    fclose(trace_out);
    return NULL;
  }
  for (ii=0; ii<n_order; ii++) {
      loci[ii] = cpl_vector_new(p_xs_3->SIZE) ;
      cpl_vector_fill(loci[ii], 0.0) ;
  }
  for (morder_cnt=p_xs_3->morder_min; morder_cnt<=p_xs_3->morder_max; morder_cnt+=1) {
    for (ii=0;ii<p_xs_3->SIZE;ii+=1) {
      trace_mm[ii]=0;
      trace_lam[ii]=0.0;
      trace_xdisp[ii]=0.0;
    }
    blaze_wav=2*(sin(-p_xs_3->nug))/(morder_cnt*p_xs_3->sg);
    lam_max=blaze_wav*((double)(morder_cnt)/((double)(morder_cnt)-0.5));
    lam_min=blaze_wav*((double)(morder_cnt)/(0.5+(double)(morder_cnt)));
    if (arm==XSH_ARM_NIR) {
      chipdist_current=3000;
    }
    else {
      chipdist_current=0;
    }
    pixxlast=0.0;
    pixylast=0.0;
    pixwavlast=mm2nm*(lam_min-p_xs_3->blaze_pad);
    for (lambda=lam_min-p_xs_3->blaze_pad; lambda<=lam_max+p_xs_3->blaze_pad;
	 lambda+=(lam_max-lam_min)/10000.0) {
      lambda_nm=mm2nm*lambda;
      xsh_3_eval(lambda,morder_cnt,ref_ind,p_xs_3);
      xsh_3_detpix(p_xs_3);
      if (p_xs_3->chippix[0]==1) {
	if (p_xs_3->chippix[1]>=1 &&
	    p_xs_3->chippix[1]<p_xs_3->ASIZE+1 &&
	    p_xs_3->chippix[2]>=1 &&
	    p_xs_3->chippix[2]<p_xs_3->BSIZE+1) {
/* 	  if (arm==XSH_ARM_NIR){ */
/* 	    //printf("%lf %d \n",p_xs_3->xpospix,chipdist_current); */
/* 	    if (p_xs_3->xpospix<(double)(chipdist_current)-0.5) { */
/* 	      trace_lam[p_xs_3->chippix[1]-1]=pixwavlast+(lambda_nm-pixwavlast)* */
/* 	       ((double)(chipdist_current)-0.5-pixxlast)/(p_xs_3->xpospix-pixxlast); */
/* 	      trace_xdisp[p_xs_3->chippix[1]-1]=pixylast+(p_xs_3->ypospix-pixylast)* */
/* 	       ((double)(chipdist_current)-0.5-pixxlast)/(p_xs_3->xpospix-pixxlast); */
/* 	      trace_mm[p_xs_3->chippix[1]-1]=morder_cnt; */
/* 	      chipdist_current=p_xs_3->chippix[1]+1; */
/* 	    } */
/* 	  } */
/* 	  else { */
	    //printf("%lf %d \n",p_xs_3->ypospix,chipdist_current);
	  if ((arm==XSH_ARM_NIR && p_xs_3->ypospix<(double)(chipdist_current)-0.5) || (arm!=XSH_ARM_NIR && p_xs_3->ypospix>(double)(chipdist_current)-0.5)) {
	      trace_lam[p_xs_3->chippix[2]-1]=pixwavlast+(lambda_nm-pixwavlast)*
	       ((double)(chipdist_current)-0.5-pixylast)/(p_xs_3->ypospix-pixylast);
	      trace_xdisp[p_xs_3->chippix[2]-1]=pixxlast+(p_xs_3->xpospix-pixxlast)*
	       ((double)(chipdist_current)-0.5-pixylast)/(p_xs_3->ypospix-pixylast);
	      trace_mm[p_xs_3->chippix[2]-1]=morder_cnt;
	      chipdist_current=p_xs_3->chippix[2]+1;
	    }
	    //}
	  pixxlast=p_xs_3->xpospix;
	  pixylast=p_xs_3->ypospix;
	}
      }
      pixwavlast=lambda_nm;
    }
    for (ii=0;ii<p_xs_3->SIZE;ii+=1) {
      fprintf(trace_out,"%d %lf %lf %d\n", trace_mm[ii], trace_lam[ii], trace_xdisp[ii], ii);
      //      loci[morder_cnt]=trace_xdisp;
      cpl_vector_set(loci[morder_cnt-p_xs_3->morder_min], ii, trace_xdisp[ii]) ;
    }
  }

  cpl_free(trace_lam);
  cpl_free(trace_xdisp);
  cpl_free(trace_mm);
  fclose(trace_out);

  if ((xsh_free2Darray(ref_ind,8))!=0) {
    cpl_msg_error(__func__, "Cannot free 2D array ref_ind");
    return NULL;
  }
 cleanup:
  return loci;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Compute the detector location (floating point pixels) of a given
            wavelength/entrance slit position 
  @param    p_xs_3    Model configuration structure
  @param    instr       The identifier of the XSH arm
  @param    lambda_nm   The wavelength in nm (double)
  @param    morder      The spectral order (int)
  @param    ent_slit_pos    Position on the slit in arcsec (double)
  @param    x           Takes the calculated x value (double)
  @param    y           Takes the calculated y value (double)
  @return   void        Result is returned with the x and y params above

  cpl_vector_delete(returned_ptr) ;
 */
/*----------------------------------------------------------------------------*/
void 
xsh_model_get_xy( xsh_xs_3* p_xs_3,
			 xsh_instrument* instr,
			 double          lambda_nm,
			 int             morder,
			 double          ent_slit_pos,
			 double* x,
			 double* y)
{
  DOUBLE lambda=0; /*wavelength in mm */

  DOUBLE** ref_ind = NULL;
  XSH_ARM arm = XSH_ARM_UNDEFINED;

  //xsh_model_io_output_cfg_txt(p_xs_3);
  XSH_ASSURE_NOT_NULL( p_xs_3);
  XSH_ASSURE_NOT_NULL( instr);
  XSH_ASSURE_NOT_NULL( x);
  XSH_ASSURE_NOT_NULL( y);

  check( arm =  xsh_instrument_get_arm( instr));

  p_xs_3->arm=arm;
  lambda=lambda_nm/mm2nm;
/*ref_ind is the array holding Sellmeier coefs for prism refractive
  index at each temp. Currently hard coded to take 6 temperatures in
  [2][*] to [7][*], can be extended. First two rows ([0][*] to [1][*])
  take the entries for the temperature bracketing the operation.
  Column [*][0] takes the temperature, the other columns, [*][1] to
  [*][6] take the Sellmeier coeffs */
  ref_ind=xsh_alloc2Darray(8,7);

  if ( arm== XSH_ARM_UVB) {
    xsh_ref_ind_read(0,ref_ind,p_xs_3->temper);
  }
  else if ( arm == XSH_ARM_VIS) {
    xsh_ref_ind_read(1,ref_ind,p_xs_3->temper);
  }
  else {
    xsh_ref_ind_read(2,ref_ind,p_xs_3->t_ir_p2);
  }
  /*initalize the model. Inside the echelle_init the cfg file is
    read and the variables assigned to the xsh structure
    initialisation. Sets up those matrices that are not dependent upon
    wavelength */

  xsh_3_init(p_xs_3);

  //p_xs_3->es_x=0.0;
  p_xs_3->es_y_tot=p_xs_3->es_y+ent_slit_pos*p_xs_3->slit_scale;

  /*call eval and detpix, then create the output vector*/
  //xsh_model_io_output_cfg_txt(p_xs_3);
  xsh_3_eval(lambda,morder,ref_ind,p_xs_3);
  xsh_3_detpix(p_xs_3);

  *x = p_xs_3->xpospix;
  *y = p_xs_3->ypospix;


 cleanup:
  if (ref_ind != NULL){
    xsh_free2Darray(ref_ind,8);
  }
  return;
}

/**
@brief corrects model for detector's binning
@param p_xs_3 pointer to model structure
@param bin_X X binning
@param bin_Y Y binning
 */
void 
xsh_model_binxy(xsh_xs_3* p_xs_3,
		     int bin_X,
		     int bin_Y)
{
  XSH_INSTRCONFIG* instr_config=NULL;
  xsh_instrument* instr = NULL;
  if (bin_X!=1 || bin_Y!=1) {
    instr = xsh_instrument_new();
    //printf("%lf %lf %lf %d %d %lf %lf \n ",p_xs_3->pix_X,p_xs_3->pix_Y,p_xs_3->pix,p_xs_3->ASIZE,p_xs_3->BSIZE,p_xs_3->chipxpix,p_xs_3->chipypix);
    if (p_xs_3->arm==0) {
      xsh_instrument_set_arm(instr, XSH_ARM_UVB);
      cpl_msg_info(__func__,"Setting %d x %d binning for UVB arm",bin_X,bin_Y);
      p_xs_3->xsize_corr=UVB_xsize_corr;
      p_xs_3->ysize_corr=UVB_ysize_corr;
    }
    else if (p_xs_3->arm==1) {
      xsh_instrument_set_arm(instr, XSH_ARM_VIS);
      cpl_msg_info(__func__,"Setting %d x %d binning for VIS arm",bin_X,bin_Y);
      p_xs_3->xsize_corr=VIS_xsize_corr;
      p_xs_3->ysize_corr=VIS_ysize_corr;
    }
    else {
      xsh_instrument_set_arm(instr, XSH_ARM_NIR);
      cpl_msg_warning(__func__,"NIR arm does not support binned data");
      p_xs_3->xsize_corr=NIR_xsize_corr;
      p_xs_3->ysize_corr=NIR_ysize_corr;
      bin_X=1;
      bin_Y=1;
    }
    instr_config=xsh_instrument_get_config(instr);
    p_xs_3->pix_X=p_xs_3->pix*(float)(bin_X);
    p_xs_3->pix_Y=p_xs_3->pix*(float)(bin_Y);
    p_xs_3->ASIZE=instr_config->nx;
    p_xs_3->ASIZE/=bin_X;
    p_xs_3->BSIZE=instr_config->ny;
    p_xs_3->BSIZE/=bin_Y;
    p_xs_3->SIZE=instr_config->ny;
    p_xs_3->SIZE/=bin_Y;
    p_xs_3->chipxpix=(float)(instr_config->nx);
    p_xs_3->chipxpix/=(float)(bin_X);
    p_xs_3->chipypix=(float)(instr_config->ny);
    p_xs_3->chipypix/=(float)(bin_Y);
    p_xs_3->xsize_corr/=(float)(bin_X);
    p_xs_3->ysize_corr/=(float)(bin_Y);

    //printf("%lf %lf %lf %d %d %lf %lf \n ",p_xs_3->pix_X,p_xs_3->pix_Y,p_xs_3->pix,p_xs_3->ASIZE,p_xs_3->BSIZE,p_xs_3->chipxpix,p_xs_3->chipypix);
    xsh_instrument_free(&instr);
  }
  return;
}

/**
@brief creates the model spectral format table
@param p_xs_3 pointer to physical model structure
@param tab_filename name of spectral format table
@return  model spectral format table frame 
 */
cpl_frame* 
xsh_model_spectralformat_create(xsh_xs_3* p_xs_3,
				const char* tab_filename)
{
  int morder_cnt=0;
  int tab_size=0;
  int blaze_flag=0;
  int cen_flag=0;
  int edge_flag;
  DOUBLE blaze_min=0.2;
  DOUBLE buff=0.0;

  DOUBLE lambda=0; /*wavelength in mm */
  DOUBLE lambda_nm=0; /* wavelength in nm */
  DOUBLE blaze_wav=0;

  int fsr_flag=0;
  DOUBLE baseline=0.0;
  DOUBLE binlfsr=0.0;
  DOUBLE binufsr=0.0;
  DOUBLE binblaze=0.0;
  DOUBLE lam_low=0.0;
  DOUBLE lam_hi=0.0;
  DOUBLE x_low=0.0;
  DOUBLE x_hi=0.0;

  DOUBLE blaze_eff=0.0;

  DOUBLE lfsr=0;
  DOUBLE ufsr=0;
  DOUBLE fsr=0;
  DOUBLE blaze=0;
  DOUBLE p_dif=0;
  DOUBLE wlmin=0;
  DOUBLE wlmax=0;
  DOUBLE wlmin_full=0;
  DOUBLE wlmax_full=0;
  DOUBLE sinc_arg=0;
  DOUBLE wlmean=0;
  DOUBLE wlcen=0;
  DOUBLE band=0;

  int xmin=0;
  int blz_frac_xmin=0;
  int blz_frac_ymin=0;
  int xmax=0;
  int blz_frac_xmax=0;
  int blz_frac_ymax=0;
  int yc=0;
  int disp_coord=0;
  int extra_ord=0;

  cpl_table* sf_tab = NULL;
  cpl_table* sf_tab2 = NULL;
  cpl_frame* sf_frame=NULL;
  cpl_frame* sf_frame2=NULL;
  cpl_propertylist *sf_plist = NULL;
  cpl_propertylist *x_plist = NULL;

  xsh_instrument* inst=NULL;
  DOUBLE** ref_ind = NULL;
  const char* tag=NULL;
  const char* tag2=NULL;
  char tab_filename2[256];

  ref_ind=xsh_alloc2Darray(8,7);

  XSH_ASSURE_NOT_NULL( p_xs_3);
  XSH_ASSURE_NOT_NULL( tab_filename);

  if (strcmp(tab_filename,"spec_form.fits")==0) {
    extra_ord=3;
  }
  else {
    extra_ord=0;
  }
  sprintf(tab_filename2,"long_%s",tab_filename);

  check(inst=xsh_instrument_new());
  if (p_xs_3->arm==0) {
    xsh_instrument_set_arm(inst,XSH_ARM_UVB);
    tag="SPEC_FORM_UVB";
    tag2="SPECTRAL_FORMAT_TAB_UVB";
    buff=0.007;
    baseline=0.00000025; /*baseline (mm) for local binsize computation*/
    xsh_ref_ind_read(0,ref_ind,p_xs_3->temper);
    disp_coord=2; /*The dispersion co-ordinate in p_xs_3->chippix)*/
  }
  else if (p_xs_3->arm==1) {
    xsh_instrument_set_arm(inst,XSH_ARM_VIS);
    tag="SPEC_FORM_VIS";
    tag2="SPECTRAL_FORMAT_TAB_VIS";
    buff=0.007;
    baseline=0.0000005; /*baseline (mm) for local binsize computation*/
    xsh_ref_ind_read(1,ref_ind,p_xs_3->temper);
    disp_coord=2; /*The dispersion co-ordinate in p_xs_3->chippix)*/
  }
  else if (p_xs_3->arm==2) {
    xsh_instrument_set_arm(inst,XSH_ARM_NIR);
    tag="SPEC_FORM_NIR";
    tag2="SPECTRAL_FORMAT_TAB_NIR";
    buff=0.007;
    baseline=0.000001; /*baseline (mm) for local binsize computation*/
    xsh_ref_ind_read(2,ref_ind,p_xs_3->t_ir_p2);
    disp_coord=2; /*The dispersion co-ordinate in p_xs_3->chippix)*/
    /*Convention is now that disp_coord=2 for all arms, so this is redundant*/
  }

  check(sf_frame=xsh_frame_product(tab_filename,
				 tag,
				 CPL_FRAME_TYPE_TABLE,
				 CPL_FRAME_GROUP_PRODUCT,
				 CPL_FRAME_LEVEL_FINAL));

/*   check(sf_frame2=xsh_frame_product(tab_filename, */
/* 				 tag2, */
/* 				 CPL_FRAME_TYPE_TABLE, */
/* 				 CPL_FRAME_GROUP_PRODUCT, */
/* 				 CPL_FRAME_LEVEL_FINAL)); */


  tab_size= p_xs_3->morder_max-p_xs_3->morder_min+1;
  check(sf_tab = cpl_table_new(tab_size));
  check(cpl_table_new_column(sf_tab, "ORDER", CPL_TYPE_INT) );
  check(cpl_table_new_column(sf_tab, "LAMP", CPL_TYPE_STRING) );
  check(cpl_table_new_column(sf_tab, "WLMIN", CPL_TYPE_FLOAT) );
  check(cpl_table_new_column(sf_tab, "WLMAX", CPL_TYPE_FLOAT) );
  check(cpl_table_new_column(sf_tab, "DISP_MIN", CPL_TYPE_FLOAT) );
  check(cpl_table_new_column(sf_tab, "DISP_MAX", CPL_TYPE_FLOAT) );
  check(cpl_table_new_column(sf_tab, "LFSR", CPL_TYPE_FLOAT) );
  check(cpl_table_new_column(sf_tab, "UFSR", CPL_TYPE_FLOAT) );
  check(cpl_table_new_column(sf_tab, "WLMINFUL", CPL_TYPE_FLOAT) );
  check(cpl_table_new_column(sf_tab, "WLMAXFUL", CPL_TYPE_FLOAT) );

  tab_size= p_xs_3->morder_max-p_xs_3->morder_min+1+(2*extra_ord);
  check(sf_tab2 = cpl_table_new(tab_size));
  check(cpl_table_new_column(sf_tab2, "ORDER", CPL_TYPE_INT) );
  check(cpl_table_new_column(sf_tab2, "LAMP", CPL_TYPE_STRING) );
  check(cpl_table_new_column(sf_tab2, "WLMIN", CPL_TYPE_FLOAT) );
  check(cpl_table_new_column(sf_tab2, "WLEN0", CPL_TYPE_FLOAT) );
  check(cpl_table_new_column(sf_tab2, "WLMAX", CPL_TYPE_FLOAT) );
  check(cpl_table_new_column(sf_tab2, "XDISP_CEN", CPL_TYPE_INT) );
  check(cpl_table_new_column(sf_tab2, "BLZ_FRAC_WLMIN", CPL_TYPE_DOUBLE) );
  check(cpl_table_new_column(sf_tab2, "BLZ_FRAC_WLMEAN", CPL_TYPE_DOUBLE) );
  check(cpl_table_new_column(sf_tab2, "BLZ_FRAC_WLMAX", CPL_TYPE_DOUBLE) );
  check(cpl_table_new_column(sf_tab2, "WLCEN", CPL_TYPE_DOUBLE) );
  check(cpl_table_new_column(sf_tab2, "BAND", CPL_TYPE_FLOAT) );
  check(cpl_table_new_column(sf_tab2, "BLZ_FRAC_DISP_MIN", CPL_TYPE_INT) );
  check(cpl_table_new_column(sf_tab2, "BLZ_FRAC_DISP_MAX", CPL_TYPE_INT) );
  check(cpl_table_new_column(sf_tab2, "DISP_MIN", CPL_TYPE_FLOAT) );
  check(cpl_table_new_column(sf_tab2, "DISP_MAX", CPL_TYPE_FLOAT) );
  check(cpl_table_new_column(sf_tab2, "BLZ_FRAC_XDISP_MIN", CPL_TYPE_INT) );
  check(cpl_table_new_column(sf_tab2, "BLZ_FRAC_XDISP_MAX", CPL_TYPE_INT) );
  check(cpl_table_new_column(sf_tab2, "LFSR", CPL_TYPE_FLOAT) );
  check(cpl_table_new_column(sf_tab2, "BLAZE", CPL_TYPE_FLOAT) );
  check(cpl_table_new_column(sf_tab2, "UFSR", CPL_TYPE_FLOAT) );
  check(cpl_table_new_column(sf_tab2, "FSR", CPL_TYPE_FLOAT) );
  check(cpl_table_new_column(sf_tab2, "BIN_LFSR", CPL_TYPE_DOUBLE) );
  check(cpl_table_new_column(sf_tab2, "BIN_BLAZE", CPL_TYPE_DOUBLE) );
  check(cpl_table_new_column(sf_tab2, "BIN_UFSR", CPL_TYPE_DOUBLE) );
  check(cpl_table_new_column(sf_tab2, "WLMINFUL", CPL_TYPE_FLOAT) );
  check(cpl_table_new_column(sf_tab2, "WLMAXFUL", CPL_TYPE_FLOAT) );

  for (morder_cnt=p_xs_3->morder_min-extra_ord;morder_cnt<=p_xs_3->morder_max+extra_ord;morder_cnt+=1) {
    blaze_wav=2000000.0*(sin(-p_xs_3->nug))/(morder_cnt*p_xs_3->sg);
    ufsr=blaze_wav*((double)(morder_cnt)/((double)(morder_cnt)-0.5));
    lfsr=blaze_wav*((double)(morder_cnt)/(0.5+(double)(morder_cnt)));
    fsr=ufsr-lfsr;
    edge_flag=0;
    blaze_flag=0;
    wlmax=0.0;
    wlmin=0.0;
    wlmax_full=0.0;
    wlmin_full=0.0;
    cen_flag=0;
    fsr_flag=0;
    binlfsr=0.0;
    binblaze=0.0;
    binufsr=0.0;
    /*loop over FSR */
    for (lambda_nm=lfsr-(1.5*fsr);lambda_nm<ufsr+(1.5*fsr);lambda_nm+=fsr/(3.0*p_xs_3->SIZE)) {
      xsh_3_init(p_xs_3);

      //p_xs_3->es_x=0.0;
      p_xs_3->es_y_tot=p_xs_3->es_y;

      lambda=lambda_nm/mm2nm;
      xsh_3_eval(lambda,morder_cnt,ref_ind,p_xs_3);
      xsh_3_detpix(p_xs_3);
      
      if (p_xs_3->chippix[0]==1) {
	if (p_xs_3->chippix[1]>=1 &&
	    p_xs_3->chippix[1]<p_xs_3->ASIZE+1 &&
	    p_xs_3->chippix[2]>=1 &&
	    p_xs_3->chippix[2]<p_xs_3->BSIZE+1) {
	  if (edge_flag==0) {
	    edge_flag=1;
	    wlmin_full=lambda_nm;
	  }
	  p_dif=(sin(p_xs_3->grat_alpha-(-p_xs_3->nug))+sin(p_xs_3->grat_beta-(-p_xs_3->nug)));
	  if (p_xs_3->grat_alpha>p_xs_3->grat_beta) {
	    sinc_arg=(M_PI/(lambda*p_xs_3->sg))*(cos(p_xs_3->grat_alpha)/cos(p_xs_3->grat_alpha-(-p_xs_3->nug)))*p_dif;
	    blaze=((sin(sinc_arg))/sinc_arg)*((sin(sinc_arg))/sinc_arg);
	  }
	  else {
	    sinc_arg=(M_PI/(lambda*p_xs_3->sg))*(cos(p_xs_3->grat_beta)/cos(p_xs_3->grat_alpha-(-p_xs_3->nug)))*p_dif;
	    blaze=(cos(p_xs_3->grat_beta)/cos(p_xs_3->grat_alpha))*(cos(p_xs_3->grat_beta)/cos(p_xs_3->grat_alpha))*((sin(sinc_arg))/sinc_arg)*((sin(sinc_arg))/sinc_arg);
	  }
	  //	  printf("lambda_nm %lf blaxe %lf \n", lambda_nm, blaze);
	  //printf(" %d %d \n", p_xs_3->chippix[disp_coord],p_xs_3->SIZE/2);
	  /*logic here may need to be changed with the new flipped UVB config */
	  if ((cen_flag==0 && p_xs_3->chippix[disp_coord]>=p_xs_3->SIZE/2
	       && p_xs_3->arm<2) ||
	      (cen_flag==0 && p_xs_3->chippix[disp_coord]<=p_xs_3->SIZE/2
	       && p_xs_3->arm==2)) {
	    yc=p_xs_3->chippix[3-disp_coord];
	    wlcen=lambda_nm;
	    cen_flag=1;
	  }
	  if (blaze_flag==0 && blaze>blaze_min) {
	    wlmin=lambda_nm;
	    blz_frac_xmin=p_xs_3->chippix[disp_coord];
	    blz_frac_ymin=p_xs_3->chippix[3-disp_coord];
	    blaze_flag=1;
	  }
	  if (blaze_flag==1 && blaze>blaze_min) {
	    wlmax=lambda_nm;
	    blz_frac_xmax=p_xs_3->chippix[disp_coord];
	    blz_frac_ymax=p_xs_3->chippix[3-disp_coord];
	  }
	  if (blaze_flag==1 && blaze<blaze_min) {
	    blaze_flag=2;
	  }
	  if (fsr_flag==0 && lambda_nm>lfsr*(1.0-buff)) {
	    fsr_flag=1;
	    xmin=p_xs_3->chippix[disp_coord];
	    lam_low=lambda-baseline;
	    xsh_3_eval(lam_low,morder_cnt,ref_ind,p_xs_3);
	    xsh_3_detpix(p_xs_3);
	    x_low=p_xs_3->ypospix;
	    lam_hi=lambda+baseline;
	    xsh_3_eval(lam_hi,morder_cnt,ref_ind,p_xs_3);
	    xsh_3_detpix(p_xs_3);
	    x_hi=p_xs_3->ypospix;
	    if (x_low>0.0 && x_hi>0.0) {
	      if (p_xs_3->arm==2) {
		binlfsr=((lam_hi-lam_low)/(x_low-x_hi))*mm2nm;
	      }
	      else {
		binlfsr=((lam_hi-lam_low)/(x_hi-x_low))*mm2nm;
	      }
	    }
	    else {
	      binlfsr=-1.0;
	    }
	  }
	  if (fsr_flag==1 && lambda_nm>blaze_wav) {
	    fsr_flag=2;
	    blaze_eff=blaze;
	    lam_low=lambda-baseline;
	    xsh_3_eval(lam_low,morder_cnt,ref_ind,p_xs_3);
	    xsh_3_detpix(p_xs_3);
	    x_low=p_xs_3->ypospix;
	    lam_hi=lambda+baseline;
	    xsh_3_eval(lam_hi,morder_cnt,ref_ind,p_xs_3);
	    xsh_3_detpix(p_xs_3);
	    x_hi=p_xs_3->ypospix;
	    if (x_low>0.0 && x_hi>0.0) {
	      if (p_xs_3->arm==2) {
		binblaze=((lam_hi-lam_low)/(x_low-x_hi))*mm2nm;
	      }
	      else {
		binblaze=((lam_hi-lam_low)/(x_hi-x_low))*mm2nm;
	      }
	    }
	    else {
	      binblaze=-1.0;
	    }
	  }
	  if (fsr_flag==2) {
	    xmax=p_xs_3->chippix[disp_coord];
	    if (lambda_nm>ufsr*(1.0+buff)) {
	      fsr_flag=3;
	      lam_low=lambda-baseline;
	      xsh_3_eval(lam_low,morder_cnt,ref_ind,p_xs_3);
	      xsh_3_detpix(p_xs_3);
	      x_low=p_xs_3->ypospix;
	      lam_hi=lambda+baseline;
	      xsh_3_eval(lam_hi,morder_cnt,ref_ind,p_xs_3);
	      xsh_3_detpix(p_xs_3);
	      x_hi=p_xs_3->ypospix;
	      if (x_low>0.0 && x_hi>0.0) {
		if (p_xs_3->arm==2) {
		  binufsr=((lam_hi-lam_low)/(x_low-x_hi))*mm2nm;
		}
		else {
		  binufsr=((lam_hi-lam_low)/(x_hi-x_low))*mm2nm;
		}
	      }
	      else {
		binufsr=-1.0;
	      }
	    //printf("%d %lf %lf %lf %lf %lf \n,",morder_cnt, lambda_nm, lam_low*mm2nm, lam_hi*mm2nm, x_low, x_hi);
	    }
	  }
	  //printf("%d lambda_nm %lf blaxe %lf %d %lf %lf %d %d \n", morder_cnt, lambda_nm, blaze,blaze_flag,wlmax,wlmin,p_xs_3->chippix[1],p_xs_3->chippix[2]);
	}
      }
      else {
	if (edge_flag==1) {
	  edge_flag=2;
	  wlmax_full=lambda_nm;
	}
      }
    }
    if (blaze_flag>0) {
      wlmean=(wlmin+wlmax)/2.0;
      band=wlmax-wlmin;
    }
    else {
      band=-1.0;
      wlmin=-1.0;
      blz_frac_xmin=-1;
      blz_frac_ymin=-1;
      wlmean=-1.0;
      wlmax=-1.0;
      blz_frac_xmax=-1;
      blz_frac_ymax=-1;
    }
    if (cen_flag!=1) {
      wlcen=-1.0;
      yc=-1;
    }
    if (fsr_flag<3) {
      binufsr=-1.0;
      if (fsr_flag<2) {
	xmax=-1.0;
	binblaze=-1.0;
	if (fsr_flag<1) {
	  binlfsr=-1.0;
	  xmin=-1.0;
	}
      }
    }
    //printf("order: %d ; lfsr: %lf ; blaze: %lf; ufsr: %lf ; binlfsr: %lf ; binblaze: %lf ; binufsr: %lf \n", morder_cnt, lfsr, blaze_wav, ufsr, binlfsr, binblaze, binufsr);

    if (morder_cnt>=p_xs_3->morder_min && morder_cnt<=p_xs_3->morder_max) {
      check(cpl_table_set_int(sf_tab, "ORDER", morder_cnt-p_xs_3->morder_min,morder_cnt));
      /*Below the wlmin based on fraction of blaze is replaced with simple 2% wavelength
	buffer on lfsr and ufsr */
      check(cpl_table_set_float(sf_tab, "WLMIN", morder_cnt-p_xs_3->morder_min,(float)((1.0-buff)*lfsr)));
      check(cpl_table_set_float(sf_tab, "WLMAX", morder_cnt-p_xs_3->morder_min,(float)((1.0+buff)*ufsr)));
      check(cpl_table_set_float(sf_tab, "DISP_MIN", morder_cnt-p_xs_3->morder_min+extra_ord, (float)(xmin)));
      check(cpl_table_set_float(sf_tab, "DISP_MAX", morder_cnt-p_xs_3->morder_min+extra_ord, (float)(xmax)));
      check(cpl_table_set_float(sf_tab, "DISP_MIN", morder_cnt-p_xs_3->morder_min+extra_ord, (float)(xmin)));
      check(cpl_table_set_float(sf_tab, "DISP_MAX", morder_cnt-p_xs_3->morder_min+extra_ord, (float)(xmax)));
      check(cpl_table_set_float(sf_tab, "WLMINFUL", morder_cnt-p_xs_3->morder_min,(float)(wlmin_full)));
      check(cpl_table_set_float(sf_tab, "WLMAXFUL", morder_cnt-p_xs_3->morder_min,(float)(wlmax_full)));
      check(cpl_table_set_float(sf_tab, "LFSR", morder_cnt-p_xs_3->morder_min+extra_ord, (float)(lfsr)));
      check(cpl_table_set_float(sf_tab, "UFSR", morder_cnt-p_xs_3->morder_min+extra_ord, (float)(ufsr)));
      if (p_xs_3->arm==0 && morder_cnt>20) {
	check(cpl_table_set_string(sf_tab, "LAMP", morder_cnt-p_xs_3->morder_min,"D2"));
      }
      else {
	check(cpl_table_set_string(sf_tab, "LAMP", morder_cnt-p_xs_3->morder_min,"QTH"));
      }
    }
    check(cpl_table_set_int(sf_tab2, "ORDER", morder_cnt-p_xs_3->morder_min+extra_ord,morder_cnt));
    if (p_xs_3->arm==0 && morder_cnt>20) {
      check(cpl_table_set_string(sf_tab2, "LAMP", morder_cnt-p_xs_3->morder_min,"D2"));
    }
    else {
      check(cpl_table_set_string(sf_tab2, "LAMP", morder_cnt-p_xs_3->morder_min,"QTH"));
    }
    check(cpl_table_set_int(sf_tab2, "XDISP_CEN", morder_cnt-p_xs_3->morder_min+extra_ord,yc));
    /*Here the wlmin,max based on fraction of blaze is put into BLZ_FRAC_WLMIN,MAX*/
    check(cpl_table_set_double(sf_tab2, "BLZ_FRAC_WLMIN", morder_cnt-p_xs_3->morder_min+extra_ord,wlmin));
    check(cpl_table_set_double(sf_tab2, "BLZ_FRAC_WLMAX", morder_cnt-p_xs_3->morder_min+extra_ord,wlmax));
    check(cpl_table_set_double(sf_tab2, "BLZ_FRAC_WLMEAN", morder_cnt-p_xs_3->morder_min+extra_ord,wlmean));
    /*Below the WLMIN is simple 2% wavelength buffer on lfsr and ufsr */
    check(cpl_table_set_float(sf_tab2, "WLMIN", morder_cnt-p_xs_3->morder_min+extra_ord,(1.0-buff)*lfsr) );
    check(cpl_table_set_float(sf_tab2, "WLMAX", morder_cnt-p_xs_3->morder_min+extra_ord,(1.0+buff)*ufsr));
    check(cpl_table_set_float(sf_tab2, "BAND", morder_cnt-p_xs_3->morder_min+extra_ord,band));
    check(cpl_table_set_float(sf_tab2, "WLEN0", morder_cnt-p_xs_3->morder_min+extra_ord,((1.0-buff)*lfsr+(1.0+buff)*ufsr)/2.0));
    check(cpl_table_set_float(sf_tab2, "WLMINFUL", morder_cnt-p_xs_3->morder_min,(float)(wlmin_full)));
    check(cpl_table_set_float(sf_tab2, "WLMAXFUL", morder_cnt-p_xs_3->morder_min,(float)(wlmax_full)));
    check(cpl_table_set_double(sf_tab2, "WLCEN", morder_cnt-p_xs_3->morder_min+extra_ord,wlcen));
    check(cpl_table_set_int(sf_tab2, "BLZ_FRAC_DISP_MIN", morder_cnt-p_xs_3->morder_min+extra_ord, blz_frac_xmin) );
    check(cpl_table_set_int(sf_tab2, "BLZ_FRAC_DISP_MAX", morder_cnt-p_xs_3->morder_min+extra_ord, blz_frac_xmax) );
    check(cpl_table_set_float(sf_tab2, "DISP_MIN", morder_cnt-p_xs_3->morder_min+extra_ord, (float)(xmin)) );
    check(cpl_table_set_float(sf_tab2, "DISP_MAX", morder_cnt-p_xs_3->morder_min+extra_ord, (float)(xmax)) );
    check(cpl_table_set_int(sf_tab2, "BLZ_FRAC_XDISP_MIN", morder_cnt-p_xs_3->morder_min+extra_ord, blz_frac_ymin) );
    check(cpl_table_set_int(sf_tab2, "BLZ_FRAC_XDISP_MAX", morder_cnt-p_xs_3->morder_min+extra_ord, blz_frac_ymax) );
    check(cpl_table_set_float(sf_tab2, "LFSR", morder_cnt-p_xs_3->morder_min+extra_ord, (float)(lfsr)));
    check(cpl_table_set_float(sf_tab2, "BLAZE", morder_cnt-p_xs_3->morder_min+extra_ord, (float)(blaze_wav)));
    check(cpl_table_set_float(sf_tab2, "UFSR", morder_cnt-p_xs_3->morder_min+extra_ord, (float)(ufsr)));
    check(cpl_table_set_float(sf_tab2, "FSR", morder_cnt-p_xs_3->morder_min+extra_ord, (float)(ufsr-lfsr)));
    check(cpl_table_set_double(sf_tab2, "BIN_LFSR", morder_cnt-p_xs_3->morder_min+extra_ord, binlfsr) );
    check(cpl_table_set_double(sf_tab2, "BIN_BLAZE", morder_cnt-p_xs_3->morder_min+extra_ord, binblaze) );
    check(cpl_table_set_double(sf_tab2, "BIN_UFSR", morder_cnt-p_xs_3->morder_min+extra_ord, binufsr ));
  }

  sf_plist = cpl_propertylist_new();
  //cpl_propertylist_append_string(sf_plist, "INSTRUME", "XSHOOTER") ;
  check( xsh_pfits_set_pcatg(sf_plist, tag));
  cpl_msg_info(__func__, "Save the tables") ;

  x_plist=cpl_propertylist_new();
  cpl_propertylist_append_int(x_plist, XSH_SPECTRALFORMAT_DIST_ORDER,9);
  
/*   check(cpl_table_save(sf_tab, sf_plist,x_plist, tab_filename, CPL_IO_DEFAULT)); */
/*   xsh_msg(" sf table %s %s %s", tab_filename, cpl_frame_get_filename(sf_frame2), */
/* 		cpl_frame_get_tag(sf_frame));  */

  check(cpl_table_save(sf_tab2, sf_plist, x_plist, tab_filename, CPL_IO_DEFAULT));
  xsh_msg(" sf table %s %s %s", tab_filename, cpl_frame_get_filename(sf_frame),
		cpl_frame_get_tag(sf_frame)); 

 cleanup:
    xsh_free_propertylist(&sf_plist);
    xsh_free_propertylist(&x_plist);

    xsh_free_table(&sf_tab);
    xsh_free_table(&sf_tab2);
  if (ref_ind != NULL){
    xsh_free2Darray(ref_ind,8);
  }

  if ( cpl_error_get_code() != CPL_ERROR_NONE){
    xsh_free_frame( &sf_frame);
    xsh_free_frame( &sf_frame2);
    return NULL;
  } else {
     return sf_frame;
  }

}

/*----------------------------------------------------------------------------*/
/**
  @brief    Compute the THE table (centroid for each feature in lamp spectrum)
  @param    p_xs_3      Model configuration data structure
  @param    instr        The XSH arm
  @param    line_list   Calibration source line list file name
  @param    num_ph      Number of pinholes in mask (int)
  @param    sep_ph      Separation of pinholes (arcsec) or <0 to use values
                        from the config file (double)
  @param   THE_filename  THE table filename
  @return THE table frame
  If sep_ph>0.0 then pinholes are regularly spaced with central pinhole at es_y,
  If sep_ph<=0.0 then config slit[n] positions are used with es_y offset and
  scaling by slit_scale param from config
  If num_ph==1 then pinhole is always at es_y (either, for sep_ph<=0.0,
  spos=slit[4]=0.0 is used or, for sep_ph>0.0, spos=0.0)

  The returned pointer must be deallocated with
  cpl_table_delete(returned_ptr);
 */
/*----------------------------------------------------------------------------*/
cpl_frame* 
xsh_model_THE_create(xsh_xs_3* p_xs_3,
		     xsh_instrument* instr,
		     const char* line_list,
		     int num_ph,
		     double sep_ph,
		     const char* THE_filename)
{
  int morder_cnt; /* grating spectral order counter */
  int spos_int;
  DOUBLE lambda; /*wavelength in mm */
  DOUBLE lambda_nm; /* wavelength in nm */
  DOUBLE blaze_wav, lam_min, lam_max, inten;
  cpl_table *lines_tab = NULL;
  int           lines_number, line_no ;
  DOUBLE spos;
  DOUBLE** ref_ind = NULL;
  cpl_table*   THE_tab = NULL;
  int fitsrow;
  int tab_size;
  XSH_ARM arm = XSH_ARM_UNDEFINED;
  cpl_frame* THE_frame=NULL;
  cpl_propertylist *THE_plist = NULL;
  const char* tag=NULL;

  fitsrow=0;
  tab_size = 150000;

  XSH_ASSURE_NOT_NULL( p_xs_3);
  XSH_ASSURE_NOT_NULL( instr);
  XSH_ASSURE_NOT_NULL( THE_filename);

  check( arm =  xsh_instrument_get_arm( instr));
  p_xs_3->arm=arm;

/*ref_ind is the array holding Sellmeier coefs for prism refractive
  index at each temp. Currently hard coded to take 6 temperatures in
  [2][*] to [7][*], can be extended. First two rows ([0][*] to [1][*])
  take the entries for the temperature bracketing the operation.
  Column [*][0] takes the temperature, the other columns, [*][1] to
  [*][6] take the Sellmeier coeffs */
  ref_ind=xsh_alloc2Darray(8,7);

  if (arm==XSH_ARM_UVB) {
    xsh_ref_ind_read(0,ref_ind,p_xs_3->temper);
  }
  else if (arm==XSH_ARM_VIS) {
    xsh_ref_ind_read(1,ref_ind,p_xs_3->temper);
  }
  else {
    xsh_ref_ind_read(2,ref_ind,p_xs_3->t_ir_p2);
  }

  /*initalize the model. Inside the echelle_init the cfg file is
    read and the variables assigned to the xsh structure
    initialisation. Sets up those matrices that are not dependent upon
    wavelength */
  xsh_3_init(p_xs_3);

  //  p_xs_3->es_x=0.0;

  THE_tab = cpl_table_new(tab_size);
  cpl_table_new_column(THE_tab, XSH_THE_MAP_TABLE_COLNAME_WAVELENGTH, CPL_TYPE_FLOAT) ;
  cpl_table_new_column(THE_tab, XSH_THE_MAP_TABLE_COLNAME_ORDER, CPL_TYPE_INT) ;
  cpl_table_new_column(THE_tab, XSH_THE_MAP_TABLE_COLNAME_SLITINDEX, CPL_TYPE_INT) ;
  cpl_table_new_column(THE_tab, XSH_THE_MAP_TABLE_COLNAME_SLITPOSITION, CPL_TYPE_FLOAT) ;
  cpl_table_new_column(THE_tab, XSH_THE_MAP_TABLE_COLNAME_DETECTORX, CPL_TYPE_DOUBLE) ;
  cpl_table_new_column(THE_tab, XSH_THE_MAP_TABLE_COLNAME_DETECTORY, CPL_TYPE_DOUBLE) ;

  /* Read the input FITS lines list */
  if ((lines_tab = cpl_table_load(line_list, 1, 0))==NULL) {
    cpl_msg_error(__func__, "Cannot find line list %s", line_list);
    return NULL;
  }
  lines_number = cpl_table_get_nrow(lines_tab) ;
  if (cpl_table_get_column_type(lines_tab, XSH_ARCLIST_TABLE_COLNAME_WAVELENGTH) == CPL_TYPE_DOUBLE) {
      check(cpl_table_duplicate_column(lines_tab,"DWAVELENGTH",lines_tab,XSH_ARCLIST_TABLE_COLNAME_WAVELENGTH));
      check(cpl_table_erase_column(lines_tab,XSH_ARCLIST_TABLE_COLNAME_WAVELENGTH));
      check(cpl_table_cast_column(lines_tab,"DWAVELENGTH",
                      XSH_ARCLIST_TABLE_COLNAME_WAVELENGTH,CPL_TYPE_FLOAT));
  }
  if (cpl_table_get_column_type(lines_tab, XSH_ARCLIST_TABLE_COLNAME_FLUX) == CPL_TYPE_DOUBLE) {
        check(cpl_table_duplicate_column(lines_tab,"DFLUX",lines_tab,XSH_ARCLIST_TABLE_COLNAME_FLUX));
        check(cpl_table_erase_column(lines_tab,XSH_ARCLIST_TABLE_COLNAME_FLUX));
        check(cpl_table_cast_column(lines_tab,"DFLUX",
                        XSH_ARCLIST_TABLE_COLNAME_FLUX,CPL_TYPE_FLOAT));
  }
  /* Loop on the lines and  call the stis model routine */
  for (line_no=0 ; line_no<lines_number ; line_no++) {
   /*
      check(lambda_nm=cpl_table_get_double(lines_tab,
          XSH_ARCLIST_TABLE_COLNAME_WAVELENGTH, line_no, NULL));
        check(inten = cpl_table_get(lines_tab,
          XSH_ARCLIST_TABLE_COLNAME_FLUX, line_no, NULL));
          */

    check(lambda_nm=cpl_table_get_float(lines_tab,
      XSH_ARCLIST_TABLE_COLNAME_WAVELENGTH, line_no, NULL));
    check(inten = cpl_table_get(lines_tab,
      XSH_ARCLIST_TABLE_COLNAME_FLUX, line_no, NULL));

  /*Calculate the order of the given wavelength */
  //  morder=(int)(0.5+(sin(p_xs_3->mug+inout/2.0)+sin(p_xs_3->mug-inout/2.0))/((p_xs_3->sg)*lambda));
  /* while there is a line in the file read it and call the stis model routine*/
  /*without order in input*/
    for (morder_cnt=p_xs_3->morder_min;morder_cnt<=p_xs_3->morder_max; morder_cnt+=1) {
      //    for (morder_cnt=morder-morder_it; morder_cnt<morder+morder_it; morder_cnt+=1) {
      blaze_wav=2*(sin(-p_xs_3->nug))/(morder_cnt*p_xs_3->sg);
      lam_max=blaze_wav*((double)(morder_cnt)/((double)(morder_cnt)-0.5));
      lam_min=blaze_wav*((double)(morder_cnt)/(0.5+(double)(morder_cnt)));
      lambda=lambda_nm*1e-6; //lambda in mm
      if (lambda>lam_min-p_xs_3->blaze_pad && lambda<lam_max+p_xs_3->blaze_pad) {
	for (spos_int=0;spos_int<num_ph; spos_int+=1) {
	  if (sep_ph>0.0) {
	    spos=sep_ph*(spos_int-((num_ph-1)/2));
	  }
	  else {
	    if (num_ph>1) {
	      spos=p_xs_3->slit[spos_int];
	    }
	    else if (num_ph==1) {
	      spos=p_xs_3->slit[4];
	    }
	  }
	  p_xs_3->es_y_tot=p_xs_3->es_y+spos*p_xs_3->slit_scale;
	  //printf("%lf %d %lf %lf %lf %lf \n",p_xs_3->slit[4], spos_int, p_xs_3->es_y_tot,spos,p_xs_3->slit_scale, p_xs_3->es_y);
	  xsh_3_eval(lambda,morder_cnt,ref_ind,p_xs_3);
	  xsh_3_detpix(p_xs_3);
	  //printf("%lf %d %lf %lf %lf %lf %d\n",lambda_nm, morder_cnt, p_xs_3->es_y_tot, spos, p_xs_3->xdet, p_xs_3->ydet,p_xs_3->chippix[0]);
	  if (p_xs_3->chippix[0]==1) {
	    //printf("%lf %lf %lf\n",p_xs_3->es_y_tot, p_xs_3->slit_scale, p_xs_3->es_y_tot/p_xs_3->slit_scale);	      
	    cpl_table_set_float(THE_tab, XSH_THE_MAP_TABLE_COLNAME_WAVELENGTH, fitsrow, lambda_nm) ;
	    cpl_table_set_int(THE_tab, XSH_THE_MAP_TABLE_COLNAME_ORDER, fitsrow, morder_cnt) ;
	    cpl_table_set_float(THE_tab, XSH_THE_MAP_TABLE_COLNAME_SLITPOSITION, fitsrow, spos);
	    cpl_table_set_int(THE_tab, XSH_THE_MAP_TABLE_COLNAME_SLITINDEX, fitsrow, spos_int);
	    cpl_table_set_double(THE_tab, XSH_THE_MAP_TABLE_COLNAME_DETECTORX, fitsrow, p_xs_3->xpospix);
	    cpl_table_set_double(THE_tab, XSH_THE_MAP_TABLE_COLNAME_DETECTORY, fitsrow, p_xs_3->ypospix);
	    fitsrow+=1;
	  }
	}
      }
    }
  }
  // AMO added to have proper binning in THE map used for SKY lines
  //cpl_table_multiply_scalar(THE_tab,XSH_THE_MAP_TABLE_COLNAME_DETECTORX,instr->binx);
  //cpl_table_multiply_scalar(THE_tab,XSH_THE_MAP_TABLE_COLNAME_DETECTORY,instr->biny);

  THE_plist = cpl_propertylist_new();
  //cpl_propertylist_append_string(THE_plist, "INSTRUME", "XSHOOTER") ;
  check( cpl_table_set_size(THE_tab,fitsrow));
 
  check( cpl_table_save(THE_tab, THE_plist, NULL, THE_filename, 
    CPL_IO_DEFAULT));

  if (arm == XSH_ARM_UVB) {
    tag="THE_UVB";
  }
  else if (arm == XSH_ARM_VIS) {
    tag="THE_VIS";
  }
  else if (arm == XSH_ARM_NIR) {
    tag="THE_NIR";
  }

  check(THE_frame=xsh_frame_product(THE_filename,
				 tag,
				 CPL_FRAME_TYPE_TABLE,
				 CPL_FRAME_GROUP_PRODUCT,
				 CPL_FRAME_LEVEL_FINAL));

  xsh_msg(" THE table %s %s",THE_filename,tag); 


 cleanup:
  xsh_free_propertylist(&THE_plist);
  xsh_free_table(&THE_tab);
  xsh_free_table(&lines_tab);
  if ( cpl_error_get_code() != CPL_ERROR_NONE){
    xsh_free_frame( &THE_frame);
  }
  if (ref_ind != NULL){
    xsh_free2Darray(ref_ind,8);
  }


  return THE_frame;

}

/*----------------------------------------------------------------------------*/
/**
  @brief    Run the annealing (optimisation) algoritm to improve the fit of the
            model parameter set to a given wavecal exposure.
  @param    cfg_frame               Model configuration frame (contains config
                                    file name)
  @param    resid_frame             Frame containing resid table - absolute x,y
                                    positions can be calculated from thpre_x,y
                                    and diff_x,y
  @param    maxit                   The numer of iterations of the annealing
                                    algorithm to be performed (int)
  @param    ann_fac                 Multiplier applied to the automatic
                                    parameter ranges (i.e. when scenario!=0).
				    For routine operations should be 1.0
  @param    scenario                selects preset flag and range combinations
                                    appropriate to common scenarios:
				    -1- Only the position across the slit and
				        camera focal length are open
				    0 - No scenario, input cfg flags and limits
				        used.
				    1 - scenario appropriate for the startup
				        recipe (large ranges for parameters
				        affecting single ph exposures, dist
				        coeff fixed)
				    2 - Like 1, but includes parameters
				        affecting all ph positions
				    3 - Scenario for use in fine tuning cfg
				        to match routine wavecal exposures. All
					parameters affecting 1ph exposures
					except dist coeffs are included and
					parameter ranges are small. (For use by
					predict in 1ph case).
				    4 - Like 3 but includes parameters
				        affecting all ph positions (Standard for
					use by predict in 9ph case and 2dmap).
				    5 - Like 4 but includes also dist coeffs
				    6 - Just dist coeffs (and chipx, chipy)
				    7 - Just anneal the cross-slit position
				        focal length of the camera for wavecal
				    8 - Optimised parameter set for QC
  @param    rec_id                  recipe identifier
  @return   MODEL_CONF_OPT_frame    The model configuration structure with
                                    modified parameters

  The returned pointer must be deallocated with
  cpl_frame_delete(MODEL_CONF_OPT_frame);
 */
/*----------------------------------------------------------------------------*/


cpl_frame* 
xsh_model_pipe_anneal(cpl_frame* cfg_frame,
				 cpl_frame* resid_frame,
				 int maxit,
				 double ann_fac,
				 int scenario,
                                 int rec_id)
{
  cpl_table*   conf_tab = NULL;
  const int model_coeff_num=300;
  ann_all_par all_par[model_coeff_num];
  ann_all_par* p_all_par = NULL;
  double abest[model_coeff_num];
  double amin[model_coeff_num];
  double amax[model_coeff_num];
  int aname[model_coeff_num];
  int wav_den[40];
  int adim=0;
 
  int ii, jj, kk;
  int size;
  DOUBLE** ref_ind = NULL;
  DOUBLE* p_wlarray = NULL;
  cpl_frame* MODEL_CONF_OPT_frame=NULL;
  cpl_propertylist*   MODEL_CONFIG_plist=NULL ;
  xsh_resid_tab* resid_tab = NULL;
  double *vlambda=NULL, *thpre_x=NULL, *thpre_y=NULL,
    *xgauss=NULL, *ygauss=NULL, *vorder=NULL;
  int *slitindex=NULL;
  coord* msp_coord = NULL;
  char out_cfg_filename[256];
  xsh_xs_3 xs_3;
  xsh_xs_3* p_xs_3=NULL;
  DOUBLE wav_den_bin_sz;

  cpl_table* resid_tbl = NULL;
  cpl_propertylist *resid_header = NULL;
  const char* tag=NULL;

  p_xs_3=&xs_3;

  XSH_ASSURE_NOT_NULL( resid_frame);
  XSH_ASSURE_NOT_NULL(cfg_frame);
  p_all_par=&all_par[0];

  /* 
   init string variables on full object size to prevent 
   Conditional jump or move depends on uninitialised value(s)
   valgrind error ( indeed xsh_model_readfits() initializes only 
   a number of elements equal to the input model cfg table size 
   (~90 params), not model_coeff_num=300
  */
  for (ii=0;ii<model_coeff_num;ii++) {
     sprintf((p_all_par+ii)->name, "%s", "\n");
  }

  //xsh_msg("passed_frames -  resid: %s %s  cfg: %s %s", cpl_frame_get_tag(resid_frame),cpl_frame_get_filename(resid_frame),cpl_frame_get_tag(cfg_frame),cpl_frame_get_filename(cfg_frame));

  /*Read parameter values in input config and their ranges and flags*/ 

  adim=xsh_model_readfits(abest,
			  amin,
			  amax,
			  aname,
			  cpl_frame_get_filename(cfg_frame),
                          cpl_frame_get_tag(cfg_frame),
			  p_xs_3,
			  p_all_par);

  //  ann_fac=0.1;

  /* iff use the scenario option to determine if the switches in the input FITS
     config file should be used or if an automatic set should be used*/

  if (scenario!=0) {
    for (ii=0;ii<model_coeff_num;ii++) {
      aname[ii]=-1;
      abest[ii]=0.0;
      amin[ii]=0.0;
      amax[ii]=0.0;
    }
    /*modify parameters for optimisation*/
    /*discover their indices and make the link with aname*/
    jj=0;
    if (scenario<=2) {
      /* For the start up scenario (1) open the parameters that may realistically
	 have physically changed due to intervention etc (eg. we don't change the
	 relative orientation of prism entrance and exit surfaces because we
	 don't expect the prism to change shape, but we do allow the
	 orientation of the prism(s) to change) and that effect the single
	 pinhole. The tolerances are >> than
	 any realistic physical movement. There are 14 parameters open in
	 total for UVB/VIS, 18 for NIR*/
      for (ii=0;ii<100;ii++) {
	/*fdet is the focal length of the camera*/
	if (strncmp((p_all_par+ii)->name,"fdet",4)==0) {
	  abest[jj]=p_xs_3->fdet;
	  amin[jj]=p_xs_3->fdet-(1.0*ann_fac);
	  amax[jj]=p_xs_3->fdet+(1.0*ann_fac);
	  aname[jj]=ii;
	  jj+=1;
	}
	else {
	/*temper is the temperature of the first prism*/
	/* 	if (strncmp((p_all_par+ii)->name,"temper",6)==0) { */
	/* 	  aname[jj]=ii; */
	/* 	  abest[jj]=p_xs_3->temper; */
	/* 	  amin[jj]=p_xs_3->temper-(5.0*ann_fac); */
	/* 	  amax[jj]=p_xs_3->temper+(5.0*ann_fac); */
	/* 	  jj+=1; */
	/* 	} */
	
	/* 	jj=xsh_model_open_param((p_all_par+ii)->name, */
	/* 				"temper", */
	/* 				&aname[jj], */
	/* 				ii, */
	/* 				&abest[jj], */
	/* 				p_xs_3->temper, */
	/* 				&amin[jj], */
	/* 				&amax[jj], */
	/* 				ann_fac, */
	/* 				5.0, */
	/* 				jj); */

	/*[mu/nu]p1 are the tip and tilt of the entrance surface (and hence
	  the whole prism) of the first prism*/
	  if (strncmp((p_all_par+ii)->name,"mup1",4)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->mup1/DEG2RAD;
	    amin[jj]=p_xs_3->mup1/DEG2RAD-(0.1*ann_fac);
	    amax[jj]=p_xs_3->mup1/DEG2RAD+(0.1*ann_fac);
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"nup1",4)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->nup1/DEG2RAD;
	    amin[jj]=p_xs_3->nup1/DEG2RAD-(0.1*ann_fac);
	    amax[jj]=p_xs_3->nup1/DEG2RAD+(0.1*ann_fac);
	    jj+=1;
	  }
	  if (p_xs_3->arm==2) {
	  /*[mu/nu]p3 are the tip and tilt of the entrance surface (and hence
	    the whole prism) of the second prism*/
	    if (strncmp((p_all_par+ii)->name,"mup3",4)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->mup3/DEG2RAD;
	      amin[jj]=p_xs_3->mup3/DEG2RAD-(0.1*ann_fac);
	      amax[jj]=p_xs_3->mup3/DEG2RAD+(0.1*ann_fac);
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"nup3",4)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->nup3/DEG2RAD;
	      amin[jj]=p_xs_3->nup3/DEG2RAD-(0.1*ann_fac);
	      amax[jj]=p_xs_3->nup3/DEG2RAD+(0.1*ann_fac);
	      jj+=1;
	    }
	    /*[mu/nu]p5 are the tip and tilt of the entrance surface (and hence
	      the whole prism) of the third prism*/
	    if (strncmp((p_all_par+ii)->name,"mup5",4)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->mup5/DEG2RAD;
	      amin[jj]=p_xs_3->mup5/DEG2RAD-(0.1*ann_fac);
	      amax[jj]=p_xs_3->mup5/DEG2RAD+(0.1*ann_fac);
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"nup5",4)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->nup5/DEG2RAD;
	      amin[jj]=p_xs_3->nup5/DEG2RAD-(0.1*ann_fac);
	      amax[jj]=p_xs_3->nup5/DEG2RAD+(0.1*ann_fac);
	      jj+=1;
	    }
	  }
	  /*[mu/nu/tau]g describe the orientation of the grating*/
	  if (strncmp((p_all_par+ii)->name,"mug",3)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->mug/DEG2RAD;
	    amin[jj]=p_xs_3->mug/DEG2RAD-(0.1*ann_fac);
	    amax[jj]=p_xs_3->mug/DEG2RAD+(0.1*ann_fac);
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"nug",3)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->nug/DEG2RAD;
	    amin[jj]=p_xs_3->nug/DEG2RAD-(1.0*ann_fac);
	    amax[jj]=p_xs_3->nug/DEG2RAD+(1.0*ann_fac);
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"taug",4)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->taug/DEG2RAD;
	    amin[jj]=p_xs_3->taug/DEG2RAD-(0.1*ann_fac);
	    amax[jj]=p_xs_3->taug/DEG2RAD+(0.1*ann_fac);
	    jj+=1;
	  }
	  /*[mu/nu/tau]d describe the orientation of the detector*/
	  if (strncmp((p_all_par+ii)->name,"mud",3)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->mud/DEG2RAD;
	    amin[jj]=p_xs_3->mud/DEG2RAD-(1.0*ann_fac);
	    amax[jj]=p_xs_3->mud/DEG2RAD+(1.0*ann_fac);
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"nud",3)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->nud/DEG2RAD;
	    amin[jj]=p_xs_3->nud/DEG2RAD-(1.0*ann_fac);
	    amax[jj]=p_xs_3->nud/DEG2RAD+(1.0*ann_fac);
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"taud",4)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->taud/DEG2RAD;
	    amin[jj]=p_xs_3->taud/DEG2RAD-(1.0*ann_fac);
	    amax[jj]=p_xs_3->taud/DEG2RAD+(1.0*ann_fac);
	    jj+=1;
	  }
	  /*es_y is the location of the central pinhole on the entrance
	    slit*/
	  if (strncmp((p_all_par+ii)->name,"es_y",4)==0) {
	    abest[jj]=p_xs_3->es_y;
	    amin[jj]=p_xs_3->es_y-(1.0*ann_fac);
	    amax[jj]=p_xs_3->es_y+(1.0*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  /* chip[x/y] is the offset of the detector in the focal plane*/
	  if (strncmp((p_all_par+ii)->name,"chipx",5)==0) {
	    abest[jj]=p_xs_3->chipx;
	    amin[jj]=p_xs_3->chipx-(5.0*ann_fac);
	    amax[jj]=p_xs_3->chipx+(5.0*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"chipy",5)==0) {
	    abest[jj]=p_xs_3->chipy;
	    amin[jj]=p_xs_3->chipy-(5.0*ann_fac);
	    amax[jj]=p_xs_3->chipy+(5.0*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  /* sg is the grating constant*/
	  if (strncmp((p_all_par+ii)->name,"sg",2)==0) {
	    abest[jj]=p_xs_3->sg;
	    amin[jj]=p_xs_3->sg-(1.0*ann_fac);
	    amax[jj]=p_xs_3->sg+(1.0*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	}
	if (scenario==2) {
      /* For the 9ph start scenario (2) add the parameters that will
	 effect any of the pinholes and may realistically have physically
	 changed due to intervention etc. (NOTE, it is assumed that "normal"
	 interventions will not involve replacing the pinhole mask with a
	 new one, therefore the slit positions are NOT included here. The
	 tolerances are >> than any realistic physical movement. This takes
	 the total open parameters to 17 for UVB/VIS, 21 for NIR*/
	  /*taues is the rotation angle of the entrance slit*/
	  if (strncmp((p_all_par+ii)->name,"taues",5)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->taues/DEG2RAD;
	    amin[jj]=p_xs_3->taues/DEG2RAD-(5.0*ann_fac);
	    amax[jj]=p_xs_3->taues/DEG2RAD+(5.0*ann_fac);
	    jj+=1;
	  }
	  /*fcol is the focal length of the collimator.*/
	  if (strncmp((p_all_par+ii)->name,"fcol",4)==0) {
	    abest[jj]=p_xs_3->fcol;
	    amin[jj]=p_xs_3->fcol-(5.0*ann_fac);
	    amax[jj]=p_xs_3->fcol+(5.0*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  /*slit_scale is the scale of the entrance slit in mm/" */
	  if (strncmp((p_all_par+ii)->name,"slit_scale",10)==0) {
	    abest[jj]=p_xs_3->slit_scale;
	    amin[jj]=p_xs_3->slit_scale-(0.05*ann_fac);
	    amax[jj]=p_xs_3->slit_scale+(0.05*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  /*es_x is the location of the central pinhole across the entrance
	      slit in mm*/
	  if (strncmp((p_all_par+ii)->name,"es_x",4)==0) {
	    abest[jj]=p_xs_3->es_x;
	    amin[jj]=p_xs_3->es_x-(0.1*ann_fac);
	    amax[jj]=p_xs_3->es_x+(0.1*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	}
      }
      adim=jj;
    }
    if (scenario>2) {
	/* For the regular scenario (3) very small changes are allowed for
	   all active parameters, except the distortion coefficients*/
      for (ii=0;ii<100;ii++) {
	if (scenario<6) {
/* 	  	if (strncmp((p_all_par+ii)->name,"temper",6)==0) { */
/* 	  	  aname[jj]=ii; */
/* 	  	  abest[jj]=p_xs_3->temper; */
/* 	  	  amin[jj]=p_xs_3->temper-(5.0*ann_fac); */
/* 	  	  amax[jj]=p_xs_3->temper+(5.0*ann_fac); */
/* 	  	  jj+=1; */
/* 	  	} */
	  /*es_y is the location of the central pinhole along the entrance
	    slit in mm*/
	  if (strncmp((p_all_par+ii)->name,"es_y",4)==0) {
	    abest[jj]=p_xs_3->es_y;
	    amin[jj]=p_xs_3->es_y-(0.01*ann_fac);
	    amax[jj]=p_xs_3->es_y+(0.01*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  /*es_x is the location of the central pinhole across the entrance
	    slit in mm*/
	  if (strncmp((p_all_par+ii)->name,"es_x",4)==0) {
	    abest[jj]=p_xs_3->es_x;
	    amin[jj]=p_xs_3->es_x-(0.01*ann_fac);
	    amax[jj]=p_xs_3->es_x+(0.01*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
 	  /*[mu/nu/tau]p1 are the orientation of the entrance surface (and hence
 	    the whole prism) of the first prism */
	  if (strncmp((p_all_par+ii)->name,"mup1",4)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->mup1/DEG2RAD;
	    amin[jj]=p_xs_3->mup1/DEG2RAD-(0.005*ann_fac);
	    amax[jj]=p_xs_3->mup1/DEG2RAD+(0.005*ann_fac);
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"nup1",4)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->nup1/DEG2RAD;
	    amin[jj]=p_xs_3->nup1/DEG2RAD-(0.005*ann_fac);
	    amax[jj]=p_xs_3->nup1/DEG2RAD+(0.005*ann_fac);
	    jj+=1;
	  }
/* 	  if (strncmp((p_all_par+ii)->name,"taup1",5)==0) { */
/* 	    aname[jj]=ii; */
/* 	    abest[jj]=p_xs_3->taup1/DEG2RAD; */
/* 	    amin[jj]=p_xs_3->taup1/DEG2RAD-(0.005*ann_fac); */
/* 	    amax[jj]=p_xs_3->taup1/DEG2RAD+(0.005*ann_fac); */
/* 	    jj+=1; */
/* 	  } */
	  /*[mu/nu/tau]p2 are the orientation of the exit surface
	    of the first prism*/
	  if (strncmp((p_all_par+ii)->name,"mup2",4)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->mup2/DEG2RAD;
	    amin[jj]=p_xs_3->mup2/DEG2RAD-(0.005*ann_fac);
	    amax[jj]=p_xs_3->mup2/DEG2RAD+(0.005*ann_fac);
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"nup2",4)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->nup2/DEG2RAD;
	    amin[jj]=p_xs_3->nup2/DEG2RAD-(0.005*ann_fac);
	    amax[jj]=p_xs_3->nup2/DEG2RAD+(0.005*ann_fac);
	    jj+=1;
	  }
/* 	  if (strncmp((p_all_par+ii)->name,"taup2",5)==0) { */
/* 	    aname[jj]=ii; */
/* 	    abest[jj]=p_xs_3->taup2/DEG2RAD; */
/* 	    amin[jj]=p_xs_3->taup2/DEG2RAD-(0.005*ann_fac); */
/* 	    amax[jj]=p_xs_3->taup2/DEG2RAD+(0.005*ann_fac); */
/* 	    jj+=1; */
/* 	  } */
	  if (p_xs_3->arm==2) {
	    /*[mu/nu/tau]p3 are the orientation of the entrance surface (and hence
	      the whole prism) of the second prism*/
	    if (strncmp((p_all_par+ii)->name,"mup3",4)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->mup3/DEG2RAD;
	      amin[jj]=p_xs_3->mup3/DEG2RAD-(0.005*ann_fac);
	      amax[jj]=p_xs_3->mup3/DEG2RAD+(0.005*ann_fac);
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"nup3",4)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->nup3/DEG2RAD;
	      amin[jj]=p_xs_3->nup3/DEG2RAD-(0.005*ann_fac);
	      amax[jj]=p_xs_3->nup3/DEG2RAD+(0.005*ann_fac);
	      jj+=1;
	    }
/* 	    if (strncmp((p_all_par+ii)->name,"taup3",5)==0) { */
/* 	      aname[jj]=ii; */
/* 	      abest[jj]=p_xs_3->taup3/DEG2RAD; */
/* 	      amin[jj]=p_xs_3->taup3/DEG2RAD-(0.005*ann_fac); */
/* 	      amax[jj]=p_xs_3->taup3/DEG2RAD+(0.005*ann_fac); */
/* 	      jj+=1; */
/* 	    } */
/* 	    /\*[mu/nu/tau]p4 are the orientation of the exit surface */
/* 	      of the second prism*\/ */
	    if (strncmp((p_all_par+ii)->name,"mup4",4)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->mup4/DEG2RAD;
	      amin[jj]=p_xs_3->mup4/DEG2RAD-(0.005*ann_fac);
	      amax[jj]=p_xs_3->mup4/DEG2RAD+(0.005*ann_fac);
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"nup4",4)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->nup4/DEG2RAD;
	      amin[jj]=p_xs_3->nup4/DEG2RAD-(0.005*ann_fac);
	      amax[jj]=p_xs_3->nup4/DEG2RAD+(0.005*ann_fac);
	      jj+=1;
	    }
/* 	    if (strncmp((p_all_par+ii)->name,"taup4",5)==0) { */
/* 	      aname[jj]=ii; */
/* 	      abest[jj]=p_xs_3->taup4/DEG2RAD; */
/* 	      amin[jj]=p_xs_3->taup4/DEG2RAD-(0.005*ann_fac); */
/* 	      amax[jj]=p_xs_3->taup4/DEG2RAD+(0.005*ann_fac); */
/* 	      jj+=1; */
/* 	    } */
	    /*[mu/nu/tau]p5 are the orientation of the entrance surface (and hence
	      the whole prism) of the third prism*/
	    if (strncmp((p_all_par+ii)->name,"mup5",4)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->mup5/DEG2RAD;
	      amin[jj]=p_xs_3->mup5/DEG2RAD-(0.005*ann_fac);
	      amax[jj]=p_xs_3->mup5/DEG2RAD+(0.005*ann_fac);
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"nup5",4)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->nup5/DEG2RAD;
	      amin[jj]=p_xs_3->nup5/DEG2RAD-(0.005*ann_fac);
	      amax[jj]=p_xs_3->nup5/DEG2RAD+(0.005*ann_fac);
	      jj+=1;
	    }
/* 	    if (strncmp((p_all_par+ii)->name,"taup5",5)==0) { */
/* 	      aname[jj]=ii; */
/* 	      abest[jj]=p_xs_3->taup5/DEG2RAD; */
/* 	      amin[jj]=p_xs_3->taup5/DEG2RAD-(0.005*ann_fac); */
/* 	      amax[jj]=p_xs_3->taup5/DEG2RAD+(0.005*ann_fac); */
/* 	      jj+=1; */
/* 	    } */
/* 	    /\*[mu/nu]p6 are the tip and tilt of the exit surface */
/* 	      of the third prism*\/ */
	    if (strncmp((p_all_par+ii)->name,"mup6",4)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->mup6/DEG2RAD;
	      amin[jj]=p_xs_3->mup6/DEG2RAD-(0.005*ann_fac);
	      amax[jj]=p_xs_3->mup6/DEG2RAD+(0.005*ann_fac);
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"nup6",4)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->nup6/DEG2RAD;
	      amin[jj]=p_xs_3->nup6/DEG2RAD-(0.005*ann_fac);
	      amax[jj]=p_xs_3->nup6/DEG2RAD+(0.005*ann_fac);
	      jj+=1;
	    }
/* 	    if (strncmp((p_all_par+ii)->name,"taup6",5)==0) { */
/* 	      aname[jj]=ii; */
/* 	      abest[jj]=p_xs_3->taup6/DEG2RAD; */
/* 	      amin[jj]=p_xs_3->taup6/DEG2RAD-(0.005*ann_fac); */
/* 	      amax[jj]=p_xs_3->taup6/DEG2RAD+(0.005*ann_fac); */
/* 	      jj+=1; */
/* 	    } */
	  }
	  /*[mu/nu/tau]g describe the orientation of the grating*/
	  if (strncmp((p_all_par+ii)->name,"mug",3)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->mug/DEG2RAD;
	    amin[jj]=p_xs_3->mug/DEG2RAD-(0.05*ann_fac);
	    amax[jj]=p_xs_3->mug/DEG2RAD+(0.05*ann_fac);
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"nug",3)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->nug/DEG2RAD;
	    amin[jj]=p_xs_3->nug/DEG2RAD-(0.5*ann_fac);
	    amax[jj]=p_xs_3->nug/DEG2RAD+(0.5*ann_fac);
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"taug",4)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->taug/DEG2RAD;
	    amin[jj]=p_xs_3->taug/DEG2RAD-(0.05*ann_fac);
	    amax[jj]=p_xs_3->taug/DEG2RAD+(0.05*ann_fac);
	    jj+=1;
	  }
	  /*[mu/nu/tau]d describe the orientation of the detector*/
	  if (strncmp((p_all_par+ii)->name,"mud",3)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->mud/DEG2RAD;
	    amin[jj]=p_xs_3->mud/DEG2RAD-(0.005*ann_fac);
	    amax[jj]=p_xs_3->mud/DEG2RAD+(0.005*ann_fac);
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"nud",3)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->nud/DEG2RAD;
	    amin[jj]=p_xs_3->nud/DEG2RAD-(0.005*ann_fac);
	    amax[jj]=p_xs_3->nud/DEG2RAD+(0.005*ann_fac);
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"taud",4)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->taud/DEG2RAD;
	    amin[jj]=p_xs_3->taud/DEG2RAD-(0.05*ann_fac);
	    amax[jj]=p_xs_3->taud/DEG2RAD+(0.05*ann_fac);
	    jj+=1;
	  }
	  /*fdet is the focal length of the camera*/
	  if (strncmp((p_all_par+ii)->name,"fdet",4)==0) {
	    abest[jj]=p_xs_3->fdet;
	    amin[jj]=p_xs_3->fdet-(0.1*ann_fac);
	    amax[jj]=p_xs_3->fdet+(0.1*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  /* chip[x/y] is the offset of the detector in the focal plane*/
	  if (strncmp((p_all_par+ii)->name,"chipx",5)==0) {
	    abest[jj]=p_xs_3->chipx;
	    amin[jj]=p_xs_3->chipx-(0.05*ann_fac);
	    amax[jj]=p_xs_3->chipx+(0.05*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"chipy",5)==0) {
	    abest[jj]=p_xs_3->chipy;
	    amin[jj]=p_xs_3->chipy-(0.05*ann_fac);
	    amax[jj]=p_xs_3->chipy+(0.05*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  /* sg is the grating constant*/
	  if (strncmp((p_all_par+ii)->name,"sg",2)==0) {
	    abest[jj]=p_xs_3->sg;
	    amin[jj]=p_xs_3->sg-(0.5*ann_fac);
	    amax[jj]=p_xs_3->sg+(0.5*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  /*Open also the 1st order terms of the distortion correction, it turns out that
	    this is the only way to remove unwanted trends in the residuals*/
	  if (strncmp((p_all_par+ii)->name,"pc_x_y1",7)==0) {
	    abest[jj]=p_xs_3->pc_x_y1;
	    amin[jj]=p_xs_3->pc_x_y1-(0.01*ann_fac);
	    amax[jj]=p_xs_3->pc_x_y1+(0.01*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"pc_y_x1",7)==0) {
	    abest[jj]=p_xs_3->pc_y_x1;
	    amin[jj]=p_xs_3->pc_y_x1-(0.01*ann_fac);
	    amax[jj]=p_xs_3->pc_y_x1+(0.01*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"pc_x_x1",7)==0) {
	    abest[jj]=p_xs_3->pc_x_x1;
	    amin[jj]=p_xs_3->pc_x_x1-(0.01*ann_fac);
	    amax[jj]=p_xs_3->pc_x_x1+(0.01*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"pc_y_y1",7)==0) {
	    abest[jj]=p_xs_3->pc_y_y1;
	    amin[jj]=p_xs_3->pc_y_y1-(0.01*ann_fac);
	    amax[jj]=p_xs_3->pc_y_y1+(0.01*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (scenario>3) {
	    /*for scenario 4 & 5 include the parameters that affect the
	      non-central slit positions*/
	    /*slit_scale is the scale of the entrance slit in mm/" */
	    if (strncmp((p_all_par+ii)->name,"slit_scale",10)==0) {
	      abest[jj]=p_xs_3->slit_scale;
	      amin[jj]=p_xs_3->slit_scale-(0.01*ann_fac);
	      amax[jj]=p_xs_3->slit_scale+(0.01*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    /*taues is the rotation angle of the entrance slit*/
	    if (strncmp((p_all_par+ii)->name,"taues",5)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->taues/DEG2RAD;
	      amin[jj]=p_xs_3->taues/DEG2RAD-(0.1*ann_fac);
	      amax[jj]=p_xs_3->taues/DEG2RAD+(0.1*ann_fac);
	      jj+=1;
	    }
	    /*offx,y describe the chromatic/slit posn correction*/
/* 	    if (strncmp((p_all_par+ii)->name,"offx",4)==0) { */
/* 	      abest[jj]=0.0;//p_xs_3->offx; */
/* 	      amin[jj]=-500.0;//p_xs_3->offx-(20.0*ann_fac); */
/* 	      amax[jj]=500.0;//p_xs_3->offx+(20.0*ann_fac); */
/* 	      aname[jj]=ii; */
/* 	      jj+=1; */
/* 	    } */
/* 	    if (strncmp((p_all_par+ii)->name,"offy",4)==0) { */
/* 	      abest[jj]=0.0012;//p_xs_3->offy; */
/* 	      amin[jj]=0.001;//p_xs_3->offy-(0.00001*ann_fac); */
/* 	      amax[jj]=0.0025;//p_xs_3->offy+(0.00001*ann_fac); */
/* 	      aname[jj]=ii; */
/* 	      jj+=1; */
/* 	    } */
	    /*fcol is the focal length of the collimator.*/
	    if (strncmp((p_all_par+ii)->name,"fcol",4)==0) {
	      abest[jj]=p_xs_3->fcol;
	      amin[jj]=p_xs_3->fcol-(0.1*ann_fac);
	      amax[jj]=p_xs_3->fcol+(0.1*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
/* 	    p_xs_3->slit[0]=-5.6; */
/* 	    p_xs_3->slit[1]=-4.2; */
/* 	    p_xs_3->slit[2]=-2.8; */
/* 	    p_xs_3->slit[3]=-1.4; */
/* 	    p_xs_3->slit[4]=0.0; */
/* 	    p_xs_3->slit[5]=1.4; */
/* 	    p_xs_3->slit[6]=2.8; */
/* 	    p_xs_3->slit[7]=4.2; */
/* 	    p_xs_3->slit[8]=5.6; */
	    /*slit[0-8] are the postions of the 9 pinholes along the slit
	      in arcsec*/
/* 	    if (strncmp((p_all_par+ii)->name,"slit[0]",7)==0) { */
/* 	      abest[jj]=p_xs_3->slit[0]; */
/* 	      amin[jj]=p_xs_3->slit[0]-(0.01*ann_fac); */
/* 	      amax[jj]=p_xs_3->slit[0]+(0.01*ann_fac); */
/* 	      aname[jj]=ii; */
/* 	      jj+=1; */
/* 	    } */
/* 	    if (strncmp((p_all_par+ii)->name,"slit[1]",7)==0) { */
/* 	      abest[jj]=p_xs_3->slit[1]; */
/* 	      amin[jj]=p_xs_3->slit[1]-(0.01*ann_fac); */
/* 	      amax[jj]=p_xs_3->slit[1]+(0.01*ann_fac); */
/* 	      aname[jj]=ii; */
/* 	      jj+=1; */
/* 	    } */
/* 	    if (strncmp((p_all_par+ii)->name,"slit[2]",7)==0) { */
/* 	      abest[jj]=p_xs_3->slit[2]; */
/* 	      amin[jj]=p_xs_3->slit[2]-(0.01*ann_fac); */
/* 	      amax[jj]=p_xs_3->slit[2]+(0.01*ann_fac); */
/* 	      aname[jj]=ii; */
/* 	      jj+=1; */
/* 	    } */
/* 	    if (strncmp((p_all_par+ii)->name,"slit[3]",7)==0) { */
/* 	      abest[jj]=p_xs_3->slit[3]; */
/* 	      amin[jj]=p_xs_3->slit[3]-(0.01*ann_fac); */
/* 	      amax[jj]=p_xs_3->slit[3]+(0.01*ann_fac); */
/* 	      aname[jj]=ii; */
/* 	      jj+=1; */
/* 	    } */
/* 	    /\*       if (strncmp((p_all_par+ii)->name,"slit[4]",7)==0) { *\/ */
/* 	    /\* 	abest[jj]=p_xs_3->slit[4]; *\/ */
/* 	    /\* 	amin[jj]=p_xs_3->slit[4]-(0.001*ann_fac); *\/ */
/* 	    /\* 	amax[jj]=p_xs_3->slit[4]+(0.001*ann_fac); *\/ */
/* 	    /\* 	aname[jj]=ii; *\/ */
/* 	    /\* 	jj+=1; *\/ */
/* 	    /\*       } *\/ */
/* 	    if (strncmp((p_all_par+ii)->name,"slit[5]",7)==0) { */
/* 	      abest[jj]=p_xs_3->slit[5]; */
/* 	      amin[jj]=p_xs_3->slit[5]-(0.01*ann_fac); */
/* 	      amax[jj]=p_xs_3->slit[5]+(0.01*ann_fac); */
/* 	      aname[jj]=ii; */
/* 	      jj+=1; */
/* 	    } */
/* 	    if (strncmp((p_all_par+ii)->name,"slit[6]",7)==0) { */
/* 	      abest[jj]=p_xs_3->slit[6]; */
/* 	      amin[jj]=p_xs_3->slit[6]-(0.01*ann_fac); */
/* 	      amax[jj]=p_xs_3->slit[6]+(0.01*ann_fac); */
/* 	      aname[jj]=ii; */
/* 	      jj+=1; */
/* 	    } */
/* 	    if (strncmp((p_all_par+ii)->name,"slit[7]",7)==0) { */
/* 	      abest[jj]=p_xs_3->slit[7]; */
/* 	      amin[jj]=p_xs_3->slit[7]-(0.01*ann_fac); */
/* 	      amax[jj]=p_xs_3->slit[7]+(0.01*ann_fac); */
/* 	      aname[jj]=ii; */
/* 	      jj+=1; */
/* 	    } */
/* 	    if (strncmp((p_all_par+ii)->name,"slit[8]",7)==0) { */
/* 	      abest[jj]=p_xs_3->slit[8]; */
/* 	      amin[jj]=p_xs_3->slit[8]-(0.01*ann_fac); */
/* 	      amax[jj]=p_xs_3->slit[8]+(0.01*ann_fac); */
/* 	      aname[jj]=ii; */
/* 	      jj+=1; */
/* 	    } */
	  }
	}
	if (scenario>=5 && scenario<8) {
	  if (scenario==6) {
	    /*5 is the scenario where we just want to optimise distortion coefficients.
	      Since we are in the scenario >2 loop, but we omitted all the non dist coef
	      settings explicitly for the scenario==6 case earlier, we need to set chipx/y
	      here (they will have already been set for scenario==5)*/
	    /* chip[x/y] is the offset of the detector in the focal plane*/
	    if (strncmp((p_all_par+ii)->name,"chipx",5)==0) {
	      abest[jj]=p_xs_3->chipx;
	      amin[jj]=p_xs_3->chipx-(0.1*ann_fac);
	      amax[jj]=p_xs_3->chipx+(0.1*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"chipy",5)==0) {
	      abest[jj]=p_xs_3->chipy;
	      amin[jj]=p_xs_3->chipy-(0.1*ann_fac);
	      amax[jj]=p_xs_3->chipy+(0.1*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	  }
/* 	  p_xs_3->pc_x_x1=1.0; */
/* 	  p_xs_3->pc_y_y1=1.0; */
/* 	  p_xs_3->pc_x_y1=0.0; */
/* 	  p_xs_3->pc_y_x1=0.0; */
/* 	  p_xs_3->pc_x_xx=0.0; */
/* 	  p_xs_3->pc_x_yy=0.0; */
/* 	  p_xs_3->pc_x_xy=0.0; */
/* 	  p_xs_3->pc_x_x3=0.0; */
/* 	  p_xs_3->pc_x_y3=0.0; */
/* 	  p_xs_3->pc_x_x2y=0.0; */
/* 	  p_xs_3->pc_x_y2x=0.0; */
/* 	  p_xs_3->pc_y_xx=0.0; */
/* 	  p_xs_3->pc_y_yy=0.0; */
/* 	  p_xs_3->pc_y_xy=0.0; */
/* 	  p_xs_3->pc_y_x3=0.0; */
/* 	  p_xs_3->pc_y_y3=0.0; */
/* 	  p_xs_3->pc_y_x2y=0.0; */
/* 	  p_xs_3->pc_y_y2x=0.0; */
/* 	  p_xs_3->d2_x1=0.0; */
/* 	  p_xs_3->d2_x2=0.0; */
/* 	  p_xs_3->d2_x3=0.0; */
/* 	  p_xs_3->d2_y1x0=0.0; */
/* 	  p_xs_3->d2_y1x1=0.0; */
/* 	  p_xs_3->d2_y2x0=0.0; */
/* 	  p_xs_3->d2_y2x1=0.0; */
/* 	  p_xs_3->d2_y3x0=0.0; */
/* 	  p_xs_3->d2_y3x1=0.0; */

	  /* For the refine dist_coefs scenarios (5 or 6), we allow very small changes
	     to the distortion coeffs as well*/
	  if (strncmp((p_all_par+ii)->name,"pc_x_x1",7)==0) {
	    abest[jj]=p_xs_3->pc_x_x1;
	    amin[jj]=p_xs_3->pc_x_x1-(0.001*ann_fac);
	    amax[jj]=p_xs_3->pc_x_x1+(0.001*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"pc_x_xx",7)==0) {
	    abest[jj]=p_xs_3->pc_x_xx;
	    amin[jj]=p_xs_3->pc_x_xx-(0.0001*ann_fac);
	    amax[jj]=p_xs_3->pc_x_xx+(0.0001*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"pc_x_y1",7)==0) {
	    abest[jj]=p_xs_3->pc_x_y1;
	    amin[jj]=p_xs_3->pc_x_y1-(0.001*ann_fac);
	    amax[jj]=p_xs_3->pc_x_y1+(0.001*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"pc_x_yy",7)==0) {
	    abest[jj]=p_xs_3->pc_x_yy;
	    amin[jj]=p_xs_3->pc_x_yy-(0.0001*ann_fac);
	    amax[jj]=p_xs_3->pc_x_yy+(0.0001*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"pc_x_xy",7)==0) {
	    abest[jj]=p_xs_3->pc_x_xy;
	    amin[jj]=p_xs_3->pc_x_xy-(0.0001*ann_fac);
	    amax[jj]=p_xs_3->pc_x_xy+(0.0001*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"pc_x_x2y",8)==0) {
	    abest[jj]=p_xs_3->pc_x_x2y;
	    amin[jj]=p_xs_3->pc_x_x2y-(0.00001*ann_fac);
	    amax[jj]=p_xs_3->pc_x_x2y+(0.00001*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"pc_x_y2x",8)==0) {
	    abest[jj]=p_xs_3->pc_x_y2x;
	    amin[jj]=p_xs_3->pc_x_y2x-(0.00001*ann_fac);
	    amax[jj]=p_xs_3->pc_x_y2x+(0.00001*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"pc_x_x3",7)==0) {
	    abest[jj]=p_xs_3->pc_x_x3;
	    amin[jj]=p_xs_3->pc_x_x3-(0.00001*ann_fac);
	    amax[jj]=p_xs_3->pc_x_x3+(0.00001*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"pc_x_y3",7)==0) {
	    abest[jj]=p_xs_3->pc_x_y3;
	    amin[jj]=p_xs_3->pc_x_y3-(0.00001*ann_fac);
	    amax[jj]=p_xs_3->pc_x_y3+(0.00001*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"pc_y_x1",7)==0) {
	    abest[jj]=p_xs_3->pc_y_x1;
	    amin[jj]=p_xs_3->pc_y_x1-(0.001*ann_fac);
	    amax[jj]=p_xs_3->pc_y_x1+(0.001*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"pc_y_xx",7)==0) {
	    abest[jj]=p_xs_3->pc_y_xx;
	    amin[jj]=p_xs_3->pc_y_xx-(0.0001*ann_fac);
	    amax[jj]=p_xs_3->pc_y_xx+(0.0001*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"pc_y_y1",7)==0) {
	    abest[jj]=p_xs_3->pc_y_y1;
	    amin[jj]=p_xs_3->pc_y_y1-(0.001*ann_fac);
	    amax[jj]=p_xs_3->pc_y_y1+(0.001*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"pc_y_yy",7)==0) {
	    abest[jj]=p_xs_3->pc_y_yy;
	    amin[jj]=p_xs_3->pc_y_yy-(0.0001*ann_fac);
	    amax[jj]=p_xs_3->pc_y_yy+(0.0001*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"pc_y_xy",7)==0) {
	    abest[jj]=p_xs_3->pc_y_xy;
	    amin[jj]=p_xs_3->pc_y_xy-(0.0001*ann_fac);
	    amax[jj]=p_xs_3->pc_y_xy+(0.0001*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"pc_y_x2y",8)==0) {
	    abest[jj]=p_xs_3->pc_y_x2y;
	    amin[jj]=p_xs_3->pc_y_x2y-(0.00001*ann_fac);
	    amax[jj]=p_xs_3->pc_y_x2y+(0.00001*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"pc_y_y2x",8)==0) {
	    abest[jj]=p_xs_3->pc_y_y2x;
	    amin[jj]=p_xs_3->pc_y_y2x-(0.00001*ann_fac);
	    amax[jj]=p_xs_3->pc_y_y2x+(0.00001*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"pc_y_x3",7)==0) {
	    abest[jj]=p_xs_3->pc_y_x3;
	    amin[jj]=p_xs_3->pc_y_x3-(0.00001*ann_fac);
	    amax[jj]=p_xs_3->pc_y_x3+(0.00001*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"pc_y_y3",7)==0) {
	    abest[jj]=p_xs_3->pc_y_y3;
	    amin[jj]=p_xs_3->pc_y_y3-(0.00001*ann_fac);
	    amax[jj]=p_xs_3->pc_y_y3+(0.00001*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (p_xs_3->arm<2) {
	    if (strncmp((p_all_par+ii)->name,"d2_x1",5)==0) {
	      abest[jj]=p_xs_3->d2_x1;
	      amin[jj]=p_xs_3->d2_x1-(0.01*ann_fac);
	      amax[jj]=p_xs_3->d2_x1+(0.01*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"d2_x2",5)==0) {
	      abest[jj]=p_xs_3->d2_x2;
	      amin[jj]=p_xs_3->d2_x2-(0.001*ann_fac);
	      amax[jj]=p_xs_3->d2_x2+(0.001*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"d2_x3",5)==0) {
	      abest[jj]=p_xs_3->d2_x3;
	      amin[jj]=p_xs_3->d2_x3-(0.0001*ann_fac);
	      amax[jj]=p_xs_3->d2_x3+(0.0001*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	  }
	  else if (p_xs_3->arm==2) {
	    if (strncmp((p_all_par+ii)->name,"pc4_x_xy3",9)==0) {
	      abest[jj]=p_xs_3->pc4_x_xy3;
	      amin[jj]=p_xs_3->pc4_x_xy3-(0.000001*ann_fac);
	      amax[jj]=p_xs_3->pc4_x_xy3+(0.000001*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"pc4_x_x3y",9)==0) {
	      abest[jj]=p_xs_3->pc4_x_x3y;
	      amin[jj]=p_xs_3->pc4_x_x3y-(0.000001*ann_fac);
	      amax[jj]=p_xs_3->pc4_x_x3y+(0.000001*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"pc4_x_x2y2",10)==0) {
	      abest[jj]=p_xs_3->pc4_x_x2y2;
	      amin[jj]=p_xs_3->pc4_x_x2y2-(0.000001*ann_fac);
	      amax[jj]=p_xs_3->pc4_x_x2y2+(0.000001*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"pc4_x_x4",8)==0) {
	      abest[jj]=p_xs_3->pc4_x_x4;
	      amin[jj]=p_xs_3->pc4_x_x4-(0.000001*ann_fac);
	      amax[jj]=p_xs_3->pc4_x_x4+(0.000001*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"pc4_x_y4",8)==0) {
	      abest[jj]=p_xs_3->pc4_x_y4;
	      amin[jj]=p_xs_3->pc4_x_y4-(0.000001*ann_fac);
	      amax[jj]=p_xs_3->pc4_x_y4+(0.000001*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"pc4_y_xy3",9)==0) {
	      abest[jj]=p_xs_3->pc4_y_xy3;
	      amin[jj]=p_xs_3->pc4_y_xy3-(0.000001*ann_fac);
	      amax[jj]=p_xs_3->pc4_y_xy3+(0.000001*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"pc4_y_xy3",9)==0) {
	      abest[jj]=p_xs_3->pc4_y_xy3;
	      amin[jj]=p_xs_3->pc4_y_xy3-(0.000001*ann_fac);
	      amax[jj]=p_xs_3->pc4_y_xy3+(0.000001*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"pc4_y_x2y2",10)==0) {
	      abest[jj]=p_xs_3->pc4_y_x2y2;
	      amin[jj]=p_xs_3->pc4_y_x2y2-(0.000001*ann_fac);
	      amax[jj]=p_xs_3->pc4_y_x2y2+(0.000001*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"pc4_y_x4",8)==0) {
	      abest[jj]=p_xs_3->pc4_y_x4;
	      amin[jj]=p_xs_3->pc4_y_x4-(0.000001*ann_fac);
	      amax[jj]=p_xs_3->pc4_y_x4+(0.000001*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"pc4_y_y4",8)==0) {
	      abest[jj]=p_xs_3->pc4_y_y4;
	      amin[jj]=p_xs_3->pc4_y_y4-(0.000001*ann_fac);
	      amax[jj]=p_xs_3->pc4_y_y4+(0.000001*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"ca_x0",5)==0) {
	      abest[jj]=p_xs_3->ca_x0;
	      amin[jj]=p_xs_3->ca_x0-(0.000001*ann_fac);
	      amax[jj]=p_xs_3->ca_x0+(0.000001*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"ca_x1",5)==0) {
	      abest[jj]=p_xs_3->ca_x1;
	      amin[jj]=p_xs_3->ca_x1-(0.000001*ann_fac);
	      amax[jj]=p_xs_3->ca_x1+(0.000001*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"ca_y0",5)==0) {
	      abest[jj]=p_xs_3->ca_y0;
	      amin[jj]=p_xs_3->ca_y0-(0.000001*ann_fac);
	      amax[jj]=p_xs_3->ca_y0+(0.000001*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"ca_y1",5)==0) {
	      abest[jj]=p_xs_3->ca_y1;
	      amin[jj]=p_xs_3->ca_y1-(0.000001*ann_fac);
	      amax[jj]=p_xs_3->ca_y1+(0.000001*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	  }
	}
	if (scenario<0) {
      	/*es_x is the location of the central pinhole across the entrance
	  slit in mm*/
	  if (strncmp((p_all_par+ii)->name,"es_x",4)==0) {
	    abest[jj]=p_xs_3->es_x;
	    amin[jj]=p_xs_3->es_x-(1.0*ann_fac);
	    amax[jj]=p_xs_3->es_x+(1.0*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	}
	if (scenario==8) {
	  if (p_xs_3->arm==0) {
	    /*[mu/nu/tau]d describe the orientation of the detector*/
	    if (strncmp((p_all_par+ii)->name,"mud",3)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->mud/DEG2RAD;
	      amin[jj]=p_xs_3->mud/DEG2RAD-(0.2*ann_fac);
	      amax[jj]=p_xs_3->mud/DEG2RAD+(0.2*ann_fac);
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"nud",3)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->nud/DEG2RAD;
	      amin[jj]=p_xs_3->nud/DEG2RAD-(0.2*ann_fac);
	      amax[jj]=p_xs_3->nud/DEG2RAD+(0.2*ann_fac);
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"taud",4)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->taud/DEG2RAD;
	      amin[jj]=p_xs_3->taud/DEG2RAD-(0.05*ann_fac);
	      amax[jj]=p_xs_3->taud/DEG2RAD+(0.05*ann_fac);
	      jj+=1;
	    }
	    /*fdet is the focal length of the camera*/
	    if (strncmp((p_all_par+ii)->name,"fdet",4)==0) {
	      abest[jj]=p_xs_3->fdet;
	      amin[jj]=p_xs_3->fdet-(0.05*ann_fac);
	      amax[jj]=p_xs_3->fdet+(0.05*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    /* chip[x/y] is the offset of the detector in the focal plane*/
	    if (strncmp((p_all_par+ii)->name,"chipx",5)==0) {
	      abest[jj]=p_xs_3->chipx;
	      amin[jj]=p_xs_3->chipx-(0.05*ann_fac);
	      amax[jj]=p_xs_3->chipx+(0.05*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"chipy",5)==0) {
	      abest[jj]=p_xs_3->chipy;
	      amin[jj]=p_xs_3->chipy-(0.05*ann_fac);
	      amax[jj]=p_xs_3->chipy+(0.05*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    /* sg is the grating constant*/
	    if (strncmp((p_all_par+ii)->name,"sg",2)==0) {
	      abest[jj]=p_xs_3->sg;
	      amin[jj]=p_xs_3->sg-(0.02*ann_fac);
	      amax[jj]=p_xs_3->sg+(0.02*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	  }
	  else if (p_xs_3->arm==1) {
	    if (strncmp((p_all_par+ii)->name,"mup1",4)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->mup1/DEG2RAD;
	      amin[jj]=p_xs_3->mup1/DEG2RAD-(0.025*ann_fac);
	      amax[jj]=p_xs_3->mup1/DEG2RAD+(0.025*ann_fac);
	      jj+=1;
	    }
	    /*[mu/nu/tau]g describe the orientation of the grating*/
	    if (strncmp((p_all_par+ii)->name,"nug",3)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->nug/DEG2RAD;
	      amin[jj]=p_xs_3->nug/DEG2RAD-(0.02*ann_fac);
	      amax[jj]=p_xs_3->nug/DEG2RAD+(0.02*ann_fac);
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"taud",4)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->taud/DEG2RAD;
	      amin[jj]=p_xs_3->taud/DEG2RAD-(0.01*ann_fac);
	      amax[jj]=p_xs_3->taud/DEG2RAD+(0.01*ann_fac);
	      jj+=1;
	    }
	  /*fdet is the focal length of the camera*/
	    if (strncmp((p_all_par+ii)->name,"fdet",4)==0) {
	      abest[jj]=p_xs_3->fdet;
	      amin[jj]=p_xs_3->fdet-(0.1*ann_fac);
	      amax[jj]=p_xs_3->fdet+(0.1*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    /* chip[x/y] is the offset of the detector in the focal plane*/
	    if (strncmp((p_all_par+ii)->name,"chipx",5)==0) {
	      abest[jj]=p_xs_3->chipx;
	      amin[jj]=p_xs_3->chipx-(0.05*ann_fac);
	      amax[jj]=p_xs_3->chipx+(0.05*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"chipy",5)==0) {
	      abest[jj]=p_xs_3->chipy;
	      amin[jj]=p_xs_3->chipy-(0.05*ann_fac);
	      amax[jj]=p_xs_3->chipy+(0.05*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    /* sg is the grating constant*/
	    if (strncmp((p_all_par+ii)->name,"sg",2)==0) {
	      abest[jj]=p_xs_3->sg;
	      amin[jj]=p_xs_3->sg-(0.01*ann_fac);
	      amax[jj]=p_xs_3->sg+(0.01*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	  }
	  else if (p_xs_3->arm==2) {
	    /*[mu/nu/tau]d describe the orientation of the detector*/
	    if (strncmp((p_all_par+ii)->name,"mup1",4)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->mup1/DEG2RAD;
	      amin[jj]=p_xs_3->mup1/DEG2RAD-(0.01*ann_fac);
	      amax[jj]=p_xs_3->mup1/DEG2RAD+(0.01*ann_fac);
	      jj+=1;
	    }
	    /*[mu/nu/tau]g describe the orientation of the grating*/
	    if (strncmp((p_all_par+ii)->name,"nug",3)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->nug/DEG2RAD;
	      amin[jj]=p_xs_3->nug/DEG2RAD-(0.01*ann_fac);
	      amax[jj]=p_xs_3->nug/DEG2RAD+(0.01*ann_fac);
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"mud",3)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->mud/DEG2RAD;
	      amin[jj]=p_xs_3->mud/DEG2RAD-(0.1*ann_fac);
	      amax[jj]=p_xs_3->mud/DEG2RAD+(0.3*ann_fac);
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"nud",3)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->nud/DEG2RAD;
	      amin[jj]=p_xs_3->nud/DEG2RAD-(0.1*ann_fac);
	      amax[jj]=p_xs_3->nud/DEG2RAD+(0.3*ann_fac);
	      jj+=1;
	    }
	    /*fdet is the focal length of the camera*/
	    if (strncmp((p_all_par+ii)->name,"fdet",4)==0) {
	      abest[jj]=p_xs_3->fdet;
	      amin[jj]=p_xs_3->fdet-(0.2*ann_fac);
	      amax[jj]=p_xs_3->fdet+(0.2*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    /* chip[x/y] is the offset of the detector in the focal plane*/
	    if (strncmp((p_all_par+ii)->name,"chipx",5)==0) {
	      abest[jj]=p_xs_3->chipx;
	      amin[jj]=p_xs_3->chipx-(0.075*ann_fac);
	      amax[jj]=p_xs_3->chipx+(0.075*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	    if (strncmp((p_all_par+ii)->name,"chipy",5)==0) {
	      abest[jj]=p_xs_3->chipy;
	      amin[jj]=p_xs_3->chipy-(0.075*ann_fac);
	      amax[jj]=p_xs_3->chipy+(0.075*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	  /*taues is the rotation angle of the entrance slit*/
	    if (strncmp((p_all_par+ii)->name,"taues",5)==0) {
	      aname[jj]=ii;
	      abest[jj]=p_xs_3->taues/DEG2RAD;
	      amin[jj]=p_xs_3->taues/DEG2RAD-(0.05*ann_fac);
	      amax[jj]=p_xs_3->taues/DEG2RAD+(0.15*ann_fac);
	      jj+=1;
	    }
	    /*fcol is the focal length of the collimator.*/
	    if (strncmp((p_all_par+ii)->name,"fcol",4)==0) {
	      abest[jj]=p_xs_3->fcol;
	      amin[jj]=p_xs_3->fcol-(1.0*ann_fac);
	      amax[jj]=p_xs_3->fcol+(1.5*ann_fac);
	      aname[jj]=ii;
	      jj+=1;
	    }
	  }
	}
	if (scenario==9) {
	  /*scenario for NIR AFC*/
	  if (p_xs_3->arm!=2) {
	    cpl_msg_error(__func__,"This scenario is only valid for NIR AFC exposures");
	    return NULL;
	  }
	  if (strncmp((p_all_par+ii)->name,"mug",3)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->mug/DEG2RAD;
	    amin[jj]=p_xs_3->mug/DEG2RAD-(0.02*ann_fac);
	    amax[jj]=p_xs_3->mug/DEG2RAD+(0.02*ann_fac);
	    jj+=1;
	  }
	  /*[mu/nu/tau]g describe the orientation of the grating*/
	  if (strncmp((p_all_par+ii)->name,"nug",3)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->nug/DEG2RAD;
	    amin[jj]=p_xs_3->nug/DEG2RAD-(0.02*ann_fac);
	    amax[jj]=p_xs_3->nug/DEG2RAD+(0.02*ann_fac);
	    jj+=1;
	  }
	  /*fdet is the focal length of the camera*/
	  if (strncmp((p_all_par+ii)->name,"fdet",4)==0) {
	    abest[jj]=p_xs_3->fdet;
	    amin[jj]=p_xs_3->fdet-(0.4*ann_fac);
	    amax[jj]=p_xs_3->fdet+(0.4*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"taud",4)==0) {
	    aname[jj]=ii;
	    abest[jj]=p_xs_3->taud/DEG2RAD;
	    amin[jj]=p_xs_3->taud/DEG2RAD-(0.025*ann_fac);
	    amax[jj]=p_xs_3->taud/DEG2RAD+(0.025*ann_fac);
	    jj+=1;
	  }
	  /* chip[x/y] is the offset of the detector in the focal plane*/
	  if (strncmp((p_all_par+ii)->name,"chipx",5)==0) {
	    abest[jj]=p_xs_3->chipx;
	    amin[jj]=p_xs_3->chipx-(0.1*ann_fac);
	    amax[jj]=p_xs_3->chipx+(0.1*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	  if (strncmp((p_all_par+ii)->name,"chipy",5)==0) {
	    abest[jj]=p_xs_3->chipy;
	    amin[jj]=p_xs_3->chipy-(0.1*ann_fac);
	    amax[jj]=p_xs_3->chipy+(0.1*ann_fac);
	    aname[jj]=ii;
	    jj+=1;
	  }
	}
      }
      adim=jj;
    }
  } /*End of setting the automatic open params and ranges*/
  else {
    if (adim==0) {
      cpl_msg_error(__func__,"The use of the phys mod config file optimisation flags and ranges was specified, however the input phys mod config has no optimisation flags set");
      return NULL;
    }
  }
  check( resid_tab = xsh_resid_tab_load(resid_frame));
  resid_header = resid_tab->header;
  check( size = xsh_resid_tab_get_size( resid_tab ) ) ;
  xsh_msg ( "   Resid Table Size: %d", size ) ;
  XSH_CALLOC( msp_coord, coord, size);

  /*Get the wavelengths, orders and slit positions matched with the
    measured x,y positions from the resid tab*/
  check( vlambda = xsh_resid_tab_get_lambda_data( resid_tab));
  check( vorder = xsh_resid_tab_get_order_data( resid_tab ));
  check( slitindex = xsh_resid_tab_get_slit_index( resid_tab));
  check( thpre_x = xsh_resid_tab_get_thpre_x_data( resid_tab ));
  check( thpre_y = xsh_resid_tab_get_thpre_y_data( resid_tab ));
  check( xgauss = xsh_resid_tab_get_xgauss_data( resid_tab ));
  check( ygauss = xsh_resid_tab_get_ygauss_data( resid_tab ));

  /*Compute density of calibration features in wavelength bins or
    per order*/
  if (p_xs_3->arm==0) {
    wav_den_bin_sz=25.0;
  }
  else if (p_xs_3->arm==1) {
    wav_den_bin_sz=50.0;
  }
  else {
    wav_den_bin_sz=125.0;
  }
  for (kk=0;kk<40;kk+=1) {
    wav_den[kk]=0;
  }
  for (kk=0;kk<size;kk+=1){
    if (vlambda[kk]>0.0) {
      wav_den[(int)(vorder[kk])]+=1;
    }
    //wav_den[(int)((vlambda[kk])/wav_den_bin_sz)]+=1;
  }

  kk=0;
  for (jj=0;jj<size;jj+=1){
    //xsh_msg("To be matched X=%f Y=%f",*(thpre_x+jj),*(thpre_y+jj));
    msp_coord[kk].wave=*(vlambda+jj);
    msp_coord[kk].x= *(xgauss+jj) ;
    //msp_coord[kk].flux=100.0; /* No flux weighting in optimisation*/
    /*weight inversely to the density of lines*/
    //msp_coord[kk].flux=10000.0/
    //(float)(wav_den[(int)((vlambda[jj])/wav_den_bin_sz)]);
    /* weight inversely to the order density of lines*/
    msp_coord[kk].flux=10000.0/(float)(wav_den[(int)(vorder[jj])]);
    msp_coord[kk].order=(int)(*(vorder+jj));
    msp_coord[kk].y= *(ygauss+jj);
    msp_coord[kk].slit_pos=slitindex[jj];
    msp_coord[kk].counter=jj;
    msp_coord[kk].arm=p_xs_3->arm;
    //printf("slit %d, wvlen %lf, x %lf , y %lf \n",msp_coord[kk].slit_pos,msp_coord[kk].wave,msp_coord[kk].x,msp_coord[kk].y);
    kk+=1;
  }

  /*Set up the refractive index information required for the arm*/
  ref_ind=xsh_alloc2Darray(8,7);
  if (p_xs_3->arm==0) {
    xsh_ref_ind_read(0,ref_ind,p_xs_3->temper);
  }
  else if (p_xs_3->arm==1) {
    xsh_ref_ind_read(1,ref_ind,p_xs_3->temper);
  }
  else if (p_xs_3->arm==2) {
    xsh_ref_ind_read(2,ref_ind,p_xs_3->t_ir_p2);
  }
  else {
    printf("Arm not set. \n");
    return NULL;
  }

  xsh_3_init(p_xs_3);

  /* now allocate memory for the data wavelength structure and fill*/
  p_wlarray=xsh_alloc1Darray(size);
  for(ii=0;ii<size;ii++) {
    p_wlarray[ii]=msp_coord[ii].wave*1e-6;
 }

#ifdef DEBUG
  printf ("Before anneal: \n");
  for (ii=0;ii<adim;ii++) {
    printf("%d %s %lf \n", aname[ii], (p_all_par+aname[ii])->name, abest[ii]);
  }

  //xsh_showmatrix(p_xs_3->e_slit);
  /*Call the model kernel with the initial values*/
  for (jj=0;jj<size;jj++) {
    int morder_cnt=msp_coord[jj].order;
    p_xs_3->es_y_tot=p_xs_3->es_y+p_xs_3->slit[msp_coord[jj].slit_pos]*p_xs_3->slit_scale;
    xsh_3_init(p_xs_3);
    //xsh_model_io_output_cfg_txt(p_xs_3);
    xsh_3_eval(p_wlarray[jj],morder_cnt,ref_ind,p_xs_3);
    xsh_3_detpix(p_xs_3);
    printf("check %d %lf %lf %d %d %lf %lf %lf %lf %d %lf %lf \n",
	   jj,p_wlarray[jj],p_xs_3->es_y_tot,p_xs_3->chippix[0],
	   msp_coord[jj].arm,p_xs_3->xpospix,p_xs_3->ypospix,
	   msp_coord[jj].x-p_xs_3->xpospix,msp_coord[jj].y-p_xs_3->ypospix,
	   msp_coord[jj].order,  p_xs_3->xdet, p_xs_3->ydet);
  }
#endif
  /*Call the main anneal algorithm in xsh_model_metric.c*/
  MODEL_CONFIG_plist=cpl_propertylist_new();
  check(xsh_model_compute_residuals(p_xs_3,msp_coord,p_wlarray,ref_ind,size,0,
                                    resid_header,resid_frame,
                                    &MODEL_CONFIG_plist));

  if ((conf_tab = xsh_model_anneal_comp(p_all_par,
					adim,
					abest,
					amin,
					amax,
					aname,
					p_xs_3,
					size,
					msp_coord,
					p_wlarray,
					ref_ind,
					maxit)) == NULL) {
      xsh_free2Darray(ref_ind,8);
      cpl_free(p_wlarray);
      return NULL ;   
  }
  //AModigliani: added dumping of final model results
  check(xsh_model_compute_residuals(p_xs_3,msp_coord,p_wlarray,ref_ind,size,1,
                                    resid_header,resid_frame,
                                    &MODEL_CONFIG_plist));
  //cpl_propertylist_dump(MODEL_CONFIG_plist,stdout);
  check(tag=xsh_get_tag_opt_mod_cfg(p_xs_3,rec_id));

  //sprintf(out_cfg_filename,"new_%s",cpl_frame_get_filename(cfg_frame));
  sprintf(out_cfg_filename,"%s.fits",tag);

  xsh_msg_dbg_medium("Save the table") ;
  xsh_msg_dbg_medium("out file=%s",out_cfg_filename);

  check(xsh_pfits_set_pcatg(MODEL_CONFIG_plist, tag ) ) ;

  check(cpl_table_save(conf_tab, MODEL_CONFIG_plist, NULL, out_cfg_filename, CPL_IO_DEFAULT));


  check(MODEL_CONF_OPT_frame=xsh_frame_product(out_cfg_filename,
				 tag,
				 CPL_FRAME_TYPE_TABLE,
				 CPL_FRAME_GROUP_PRODUCT,
				 CPL_FRAME_LEVEL_FINAL));
  xsh_msg_dbg_medium("optimised model parameter table %s %s", cpl_frame_get_filename(MODEL_CONF_OPT_frame),cpl_frame_get_tag(MODEL_CONF_OPT_frame)); 

  cleanup:

    xsh_free_table(&resid_tbl);
    xsh_free_table(&conf_tab);
    xsh_resid_tab_free(&resid_tab);
    if ( cpl_error_get_code() != CPL_ERROR_NONE){
      xsh_free_frame( &MODEL_CONF_OPT_frame);
    }
    XSH_FREE( msp_coord);
    XSH_FREE( p_wlarray);
    xsh_free_propertylist( &MODEL_CONFIG_plist);

    if (ref_ind!=NULL){
      xsh_free2Darray(ref_ind,8);
    } 
    return MODEL_CONF_OPT_frame;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Open a parameter in the model config structure for annealing and
            set the limits.
  @param    listname      (char)
  @param    findname      (char)
  @param    ref           (int*)
  @param    setref        (int)
  @param    best          (double*)
  @param    setbest       (doublle
  @param    min           (double*)
  @param    max           (double*)
  @param    gfac           (double)
  @param    fac           (double)
  @param    counter       (int)
  @return   counter       (int)
 */
/*----------------------------------------------------------------------------*/
int xsh_model_open_param(char * listname,
			 char * findname,
			 int * ref,
			 int setref,
			 double * best,
			 double setbest,
			 double * min,
			 double * max,
			 double gfac,
			 double fac,
			 int counter)
{
  if (strncmp(listname,findname,strlen(findname))==0) {
    *ref=setref;
    *best=setbest;
    *min=setbest-(fac*gfac);
    *max=setbest=(fac*gfac);
    counter++;
  }
   return counter; 
 } 
/*----------------------------------------------------------------------------*/
/**
  @brief    Get the refractive index for a given temperature and wavelength
            from the (hard coded) extended Sellmeier co-efficients for infrasil
	    (NIR) and Silica (UVB)
  @param    arm              ram selector
  @param    temper           Temperature of Infrasil prism in K (double)
  @param    lam_sqr          Square of wavelength in um (double)
  @return   sqrt(ref_ind)    Refractive index (double)
 */
/*----------------------------------------------------------------------------*/

double xsh_model_sellmeier_ext(int arm, double temper, double lam_sqr)
{
  typedef DOUBLE sellmeier_mat[3][5];
  int ii, jj;
  double ref_ind,top,bottom;
  double T[5];
  sellmeier_mat S_UVB={{1.10127,     -4.94251E-05, 5.27414E-07,  -1.59700E-09, 1.75949E-12},
		       {1.78752E-05, 4.76391E-05,  -4.49019E-07, 1.44546E-09,  -1.57223E-12},
		       {0.793552,    -1.27815E-03, 1.84595E-05,  -9.20275E-08, 1.48829E-10}};
  sellmeier_mat L_UVB={{-0.08906,    9.08730E-06,  -6.53638E-08, 7.77072E-11,  6.84605E-14},
		       {0.297562,    -859578E-04,  6.59069E-06,  -1.09482E-08, 7.85145E-13},
		       {9.34454,     -7.09788E-03, 1.01968E-04,  -5.07660E-07, 8.21348E-10}};

  sellmeier_mat S_NIR={{0.104940144,5.40E-06,3.23E-08,1.83E-13,-3.60E-14},
		   {0.996335571,-3.29E-06,1.48E-08,-3.01E-11,4.99E-14},
		   {0.832484961,6.38E-04,-2.40E-06,6.10E-10,4.77E-12}};
  sellmeier_mat L_NIR={{-3.07E-03,-2.56E-05,6.21E-07,-2.54E-09,2.88E-12},
		   {9.40E-02,-1.59E-06,1.28E-08,1.82E-12,-3.01E-14},
		   {9.598633568,3.15E-03,-1.22E-05,5.48E-09,1.96E-11}};
  T[0]=1.0;
  T[1]=temper;
  T[2]=temper*temper;
  T[3]=T[2]*temper;
  T[4]=T[3]*temper;
  ref_ind=1.0;
  if (arm==0) {
    for (ii=0;ii<3;ii++) {
      top=bottom=0.0;
      for (jj=0;jj<5;jj++) {
	top+=S_UVB[ii][jj]*T[jj];
	bottom+=L_UVB[ii][jj]*T[jj];
      }
      ref_ind+=(top*lam_sqr)/(lam_sqr-(bottom*bottom));
    }
  }
  else if (arm==2) {
    for (ii=0;ii<3;ii++) {
      top=bottom=0.0;
      for (jj=0;jj<5;jj++) {
	top+=S_NIR[ii][jj]*T[jj];
	bottom+=L_NIR[ii][jj]*T[jj];
      }
      ref_ind+=(top*lam_sqr)/(lam_sqr-(bottom*bottom));
    }
  }
  return sqrt(ref_ind);
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Return the refractive index of air at a given wavelength and
            temperature
  @param    temper      the temperature (deg K)
  @param    lam_sqr     wavelength in micron, squared
  @return   refractive index of air
All constants from Schott document TIE-19, Jul 2008 pp3
 */
/*----------------------------------------------------------------------------*/
double 
xsh_model_ref_ind_air(double temper, double lam_sqr)
{
  double n288=0, n_air=0;
  n288=1.0+(6432.8+((2949810.0*lam_sqr)/(146.0*lam_sqr-1.0))+((25540.0*lam_sqr)/(41.0*lam_sqr-1.0)))*1.0E-08;
  n_air=1.0+(n288-1.0)/(1.0+0.0034785*(temper-288.0));
  return n_air;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Detect the brightest features in a spectrum
  @param    in      the spectrum (cpl_vector)
  @param    fwhm    the FWHM used for the lines convolution in pixels (int)
  @param    sigma   No. of standard deviation for detection (double)
  @param    display the flag to display (int)
  @return   The bright lines positions or NULL in error case
 */
/*----------------------------------------------------------------------------*/
cpl_vector * 
xsh_model_refining_detect(
        const cpl_vector    *   in,
        int                     fwhm,
        double                  sigma,
        int                     display)
{
    cpl_vector      *   filtered =NULL;
    cpl_vector      *   spec_clean =NULL;
    double          *   pspec_clean =NULL;
    int                 filt_size =0;
    cpl_vector      *   conv_kernel =NULL;
    cpl_vector      *   big_detected =NULL;
    double          *   pbig_detected =NULL;
    cpl_vector      *   detected =NULL;
    double          *   pdetected =NULL;
    double              max=0, med=0, stdev=0, cur_val=0 ;
    int                 nb_det=0, nb_samples=0 ;
    int                 i=0;
    int                 j=0;

    /* Test entries */
    if (in == NULL) return NULL ;


    /* Initialise */
    check(nb_samples = cpl_vector_get_size(in)) ;
    filt_size = 50 ;

    /* Subrtract the low frequency part */
    //cpl_msg_info(__func__, "Low Frequency signal removal") ;
    if ((filtered=cpl_vector_filter_median_create(in, filt_size))==NULL){
        cpl_msg_error(__func__, "Cannot filter the spectrum") ;
        return NULL ;
    }
    spec_clean = cpl_vector_duplicate(in) ;
    cpl_vector_subtract(spec_clean, filtered) ;
    cpl_vector_delete(filtered) ;

    /* Display if requested */
    if (display) {
        cpl_plot_vector(
    "set grid;set xlabel 'Position (pixels)';set ylabel 'Intensity (ADU)';",
        "t 'Filtered extracted spectrum' w lines", "", spec_clean);
    }

    /* Convolve */
    //cpl_msg_info(__func__, "Spectrum convolution") ;
    /* Create convolution kernel */
    if ((conv_kernel = cpl_wlcalib_xc_convolve_create_kernel(fwhm,
                    fwhm)) == NULL) {
        cpl_msg_error(cpl_func, "Cannot create convolution kernel") ;
        cpl_vector_delete(spec_clean) ;
        return NULL ;
    }

    /* Smooth the instrument resolution */
    if (cpl_wlcalib_xc_convolve(spec_clean, conv_kernel)) {
        cpl_msg_error(cpl_func, "Cannot smoothe the signal");
        cpl_vector_delete(spec_clean) ;
        cpl_vector_delete(conv_kernel) ;
        return NULL ;
    }
    cpl_vector_delete(conv_kernel) ;

    /* Display if requested */
    if (display) {
        cpl_plot_vector(
        "set grid;set xlabel 'Position (pixels)';set ylabel 'Intensity (ADU)';",
        "t 'Convolved extracted spectrum' w lines", "", spec_clean);
    }

    /* Apply the detection */
    big_detected = cpl_vector_duplicate(spec_clean) ;
    pbig_detected = cpl_vector_get_data(big_detected) ;
    pspec_clean = cpl_vector_get_data(spec_clean) ;

    /* To avoid detection on the side */
    pspec_clean[0] = pspec_clean[nb_samples-1] = 0.0 ;

    /* Compute stats */
    max     =   cpl_vector_get_max(spec_clean) ;
    stdev   =   cpl_vector_get_stdev(spec_clean) ;
    med     =   cpl_vector_get_median_const(spec_clean) ;

    /* Loop on the detected lines */
    nb_det = 0 ;
    while (max > med + stdev * sigma) {
        /* Compute the position */
        i=0 ;
        while (pspec_clean[i] < max) i++ ;
        if (i<=0 || i>=nb_samples-1) break ;

        /* Store the detected line */
        pbig_detected[nb_det] = (pspec_clean[i]*i +
                pspec_clean[i-1]*(i-1) + pspec_clean[i+1]*(i+1)) /
            (pspec_clean[i]+pspec_clean[i-1]+pspec_clean[i+1]);
        /* Position = index + 1 */

        pbig_detected[nb_det] ++ ;
        //cpl_msg_info(__func__, "Line nb %d at position %g", 
	//nb_det+1, pbig_detected[nb_det]) ;
        nb_det ++ ;

        /* Cancel out the line on the left */
        j = i-1 ;
        cur_val = pspec_clean[i] ;
        while (j>=0 && pspec_clean[j] < cur_val) {
            cur_val = pspec_clean[j] ;
            pspec_clean[j] = 0.0 ;
            j-- ;
        }
        /* Cancel out the line on the right */
        j = i+1 ;
        cur_val = pspec_clean[i] ;
        while (j<=nb_samples-1 && pspec_clean[j] < cur_val) {
            cur_val = pspec_clean[j] ;
            pspec_clean[j] = 0.0 ;
            j++ ;
        }
        /* Cancel out the line on center */
        pspec_clean[i] = 0.0 ;

        /* Recompute the stats */
        max     =   cpl_vector_get_max(spec_clean) ;
        stdev   =   cpl_vector_get_stdev(spec_clean) ;
        med     =   cpl_vector_get_median_const(spec_clean) ;
    }
    cpl_vector_delete(spec_clean) ;

    /* Create the output vector */
    if (nb_det == 0) {
        detected = NULL ;
    } else {
        detected = cpl_vector_new(nb_det) ;
        pdetected = cpl_vector_get_data(detected) ;
        pbig_detected = cpl_vector_get_data(big_detected) ;
        for (i=0 ; i<nb_det ; i++) pdetected[i] = pbig_detected[i] ;
    }
    cpl_vector_delete(big_detected) ;

 cleanup:
    if(cpl_error_get_code() != CPL_ERROR_NONE) {
      xsh_print_rec_status(0);
    }
    /* Return  */
    return detected ;
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Interpret the command line options and execute the data processing
   @param    parlist     the parameters list
   @param    frameset   the frames list
   @return   0 if everything is ok
*/
/*---------------------------------------------------------------------------*/
int 
xsh_model_first_anneal(cpl_parameterlist* parlist, cpl_frameset* frameset)
{
   cpl_frame*   xs_config =NULL;
   cpl_frame*   meas_coord =NULL;
   cpl_parameter* param=NULL;
   xsh_instrument* instrument = NULL;
   const char* arm=NULL;
   int nraw=0;
   int nrows=0;

  cpl_table *   conf_tab = NULL;
  int ii=0, jj=0;

  int sizearraywavelengths=0, adim=0;

  struct xs_3 xs_model, *p_xs_3;
  ann_all_par all_par[300], *p_all_par;
  double abest[300];
  double amin[300];
  double amax[300];
  int aname[300];
  int coord_switch=0;


  coord *msp_coord = NULL;
  DOUBLE ** ref_ind = NULL;
  DOUBLE *p_wlarray = NULL;
  cpl_table * meas_coord_temp=NULL;
  double ann_fac=1.0000000000001;

  int MAXIT=10;

  FILE* file_list=NULL;
  int cnt=0;
  double* pw=NULL;
  double* px=NULL;
  double* py=NULL;
  int* po=NULL;
  const char * name_i=NULL ;
  float wave=0;
  float x=0;
  float y=0;
  int ord=0;

  if( (nraw=cpl_frameset_get_size(frameset)) ==0) goto cleanup;

  param = cpl_parameterlist_find(parlist,"xsh.xsh_model_compute.arm");
  arm = cpl_parameter_get_string(param);
  xsh_msg("User selected arm '%s'. Recipe expects '%s' input data",arm,arm);

  param = cpl_parameterlist_find(parlist,"xsh.xsh_model_compute.niter");
  MAXIT = cpl_parameter_get_int(param);

  coord_switch = cpl_parameter_get_int(cpl_parameterlist_find(parlist,"xsh.xsh_model_compute.coord_frame"));

  if (arm==NULL) {
     xsh_msg_error("arm parameter value not set. exit!");
     goto cleanup; 
  }

  instrument=xsh_instrument_new();
  if(strcmp(arm,"uvb") == 0) xsh_instrument_set_arm(instrument,XSH_ARM_UVB);
  if(strcmp(arm,"vis") == 0) xsh_instrument_set_arm(instrument,XSH_ARM_VIS);
  if(strcmp(arm,"nir") == 0) xsh_instrument_set_arm(instrument,XSH_ARM_NIR);




  /* Retrieve calibration data */
  if((xs_config  = 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;
  }

  if((meas_coord = xsh_find_frame_with_tag(frameset,XSH_MEASCOORD,
                                          instrument))==NULL) {
     xsh_msg_warning("Frame %s not found",
                   xsh_stringcat_any(XSH_MEASCOORD,
                                     xsh_instrument_arm_tostring(instrument),
                                     (void*)NULL ));
 

      check(param = cpl_parameterlist_find(parlist, 
					   "xsh.xsh_model_compute.name_i"));
      check(name_i = cpl_parameter_get_string(param));
   xsh_msg("name_i=%s",name_i);
    if ( NULL == (file_list = fopen (name_i, "r" ) ) )
      {      
	xsh_msg_error("cannot open %s\n", name_i) ;
	goto cleanup ;
      }
 
    cnt = 0 ;
    while ( fscanf( file_list, "%64g %64g %64g %64d",&wave, &x, &y, &ord ) != EOF )
      {
	cnt ++ ;
      }
    fclose(file_list);
   
    nrows= cnt;
    check(meas_coord_temp=cpl_table_new(nrows));
    check(cpl_table_new_column(meas_coord_temp,"Wavelength",CPL_TYPE_DOUBLE));
    check(cpl_table_new_column(meas_coord_temp,"x",CPL_TYPE_DOUBLE));
    check(cpl_table_new_column(meas_coord_temp,"y",CPL_TYPE_DOUBLE));
    check(cpl_table_new_column(meas_coord_temp,"ORDER",CPL_TYPE_INT));

    check(cpl_table_fill_column_window(meas_coord_temp,"Wavelength",0,nrows,-1));
    check(cpl_table_fill_column_window(meas_coord_temp,"x",0,nrows,-1));
    check(cpl_table_fill_column_window(meas_coord_temp,"y",0,nrows,-1));
    check(cpl_table_fill_column_window(meas_coord_temp,"ORDER",0,nrows,-1));

    check(pw=cpl_table_get_data_double(meas_coord_temp,"Wavelength"));
    check(px=cpl_table_get_data_double(meas_coord_temp,"x"));
    check(py=cpl_table_get_data_double(meas_coord_temp,"y"));
    check(po=cpl_table_get_data_int(meas_coord_temp,"ORDER"));

    if ( NULL == (file_list = fopen (name_i, "r" ) ) )
      {      
	xsh_msg_error("cannot open %s\n", name_i) ;
	goto cleanup ;
      }

    cnt=0;
    while ( fscanf( file_list, "%64g %64g %64g %64d",&wave, &x, &y, &ord ) != EOF )
      {
         pw[cnt]=wave;
        px[cnt]=x;
        py[cnt]=y;
        po[cnt]=ord;

	cnt ++ ;
      }

    fclose(file_list);
    check(cpl_table_save(meas_coord_temp, NULL, NULL,"lin_xy_hand.fits",
			 CPL_IO_DEFAULT));


    check(meas_coord=xsh_frame_product("lin_xy_hand.fits",
                                       "LIN_XY_HAND",
				       CPL_FRAME_TYPE_TABLE,
				       CPL_FRAME_GROUP_CALIB,
				       CPL_FRAME_LEVEL_TEMPORARY));


  }

 
  /* Apply the computation here */
  p_xs_3=&xs_model;
  p_all_par=&all_par[0];

  cknull_msg(meas_coord_temp=cpl_table_load(cpl_frame_get_filename(meas_coord),1,0),"Cannot load table %s",cpl_frame_get_filename(meas_coord));
  check(sizearraywavelengths=cpl_table_get_nrow(meas_coord_temp));
  XSH_CALLOC(msp_coord, coord, sizearraywavelengths+5);

  adim=xsh_model_readfits(abest,
                          amin,
                          amax,
                          aname,
                          cpl_frame_get_filename(xs_config),
                          cpl_frame_get_tag(xs_config),
                          p_xs_3,
                          p_all_par);

  if (adim==0) {

    for (ii=0;ii<300;ii++) {
      aname[ii]=-1;
      abest[ii]=0.0;
      amin[ii]=0.0;
      amax[ii]=0.0;
    }
    /*modify parameters for optimisation*/
    /*discover their indices and make the link with aname*/
    jj=0;
    for (ii=0;ii<100;ii++) {
      /* ann_fac allows the tolerances on all open parameters to be scaled*/
      /*[mu/nu]p1 are the tip and tilt of the entrance surface (and hence
	the whole prism) of the first prism*/
      if (strncmp((p_all_par+ii)->name,"temper",6)==0) {
	aname[jj]=ii;
	abest[jj]=p_xs_3->temper;
	amin[jj]=p_xs_3->temper-(5.0*ann_fac);
	amax[jj]=p_xs_3->temper+(5.0*ann_fac);
	jj+=1;
      }
      if (strncmp((p_all_par+ii)->name,"fcol",4)==0) {
	aname[jj]=ii;
	abest[jj]=p_xs_3->fcol;
	amin[jj]=p_xs_3->fcol-(5.0*ann_fac);
	amax[jj]=p_xs_3->fcol+(5.0*ann_fac);
	jj+=1;
      }
      if (strncmp((p_all_par+ii)->name,"mup1",4)==0) {
	aname[jj]=ii;
	abest[jj]=p_xs_3->mup1/DEG2RAD;
	amin[jj]=p_xs_3->mup1/DEG2RAD-(5.0*ann_fac);
	amax[jj]=p_xs_3->mup1/DEG2RAD+(5.0*ann_fac);
	jj+=1;
      }
      if (strncmp((p_all_par+ii)->name,"nup1",4)==0) {
	aname[jj]=ii;
	abest[jj]=p_xs_3->nup1/DEG2RAD;
	amin[jj]=p_xs_3->nup1/DEG2RAD-(5.0*ann_fac);
	amax[jj]=p_xs_3->nup1/DEG2RAD+(5.0*ann_fac);
	jj+=1;
      }

      if (p_xs_3->arm==2) {
	/*[mu/nu]p3 are the tip and tilt of the entrance surface (and hence
	  the whole prism) of the second prism*/
	if (strncmp((p_all_par+ii)->name,"cmup1",5)==0) {
	  aname[jj]=ii;
	  abest[jj]=p_xs_3->cmup1/DEG2RAD;
	  amin[jj]=p_xs_3->cmup1/DEG2RAD-(5.0*ann_fac);
	  amax[jj]=p_xs_3->cmup1/DEG2RAD+(5.0*ann_fac);
	  jj+=1;
	}
	if (strncmp((p_all_par+ii)->name,"mup3",4)==0) {
	  aname[jj]=ii;
	  abest[jj]=p_xs_3->mup3/DEG2RAD;
	  amin[jj]=p_xs_3->mup3/DEG2RAD-(5.0*ann_fac);
	  amax[jj]=p_xs_3->mup3/DEG2RAD+(5.0*ann_fac);
	  jj+=1;
	}
	if (strncmp((p_all_par+ii)->name,"nup3",4)==0) {
	  aname[jj]=ii;
	  abest[jj]=p_xs_3->nup3/DEG2RAD;
	  amin[jj]=p_xs_3->nup3/DEG2RAD-(5.0*ann_fac);
	  amax[jj]=p_xs_3->nup3/DEG2RAD+(5.0*ann_fac);
	  jj+=1;
	}
	/*[mu/nu]p5 are the tip and tilt of the entrance surface (and hence
	  the whole prism) of the third prism*/
	if (strncmp((p_all_par+ii)->name,"mup5",4)==0) {
	  aname[jj]=ii;
	  abest[jj]=p_xs_3->mup5/DEG2RAD;
	  amin[jj]=p_xs_3->mup5/DEG2RAD-(5.0*ann_fac);
	  amax[jj]=p_xs_3->mup5/DEG2RAD+(5.0*ann_fac);
	  jj+=1;
	}
	if (strncmp((p_all_par+ii)->name,"nup5",4)==0) {
	  aname[jj]=ii;
	  abest[jj]=p_xs_3->nup5/DEG2RAD;
	  amin[jj]=p_xs_3->nup5/DEG2RAD-(5.0*ann_fac);
	  amax[jj]=p_xs_3->nup5/DEG2RAD+(5.0*ann_fac);
	  jj+=1;
	}
      }

      /*[mu/nu]g describe the orientation of the grating*/
      if (strncmp((p_all_par+ii)->name,"mug",3)==0) {
	aname[jj]=ii;
	abest[jj]=p_xs_3->mug/DEG2RAD;
	amin[jj]=p_xs_3->mug/DEG2RAD-(5.0*ann_fac);
	amax[jj]=p_xs_3->mug/DEG2RAD+(5.0*ann_fac);
	jj+=1;
      }
      if (strncmp((p_all_par+ii)->name,"nug",3)==0) {
	aname[jj]=ii;
	abest[jj]=p_xs_3->nug/DEG2RAD;
	amin[jj]=p_xs_3->nug/DEG2RAD-(5.0*ann_fac);
	amax[jj]=p_xs_3->nug/DEG2RAD+(5.0*ann_fac);
	jj+=1;
      }
      /*taud is the rotation of the detector*/
      if (strncmp((p_all_par+ii)->name,"taud",4)==0) {
	aname[jj]=ii;
	abest[jj]=p_xs_3->taud/DEG2RAD;
	amin[jj]=p_xs_3->taud/DEG2RAD-(5.0*ann_fac);
	amax[jj]=p_xs_3->taud/DEG2RAD+(5.0*ann_fac);
	jj+=1;
      }
      /*fdet is the focal length of the camera*/
      if (strncmp((p_all_par+ii)->name,"fdet",4)==0) {
	abest[jj]=p_xs_3->fdet;
	amin[jj]=p_xs_3->fdet-(10.0*ann_fac);
	amax[jj]=p_xs_3->fdet+(10.0*ann_fac);
	aname[jj]=ii;
	jj+=1;
      }

      /* chip[x/y] is the offset of the detector in the focal plane*/
      if (strncmp((p_all_par+ii)->name,"chipx",5)==0) {
	abest[jj]=p_xs_3->chipx;
	amin[jj]=p_xs_3->chipx-(15.0*ann_fac);
	amax[jj]=p_xs_3->chipx+(15.0*ann_fac);
	aname[jj]=ii;
	jj+=1;
      }
      if (strncmp((p_all_par+ii)->name,"chipy",5)==0) {
	abest[jj]=p_xs_3->chipy;
	amin[jj]=p_xs_3->chipy-(15.0*ann_fac);
	amax[jj]=p_xs_3->chipy+(15.0*ann_fac);
	aname[jj]=ii;
	jj+=1;
      }
      /* sg is the grating constant*/
      if (strncmp((p_all_par+ii)->name,"sg",2)==0) {
	abest[jj]=p_xs_3->sg;
	amin[jj]=p_xs_3->sg-(1.0*ann_fac);
	amax[jj]=p_xs_3->sg+(1.0*ann_fac);
	aname[jj]=ii;
	jj+=1;
      }
    }
    adim=jj;
  }

  ref_ind=xsh_alloc2Darray(8,7);

   if (p_xs_3->arm==0) { 
     xsh_ref_ind_read(0,ref_ind,p_xs_3->temper); 
   } 
   else if (p_xs_3->arm==1) { 
     xsh_ref_ind_read(1,ref_ind,p_xs_3->temper); 
   } 
   else if (p_xs_3->arm==2) { 
     xsh_ref_ind_read(2,ref_ind,p_xs_3->t_ir_p2); 
   } 
   else { 
     printf("Arm not set. \n"); 
     return 1; 
   } 

  /*We now need to update several matrices (that were set in the
    xsh_3_init routine outside of the current loop) for this prism angle */
  xsh_3_init(p_xs_3);

  /* now allocate memory for the data structure*/
  p_wlarray=xsh_alloc1Darray(sizearraywavelengths);
  for (ii=0; ii<sizearraywavelengths; ii++) {
    msp_coord[ii].counter=ii;
    if (coord_switch==1) {
      msp_coord[ii].x=cpl_table_get_double(meas_coord_temp,"x",ii,NULL);
      msp_coord[ii].y=cpl_table_get_double(meas_coord_temp,"y",ii,NULL);
    }
    else {
      /*if raw co-ordinates were used then the transformation from RAW to PRE,
	appropriate to the arm, needs to be applied*/
      if (p_xs_3->arm==0) {
	msp_coord[ii].x=2097-cpl_table_get_double(meas_coord_temp,"x",ii,NULL);
	msp_coord[ii].y=3001-cpl_table_get_double(meas_coord_temp,"y",ii,NULL);
      }      
      if (p_xs_3->arm==1) {
	msp_coord[ii].x=-10.0+cpl_table_get_double(meas_coord_temp,"x",ii,NULL);
	msp_coord[ii].y=0.0+cpl_table_get_double(meas_coord_temp,"y",ii,NULL);
      }      
      if (p_xs_3->arm==2) {
	msp_coord[ii].x=-20.0+cpl_table_get_double(meas_coord_temp,"y",ii,NULL);
	msp_coord[ii].y=2045.0-cpl_table_get_double(meas_coord_temp,"x",ii,NULL);
	printf("%lf %lf \n",msp_coord[ii].x,msp_coord[ii].y);
      }      
    }
    msp_coord[ii].arm=p_xs_3->arm;
    msp_coord[ii].flux=100.0;
    msp_coord[ii].slit_pos=4;
    msp_coord[ii].wave=cpl_table_get_double(meas_coord_temp,"Wavelength",ii,NULL);
    msp_coord[ii].order=cpl_table_get_int(meas_coord_temp,"ORDER",ii,NULL);
    p_wlarray[ii]=msp_coord[ii].wave*1e-6;
  }
  xsh_free_table(&meas_coord_temp);

#ifdef DEBUG 
  printf ("Before anneal: \n");
  for (ii=0;ii<adim;ii++) {
    printf("%d %s %lf \n", aname[ii], (p_all_par+aname[ii])->name, abest[ii]);
  }

  xsh_showmatrix(p_xs_3->e_slit);
  /*Call the model kernel with the initial values*/

  for (jj=0;jj<sizearraywavelengths;jj++) {
    int morder=msp_coord[jj].order;
    p_xs_3->es_y_tot=p_xs_3->es_y+p_xs_3->slit[msp_coord[jj].slit_pos]*p_xs_3->slit_scale;
    xsh_3_init(p_xs_3);
    xsh_3_eval(p_wlarray[jj],morder,ref_ind,p_xs_3);
    xsh_3_detpix(p_xs_3);
    printf("check %d %lf %lf %d %d %lf %lf %lf %lf %d\n",
	   jj,p_wlarray[jj],p_xs_3->es_y_tot,p_xs_3->chippix[0],
	   msp_coord[jj].arm,p_xs_3->xpospix,p_xs_3->ypospix,
	   msp_coord[jj].x-p_xs_3->xpospix,msp_coord[jj].y-p_xs_3->ypospix,
	   msp_coord[jj].order);
  }
#endif

  /*Call the main anneal algorithm in crires_model_metric.c*/
  conf_tab = xsh_model_anneal_comp( p_all_par,
					adim,
					abest,
					amin,
					amax,
					aname,
					p_xs_3,
					sizearraywavelengths,
					msp_coord,
					p_wlarray,
					ref_ind,
					MAXIT);

   /* Save the result */
   cpl_msg_info(__func__, "Save the products") ;
   cpl_msg_indent_more() ;
   if (xsh_model_first_anneal_save((const cpl_table*)conf_tab, instrument, 
                                   parlist,frameset) == -1) {
      cpl_msg_error(__func__, "Cannot save products") ;
      cpl_msg_indent_less() ;
      xsh_free_table(&conf_tab) ;
      return -1 ;
   }
   xsh_free_table(&conf_tab) ;
   cpl_msg_indent_less() ;
  goto cleanup;

  cleanup:
   xsh_instrument_free(&instrument);
   if(ref_ind!=NULL) xsh_free2Darray(ref_ind,8);
   cpl_free(p_wlarray);
   xsh_free_table(&conf_tab) ;

   /* Return */
   if (cpl_error_get_code()) 
      return -1 ;
   else 
      return 0 ;
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Save the product of the recipe
   @param    out_table   the table 
   @param    instr       instrument arm setting 
   @param    parlist     the input list of parameters
   @param    set         the input frame set
   @return   0 if everything is ok, -1 otherwise
*/
/*---------------------------------------------------------------------------*/
int 
xsh_model_first_anneal_save(
			    const cpl_table*   out_table,
			    xsh_instrument* instr,
			    cpl_parameterlist*   parlist,
			    cpl_frameset*   set)
{
   char                    name_o[512] ;
   cpl_propertylist*   plist=NULL ;
   cpl_frame*   product_frame=NULL ;
   cpl_frameset* raws=NULL;
   cpl_frame* ref_frame=NULL;

   const char* pro_catg=xsh_get_tag_from_arm(XSH_MOD_CFG_FAN,instr);
   /* Get the reference frame */
   raws=cpl_frameset_new();
   check(xsh_dfs_extract_raw_frames(set,raws));
   check(ref_frame=cpl_frameset_get_frame(raws,0));
   check(plist=cpl_propertylist_load(cpl_frame_get_filename(ref_frame),0));
   xsh_free_frameset(&raws);

   /* Set the file name */
   sprintf(name_o,"%s%s",
	   xsh_get_tag_from_arm(XSH_MOD_CFG_FAN,instr),".fits") ;

   cpl_msg_info(__func__, "Writing %s" , name_o) ;

   /* Get FITS header from reference file */
   cpl_propertylist_append_int(plist,"Num_pinh",9);


   /* Create product frame */
   check(product_frame=xsh_frame_product(name_o,pro_catg,CPL_FRAME_TYPE_TABLE,
                                         CPL_FRAME_GROUP_PRODUCT,
                                         CPL_FRAME_LEVEL_FINAL));

   if (cpl_table_save(out_table, plist, NULL, name_o,
                      CPL_IO_DEFAULT) != CPL_ERROR_NONE) {
      cpl_msg_error(__func__, "Cannot save the product");
      xsh_free_frame(&product_frame) ;
      xsh_free_propertylist(&plist) ;
      return -1 ;
   }

   check(xsh_add_product_table(product_frame,set,parlist,"xsh_startup",
				     instr,NULL));

  cleanup:
   xsh_free_propertylist(&plist) ;

   /* Return */
 if (cpl_error_get_code()) 
    return -1 ;
  else 
    return 0 ;

}
/*---------------------------------------------------------------------------*/
/**
   @brief    convert a pixel shift measured on the detector to a shift in
             detector centroid
   @param    disp_pix_shift  The shift of the slit centre in dispersion pixels
             (new position - old position)
   @param    slit_pix_shift  The shift of the slit centre in slit pixels (new 
             position - old position)
   @param    p_xs_3          The phys mod parameter structure
   @return   0 if everything is ok, -1 otherwise (result is in the updated
             p_xs_3->chipx value).
Strictly this should use the location in the detector plane and the
corresponding distortion, but this is an nth order effect...

Otherwise this reduces to simple independent chipx and chipy shifts since
for XSH (but not for eg. CRIRES) there is no rotation of the detector chip
within the detector plane.
*/
/*---------------------------------------------------------------------------*/
int 
xsh_model_offset(DOUBLE slit_pix_shift,
		 DOUBLE disp_pix_shift,
		 struct xs_3* p_xs_3)
{
  if (p_xs_3->arm!=2) {
    p_xs_3->chipy+=p_xs_3->pix_Y*slit_pix_shift;
    p_xs_3->chipx+=p_xs_3->pix_X*disp_pix_shift;
  }
  else {
    p_xs_3->chipx-=p_xs_3->pix_X*slit_pix_shift;
    p_xs_3->chipy-=p_xs_3->pix_Y*disp_pix_shift;
  }
  return 0;
}


static int 
comp_center2( const void * one, const void * two )
{
  CENTER_ORDER * first = (CENTER_ORDER *)one ;
  CENTER_ORDER * secnd = (CENTER_ORDER *)two ;

  if ( first->order < secnd->order ) return -1 ;
  else if (  first->order > secnd->order ) return 1 ;
  else return 0 ;
}

static void 
save_centers(CENTER_ORDER * pcent, int fpos, int npos, const char * arm )
{
  static FILE * fgnu = NULL, * freg = NULL ;
  static const char * gnuname =NULL ;
  int first_call =0;
  FILE *fout ;
  char fname[32] ;
  int i=0, order=0 ;
  CENTER_ORDER * ppcent=NULL ;

  if ( fgnu == NULL ) {
    gnuname = xsh_stringcat_any( "all_orders_", arm, ".gnu", (void*)NULL ) ;
    fgnu = fopen( gnuname, "w" ) ;
    fprintf( fgnu, "set term x11\nplot " ) ;
    first_call = 1 ;
  }
  else first_call = 0 ;
  ppcent = pcent + fpos ;
  order = ppcent->order ;
  sprintf( fname, "order_%s_%02d.dat", arm, order ) ;
  fout = fopen( fname, "w" ) ;

  if ( !first_call ) fprintf( fgnu, "," ) ;
  fprintf( fgnu, "'%s' u 1:2 w points pt 5 t''", fname ) ;

  for( i = fpos ; i<npos; i++, ppcent++ )
    fprintf( fout, "%d %d %.3lf\n",
	     ppcent->pos_x, ppcent->pos_y, ppcent->flux ) ;

  fclose( fout ) ;
  if ( order == 0 ) {
    fprintf( fgnu, "\n" ) ;
    fclose( fgnu ) ;
  }

  /* Now create a .reg file */
  if ( freg == NULL ) {
    freg = fopen( "order_create.reg", "w" ) ;
  }
  fprintf( freg, "# Region file format: DS9 version 4.0\n" ) ;
  fprintf( freg, "global color=red font=\"helvetica 4 normal\"select=1 highlite=1 edit=1 move=1 delete=1 include=1 fixed=0 source\n" ) ;
  fprintf( freg, "image\n# RED center_x center_y (pixels)\n" ) ;
  for( ppcent = pcent+fpos, i = fpos ; i <npos ; i++, ppcent++ ) {
    fprintf( freg, "point(%d.,%d.) #point=cross color=red font=\"helvetica 4 normal\"\n", ppcent->pos_x, ppcent->pos_y ) ;
  }
  if ( order == 0 ) {
    fclose( freg ) ;
  }
}

/**
@brief Fit edge of an order
@param[in] list structure containing order trace locations
@param[in] size size of list
@param[out] order order values
@param[out] posx  x edge position values
@param[out] posy  y edge position values
@param      deg_poly degree of polynomial to be fit to edges
@param      edge    parameter indicating edge to fit (up: -1, cen: 0, low=1)  
 */
void 
xsh_order_edge_list_fit(xsh_order_list *list, 
                        int size, 
                        double* order,
			double* posx, 
                        double* posy, 
                        int deg_poly, 
                        int edge)
{
  int ordersize=0;
  int i=0;
  int nborder=0;
  int nb_keep_order=0;
  cpl_vector *vx = NULL;
  cpl_vector *vy = NULL;
  
  XSH_ASSURE_NOT_NULL( list);
  XSH_ASSURE_NOT_NULL( order);
  XSH_ASSURE_NOT_NULL( posx);
  XSH_ASSURE_NOT_NULL( posy);
  XSH_ASSURE_NOT_ILLEGAL( deg_poly >= 0);

  xsh_msg("List size=%d",size);
  xsh_msg("Fit a polynomial of degree %d by order",deg_poly);
  xsh_msg("Search from order %d to %d", list->absorder_min, 
    list->absorder_max);
  for(i=1; i <= size; i++) {
    if ( i < size && fabs(order[i-1] - order[i] ) < 0.0001) {
      ordersize++;
    }
    else {
      int absorder = order[i-1];

      if(  (absorder >= list->absorder_min) && 
        (absorder <= list->absorder_max) ){

        ordersize++;
        check( vx = cpl_vector_wrap( ordersize, &(posx[i-ordersize])));
        check( vy = cpl_vector_wrap( ordersize, &(posy[i-ordersize])));
        xsh_msg_dbg_low("%d) absorder %lg nbpoints %d",
		      nborder+1, order[i-1],ordersize);
        XSH_ASSURE_NOT_ILLEGAL_MSG(ordersize > deg_poly,
        "You must have more points to fit correctly this order");
	if (edge==-1) {
        check( list->list[nb_keep_order].edguppoly = 
          xsh_polynomial_fit_1d_create(vy, vx, deg_poly,NULL));
	} else if (edge==0) {
        check( list->list[nb_keep_order].cenpoly = 
          xsh_polynomial_fit_1d_create(vy, vx, deg_poly,NULL));
	} else if (edge==1) {
        check( list->list[nb_keep_order].edglopoly = 
          xsh_polynomial_fit_1d_create(vy, vx, deg_poly,NULL));
	}
        list->list[nb_keep_order].order = nborder;
        list->list[nb_keep_order].absorder = (int)(order[i-1]);

        check( xsh_unwrap_vector(&vx));
        check( xsh_unwrap_vector(&vy));
        nb_keep_order++;
      }
      else{
        xsh_msg("WARNING skipping absorder %d because is not in range", 
          absorder);
      }
      nborder++;
      ordersize = 0; 
    }
  }
  XSH_ASSURE_NOT_ILLEGAL( list->size == nb_keep_order);
  cleanup:
    xsh_unwrap_vector(&vx);
    xsh_unwrap_vector(&vy);
    return;
}

static void 
fit_order_edge_list( xsh_order_list * list,
		     int npos, 
                     CENTER_ORDER * pcent, 
                     int degree, 
                     int edge)
{
  double * vorder = NULL, * po =NULL;
  double * pos_x = NULL, * px =NULL;
  double * pos_y = NULL, * py =NULL;
  int i =0;

  XSH_CALLOC( vorder, double, npos ) ;
  XSH_CALLOC( pos_x, double, npos ) ;
  XSH_CALLOC( pos_y, double, npos ) ;

  po = vorder ;
  px = pos_x ;
  py = pos_y ;
  for( i = 0 ; i<npos ; i++, po++, px++, py++, pcent++ ) {
    *po = pcent->order ;
    *px = pcent->pos_x ;
    *py = pcent->pos_y ;
  }

  xsh_order_edge_list_fit(list, npos, vorder, pos_x, pos_y, degree, edge) ;

 cleanup:
  XSH_FREE( vorder ) ;
  XSH_FREE( pos_x ) ;
  XSH_FREE( pos_y ) ;
  return ;
}


/*----------------------------------------------------------------------------*/
/**
   I have copied the method for fitting and creating the table from
   xsh_order_table_from_fmtchk.c, including variable names like res_list and
   centers that may have lost their context here.
  @brief    Create an order edges table using the phys mod
  @param    p_xs_3       Model configuration data structure
  @param   tab_filename Name of the cpl_table to be created
  @return the order edge table frame
  The returned pointer must be deallocated with xsh_free_frame()
  
 */
/*----------------------------------------------------------------------------*/
cpl_frame* 
xsh_model_order_edges_tab_create(xsh_xs_3* p_xs_3, 
				 const char* tab_filename)
{
  int morder_cnt=0; /* grating spectral order */
  DOUBLE lambda=0; /*wavelength in mm */
  DOUBLE lambda_nm=0; /* wavelength in nm */
  DOUBLE blaze_wav=0, lam_min=0, lam_max=0, lam_inc=0;
 
  int ii=0;

  int iord=0,fpos=0,edge=0;
  double es_x_config=0;
  DOUBLE** ref_ind;
  cpl_propertylist* plist=NULL;
  CENTER_ORDER * centers = NULL ;
  xsh_order_list * res_list = NULL ;
  int low_y=0,up_y=0;


  cpl_frame* order_edges_frame=NULL;

  xsh_instrument* instr=NULL;
  const char* tag=NULL;

  char filename[256];

  XSH_ASSURE_NOT_NULL(p_xs_3);
  XSH_ASSURE_NOT_NULL(tab_filename);

/*znse_ref is the array holding Sellmeier coefs for ZnSe refractive index
  at each temp. Currently hard coded to take 6 temperatures in [2][*] to
  [7][*], can be extended. First two rows ([0][*] to [1][*]) take the entries
  for the temperature bracketing the operation.
  Column [*][0] takes the temperature, the other columns, [*][1] to [*][6]
  take the Sellmeier coeffs */

  ref_ind=xsh_alloc2Darray(8,7);
  instr = xsh_instrument_new() ;

  if (p_xs_3->arm==0) {
    tag="XSH_ORDER_TAB_EDGES_SLIT_UVB";
    xsh_ref_ind_read(0,ref_ind,p_xs_3->temper);
    xsh_instrument_set_arm(instr,XSH_ARM_UVB);
  }
  else if (p_xs_3->arm==1) {
    tag="XSH_ORDER_TAB_EDGES_VIS";
    xsh_ref_ind_read(1,ref_ind,p_xs_3->temper);
    xsh_instrument_set_arm(instr,XSH_ARM_VIS);
  }
  else {
    tag="XSH_ORDER_TAB_EDGES_NIR";
    xsh_ref_ind_read(2,ref_ind,p_xs_3->t_ir_p2);
    xsh_instrument_set_arm(instr,XSH_ARM_NIR);
  }

  check(res_list=xsh_order_list_create(instr));

  /*initalize the model. Inside the echelle_init the cfg file is
    read and the variables assigned to the xsh structure
    initialisation. Sets up those matrices that are not dependent upon
    wavelength */
  xsh_3_init(p_xs_3);
  es_x_config=p_xs_3->es_x;

  for (edge=-1;edge<2;edge++) {
    XSH_CALLOC(centers,CENTER_ORDER,((p_xs_3->morder_max-p_xs_3->morder_min+1)*2)*100);
    ii=0;
    iord=0;
    fpos=0;
    p_xs_3->es_y_tot=p_xs_3->es_y+fabs(edge)*p_xs_3->es_s/2.0;
    for (morder_cnt=p_xs_3->morder_min; morder_cnt<=p_xs_3->morder_max; morder_cnt+=1) {
      blaze_wav=2*(sin(-p_xs_3->nug))/(morder_cnt*p_xs_3->sg);
      lam_max=blaze_wav*((double)(morder_cnt)/((double)(morder_cnt)-0.5));//+p_xs_3->blaze_pad;
      lam_min=blaze_wav*((double)(morder_cnt)/(0.5+(double)(morder_cnt)));//-p_xs_3->blaze_pad;
      lam_inc=(lam_max-lam_min)/(99.99);
    //printf("blaze wav=%lf %lf %lf\n",blaze_wav,lam_min,lam_max);
      for (lambda=lam_min; lambda<=lam_max; lambda+=lam_inc) {
	lambda_nm=lambda*mm2nm;
	xsh_3_eval(lambda,morder_cnt,ref_ind,p_xs_3);
	xsh_3_detpix(p_xs_3);
	if (lambda==lam_min) low_y=p_xs_3->chippix[2];
	if (p_xs_3->chippix[0]==1) {
	  if (p_xs_3->chippix[1]>=1 &&
	      p_xs_3->chippix[1]<p_xs_3->ASIZE+1 &&
	      p_xs_3->chippix[2]>=1 &&
	      p_xs_3->chippix[2]<p_xs_3->BSIZE+1) {
	    printf("%d %d %d %d %lf %lf %lf \n",edge, morder_cnt, ii, fpos, lambda_nm,p_xs_3->xpospix,p_xs_3->ypospix);
	    centers[ii].order = morder_cnt;
	    centers[ii].pos_x = p_xs_3->chippix[1] ;
	    centers[ii].pos_y = p_xs_3->chippix[2] ;
	    centers[ii].flux = 0.0 ;
	  }
	}
	ii++;
      }
      up_y=p_xs_3->chippix[2];
      save_centers(centers, fpos, ii,xsh_instrument_arm_tostring(instr));
      printf("%d %d %d, %d %d \n", ii, fpos, morder_cnt, low_y, up_y);
      fpos=ii;
      res_list->list[iord].starty = low_y ;
      res_list->list[iord].endy = up_y ;
      res_list->list[iord].absorder = morder_cnt; 
      iord++;
    }
    qsort(centers, ii, sizeof(CENTER_ORDER), comp_center2);

    fit_order_edge_list(res_list, ii, centers, 5, edge);
    XSH_FREE(centers) ;
  }

  if ((xsh_free2Darray(ref_ind,8))!=0) {
    cpl_msg_error(__func__, "Cannot free 2D array ref_ind");
    return NULL;
  }

  check(plist=cpl_propertylist_new());
  //cpl_propertylist_append_string(plist, "INSTRUME", "XSHOOTER") ;
  sprintf(filename,"%s.fits",tag);
  check(xsh_pfits_set_pcatg(plist, tag ) ) ;
  cpl_msg_info(__func__, "Save the tables") ;

  check(order_edges_frame=xsh_order_list_save(res_list,instr,tab_filename,tag,p_xs_3->BSIZE)) ;

  cleanup:
	      xsh_free_propertylist(&plist);
	      XSH_FREE( centers ) ;
    return order_edges_frame;
}


/**@}*/




