/*
 * This file is part of the ESO SINFONI Pipeline
 * Copyright (C) 2004,2005 European Southern Observatory
 *
 * This program 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
 */
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif
#include <irplib_stdstar.h>

//Used only for sinfo_propertylist_has
#include "sinfo_dfs.h"

//Used only for sinfo_band
#include "sinfo_tpl_utils.h"

#include "sinfo_utilities_scired.h"
#include "sinfo_functions.h"
#include "sinfo_pfits.h"
#include "sinfo_spiffi_types.h"
#include "sinfo_utils_wrappers.h"
#include "sinfo_error.h"

static double
sinfo_sess2deg(const double sess);

static void
sinfo_set_spect_coord1(cpl_propertylist** plist,
               const int crpix1,
               const double crval1,
               const double cdelt1);

static void
sinfo_set_spect_coord2(cpl_propertylist** plist,
               const int crpix2,
               const double crval2,
               const double cdelt2);


static void
sinfo_set_coord1(cpl_propertylist** plist,
                 const double crpix1,
                 const double crval1,
                 const double cdelt1);
static void
sinfo_set_coord2(cpl_propertylist** plist,
                 const double crpix2,
                 const double crval2,
                 const double cdelt2);
static void
sinfo_set_coord3(cpl_propertylist** plist,
                 const int crpix3,
                 const double crval3,
                 const double cdelt3);


static void
sinfo_set_cd_matrix2(cpl_propertylist** plist,
            const double cd1_1,
            const double cd1_2,
            const double cd2_1,
            const double cd2_2);


static void
sinfo_set_cd_matrix3(cpl_propertylist** plist,
                     const double cd1_3,
                     const double cd2_3,
                     const double cd3_1,
                     const double cd3_2,
                     const double cd3_3);


static void
sinfo_new_change_plist_cube (cpl_propertylist * plist,
                             float cenLambda,
                             float dispersion,
                             int   center_z,
                             float center_x,
			     float center_y );


static void
sinfo_new_change_plist_image (cpl_propertylist * plist,
                              float center_x,
			      float center_y );


static void
sinfo_new_change_plist_spectrum (cpl_propertylist * plist,
				 double cenLambda,
				 double dispersion,
				 int   cenpix);

static cpl_image *
sinfo_new_image_getvig(
        cpl_image    *   image_in,
        int             loleft_x,
        int             loleft_y,
        int             upright_x,
        int             upright_y);



/**@{*/

/**
 * @addtogroup sinfo_utilities science utilities
 *
 * TBD
 */
/**
  @brief    Check input data
  @param    cfg   object configuration parameter
  @return 0 if suggess, else -1;
*/
int
sinfo_check_input_data(object_config* cfg)
{


    if (cfg == NULL)
    {
        sinfo_msg_error (" could not parse cpl input!\n") ;
        return -1 ;
    }


    if(sinfo_is_fits_file(cfg->wavemap) != 1) {
      sinfo_msg_error("Input file wavemap %s is not FITS",cfg->wavemap);
      return -1;
    }


    if (cfg->halocorrectInd == 1)
    {
       if(sinfo_is_fits_file(cfg->halospectrum) != 1) {
          sinfo_msg_error("Input file %s is not FITS",cfg->halospectrum);
          return -1;
       }

    }

    if (cfg->northsouthInd == 0) {
      if (sinfo_is_fits_file(cfg->poslist) != 1)
    {
      sinfo_msg_error("File %s with tag %s is not FITS!",
                          cfg->poslist,PRO_SLIT_POS);
      return -1 ;
    }
    } else {

      if (sinfo_is_fits_file(cfg->distlist) != 1)
    {
      sinfo_msg_error("File %s with tag %s is not FITS!",
                           cfg->distlist,PRO_SLITLETS_DISTANCE);
      return -1;
    }
    }


    return 0;


}
/**
  @brief    Convert a double from ssessagesimal to deg:
            110905.197316= 11h:09m:05.197316s = 167.271655483
  @param    sess   angle in seesagesimal units (see above)
  @return 0 if suggess, else -1;
*/

static double
sinfo_hms2deg(const double hms)
{
  int hrs=0;
  int min=0;
  double sec=0;
  double deg=0;
  double rest=hms;
  int sign=1;

  //sinfo_msg("hms=%f",hms);

  if(hms<0) {
    sign=-1;
    rest=-hms;
  }
  //sinfo_msg("rest=%f",rest);
  //sinfo_msg("sign=%d",sign);

  hrs=(int)(rest/10000.);
  //sinfo_msg("hrs=%d",hrs);

  rest=rest-(double)(hrs*10000.);
  min=(int)(rest/100.);
  //sinfo_msg("min=%d",min);

  sec=rest-(double)(min*100.);
  //sinfo_msg("sec=%f",sec);

  deg=hrs*15+(double)(min/4.)+(double)(sec/240.);
  //sinfo_msg("deg=%f",deg);

  deg=sign*deg;
  //sinfo_msg("deg=%f",deg);

  return deg;

}

/**
  @brief    Convert a double from ssessagesimal to deg:
            203049.197= 20:30:49.197 = 20.5136658333
  @param    sess   angle in seesagesimal units (see above)
  @return 0 if suggess, else -1;
*/

static double
sinfo_sess2deg(const double sess)
{
  int grad=0;
  int min=0;
  double sec=0;
  double deg=0;
  double rest=sess;
  int sign=1;

  //sinfo_msg("sess=%f",sess);

  if(sess<0) {
    sign=-1;
    rest=-sess;
  }
  //sinfo_msg("rest=%f",rest);
  //sinfo_msg("sign=%d",sign);

  grad=(int)(rest/10000.);
  //sinfo_msg("grad=%d",grad);

  rest=rest-(double)(grad*10000.);
  min=(int)(rest/100.);
  //sinfo_msg("min=%d",min);

  sec=rest-(double)(min*100.);
  //sinfo_msg("sec=%f",sec);

  deg=grad+(double)(min/60.)+(double)(sec/3600.);
  //sinfo_msg("deg=%f",deg);

  deg=sign*deg;
  //sinfo_msg("deg=%f",deg);

  return deg;

}


/**
  @brief    Computes size of coadded cube
  @param    offsetx  input offset list
  @param    offsety  input offset list
  @param    nframes  input number of values
  @param    ref_offx input reference offset array
  @param    ref_offy input reference offset array
  @param    size_x   input/output coadded cube x size
  @param    size_y   input/output coadded cube y size
  @return   size of  coadded cube
*/

int
sinfo_auto_size_cube(float* offsetx,
                      float* offsety,
              const int nframes,
                    float* ref_offx,
                    float* ref_offy,
                    int* size_x,
                    int* size_y)
{

  int n=0;
  float offx=0;
  float offy=0;
  float min_offx=0;
  float max_offx=0;
  float min_offy=0;
  float max_offy=0;

  sinfo_msg ("Computation of output cube size") ;
  for ( n = 0 ; n < nframes ; n++ ) {
    offx = offsetx[n];  /* was - */
    offy = offsety[n];  /* was - */
    /* sinfo_msg("frame %d offx=%f offy=%f",n,offx,offy); */
    if(n==0) {
      min_offx=offx;
      min_offy=offy;
      max_offx=offx;
      max_offy=offy;
    } else {
      if(offx > max_offx) max_offx=offx;
      if(offy > max_offy) max_offy=offy;
      if(offx < min_offx) min_offx=offx;
      if(offy < min_offy) min_offy=offy;
    }
  }
  /*
  sinfo_msg("max_offx=%f max_offy=%f",max_offx,max_offy);
  sinfo_msg("min_offx=%f min_offy=%f",min_offx,min_offy);
  */
  *ref_offx=(min_offx+max_offx)/2;
  *ref_offy=(min_offy+max_offy)/2;
  *size_x+=2*floor(max_offx-min_offx+0.5);
  *size_y+=2*floor(max_offy-min_offy+0.5);
  sinfo_msg("Output cube size: %d x %d",*size_x,*size_y);
  sinfo_msg("Ref offset. x: %f y: %f",*ref_offx,*ref_offy);
  sinfo_msg_debug("Max offset. x: %f y: %f",max_offx,max_offy);
  sinfo_msg_debug("Min offset. x: %f y: %f",min_offx,min_offy);
  return 0;

}

/**
  @brief    Computes size of coadded cube
  @param    cfg          inpout parameters configuration
  @param    ref_offx     inpout reference offset array
  @param    ref_offy     inpout reference offset array
  @return   size of coadded cube
*/
int
sinfo_auto_size_cube5(object_config * cfg,
                    float* ref_offx, float* ref_offy,
                    float* min_offx, float* min_offy,
                    float* max_offx, float* max_offy)
{

  char* name =NULL;
  int n=0;
  float offx=0;
  float offy=0;

  cpl_propertylist * plist=NULL;
  sinfo_msg ("Automatic computation of output cube size") ;
  for ( n = 0 ; n < cfg->nframes ; n++ ) {
    name = cfg->framelist[n] ;
    plist=cpl_propertylist_load(name,0);
    offx = sinfo_pfits_get_cumoffsetx(plist);  /* was - */
    if(cpl_error_get_code() != CPL_ERROR_NONE) {
      sinfo_msg_warning(" could not read fits header keyword cummoffsetx!");
      sinfo_msg_warning(" set it to  0");
      offx = 0;
      cpl_error_reset();
      /* return -1 ; */
    }

    offy = sinfo_pfits_get_cumoffsety(plist); /* was - */
    sinfo_free_propertylist(&plist);
    if(cpl_error_get_code() != CPL_ERROR_NONE) {
      sinfo_msg_warning(" could not read fits header keyword! cumoffsety") ;
      sinfo_msg_warning(" set it to 0");
      offy = 0;
      cpl_error_reset();
      /* return -1 ; */
    }
    //sinfo_msg("n=%d offx=%f offy=%f",n,offx,offy);

    if(n==0) {
      *min_offx=offx;
      *min_offy=offy;
      *max_offx=offx;
      *max_offy=offy;
    } else {
      if(offx > *max_offx) *max_offx=offx;
      if(offy > *max_offy) *max_offy=offy;
      if(offx < *min_offx) *min_offx=offx;
      if(offy < *min_offy) *min_offy=offy;
    }
  }
  *ref_offx=(*min_offx+*max_offx)/2;
  *ref_offy=(*min_offy+*max_offy)/2;

  if(cfg->size_x == 0) cfg->size_x=2*floor(*max_offx-*min_offx+0.5)+64 ;
/* The formula above doesn't give always the right result (DSF07663)
 * for example, if diff in offset is 35.5, the formula gives 72 but 71 would be
 * enough, the following candidate is working fine:
 *   if(cfg->size_x == 0)
	  cfg->size_x=floor(2.0*(*max_offx-*min_offx + 0.5 - 0.00001))+64 ;
	  Currently the ticket is suspended, because the formula above
	  would change the scientific results for the previous data.
	  The same is actual for Y axis.
*/
  if(cfg->size_y == 0) cfg->size_y=2*floor(*max_offy-*min_offy+0.5)+64 ;

  sinfo_msg("Output cube size: %d x %d",cfg->size_x,cfg->size_y);
  sinfo_msg("Ref offset. x: %f y: %f",*ref_offx,*ref_offy);
  sinfo_msg("Max offset. x: %f y: %f",*max_offx,*max_offy);
  sinfo_msg("Min offset. x: %f y: %f",*min_offx,*min_offy);
  return 0;


}

/**
  @brief    Read slitlets distances
  @param    nslits input number of slitlets
  @param    distlist input slit distances file name
  @return   array with slitlet distances
*/



float*
sinfo_read_distances(const int nslits, const char* distlist)
{
  int i=0;
  int* status=NULL;
  float * distances = NULL;
  float tmp_float=0;
  char tbl_distances_name[FILE_NAME_SZ];
  cpl_table* tbl_distances = NULL;

  sinfo_msg("Read distances");
  distances = (float*) cpl_calloc (nslits - 1, sizeof (float));

  if ( NULL == distances )
    {
      sinfo_msg_error ("could allocate memory!") ;
      return NULL ;
    }

            /*READ TFITS TABLE*/
  if(cpl_error_get_code() != CPL_ERROR_NONE) {
    sinfo_msg_error("Before loading input table");
    sinfo_msg_error("%s", (char* ) cpl_error_get_message());
    return NULL;
  }
  strcpy(tbl_distances_name,distlist);
  tbl_distances = cpl_table_load(tbl_distances_name,1,0);
  if(cpl_error_get_code() != CPL_ERROR_NONE) {
    sinfo_msg_error("loading input table %s",tbl_distances_name);
    sinfo_msg_error("%s", (char* ) cpl_error_get_message());
    return NULL;
  }

  for (i =0 ; i< nslits-1; i++){
    tmp_float=cpl_table_get_float(tbl_distances,"slitlet_distance",i,status);
    if(cpl_error_get_code() != CPL_ERROR_NONE) {
      sinfo_msg_error("reading col %s from table %s","slitlet_distance",
                       tbl_distances_name);
      sinfo_msg_error("%s", (char* ) cpl_error_get_message());
      return NULL;
    }
    sinfo_new_array_set_value(distances,tmp_float,i);
  }
  cpl_table_delete(tbl_distances);
  return distances;

}



/**
  @brief    Read slitlets edges
  @param    nslits number of input slitlets
  @param    poslist input file name with slit positions
  @return   array with slitlet edges
*/

float**
sinfo_read_slitlets_edges(const int nslits, const char* poslist)
{


  char tbl_slitpos_name[FILE_NAME_SZ];
  cpl_table* tbl_slitpos=NULL;
  int n=0;
  int i=0;
  int* status=NULL;
  float edge_x=0;
  float edge_y=0;
  float ** slit_edges = NULL;

  slit_edges = sinfo_new_2Dfloatarray(nslits, 2) ;

  strcpy(tbl_slitpos_name,poslist);
  tbl_slitpos = cpl_table_load(tbl_slitpos_name,1,0);
  if(cpl_error_get_code() != CPL_ERROR_NONE) {
    sinfo_msg_error("error loading tbl %s",tbl_slitpos_name);
    sinfo_msg_error("%s", (char* ) cpl_error_get_message());
    return NULL;
  }
  n = cpl_table_get_nrow(tbl_slitpos);
  if (n != nslits) {
    sinfo_msg_error("No of slitlets in table is n = %d != %d !",n,nslits);
    return NULL;
  }

  for (i =0 ; i< nslits; i++){
    edge_x=cpl_table_get_double(tbl_slitpos,"pos1",i,status);
    edge_y=cpl_table_get_double(tbl_slitpos,"pos2",i,status);
    if(cpl_error_get_code() != CPL_ERROR_NONE) {
      sinfo_msg_error("error reading tbl %s row %d",tbl_slitpos_name,i);
      sinfo_msg_error("%s", (char* ) cpl_error_get_message());
      return NULL;
    }
    sinfo_new_array2D_set_value(slit_edges,edge_x,i,0);
    sinfo_new_array2D_set_value(slit_edges,edge_y,i,1);
  }
  cpl_table_delete(tbl_slitpos);
  if(cpl_error_get_code() != CPL_ERROR_NONE) {
    sinfo_msg_error("error reading tbl %s",tbl_slitpos_name);
    sinfo_msg_error("%s", (char* ) cpl_error_get_message());
    return NULL;
  }

  return slit_edges;

}


/*---------------------------------------------------------------------------*/
/**
  @brief    Extract a rectangular zone from a cube into another cube.
  @param    cube_in     Input cube
  @param    loleft_x    Lower left X coordinate
  @param    loleft_y    Lower left Y coordinate
  @param    upright_x   Upper right X coordinate
  @param    upright_y   Upper right Y coordinate
  @return   1 newly allocated cube.

  The input coordinates define the extracted region by giving the
  coordinates of the lower left and upper right corners (inclusive).

  Coordinates must be provided in the FITS convention: lower left
  corner of the image is at (1,1), x growing from left to right,
  y growing from bottom to top.

  The same rectangle is extracted from each plane in the input cube,
  and appended to the output cube.

  The returned cube contains pixel copies of the input pixels. It must be
  freed using cube_del().
 */
/*---------------------------------------------------------------------------*/
cpl_imagelist * sinfo_new_cube_getvig(
        cpl_imagelist *        cube_in,
        int             loleft_x,
        int             loleft_y,
        int             upright_x,
        int             upright_y)
{
    cpl_imagelist     *        cube_out ;
    int                 i ;
    /*
    int                 outlx,
                                        outly ;

    int ilx=0;
    int ily=0;
    int inp=0;
    */
    cpl_image* i_img=NULL;
    cpl_image* o_img=NULL;

    if (cube_in==NULL) return NULL ;
/*
    ilx=cpl_image_get_size_x(cpl_imagelist_get(cube_in,0));
    ily=cpl_image_get_size_y(cpl_imagelist_get(cube_in,0));
    inp=cpl_imagelist_get_size(cube_in);
*/
        if ((loleft_x>upright_x) ||
            (loleft_y>upright_y)) {
            sinfo_msg_error("ill-defined slit for extraction: aborting");
            return NULL ;
        }

    /* Extraction coordinates include rectangular zone  */
        /*
    outlx = upright_x - loleft_x + 1 ;
    outly = upright_y - loleft_y + 1 ;
    */
    /*
    cube_out = sinfo_new_cube(outlx, outly, cube_in->np) ;
    */
    cube_out = cpl_imagelist_new() ;
    /* Loop on all input planes */
    for (i=0 ; i<cpl_imagelist_get_size(cube_in) ; i++) {

      i_img=cpl_imagelist_get(cube_in,i);
        /* Extract a slit from this plane   */
                o_img = sinfo_new_image_getvig(i_img,
                        loleft_x, loleft_y,
                        upright_x, upright_y) ;
        cpl_imagelist_set(cube_out,o_img,i);
    }
    return cube_out ;
}
/*---------------------------------------------------------------------------*/
/**
  @brief    Extract a rectangular zone from an image into another image.
  @param    image_in    Input image
  @param    loleft_x    Lower left X coordinate
  @param    loleft_y    Lower left Y coordinate
  @param    upright_x   Upper right X coordinate
  @param    upright_y   Upper right Y coordinate
  @return   1 newly allocated image.

  The input coordinates define the extracted region by giving the
  coordinates of the lower left and upper right corners (inclusive).

  Coordinates must be provided in the FITS convention: lower left
  corner of the image is at (1,1), x growing from left to right,
  y growing from bottom to top.
 */
/*---------------------------------------------------------------------------*/

static cpl_image *
sinfo_new_image_getvig(
        cpl_image    *    image_in,
        int             loleft_x,
        int             loleft_y,
        int             upright_x,
        int             upright_y)
{
    cpl_image    *        slit_img ;
    int                 i, j ;
    register
    pixelvalue  *       inpt,
                                *       outpt ;
    int         outlx, outly ;
    int ilx=0;
    int ily=0;

    float* pidata=NULL;
    float* podata=NULL;

    if (image_in==NULL) return NULL ;

    ilx=cpl_image_get_size_x(image_in);
    ily=cpl_image_get_size_y(image_in);
    pidata=cpl_image_get_data_float(image_in);

    if ((loleft_x<1) || (loleft_x>ilx) ||
        (loleft_y<1) || (loleft_y>ily) ||
        (upright_x<1) || (upright_x>ilx) ||
        (upright_y<1) || (upright_y>ily) ||
        (loleft_x>upright_x) || (loleft_y>upright_y)) {
        sinfo_msg_error("extraction zone is [%d %d] [%d %d]\n"
                        "cannot extract such zone: aborting slit extraction",
                loleft_x, loleft_y, upright_x, upright_y) ;
        return NULL ;
    }

    outlx = upright_x - loleft_x + 1 ;
    outly = upright_y - loleft_y + 1 ;
    slit_img = cpl_image_new(outlx, outly,CPL_TYPE_FLOAT) ;
    podata=cpl_image_get_data_float(slit_img);

    for (j=0 ; j<outly ; j++) {
        inpt = pidata+loleft_x-1 + (j+loleft_y-1)*ilx ;
        outpt = podata + j*outlx ;
        for (i=0 ; i<outlx ; i++) {
            *outpt++ = *inpt++ ;
        }
    }
    return slit_img ;
}

/**
@brief set world coordinate system for a cube
@name sinfo_new_set_wcs_cube
@param cub input cube
@param name file name
@param clambda central wawelength
@param dis   dispersion
@param cpix central pixel
@param cx   center x
@param cy   center y
*/
int
sinfo_new_set_wcs_cube(cpl_imagelist* cub, const char* name, double clambda,
         double dis, double cpix, double cx, double cy)
{
  cpl_propertylist* plist=NULL;

  if ((cpl_error_code)((plist = cpl_propertylist_load(name, 0)) == NULL)) {
    sinfo_msg_error( "getting header from frame %s",name);
    cpl_propertylist_delete(plist) ;
    return -1 ;
  }

  sinfo_new_change_plist_cube(plist, clambda, dis, cpix, cx, cy) ;
  sinfo_plist_set_extra_keys(plist,"IMAGE","DATA","RMSE",
			     "DATA","ERRS","QUAL",0);
  if (cpl_imagelist_save(cub, name, CPL_BPP_IEEE_FLOAT,
                         plist,CPL_IO_DEFAULT)!=CPL_ERROR_NONE) {
    sinfo_msg_error( "Cannot save the product %s",name);
    cpl_propertylist_delete(plist) ;
    return -1 ;
  }
  cpl_propertylist_delete(plist) ;
  return 0;

}
/**
@brief set world coordinate system for an image
@name sinfo_new_set_wcs_image
@param img input image
@param name file name
@param cx   center x
@param cy   center y
*/
int
sinfo_new_set_wcs_image(cpl_image* img,
                        const char* name,
                        double cx,
                        double cy)
{
  cpl_propertylist* plist=NULL;

  if ((cpl_error_code)((plist = cpl_propertylist_load(name, 0)) == NULL)) {
    sinfo_msg_error( "getting header from frame %s",name);
    cpl_propertylist_delete(plist) ;
    return -1 ;
  }
  sinfo_new_change_plist_image(plist, cx, cy) ;

  if (cpl_image_save(img, name, CPL_BPP_IEEE_FLOAT,
                     plist,CPL_IO_DEFAULT)!=CPL_ERROR_NONE) {
    sinfo_msg_error( "Cannot save the product %s",name);
    cpl_propertylist_delete(plist) ;
    return -1 ;
  }
  cpl_propertylist_delete(plist) ;
  return 0;

}


/**
@brief set world coordinate system for a spectrum image
@name sinfo_new_set_wcs_spectrum
@param cub input image spectrum
@param name file name
@param clambda central wawelength
@param dis   dispersion
@param cpix central pixel
*/
int
sinfo_new_set_wcs_spectrum(cpl_image* img, const char* name, double clambda,
             double dis, double cpix)
{
  cpl_propertylist* plist=NULL;

  if ((cpl_error_code)((plist = cpl_propertylist_load(name, 0)) == NULL)) {
    sinfo_msg_error( "getting header from frame %s",name);
    cpl_propertylist_delete(plist) ;
    return -1 ;
  }
  sinfo_new_change_plist_spectrum(plist, clambda, dis,cpix) ;

  if (cpl_image_save(img, name, CPL_BPP_IEEE_FLOAT,
                     plist,CPL_IO_DEFAULT)!=CPL_ERROR_NONE) {
    sinfo_msg_error( "Cannot save the product %s",name);
    cpl_propertylist_delete(plist) ;
    return -1 ;
  }
  cpl_propertylist_delete(plist) ;
  return 0;

}
/**
@brief set world coordinate system for a cube
@name sinfo_new_change_plist_cube
@param plist input propertylist
@param name file name
@param cenLambda central wawelength
@param dispersion   dispersion
@param cenpix central pixel
@param center_x   center x
@param center_y   center y
*/
static void
sinfo_new_change_plist_cube (cpl_propertylist * plist,
            float cenLambda,
            float dispersion,
            int   center_z,
            float center_x,
            float center_y )
{

    float pixelscale ;
    double ra ;
    double dec ;
    double angle ;
    float radangle ;
    double cd1_1, cd1_2, cd2_1, cd2_2 ;
    int sign_swap = -1;
    char firsttext[2*FILE_NAME_SZ] ;

    double cdelt1=0;
    double cdelt2=0;
    double cdelt3=dispersion;

    double crpix1=center_x;
    double crpix2=center_y;
    int crpix3=center_z;

    double crval1=0;
    double crval2=0;
    double crval3=cenLambda;


    strcpy(firsttext, "sinfo_rec_objnod -f \0") ;

    pixelscale = sinfo_pfits_get_pixscale(plist)/2. ;
    ra = sinfo_pfits_get_ra(plist) ;
    dec = sinfo_pfits_get_DEC(plist) ;

    //get better coordinate values
    ra=sinfo_pfits_get_targ_alpha(plist);
    dec=sinfo_pfits_get_targ_delta(plist);
    //sinfo_msg("ra=%f",ra);
    //sinfo_msg("dec=%f",dec);
    ra=sinfo_hms2deg(ra);
    dec=sinfo_sess2deg(dec);
    //sinfo_msg("ra=%f",ra);
    //sinfo_msg("dec=%f",dec);

    crval1=ra;
    crval2=dec;

    angle = sinfo_pfits_get_posangle(plist) ;
    /* in PUPIL data there is not posangle info: we reset the error */
    if(cpl_error_get_code() != CPL_ERROR_NONE) {
       cpl_error_reset();
    }
    cdelt1=sign_swap*pixelscale / 3600.;
    cdelt2=         +pixelscale / 3600.;


    radangle = angle * PI_NUMB / 180. ;
    cd1_1 = +cdelt1*cos(radangle);
    cd1_2 = -cdelt2*sin(radangle);
    cd2_1 = +cdelt1*sin(radangle);
    cd2_2 = +cdelt2*cos(radangle);


    sinfo_set_coord1(&plist,crpix1,crval1,cdelt1);
    sinfo_set_coord2(&plist,crpix2,crval2,cdelt2);
    sinfo_set_coord3(&plist,crpix3,crval3,cdelt3);
    sinfo_set_cd_matrix2(&plist,cd1_1,cd1_2,cd2_1,cd2_2);
    sinfo_set_cd_matrix3(&plist,0,0,0,0,dispersion);


    }




/**
@brief set world coordinate system
@param plist input propertylist
@param crpix1 value of CRPIX1 (ref pixel axis 1 coord in pix coordinates)
@param crval1 value of CRVAL1 (ref pixel axis 1 coord in sky coordinates)
@param cdelt1 value of CDELT1 (ref pixel axis 1 size )
@return updated propertylist
*/
static void
sinfo_set_coord1(cpl_propertylist** plist,
                 const double crpix1,
                 const double crval1,
                 const double cdelt1)
{
   cpl_propertylist_erase_regexp(*plist, "^CTYPE1",0);
    cpl_propertylist_insert_after_string(*plist,"EXPTIME","CTYPE1","RA---TAN");
    cpl_propertylist_set_comment(*plist, "CTYPE1", "Projected Rectascension");
    cpl_propertylist_erase_regexp(*plist, "^CRPIX1",0);
    cpl_propertylist_insert_after_double(*plist,"CTYPE1","CRPIX1", crpix1) ;
    cpl_propertylist_set_comment(*plist, "CRPIX1","Reference pixel in RA" ) ;

    cpl_propertylist_erase_regexp(*plist, "^CRVAL1",0);
    cpl_propertylist_insert_after_double(*plist, "CRPIX1", "CRVAL1", crval1 ) ;
    cpl_propertylist_set_comment(*plist, "CRVAL1","Reference RA" ) ;

    cpl_propertylist_erase_regexp(*plist, "^CDELT1",0);
    cpl_propertylist_insert_after_double(*plist,"CRVAL1","CDELT1",cdelt1 ) ;
    cpl_propertylist_set_comment(*plist, "CDELT1","pixel scale" ) ;

    cpl_propertylist_erase_regexp(*plist, "^CUNIT1",0);
    cpl_propertylist_insert_after_string(*plist, "CDELT1",  "CUNIT1", "deg" ) ;
    cpl_propertylist_set_comment(*plist, "CUNIT1","RA-UNIT" ) ;

    return;
}


/**
@brief set world coordinate system
@param plist input propertylist
@param crpix2 value of CRPIX2 (ref pixel axis 2 coord in pix coordinates)
@param crval2 value of CRVAL2 (ref pixel axis 2 coord in sky coordinates)
@param cdelt2 value of CDELT2 (ref pixel axis 2 size )
@return updated propertylist
*/
static void
sinfo_set_coord2(cpl_propertylist** plist,
                 const double crpix2,
                 const double crval2,
                 const double cdelt2)
{
    cpl_propertylist_erase_regexp(*plist, "^CTYPE2",0);
    cpl_propertylist_insert_after_string(*plist,"CUNIT1","CTYPE2","DEC--TAN");
    cpl_propertylist_set_comment(*plist, "CTYPE2", "Projected Declination") ;

    cpl_propertylist_erase_regexp(*plist, "^CRPIX2",0);
    cpl_propertylist_insert_after_double(*plist,"CTYPE2","CRPIX2",crpix2 ) ;
    cpl_propertylist_set_comment(*plist, "CRPIX2", "Reference pixel in DEC") ;

    cpl_propertylist_erase_regexp(*plist,"^CRVAL2",0);
    cpl_propertylist_insert_after_double(*plist,"CRPIX2","CRVAL2",crval2) ;
    cpl_propertylist_set_comment(*plist,"CRVAL2","Reference DEC") ;

    cpl_propertylist_erase_regexp(*plist,"^CDELT2",0);
    cpl_propertylist_insert_after_double(*plist,"CRVAL2","CDELT2",cdelt2 ) ;
    cpl_propertylist_set_comment(*plist,"CDELT2","pixel scale") ;

    cpl_propertylist_erase_regexp(*plist,"^CUNIT2",0);
    cpl_propertylist_insert_after_string(*plist,"CDELT2","CUNIT2", "deg" ) ;
    cpl_propertylist_set_comment(*plist,"CUNIT2","DEC-UNIT") ;


}



/**
@brief set world coordinate system
@param plist input propertylist
@param crpix3 value of CRPIX3 (ref pixel axis 3 coord in pix coordinates)
@param crval3 value of CRVAL3 (ref pixel axis 3 coord in sky coordinates)
@param cdelt3 value of CDELT3 (ref pixel axis 3 size )
@return updated propertylist
*/
static void
sinfo_set_coord3(cpl_propertylist** plist,
                 const int crpix3,
                 const double crval3,
                 const double cdelt3)
{
    cpl_propertylist_erase_regexp(*plist, "^CTYPE3",0);
    cpl_propertylist_insert_after_string(*plist,"EXPTIME", "CTYPE3", "WAVE" ) ;
    cpl_propertylist_set_comment(*plist,"CTYPE3","wavelength axis in microns") ;

    cpl_propertylist_erase_regexp(*plist, "^CRPIX3",0);
    cpl_propertylist_insert_after_double(*plist,"CTYPE3","CRPIX3", (double)crpix3 ) ;
    cpl_propertylist_set_comment(*plist, "CRPIX3", "Reference pixel in z") ;

    cpl_propertylist_erase_regexp(*plist, "^CRVAL3",0);
    cpl_propertylist_insert_after_double(*plist,"CRPIX3", "CRVAL3", crval3) ;
    cpl_propertylist_set_comment(*plist, "CRVAL3", "central wavelength") ;

    cpl_propertylist_erase_regexp(*plist, "^CDELT3",0);

    cpl_propertylist_insert_after_double(*plist,"CRVAL3","CDELT3",cdelt3) ;
    cpl_propertylist_set_comment(*plist, "CDELT3", "microns per pixel") ;

    cpl_propertylist_erase_regexp(*plist, "^CUNIT3",0);
    cpl_propertylist_insert_after_string(*plist,"CDELT3", "CUNIT3", "um" ) ;
    cpl_propertylist_set_comment(*plist, "CUNIT3",  "spectral unit" ) ;

    cpl_propertylist_erase_regexp(*plist, "^SPECSYS",0);
    cpl_propertylist_insert_after_string(*plist,"CUNIT3", "SPECSYS", "TOPOCENT" ) ;
    cpl_propertylist_set_comment(*plist, "SPECSYS",  "Coordinate reference frame" ) ;
}


/**
@brief set world coordinate system: CD matrix
@param plist input propertylist
@param cd1_1 value of CD1_1
@param cd1_2 value of CD1_2
@param cd2_1 value of CD2_1
@param cd2_2 value of CD2_2
@return updated propertylist
*/

static void
sinfo_set_cd_matrix2(cpl_propertylist** plist,
            const double cd1_1,
            const double cd1_2,
            const double cd2_1,
            const double cd2_2)
{

    check_nomsg(cpl_propertylist_erase_regexp(*plist, "^CD1_1",0));
    check_nomsg(cpl_propertylist_insert_after_double(*plist,"EXPTIME",
						     "CD1_1", cd1_1 )) ;
    check_nomsg(cpl_propertylist_set_comment(*plist, "CD1_1",
					     "CD rotation matrix" )) ;

    check_nomsg(cpl_propertylist_erase_regexp(*plist, "^CD1_2",0));
    check_nomsg(cpl_propertylist_insert_after_double(*plist, "CD1_1",
						     "CD1_2", cd1_2 )) ;
    check_nomsg(cpl_propertylist_set_comment(*plist, "CD1_2",
					     "CD rotation matrix" )) ;

    check_nomsg(cpl_propertylist_erase_regexp(*plist, "^CD2_1",0));
    check_nomsg(cpl_propertylist_insert_after_double(*plist, "CD1_2",
						     "CD2_1", cd2_1 )) ;
    check_nomsg(cpl_propertylist_set_comment(*plist, "CD2_1",
					     "CD rotation matrix" )) ;

    check_nomsg(cpl_propertylist_erase_regexp(*plist, "^CD2_2",0));
    check_nomsg(cpl_propertylist_insert_after_double(*plist, "CD2_1",
						     "CD2_2", cd2_2 )) ;
    check_nomsg(cpl_propertylist_set_comment(*plist, "CD2_2",
					     "CD rotation matrix" )) ;

 cleanup:
    return;


}


/**
@brief set world coordinate system: CD matrix
@param plist input propertylist
@param cd1_3 value of CD1_3
@param cd2_3 value of CD2_3
@param cd3_1 value of CD3_1
@param cd3_2 value of CD3_2
@param cd3_3 value of CD3_3

@return updated propertylist
*/

static void
sinfo_set_cd_matrix3(cpl_propertylist** plist,
                     const double cd1_3,
                     const double cd2_3,
                     const double cd3_1,
                     const double cd3_2,
                     const double cd3_3)
{


    check_nomsg(cpl_propertylist_erase_regexp(*plist, "^CD1_3",0));
    check_nomsg(cpl_propertylist_insert_after_double(*plist,"EXPTIME",
						     "CD1_3", cd1_3 )) ;
    check_nomsg(cpl_propertylist_set_comment(*plist, "CD1_3",
					     "CD rotation matrix" )) ;


    check_nomsg(cpl_propertylist_erase_regexp(*plist, "^CD2_3",0));
    check_nomsg(cpl_propertylist_insert_after_double(*plist,"CD1_3",
						     "CD2_3", cd2_3 )) ;
    check_nomsg(cpl_propertylist_set_comment(*plist, "CD2_3",
					     "CD rotation matrix" )) ;



    check_nomsg(cpl_propertylist_erase_regexp(*plist, "^CD3_1",0));
    check_nomsg(cpl_propertylist_insert_after_double(*plist,"CD2_3",
						     "CD3_1", cd3_1 )) ;
    check_nomsg(cpl_propertylist_set_comment(*plist, "CD3_1",
					     "CD rotation matrix" )) ;

    check_nomsg(cpl_propertylist_erase_regexp(*plist, "^CD3_2",0));
    check_nomsg(cpl_propertylist_insert_after_double(*plist, "CD3_1",
						     "CD3_2", cd3_2 )) ;
    check_nomsg(cpl_propertylist_set_comment(*plist, "CD3_2",
					     "CD rotation matrix" )) ;

    check_nomsg(cpl_propertylist_erase_regexp(*plist, "^CD3_3",0));
    check_nomsg(cpl_propertylist_insert_after_double(*plist, "CD3_2",
						     "CD3_3", cd3_3 )) ;
    check_nomsg(cpl_propertylist_set_comment(*plist, "CD3_3",
					     "CD rotation matrix" )) ;

 cleanup:
    return;


}


/**
@brief set world coordinate system
@param plist input propertylist
@param crpix1 value of CRPIX1 (ref pixel axis 1 coord in pix coordinates)
@param crval1 value of CRVAL1 (ref pixel axis 1 coord in sky coordinates)
@param cdelt1 value of CDELT1 (ref pixel axis 1 size )
@return updated propertylist
*/
static void
sinfo_set_spect_coord1(cpl_propertylist** plist,
                 const int crpix1,
                 const double crval1,
                 const double cdelt1)
{

    cpl_propertylist_erase_regexp(*plist, "^CTYPE1",0);
    cpl_propertylist_insert_after_string(*plist,"EXPTIME",  "CTYPE1", "PIXEL");
    cpl_propertylist_set_comment(*plist, "CTYPE1", "Pixel coordinate system.");

    cpl_propertylist_erase_regexp(*plist, "^CRPIX1",0);
    cpl_propertylist_insert_after_double(*plist, "CTYPE1",  "CRPIX1", (double)crpix1 ) ;
    cpl_propertylist_set_comment(*plist, "CRPIX1", "Reference pixel in x") ;

    cpl_propertylist_erase_regexp(*plist, "^CRVAL1",0);
    cpl_propertylist_insert_after_double(*plist,"CRPIX1",  "CRVAL1", crval1 ) ;
    cpl_propertylist_set_comment(*plist, "CRVAL1", "value of ref pixel.") ;

    cpl_propertylist_erase_regexp(*plist, "^CDELT1",0);
    cpl_propertylist_insert_after_double(*plist,"CRVAL1",  "CDELT1", cdelt1 ) ;
    cpl_propertylist_set_comment(*plist,"CDELT1", "pixel scale") ;


    cpl_propertylist_erase_regexp(*plist, "^CUNIT1",0);
    cpl_propertylist_insert_after_string(*plist,"CDELT1",  "CUNIT1", "Pixel" );
    cpl_propertylist_set_comment(*plist, "CUNIT1",  "spectral unit" );

}





/**
@brief set world coordinate system
@param plist input propertylist
@param crpix2 value of CRPIX2 (ref pixel axis 2 coord in pix coordinates)
@param crval2 value of CRVAL2 (ref pixel axis 2 coord in sky coordinates)
@param cdelt2 value of CDELT2 (ref pixel axis 2 size )
@return updated propertylist
*/
static void
sinfo_set_spect_coord2(cpl_propertylist** plist,
                 const int crpix2,
                 const double crval2,
                 const double cdelt2)
{

    cpl_propertylist_erase_regexp(*plist, "^CTYPE2",0);
    cpl_propertylist_insert_after_string(*plist, "EXPTIME","CTYPE2","WAVE" );
    cpl_propertylist_set_comment(*plist,"CTYPE2","wavelength axis in microns");

    cpl_propertylist_erase_regexp(*plist, "^CRPIX2",0);
    cpl_propertylist_insert_after_double(*plist, "CTYPE2",  "CRPIX2",(double)crpix2 ) ;
    cpl_propertylist_set_comment(*plist, "CRPIX2", "Reference pixel in x") ;

    cpl_propertylist_erase_regexp(*plist, "^CRVAL2",0);
    cpl_propertylist_insert_after_double(*plist, "CRPIX2","CRVAL2",crval2 ) ;
    cpl_propertylist_set_comment(*plist,"CRVAL2", "central wavelength") ;

    cpl_propertylist_erase_regexp(*plist, "^CDELT2",0);
    cpl_propertylist_insert_after_double(*plist, "CRVAL2", "CDELT2",cdelt2);
    cpl_propertylist_set_comment(*plist,"CDELT2", "microns per pixel");

    cpl_propertylist_erase_regexp(*plist, "^CUNIT2",0);
    cpl_propertylist_insert_after_string(*plist,"CDELT2",  "CUNIT2", "um");
    cpl_propertylist_set_comment(*plist, "CUNIT2",  "spectral unit" );


}
/**
@brief set world coordinate system for a spectrum
@name sinfo_new_change_plist_spectrum
@param plist input propertylist
@param cenLambda central wawelength
@param dispersion   dispersion
@param cenpix central pixel
@return updated propertylist
*/
static void
sinfo_new_change_plist_spectrum (cpl_propertylist * plist,
                double cenLambda,
                double dispersion,
                int   cenpix)
{

  int crpix1=1;
  double crval1=1;
  double cdelt1=1;

  int crpix2=cenpix;
  double crval2=cenLambda;
  double cdelt2=dispersion;



  cpl_propertylist_erase_regexp(plist, "^CTYPE3",0);
  cpl_propertylist_erase_regexp(plist, "^CRPIX3",0);
  cpl_propertylist_erase_regexp(plist, "^CRVAL3",0);
  cpl_propertylist_erase_regexp(plist, "^CDELT3",0);
  cpl_propertylist_erase_regexp(plist, "^CUNIT3",0);

  cpl_propertylist_erase_regexp(plist, "^CTYPE2",0);
  cpl_propertylist_erase_regexp(plist, "^CRPIX2",0);
  cpl_propertylist_erase_regexp(plist, "^CRVAL2",0);
  cpl_propertylist_erase_regexp(plist, "^CDELT2",0);
  cpl_propertylist_erase_regexp(plist, "^CUNIT2",0);


  cpl_propertylist_erase_regexp(plist, "^CD1_1",0);
  cpl_propertylist_erase_regexp(plist, "^CD1_2",0);
  cpl_propertylist_erase_regexp(plist, "^CD2_1",0);
  cpl_propertylist_erase_regexp(plist, "^CD2_2",0);




  sinfo_set_spect_coord1(&plist,crpix1,crval1,cdelt1);
  sinfo_set_spect_coord2(&plist,crpix2,crval2,cdelt2);



}
/**
@brief set world coordinate system for an image
@name sinfo_new_change_plist_image
@param plist input propertylist
@param name file name
@param center_x center x
@param center_y center y
*/

static void
sinfo_new_change_plist_image (cpl_propertylist * plist,
            float center_x,
            float center_y )
{

    float pixelscale ;
    double ra ;
    double dec ;
    double angle ;
    float radangle ;
    float cd1_1, cd1_2, cd2_1, cd2_2 ;
    char firsttext[2*FILE_NAME_SZ] ;
    int sign_swap = -1;


    double cdelt1=0;
    double cdelt2=0;

    double crpix1=center_x;
    double crpix2=center_y;

    double crval1=0;
    double crval2=0;




    strcpy(firsttext, "sinfo_rec_objnod -f \0") ;

    pixelscale = sinfo_pfits_get_pixscale(plist)/2. ;
    ra = sinfo_pfits_get_ra(plist) ;
    dec = sinfo_pfits_get_DEC(plist) ;



    //get better coordinate values
    ra=sinfo_pfits_get_targ_alpha(plist);
    dec=sinfo_pfits_get_targ_delta(plist);
    ra=sinfo_hms2deg(ra);
    dec=sinfo_sess2deg(dec);



    crval1=ra;
    crval2=dec;

    angle = sinfo_pfits_get_posangle(plist) ;
    /* in PUPIL data there is not posangle info: we reset the error */
    if(cpl_error_get_code() != CPL_ERROR_NONE) {
       cpl_error_reset();
    }

    radangle = angle * PI_NUMB / 180. ;

    cdelt1=sign_swap * pixelscale / 3600. ;
    cdelt2=            pixelscale / 3600. ;


    cd1_1 = +cdelt1*cos(radangle) ;
    cd1_2 = -cdelt2*sin(radangle) ;
    cd2_1 = +cdelt1*sin(radangle) ;
    cd2_2 = +cdelt2*cos(radangle) ;





    check_nomsg(sinfo_set_coord1(&plist,crpix1,crval1,cdelt1));
    check_nomsg(sinfo_set_coord2(&plist,crpix2,crval2,cdelt2));
    check_nomsg(sinfo_set_cd_matrix2(&plist,cd1_1,cd1_2,cd2_1,cd2_2));


 cleanup:
    return;
}

/**
@brief subtract from each cube's plane its median
@name sinfo_new_sinfoni_correct_median
@param cubes input imagelist
@param n_cubes number of cubes
*/

cpl_imagelist**
sinfo_new_sinfoni_correct_median(cpl_imagelist** cubes, const int n_cubes)
{
  int i=0;
  cpl_imagelist** cubes_cor=NULL;
  double local_median=0;
  int z=0;
  cpl_image* i_img=NULL;
  cpl_image* o_img=NULL;


  if ( cubes == NULL ) {
    sinfo_msg_error ("no cube list given!") ;
    return NULL ;
  }
  if ( n_cubes <= 0 ) {
    sinfo_msg_error ("wrong number of data cubes in list!") ;
    return NULL ;
  }

  cubes_cor = (cpl_imagelist**) cpl_calloc (n_cubes, sizeof (cpl_imagelist*)) ;

  for ( i = 0 ; i < n_cubes ; i++ ) {
    cubes_cor[i] = cpl_imagelist_new();
    for(z=0;z< cpl_imagelist_get_size(cubes[i]); z++) {
      i_img=cpl_imagelist_get(cubes[i],z);
      local_median=cpl_image_get_median(i_img);;
      o_img=cpl_image_duplicate(i_img);
      if(!isnan(local_median)) {
        cpl_image_subtract_scalar(o_img,local_median);
       }
      cpl_imagelist_set(cubes_cor[i],o_img,z);
    }
  }

  return cubes_cor;
}

/**
@brief subtract from each cube's plane its median
@name sinfo_new_sinfoni_correct_median_it
@param inp input imagelist
*/

int sinfo_new_sinfoni_correct_median_it(cpl_imagelist** inp)
{

  double local_median=0;
  int z=0;
  cpl_image* img=NULL;

  for(z=0;z< cpl_imagelist_get_size((*inp)); z++) {
    img=cpl_imagelist_get((*inp),z);
    local_median=sinfo_new_my_median_image(img);
    if(!isnan(local_median)) {
      cpl_image_subtract_scalar(img,local_median);
    }  else {
      sinfo_msg_error("local_median is NAN");
    }
    cpl_imagelist_set((*inp),img,z);
  }

  return 0;
}

/**
@brief subtract from each object cube's plane each sky cube's
       plane and return the sky cube
@name sinfo_new_sinfoni_correct_sky
@param inp input imagelist
@param nc  size of cube
@param sky_cube output sky cube
*/

cpl_imagelist** sinfo_new_sinfoni_correct_sky(cpl_imagelist** cubes,
                  const int nc,
                  cpl_imagelist* sky_cube)

{
  cpl_imagelist** cubes_sky=NULL;
  int x=0;
  int y=0;
  int z=0;
  int i=0;
  float k=0.5;
  int ovr=0;
  int ks=0;
  int nclip=0;
  double med=0;
  double avg=0;
  double sig=0;
  int msk_sum=0;
  double val_msk_sum=0;
  cpl_vector* val=NULL;
  cpl_vector* msk=NULL;
  int ilx=0;
  int ily=0;
  int inp=0;


  int sky_lx=0;
  /* int sky_ly=0; */

  float* pidata=NULL;
  float* p_sky_data=NULL;
  cpl_image* i_img=NULL;
  cpl_image* sky_img=NULL;


  if ( cubes == NULL ) {
    sinfo_msg_error ("no cube list given!") ;
    return NULL ;
  }
  ilx=cpl_image_get_size_x(cpl_imagelist_get(cubes[0],0));
  ily=cpl_image_get_size_y(cpl_imagelist_get(cubes[0],0));
  inp=cpl_imagelist_get_size(cubes[0]);


  sky_lx=cpl_image_get_size_x(cpl_imagelist_get(sky_cube,0));
  /* sky_ly=cpl_image_get_size_y(cpl_imagelist_get(sky_cube,0)); */
  if ( nc <= 0 ) {
    sinfo_msg_error ("wrong number of data cubes in list!") ;
    return NULL ;
  }

  cubes_sky = (cpl_imagelist**) cpl_calloc (nc, sizeof (cpl_imagelist*)) ;
  for(z=0;z< inp; z++) {
    sky_img=cpl_imagelist_get(sky_cube,z);
    p_sky_data=cpl_image_get_data_float(sky_img);
    for(y=0;y< ily; y++) {
      for(x=0;x< ilx; x++) {
        /* here we start to do a k-s clipping */
    msk=cpl_vector_new(nc);
    for (i=0;i<nc;i++) {
      cpl_vector_set(msk,i,1);
    }
        nclip=0;
        for (ks=0;ks<nc;ks++) {
      sig=0;
      med=0;
      ovr=0;
      val=cpl_vector_new(nc-nclip);

      for ( i = 0 ; i < nc ; i++ ) {
            i_img=cpl_imagelist_get(cubes[i],z);
            pidata=cpl_image_get_data_float(i_img);
        if ((!isnan(pidata[x+y*ilx])) &&
                 (cpl_vector_get(msk,i) != 0) ) {
          cpl_vector_set(val,ovr,(double)pidata[x+y*ilx]);
          ovr++;
        }
      }

      if(ovr>0) {
        avg=cpl_vector_get_mean(val);
        med=cpl_vector_get_median_const(val);
        if(ovr>1) {
          sig=cpl_vector_get_stdev(val);
        } else {
              sig=0;
        }
      } else {
        avg=cpl_vector_get(val,0);
        med=avg;
        sig=0;
      }

      cpl_vector_delete(val);
      for ( i = 0 ; i < nc ; i++ ) {
            i_img=cpl_imagelist_get(cubes[i],z);
            pidata=cpl_image_get_data_float(i_img);
      /* Do k-s clipping at each pixel */
        if ((!isnan(pidata[x+y*ilx])) &&
                (cpl_vector_get(msk,i) != 0)) {
          if(abs((pidata[x+y*ilx]-med))> k*sig) {
        cpl_vector_set(msk,i,0);
                nclip++;
          }
        }
      }
    }/* end of k-s clipping */
    msk_sum=0;
    val_msk_sum=0;
    for ( i = 0 ; i < nc ; i++ ) {
      /* computes sky at each point */
      if (!isnan(pidata[x+y*ilx])) {
        msk_sum+=cpl_vector_get(msk,i);
                val_msk_sum+=pidata[x+y*ilx]*
          cpl_vector_get(msk,i);
      }
    }
    p_sky_data[x+y*sky_lx]=val_msk_sum/msk_sum;
    cpl_vector_delete(msk);
      } /* end loop over x */
    } /* end loop over y */
  } /* end loop over z */
  for ( i = 0 ; i < nc ; i++ ) {
    cubes_sky[i]=cpl_imagelist_duplicate(cubes[i]);
    /* subtract the variable clean sky */
    cpl_imagelist_subtract(cubes_sky[i],sky_cube);

  }


  return cubes_sky;
}

/**
@brief subtract from each object cube's plane each sky cube's plane and
       output a sky, a median, a mask, an average, a sigma and and
       overlapping imagelist
@name sinfo_new_sinfoni_correct_sky2
@param inp input imagelist
@param nc  size of imagelist
@param sky_cube sky
@param med_cube median
@param msk_cube mask
@param avg_cube average
@param sig_cube sigma
@param ovr_cube overlapping points
*/
cpl_imagelist** sinfo_new_sinfoni_correct_sky2(cpl_imagelist** cubes,
                  const int nc,
                  cpl_imagelist* sky_cube,
                              cpl_imagelist* med_cube,
                              cpl_imagelist* msk_cube,
                              cpl_imagelist* avg_cube,
                              cpl_imagelist* sig_cube,
                              cpl_imagelist* ovr_cube)
{
  cpl_imagelist** cubes_sky=NULL;
  int x=0;
  int y=0;
  int z=0;
  int i=0;
  float k=0.5;
  int ovr=0;
  int ks=0;
  int nclip=0;
  double med=0;
  double avg=0;
  double sig=0;
  int msk_sum=0;
  double val_msk_sum=0;
  cpl_vector* val=NULL;
  cpl_vector* msk=NULL;

  int ilx=0;
  int ily=0;
  int inp=0;

  int ovr_lx=0;
  int msk_lx=0;
  int avg_lx=0;
  int sig_lx=0;
  int sky_lx=0;
  int med_lx=0;


  float* p_ovr_data=NULL;
  float* p_msk_data=NULL;
  float* p_avg_data=NULL;
  float* p_sig_data=NULL;
  float* p_sky_data=NULL;
  float* p_med_data=NULL;

  float* pidata=NULL;

  if ( cubes == NULL ) {
    sinfo_msg_error ("no cube list given!") ;
    return NULL ;
  }

  ilx=cpl_image_get_size_x(cpl_imagelist_get(cubes[0],0));
  ily=cpl_image_get_size_y(cpl_imagelist_get(cubes[0],0));
  inp=cpl_imagelist_get_size(cubes[0]);

  if ( nc <= 0 ) {
    sinfo_msg_error ("wrong number of data cubes in list!") ;
    return NULL ;
  }

  cubes_sky = (cpl_imagelist**) cpl_calloc (nc, sizeof (cpl_imagelist*)) ;

  ovr_lx=ilx;
  msk_lx=ilx;
  avg_lx=ilx;
  sig_lx=ilx;
  sky_lx=ilx;
  med_lx=ilx;

  for(z=0;z< inp; z++) {
    p_ovr_data=cpl_image_get_data_float(cpl_imagelist_get(ovr_cube,z));
    p_msk_data=cpl_image_get_data_float(cpl_imagelist_get(msk_cube,z));
    p_avg_data=cpl_image_get_data_float(cpl_imagelist_get(avg_cube,z));
    p_sig_data=cpl_image_get_data_float(cpl_imagelist_get(sig_cube,z));
    p_sky_data=cpl_image_get_data_float(cpl_imagelist_get(sky_cube,z));
    p_med_data=cpl_image_get_data_float(cpl_imagelist_get(med_cube,z));


    for(y=0;y< ily; y++) {
      for(x=0;x< ilx; x++) {
        /* here we start to do a k-s clipping */
    msk=cpl_vector_new(nc);
    for (i=0;i<nc;i++) {
      cpl_vector_set(msk,i,1);
    }
    p_ovr_data[x+y*ovr_lx]=nc;
    p_msk_data[x+y*msk_lx]=nc;
        nclip=0;
        for (ks=0;ks<nc;ks++) {
      sig=0;
      med=0;
      ovr=0;
      val=cpl_vector_new(nc-nclip);

      for ( i = 0 ; i < nc ; i++ ) {
            pidata=cpl_image_get_data_float(cpl_imagelist_get(cubes[i],z));
        if ((!isnan(pidata[x+y*ilx])) &&
                 (cpl_vector_get(msk,i) != 0) ) {
          cpl_vector_set(val,ovr,(double)pidata[x+y*ilx]);
          ovr++;
        }
      }

      if(ovr>1) {
        avg=cpl_vector_get_mean(val);
        med=cpl_vector_get_median_const(val);
        sig=cpl_vector_get_stdev(val);
      } else {
        avg=cpl_vector_get(val,0);
        med=avg;
        sig=0;
      }

      p_med_data[x+y*med_lx]=med;
      p_avg_data[x+y*avg_lx]=avg;
      p_sig_data[x+y*sig_lx]=sig;
      cpl_vector_delete(val);
      for ( i = 0 ; i < nc ; i++ ) {
           pidata=cpl_image_get_data_float(cpl_imagelist_get(cubes[i],z));
      /* Do k-s clipping at each pixel */
        if ((!isnan(pidata[x+y*ilx])) &&
                (cpl_vector_get(msk,i) != 0)) {
          if(abs((pidata[x+y*ilx]-med))> k*sig) {
        /* pidata[x+y*ilx]=0; */
        p_msk_data[x+y*msk_lx]-=1;
        cpl_vector_set(msk,i,0);
                nclip++;
          }
        }
      }
    }/* end of k-s clipping */
    msk_sum=0;
    val_msk_sum=0;
    for ( i = 0 ; i < nc ; i++ ) {
           pidata=cpl_image_get_data_float(cpl_imagelist_get(cubes[i],z));
      /* computes sky at each point */
      if (!isnan(pidata[x+y*ilx])) {
        /*
        msk_sum+=p_msk_data[x+y*msk_lx];
                val_msk_sum+=pidata[x+y*cubes[i]->lx]*
          p_msk_data[x+y*msk_lx];
        */
        msk_sum+=cpl_vector_get(msk,i);
                val_msk_sum+=pidata[x+y*ilx]*
          cpl_vector_get(msk,i);
      }
    }
    p_sky_data[x+y*sky_lx]=val_msk_sum/msk_sum;
    cpl_vector_delete(msk);
      } /* end loop over x */
    } /* end loop over y */
  } /* end loop over z */
  for ( i = 0 ; i < nc ; i++ ) {
    cubes_sky[i]=cpl_imagelist_duplicate(cubes[i]);
    /* subtract the variable clean sky */
    cpl_imagelist_subtract(cubes_sky[i],sky_cube);
  }


  return cubes_sky;
}


/**
@brief extracts from each object frame set information
       relative to the ao setting
@name sinfo_new_assign_offset
@param n      frame index in list
@param name   file name
@param offsetx  reference frame X offset
@param offsety  reference frame Y offset
@param offsetx frames X offset array
@param offsety frames Y offset array
*/

int
sinfo_new_assign_offset(const int n,
                        const char* name,
                        float* offsetx,
                        float* offsety,
                        const float ref_offx,
                        const float ref_offy)
{

  float offx=0;
  float offy=0;
  double mjd_obs=0;
  /*
  double pixelscale=0;
  double angle=0;
  double radangle=0;
  double cd1_1=0;
  double cd1_2=0;
  double cd2_1=0;
  double cd2_2=0;
  double ra=0;
  double dec=0;
  */

  cpl_propertylist * plist=NULL;
  sinfo_msg_debug("Assign offsets");

  if ((cpl_error_code)((plist = cpl_propertylist_load(name, 0)) == NULL)) {
    sinfo_msg_error( "getting header from reference frame %s",name);
    cpl_propertylist_delete(plist) ;
    return -1 ;
  }

  offx = sinfo_pfits_get_cumoffsetx(plist) - ref_offx ;  /* was - */
  if(cpl_error_get_code() != CPL_ERROR_NONE) {
    sinfo_msg_warning(" could not read fits header keyword cummoffsetx!") ;
    sinfo_msg_warning(" Set relative offset to 0 - %f!",ref_offx) ;
    offx =  - ref_offx;
    cpl_error_reset();
    /* return -1 ; */
  }

  offy = sinfo_pfits_get_cumoffsety(plist) - ref_offy ; /* was - */
  if(cpl_error_get_code() != CPL_ERROR_NONE) {
    sinfo_msg_warning(" could not read fits header keyword! cumoffsety") ;
    sinfo_msg_warning(" Set relative offset to 0 - %f!",ref_offx) ;
    offy =  - ref_offy;
    cpl_error_reset();
    /* return -1 ; */
  }
  sinfo_msg_debug("offx=%f offy=%f",offx,offy);

  if (sinfo_propertylist_has(plist, KEY_NAME_MJD_OBS)) {
    mjd_obs=cpl_propertylist_get_double(plist, KEY_NAME_MJD_OBS);
  } else {
    sinfo_msg_error("keyword %s does not exist",KEY_NAME_MJD_OBS);
    cpl_propertylist_delete(plist) ;
    return -1;
  }

  cpl_propertylist_delete(plist) ;

  if (mjd_obs > 53825. ) {
    /* April 1st 2006 */
    //sinfo_msg("New cumoffset setting convention");
    sinfo_new_array_set_value(offsetx,2*offx,n);
    sinfo_new_array_set_value(offsety,2*offy,n);
  } else if ((mjd_obs > 53421.58210082 ) && (mjd_obs <= 53825.)){
    /* after detector's upgrade */
    /*
    sinfo_new_array_set_value(offsetx,-offx*2,n);
    sinfo_new_array_set_value(offsety,+offy*2,n);
    */
    sinfo_new_array_set_value(offsetx,-2*offx,n);
    sinfo_new_array_set_value(offsety,2*offy,n);
  } else {
    /* before detector's upgrade */
    /*
    sinfo_new_array_set_value(offsetx,+offx*2,n);
    sinfo_new_array_set_value(offsety,-offy*2,n);
    */
    sinfo_new_array_set_value(offsetx,2*offx,n);
    sinfo_new_array_set_value(offsety,-2*offy,n);
  }

  return 0;


}





/**
@brief extracts from each object frame set information
       relative to the ao setting
@name sinfo_new_assign_offset
@param n      frame index in list
@param name   file name
@param offsetx  reference frame X offset
@param offsety  reference frame Y offset
@param offsetx frames X offset array
@param offsety frames Y offset array
*/

int
sinfo_new_assign_offset2(const int n,
                        const char* name,
                        float* offsetx,
                        float* offsety,
                        const float ref_offx,
                        const float ref_offy)
{

  float offx=0;
  float offy=0;
  double mjd_obs=0;

  cpl_propertylist * plist=NULL;
  sinfo_msg_debug("Assign offsets as set by user");
  offx = offsetx[n] - ref_offx ;  /* was - */
  offy = offsety[n] - ref_offy ;  /* was - */
  sinfo_msg_debug("offx=%f offy=%f",offx,offy);

  sinfo_msg_debug("Assign offsets");

  if ((cpl_error_code)((plist = cpl_propertylist_load(name, 0)) == NULL)) {
    sinfo_msg_error( "getting header from reference frame %s",name);
    cpl_propertylist_delete(plist) ;
    return -1 ;
  }

  if (sinfo_propertylist_has(plist, KEY_NAME_MJD_OBS)) {
    mjd_obs=cpl_propertylist_get_double(plist, KEY_NAME_MJD_OBS);
  } else {
    sinfo_msg_error("keyword %s does not exist",KEY_NAME_MJD_OBS);
    cpl_propertylist_delete(plist) ;
    return -1;
  }
  cpl_propertylist_delete(plist) ;

  //sinfo_new_array_set_value(offsetx,-2*offx,n);
  //sinfo_new_array_set_value(offsety,2*offy,n);

  if (mjd_obs > 53825. ) {
    /* April 1st 2006 */
    //sinfo_msg("New cumoffset setting convention");
    sinfo_new_array_set_value(offsetx,2*offx,n);
    sinfo_new_array_set_value(offsety,2*offy,n);
  } else if ((mjd_obs > 53421.58210082 ) && (mjd_obs <= 53825.)){
    /* after detector's upgrade */
    /*
    sinfo_new_array_set_value(offsetx,-offx*2,n);
    sinfo_new_array_set_value(offsety,+offy*2,n);
    */
    sinfo_new_array_set_value(offsetx,-2*offx,n);
    sinfo_new_array_set_value(offsety,2*offy,n);
  } else {
    /* before detector's upgrade */
    /*
    sinfo_new_array_set_value(offsetx,+offx*2,n);
    sinfo_new_array_set_value(offsety,-offy*2,n);
    */
    sinfo_new_array_set_value(offsetx,2*offx,n);
    sinfo_new_array_set_value(offsety,-2*offy,n);
  }


  return 0;


}


/**
@brief extracts from each object frame set information
       relative to the ao setting
@name sinfo_new_assign_offset
@param n      frame index in list
@param name   file name
@param offsetx  reference frame X offset
@param offsety  reference frame Y offset
@param offsetx frames X offset array
@param offsety frames Y offset array
*/

int
sinfo_new_object_assign_offset(const char* name,
                               const int n,
                               double* ref_offx,
                               double* ref_offy,
                               float** offsetx,
                               float** offsety)
{

  float offx=0;
  float offy=0;
  double mjd_obs=0;
  cpl_propertylist * plist=NULL;
  sinfo_msg_debug("Assign offsets");

  if ((cpl_error_code)((plist = cpl_propertylist_load(name, 0)) == NULL)) {
    sinfo_msg_error( "getting header from reference frame %s",name);
    cpl_propertylist_delete(plist) ;
    return -1 ;
  }
  if ( n == 0 ) {

    *ref_offx = sinfo_pfits_get_cumoffsetx(plist) ;
    if(cpl_error_get_code() != CPL_ERROR_NONE) {
      sinfo_msg_error(" could not read fits header keyword cummoffsetx!") ;
      /* return -1 ; */
      cpl_error_reset();
    }

    *ref_offy = sinfo_pfits_get_cumoffsety(plist) ;
    if(cpl_error_get_code() != CPL_ERROR_NONE) {
      sinfo_msg_error(" could not read fits header keyword! cumoffsety") ;
      cpl_error_reset();
       /* return -1 ; */
    }
    sinfo_msg_debug("Reference offx=%f offy=%f",*ref_offx,*ref_offy);

    offx = 0. ;
    offy = 0. ;

  } else {

    offx = sinfo_pfits_get_cumoffsetx(plist) - *ref_offx ;  /* was - */
    if(cpl_error_get_code() != CPL_ERROR_NONE) {
      sinfo_msg_error(" could not read fits header keyword cummoffsetx!") ;
      cpl_error_reset();
      /* return -1 ; */
    }

    offy = sinfo_pfits_get_cumoffsety(plist) - *ref_offy ; /* was - */
    if(cpl_error_get_code() != CPL_ERROR_NONE) {
      sinfo_msg_error(" could not read fits header keyword! cumoffsety") ;
      /* return -1 ; */
      cpl_error_reset();
    }
    sinfo_msg_debug("offx=%f offy=%f",offx,offy);
  }


    /* rotate the coordinates
       offx_rot = cd1_1 * offx + cd2_1 * offy ;
       offy_rot = cd1_2 * offx + cd2_2 * offy ;
        convert the coordinates to pixel units
       offx_rot_pix = offx_rot / pixelscale ;
       offy_rot_pix = offy_rot / pixelscale ;
       offsetx[i] = offx_rot_pix ;
       offsety[i] = offy_rot_pix ;
    */


  if (sinfo_propertylist_has(plist, KEY_NAME_MJD_OBS)) {
    mjd_obs=cpl_propertylist_get_double(plist, KEY_NAME_MJD_OBS);
  } else {
    sinfo_msg_error("keyword %s does not exist",KEY_NAME_MJD_OBS);
    cpl_propertylist_delete(plist) ;
    return -1;
  }

  cpl_propertylist_delete(plist) ;

  if (mjd_obs > 53825. ) {
    /* April 1st 2006 */
    //sinfo_msg("New cumoffset setting convention");
    sinfo_new_array_set_value(*offsetx,2*offx,n);
    sinfo_new_array_set_value(*offsety,2*offy,n);
  } else if ((mjd_obs > 53421.58210082 ) && (mjd_obs <= 53825.)){
    /* after detector's upgrade */
    sinfo_new_array_set_value(*offsetx,-offx*2,n);
    sinfo_new_array_set_value(*offsety,+offy*2,n);
  } else {
    /* before detector's upgrade */
    sinfo_new_array_set_value(*offsetx,+offx*2,n);
    sinfo_new_array_set_value(*offsety,-offy*2,n);
  }

  return 0;
}

/**
@brief Fine tune slitlet distances values
@name sinfo_new_fine_tune
@param cube input imagelist
@param correct_dist array with correct distances
@param method  fine tune method
@param order   polynomial order
@param nslits number of slits
*/


cpl_imagelist*
sinfo_new_fine_tune(cpl_imagelist* cube,
              float* correct_dist,
              const char* method,
              const int order,
              const int nslits) {
  int i =0;
  cpl_imagelist* outcube2=NULL;
  float* neg_dist=NULL;
  sinfo_msg("Finetuning, method=%s",method);

  if (strcmp(method,"P")==0)
    {
      outcube2 = sinfo_new_fine_tune_cube( cube, correct_dist, order ) ;
      if (outcube2 == NULL)
    {
      sinfo_msg_error (" could not fine tune the data cube\n") ;
      return NULL ;
    }
    }
  else if (strcmp(method,"F")==0)
    {
      neg_dist=cpl_calloc(nslits,sizeof(float));
      for ( i = 0 ; i < nslits ; i++ )
    {
      neg_dist[i] = -correct_dist[i] ;
    }
      outcube2 = sinfo_new_fine_tune_cube_by_FFT( cube, neg_dist ) ;
     cpl_free(neg_dist);
      if ( outcube2 == NULL )
    {
      sinfo_msg_error (" could not fine tune the data cube\n") ;
      return NULL ;
    }
    }
  else if (strcmp(method,"S")==0)
    {
      outcube2 = sinfo_new_fine_tune_cube_by_spline( cube, correct_dist ) ;
      if ( outcube2 == NULL )
    {
      sinfo_msg_error (" could not fine tune the data cube\n") ;
      return NULL ;
    }
    }
  else
    {
      sinfo_msg_error (" wrong method indicator given!") ;
      return NULL ;
    }



return outcube2;

}

/*----------------------------------------------------------------------------*/
/**
  @brief    Get the broad band filter
  @param    f           the filter name
  @return   the broadband filter id
 */
/*----------------------------------------------------------------------------*/
sinfo_band sinfo_get_associated_filter(const char * f)
{
    if (!strcmp(f, "J"))            return SINFO_BAND_J ;
    if (!strcmp(f, "Js"))           return SINFO_BAND_JS ;
    if (!strcmp(f, "Z"))            return SINFO_BAND_Z ;
    if (!strcmp(f, "SZ"))           return SINFO_BAND_SZ ;
    if (!strcmp(f, "SH"))           return SINFO_BAND_SH ;
    if (!strcmp(f, "H"))            return SINFO_BAND_H ;
    if (!strcmp(f, "Ks"))           return SINFO_BAND_KS ;
    if (!strcmp(f, "K"))            return SINFO_BAND_K ;
    if (!strcmp(f, "SK"))           return SINFO_BAND_SK ;
    if (!strcmp(f, "L"))            return SINFO_BAND_L ;
    if (!strcmp(f, "SL"))           return SINFO_BAND_SL ;
    if (!strcmp(f, "M"))            return SINFO_BAND_M ;
    if (!strcmp(f, "M_NB"))         return SINFO_BAND_M ;
    if (!strcmp(f, "NB_1.06"))      return SINFO_BAND_J ;
    if (!strcmp(f, "NB_1.08"))      return SINFO_BAND_J ;
    if (!strcmp(f, "NB_1.19"))      return SINFO_BAND_J ;
    if (!strcmp(f, "NB_1.21"))      return SINFO_BAND_J ;
    if (!strcmp(f, "NB_1.26"))      return SINFO_BAND_J ;
    if (!strcmp(f, "NB_1.28"))      return SINFO_BAND_J ;
    if (!strcmp(f, "NB_1.64"))      return SINFO_BAND_H ;
    if (!strcmp(f, "NB_1.71"))      return SINFO_BAND_H ;
    if (!strcmp(f, "NB_2.07"))      return SINFO_BAND_KS ;
    if (!strcmp(f, "NB_2.09"))      return SINFO_BAND_KS ;
    if (!strcmp(f, "NB_2.13"))      return SINFO_BAND_KS ;
    if (!strcmp(f, "NB_2.17"))      return SINFO_BAND_KS ;
    if (!strcmp(f, "NB_2.19"))      return SINFO_BAND_KS ;
    if (!strcmp(f, "NB_2.25"))      return SINFO_BAND_KS ;
    if (!strcmp(f, "NB_2.29"))      return SINFO_BAND_KS ;
    if (!strcmp(f, "NB_2.34"))      return SINFO_BAND_KS ;
    if (!strcmp(f, "NB_3.21"))      return SINFO_BAND_L ;
    if (!strcmp(f, "NB_3.28"))      return SINFO_BAND_L ;
    if (!strcmp(f, "NB_3.80"))      return SINFO_BAND_L ;
    if (!strcmp(f, "NB_4.07"))      return SINFO_BAND_L ;
    return SINFO_BAND_UNKNOWN ;
}



/*----------------------------------------------------------------------------*/
/**
  @brief    Get the broad band filter
  @param    f           the filter name
  @return   the broadband filter id
 */
/*----------------------------------------------------------------------------*/
sinfo_band sinfo_get_bbfilter(const char * f)
{
    if (!strcmp(f, "J"))            return SINFO_BAND_J ;
    if (!strcmp(f, "J+Block"))      return SINFO_BAND_J ;
    if (!strcmp(f, "Js"))           return SINFO_BAND_J ;
    if (!strcmp(f, "Z"))            return SINFO_BAND_J ;
    if (!strcmp(f, "SZ"))           return SINFO_BAND_J ;
    if (!strcmp(f, "SH"))           return SINFO_BAND_H ;
    if (!strcmp(f, "H"))            return SINFO_BAND_H ;
    if (!strcmp(f, "Ks"))           return SINFO_BAND_KS ;
    if (!strcmp(f, "K"))            return SINFO_BAND_K ;
    if (!strcmp(f, "SK"))           return SINFO_BAND_K ;
    if (!strcmp(f, "L"))            return SINFO_BAND_L ;
    if (!strcmp(f, "SL"))           return SINFO_BAND_L ;
    if (!strcmp(f, "M"))            return SINFO_BAND_M ;
    if (!strcmp(f, "M_NB"))         return SINFO_BAND_M ;
    if (!strcmp(f, "NB_1.06"))      return SINFO_BAND_J ;
    if (!strcmp(f, "NB_1.08"))      return SINFO_BAND_J ;
    if (!strcmp(f, "NB_1.19"))      return SINFO_BAND_J ;
    if (!strcmp(f, "NB_1.21"))      return SINFO_BAND_J ;
    if (!strcmp(f, "NB_1.26"))      return SINFO_BAND_J ;
    if (!strcmp(f, "NB_1.28"))      return SINFO_BAND_J ;
    if (!strcmp(f, "NB_1.64"))      return SINFO_BAND_H ;
    if (!strcmp(f, "NB_1.71"))      return SINFO_BAND_H ;
    if (!strcmp(f, "NB_2.07"))      return SINFO_BAND_KS ;
    if (!strcmp(f, "NB_2.09"))      return SINFO_BAND_KS ;
    if (!strcmp(f, "NB_2.13"))      return SINFO_BAND_KS ;
    if (!strcmp(f, "NB_2.17"))      return SINFO_BAND_KS ;
    if (!strcmp(f, "NB_2.19"))      return SINFO_BAND_KS ;
    if (!strcmp(f, "NB_2.25"))      return SINFO_BAND_KS ;
    if (!strcmp(f, "NB_2.29"))      return SINFO_BAND_KS ;
    if (!strcmp(f, "NB_2.34"))      return SINFO_BAND_KS ;
    if (!strcmp(f, "NB_3.21"))      return SINFO_BAND_L ;
    if (!strcmp(f, "NB_3.28"))      return SINFO_BAND_L ;
    if (!strcmp(f, "NB_3.80"))      return SINFO_BAND_L ;
    if (!strcmp(f, "NB_4.07"))      return SINFO_BAND_L ;
    return SINFO_BAND_UNKNOWN ;
}


/**@}*/
