/*
 * This file is part of the ESO SINFONI Pipeline
 * Copyright (C) 2004-2009 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
 */
/*
 * $Author: amodigli $
 * $Date: 2012/03/03 10:17:31 $
 * $Revision: 1.17 $
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <math.h>
#include <cpl.h>
/* irplib */
#include <irplib_utils.h>

#include <sinfo_pfits.h>
#include <sinfo_msg.h>
#include <sinfo_dfs.h>
#include <sinfo_error.h>
#include <sinfo_utils_wrappers.h>
#include "sinfo_utl_efficiency.h"
#include <sinfo_star_index.h>

#define PRO_STD_STAR_SPECTRA "STD_STAR_SPECTRA"
static const char COL_NAME_WAVELENGTH[] = "WAVELENGTH";
static const char COL_NAME_WAVELENGTH_C[] = "WAVELENGTH";
static const char COL_NAME_LAMBDA[] 	= "LAMBDA";
static const char COL_NAME_LA_SILLA[]	= "LA_SILLA";
static const char COL_NAME_REF[]		= "REF";
static const char COL_NAME_COR[]		= "COR";
static const char COL_NAME_SRC_COR[]	= "SRC_COR";
static const char COL_NAME_COUNTS_BKG[]	= "INT_OBJ";//"counts_tot";
static const char COL_NAME_FLUX[]		= "FLUX";
static const char COL_NAME_EPHOT[]		= "EPHOT";
static const char COL_NAME_EXT[]		= "EXT";
static const char COL_NAME_SRC_EFF[]	= "EFF";
static const char PAR_NAME_DIT[]		= "ESO DET DIT";

static char FRM_RAW_IMA_SLIT[]	= PRO_STD_STAR_SPECTRA;
static char FRM_FLUX_STD_TAB[]	= FLUX_STD_TABLE;
static char FRM_FLUX_STD_CAT[]	= FLUX_STD_CATALOG;
static char FRM_EXTCOEFF_TAB[]	= EXTCOEFF_TABLE;

static int 
sinfo_column_to_double(cpl_table* ptable, const char* column);

static double 
sinfo_table_interpolate(cpl_table* tbl,
		  double wav,
		  const char* colx,
		  const char* coly);
static double* 
sinfo_create_column_double(cpl_table* tbl, const char* col_name, int nrow);



cpl_error_code
sinfo_get_std_obs_values(cpl_propertylist* plist,
                       double* exptime,
                       double* airmass,
                       double* dRA,
                       double* dDEC);

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

/**@{*/
/*---------------------------------------------------------------------------*/
/**
  @brief    load reference table

  @param    frames    input frames list
  @param    dRA       Right Ascension
  @param    dDEC      Declination
  @param    EPSILON   tolerance to find ref spectra on catalog on (ra,dec)
  @param    ptable    pointer to new table
  @return   Interpolated data points
 */
/*---------------------------------------------------------------------------*/

void 
sinfo_load_ref_table(cpl_frameset* frames, 
                   double dRA, 
                   double dDEC, 
                   double EPSILON, 
                   cpl_table** pptable)
{
  const char* name = NULL;
  cpl_frame* frm_ref = NULL;

  /* REF STD frame */
  frm_ref=cpl_frameset_find(frames,FRM_FLUX_STD_TAB);
  if (!frm_ref)
    {
      sinfo_msg("REF frame is not found, trying to get REF from the catalog");
     /* REF STD catalog frame */
      // get from catalog
      check_nomsg(frm_ref=cpl_frameset_find(frames,FRM_FLUX_STD_CAT));
      if (frm_ref)
	{
	  check_nomsg(name=cpl_frame_get_filename(frm_ref));
	  if (name)
	    {
	      star_index* pstarindex = star_index_load(name);
	      if (pstarindex)
		{
		  const char* star_name = 0;
		  sinfo_msg("The catalog is loaded, looking for star in RA[%f] DEC[%f] tolerance[%f]", dRA, dDEC, EPSILON);
		  *pptable = star_index_get(pstarindex, dRA, dDEC, EPSILON, EPSILON, &star_name);
		  if (*pptable && star_name)
		    {
		      sinfo_msg("REF table is found in the catalog, star name is [%s]", star_name);
		    }
		  else
		    {
		      sinfo_msg("ERROR - REF table could not be found in the catalog");
		    }
		}
	      else
		{
		  sinfo_msg("ERROR - could not load the catalog");
		}
	    }
	}
    }
  else
    {
      sinfo_msg("REF frame is found");
      check_nomsg(name=cpl_frame_get_filename(frm_ref));
      check_nomsg(*pptable=cpl_table_load(name,1,0));
    }
  return;
 cleanup:
  return;
}




/*---------------------------------------------------------------------------*/
/**
  @brief    load reference table

  @param    cat        input frame catalog
  @param    dRA        Right Ascension
  @param    dDEC       Declination
  @param    EPSILON    tolerance to find ref spectra on catalog on (ra,dec)
  @param    ptable     pointer to new table
  @return   Interpolated data points
 */
/*---------------------------------------------------------------------------*/

static void 
sinfo_parse_catalog_std_stars(cpl_frame* cat, 
			    double dRA, 
			    double dDEC, 
			    double EPSILON, 
			    cpl_table** pptable)
{
  const char* name = NULL;

  if (cat) {
    check_nomsg(name=cpl_frame_get_filename(cat));
    if (name) {
      star_index* pstarindex = star_index_load(name);
      if (pstarindex) {
	const char* star_name = 0;
	sinfo_msg("The catalog is loaded, looking for star in RA[%f] DEC[%f] tolerance[%f]", dRA, dDEC, EPSILON);
	*pptable = star_index_get(pstarindex, dRA, dDEC, EPSILON, EPSILON, &star_name);
	if (*pptable && star_name) {
	  sinfo_msg("REF table is found in the catalog, star name is [%s]", star_name);
	}
	else {
	  sinfo_msg("ERROR - REF table could not be found in the catalog");
	}
      }
      else {
	sinfo_msg("ERROR - could not load the catalog");
      }

    }
  }

 cleanup:
  return;
}




/*---------------------------------------------------------------------------*/
/**
  @brief    Interpolate efficiency data points
  @param    wav       wavelength
     number of table raws
  @param    pw        pointer to wave array
  @param    pe        pointer to efficiency array
  @return   Interpolated data points
 */
/*---------------------------------------------------------------------------*/


double
sinfo_data_interpolate(
		     double wav,
		     int nrow,
		     double* pw,
		     double* pe
		     )
{
  double y = 0;
  double w1=pw[0];
  double w2=pw[nrow-1];
  double y1_=pe[0]; /*was changed from y1 to y1_ due a warning from compiler - shadowed variable*/
  double y2=pe[nrow-1];
  if(wav < pw[0])
    {
      w1=pw[0];
      w2=pw[1];
      y1_=pe[0];
      y2=pe[1];
    }
  else if (wav > pw[nrow - 1])
    {
      w1=pw[nrow - 2];
      w2=pw[nrow - 1];
      y1_=pe[nrow - 2];
      y2=pe[nrow - 1];
    }
  else
    {
      int l = 0;
      int h = nrow - 1;
      int curr_row = 0;
      curr_row = (h-l) / 2;
      while( h-l >1 )
	{
	  if(wav < pw[curr_row])
	    {
	      h = curr_row;
	    }
	  else
	    {
	      l = curr_row;
	    }
	  curr_row = (h-l) / 2 + l;
	}
      w1=pw[curr_row];
      w2=pw[curr_row + 1];
      y1_=pe[curr_row];
      y2=pe[curr_row + 1];
    }
  y=y1_+(y2-y1_)/(w2-w1)*(wav-w1);
  return y;
}
static double
sinfo_table_interpolate(cpl_table* tbl,
		  double wav,
		  const char* colx,
		  const char* coly)
{

  double y=0;
  double* pe=NULL;
  double* pw=NULL;
  int nrow=0;

  check_nomsg(pw=cpl_table_get_data_double(tbl,colx));
  check_nomsg(pe=cpl_table_get_data_double(tbl,coly));
  check_nomsg(nrow=cpl_table_get_nrow(tbl));

  y = sinfo_data_interpolate(wav, nrow, pw, pe);
 cleanup:
  return y;

}

static double* 
sinfo_create_column_double(cpl_table* tbl, const char* col_name, int nrow)
{
  double* retval = 0;
  check_nomsg(cpl_table_new_column(tbl, col_name, CPL_TYPE_DOUBLE));
  check_nomsg(cpl_table_fill_column_window_double(tbl, col_name, 0, nrow, -1));
  check_nomsg(retval = cpl_table_get_data_double(tbl,col_name));
  return retval;
 cleanup:
  return retval;
}


/*---------------------------------------------------------------------------*/
/**
  @brief    get STD star observation exptime, airmass, RA, DEC
  @param    plist    (input) property list
  @param    exptime  (output) exposure time
  @param    airmass  (output) airmass (average of start and end)
  @param    dRA      (output) Right Ascension
  @param    dDEC     (output) Declination
  @return   CPL error code
 */
/*---------------------------------------------------------------------------*/

cpl_error_code
sinfo_get_std_obs_values(cpl_propertylist* plist,
                       double* exptime,
                       double* airmass,
                       double* dRA,
                       double* dDEC)
{
   double airmass_start=0;
   double airmass_end=0;

   check_nomsg(*exptime=sinfo_pfits_get_exp_time(plist));
   airmass_start=sinfo_pfits_get_airmass_start(plist);
   airmass_end=sinfo_pfits_get_airmass_end(plist);
   *dRA=sinfo_pfits_get_ra(plist);
   *dDEC=sinfo_pfits_get_dec(plist);
   *airmass=0.5*(airmass_start+airmass_end);

 cleanup:
   return cpl_error_get_code();

}

/*---------------------------------------------------------------------------*/
/**
  @brief Compute efficiency
  @param frames     input frameset
  @param prod_name  the product name
  @param dGain      detector's gain value
  @param dEpsilon   tolerance to find ref spectra on catalog on (ra,dec)
  @param airprim    airmass
  @param col_name_atm_wave atmospheric extinction table wave column name
  @param col_name_atm_abs  atmospheric extinction table absorption column name
  @param col_name_ref_wave reference flux std table wave column name
  @param col_name_ref_flux reference flux std table flux column name
  @param col_name_obj_wave observed std table wave column name
  @param col_name_obj_flux observed std table flux column name

  @return   0 if everything is ok
 */
/*---------------------------------------------------------------------------*/

cpl_table*
sinfo_utl_efficiency(
		     cpl_frameset * frames,
		     double dGain,
		     double dEpsilon,
		     double aimprim,
                     const char* col_name_atm_wave,
		     const char* col_name_atm_abs,
                     const char* col_name_ref_wave,
                     const char* col_name_ref_flux,
                     const char* col_name_ref_bin,
                     const char* col_name_obj_wave,
                     const char* col_name_obj_flux
		     )
{
  cpl_frame* frm_sci = NULL;
  cpl_frame* frm_atmext = NULL;
  cpl_table* tbl_obj_spectrum = NULL; // input table with spectrum
  cpl_table* tbl_atmext = NULL;
  double exptime = 600;

  cpl_propertylist* plist = NULL;
  cpl_table* tbl_ref = NULL;
  cpl_table* tbl_result=NULL;

  const char* name=NULL;
  double dRA = 0;
  double dDEC = 0;

  double airmass=0;
  const double mk2AA=1E4; /* mkm/AA */


  // read all input data and call the internal function
  // read the input tables
  // 1. observation
  check_nomsg(frm_sci=cpl_frameset_find(frames, FRM_RAW_IMA_SLIT));
  check_nomsg(name=cpl_frame_get_filename(frm_sci));
  sinfo_msg("name=%s",name);
  check_nomsg(tbl_obj_spectrum=cpl_table_load(name,1,0));
  check_nomsg(plist=cpl_propertylist_load(name,0));

  sinfo_get_std_obs_values(plist,&exptime,&airmass,&dRA,&dDEC);

  // 2. reference table
  sinfo_load_ref_table(frames, dRA, dDEC, dEpsilon, &tbl_ref);
  if (tbl_ref)
    {
      // 3. atmext
      check_nomsg(frm_atmext=cpl_frameset_find(frames,FRM_EXTCOEFF_TAB));
      check_nomsg(name=cpl_frame_get_filename(frm_atmext));
      check_nomsg(tbl_atmext=cpl_table_load(name,1,0));

      tbl_result = sinfo_utl_efficiency_internal(
						 tbl_obj_spectrum,
						 tbl_atmext,
						 tbl_ref,
						 exptime,
						 airmass,
						 aimprim,
						 dGain,
                                                 1,
                                                 mk2AA,//valid only for SINFONI
                                                 col_name_atm_wave,
                                                 col_name_atm_abs,
                                                 col_name_ref_wave,
                                                 col_name_ref_flux,
                                                 col_name_ref_bin,
                                                 col_name_obj_wave,
                                                 col_name_obj_flux
         );
     }

 cleanup:
  sinfo_free_propertylist(&plist);
  sinfo_free_table(&tbl_atmext);
  sinfo_free_table(&tbl_obj_spectrum);
  sinfo_free_table(&tbl_ref);
  return tbl_result;
}
static int 
sinfo_column_to_double(cpl_table* ptable, const char* column)
{
  const char* TEMP = "_temp_";
  check_nomsg(cpl_table_duplicate_column(ptable, TEMP, ptable, column));
  check_nomsg(cpl_table_erase_column(ptable, column));
  check_nomsg(cpl_table_cast_column(ptable, TEMP, column, CPL_TYPE_DOUBLE));
  check_nomsg(cpl_table_erase_column(ptable, TEMP ));
  return 0;
 cleanup:
  sinfo_msg(" error column to double [%s]", column);
  return -1;
}


/*---------------------------------------------------------------------------*/
/**
  @brief Compute efficiency
  @param tbl_obj_spectrum     input object spectrum
  @param tbl_atmext           input atmospheric extinction table
  @param tbl_ref              input reference flux STD table
  @param exptime              input exposure time
  @param airprim              input airmass
  @param gain                 input gain
  @param src2ref_wave_sampling input cnversion factor to pass from src 2 ref units
  @param airprim              input airmass

  @param col_name_atm_wave atmospheric extinction table wave column name
  @param col_name_atm_abs  atmospheric extinction table absorption column name
  @param col_name_ref_wave reference flux std table wave column name
  @param col_name_ref_flux reference flux std table flux column name
  @param col_name_obj_wave observed std table wave column name
  @param col_name_obj_flux observed std table flux column name

  @return   0 if everything is ok
 */
/*---------------------------------------------------------------------------*/

cpl_table* 
sinfo_utl_efficiency_internal(
			      cpl_table* tbl_obj_spectrum,
			      cpl_table* tbl_atmext,
			      cpl_table* tbl_ref,
			      double exptime,
			      double airmass,
			      double aimprim,
			      double gain,
			      int    biny,
                              double src2ref_wave_sampling,
                              const char* col_name_atm_wave,
                              const char* col_name_atm_abs,
                              const char* col_name_ref_wave,
                              const char* col_name_ref_flux,
                              const char* col_name_ref_bin,
                              const char* col_name_obj_wave,
                              const char* col_name_obj_flux
			      )
{

  const double TEL_AREA		= 51.2e4; /* collecting area in cm2 */
  double cdelta1 = 0;
  int i = 0;
  cpl_table* tbl_sel = NULL;

  /* structure of the input table
   * col			type	description
   * wavelength	double
   * flux			double
   * */
  cpl_table* tbl_result = NULL; // output table

  /*
   * structure of the output table
   * col			type	description
   * wavelength	double
   * EFF			double	efficiency in range 0-1
   * */

  double* pref = NULL;
  double* pext = NULL;
  double* pcor = NULL;
  double* peph = NULL;

  double* pw = NULL; // wavelength of the input table
  double* pf = NULL; // flux of the input table
  int nrow = 0;
  double ref_bin_size=0;

  nrow = cpl_table_get_nrow(tbl_obj_spectrum);
  sinfo_msg("Starting efficiency calculation: exptime[%f] airmass[%f] nrow[%d]", 
	  exptime, airmass, nrow);

  //cpl_table_dump(tbl_obj_spectrum,0,3,stdout);
  //sinfo_msg("col wave=%s col_flux=%s",col_name_obj_wave,col_name_obj_flux);

  /* convert to double */
  sinfo_column_to_double(tbl_obj_spectrum,col_name_obj_wave);
  sinfo_column_to_double(tbl_obj_spectrum,col_name_obj_flux);

  check_nomsg(sinfo_column_to_double(tbl_atmext,col_name_atm_wave ));
  check_nomsg(sinfo_column_to_double(tbl_atmext,col_name_atm_abs ));
  check_nomsg(sinfo_column_to_double(tbl_ref,col_name_ref_wave ));
  check_nomsg(sinfo_column_to_double(tbl_ref,col_name_ref_flux ));
  check_nomsg(sinfo_column_to_double(tbl_ref,col_name_ref_bin ));

  /* get bin size of ref STD star spectrum */
  ref_bin_size=cpl_table_get_double(tbl_ref,col_name_ref_bin,0,NULL);
  sinfo_msg("ref_bin_size[AA]=%g",ref_bin_size);
  /*
  sinfo_msg("Unit conversion factor src/ref STD spectrum=%g",
          src2ref_wave_sampling);
  */

  /* convert obj spectrum wave unit to the same of the reference one */
  check_nomsg(cpl_table_multiply_scalar(tbl_obj_spectrum,col_name_obj_wave,
                                 src2ref_wave_sampling));

  check_nomsg(cpl_table_save(tbl_ref,NULL,NULL,"ref2.fits",CPL_IO_DEFAULT));
  check_nomsg(cpl_table_save(tbl_atmext,NULL,NULL,"atm2.fits",CPL_IO_DEFAULT));
  check_nomsg(cpl_table_save(tbl_obj_spectrum,NULL,NULL,"sci2.fits",CPL_IO_DEFAULT));
  sinfo_msg("object 2 src std %g",src2ref_wave_sampling);
  check_nomsg(pw=cpl_table_get_data_double(tbl_obj_spectrum,col_name_obj_wave));
  check_nomsg(pf=cpl_table_get_data_double(tbl_obj_spectrum,col_name_obj_flux));

  // prepare columns for the output data
  check_nomsg(tbl_result=cpl_table_new(nrow));
  check_nomsg(pref=sinfo_create_column_double(tbl_result, COL_NAME_REF, nrow));
  check_nomsg(pext=sinfo_create_column_double(tbl_result, COL_NAME_EXT, nrow));
  check_nomsg(pcor=sinfo_create_column_double(tbl_result, COL_NAME_COR, nrow));
  check_nomsg(peph=sinfo_create_column_double(tbl_result, COL_NAME_EPHOT, nrow));
  sinfo_msg("wave range: [%g,%g]",pw[0],pw[nrow-1]); 
  sinfo_msg("src_bin_size[AA]=%g",pw[1] - pw[0]);
  
  cdelta1 = (pw[1] - pw[0]) / src2ref_wave_sampling ; /* we want the delta in original units. As we rescaled to AA we need to correct for this */
  //sinfo_msg("nrow=%d cdelta1=%g",nrow,cdelta1);
  for (i = 0; i < nrow; i++)
    {
      check_nomsg(pext[i] = sinfo_table_interpolate(tbl_atmext, pw[i],col_name_atm_wave, col_name_atm_abs));
      check_nomsg(pref[i] = sinfo_table_interpolate(tbl_ref, pw[i], col_name_ref_wave,col_name_ref_flux));
      pcor[i] = pow(10,(0.4*pext[i] * (aimprim - airmass)));
      peph[i] = 1.e7*1.986e-19/(pw[i]*1e-4);
      /* ph energy: 1.986*10^-19(J.ph^-1)/lam(um) ==> 
         in as pw is expressed in Angstrom units we need to multiply by 10-4 
       */
      /*
      if(i< 2) {
         sinfo_msg("pw[i]=%g,pcor=%g peph=%g",pw[i],pcor[i],peph[i]);
      }
      */
    }


  /*
  sinfo_msg("atm: %s, %s ref: %s, %s obj: %s, %s",
          col_name_atm_wave,col_name_atm_abs,
          col_name_ref_wave,col_name_ref_flux,
          col_name_obj_wave,col_name_obj_flux);
  */
  check_nomsg(cpl_table_duplicate_column(tbl_result,COL_NAME_SRC_COR,
				   tbl_obj_spectrum, col_name_obj_flux));
  check_nomsg(cpl_table_duplicate_column(tbl_result,col_name_obj_wave,
				   tbl_obj_spectrum,col_name_obj_wave));
  /* correct for atmospheric extintion */
  check_nomsg(cpl_table_multiply_columns(tbl_result,COL_NAME_SRC_COR,COL_NAME_COR));

  /* correct object flux by binning: 
      divides by binsize in ref_wave_sampling (usually AA): 
     cdelt1[src_sampling]*src2ref_wave_sampling */
  cpl_table_divide_scalar(tbl_result, COL_NAME_SRC_COR, src2ref_wave_sampling);

  cpl_table_divide_scalar(tbl_result, COL_NAME_SRC_COR, cdelta1);
  /* correct for spatial bin size */

  cpl_table_divide_scalar(tbl_result,COL_NAME_SRC_COR,biny); 


  /*correct ref std star flux by binning: 
    divides by the bin size in ref_wave_sampling (usually AA) */
  check_nomsg(cpl_table_divide_scalar(tbl_result,COL_NAME_REF,ref_bin_size));

  check_nomsg(cpl_table_duplicate_column(tbl_result,COL_NAME_SRC_EFF,
				   tbl_result,COL_NAME_SRC_COR));


  /* correct for detector gain, exposure time, telescope area */
  check_nomsg(cpl_table_multiply_scalar(tbl_result,COL_NAME_SRC_EFF,
				  gain / (exptime * TEL_AREA)));

  /* correct for photon energy */
  check_nomsg(cpl_table_multiply_columns(tbl_result,COL_NAME_SRC_EFF,
				   COL_NAME_EPHOT));


  check_nomsg(cpl_table_divide_columns(tbl_result,COL_NAME_SRC_EFF,COL_NAME_REF));
  /* apply factor 1.e16 as reference catalog has fluxes in units of 1e-16 */
  check_nomsg(cpl_table_multiply_scalar(tbl_result,COL_NAME_SRC_EFF,1.e16));
  //check_nomsg(cpl_table_save(tbl_result,NULL,NULL,"pippo.fits", CPL_IO_DEFAULT));
  /* clean from outliers */
  cpl_table_and_selected_double(tbl_result,COL_NAME_SRC_EFF,
				CPL_GREATER_THAN,1.e-5);
  cpl_table_and_selected_double(tbl_result,COL_NAME_SRC_EFF,
				CPL_LESS_THAN,100.);
  tbl_sel=cpl_table_extract_selected(tbl_result);
  check_nomsg(cpl_table_save(tbl_result,NULL,NULL,"result9.fits",CPL_IO_DEFAULT));

 cleanup:
  sinfo_free_table(&tbl_result);
  return tbl_sel;
}


cpl_table*
sinfo_efficiency_compute(cpl_frame* frm_sci, 
                       cpl_frame* frm_cat,
                       cpl_frame* frm_atmext)

{

  cpl_propertylist* plist=NULL;

  cpl_table* tbl_eff=NULL;
  cpl_table* tbl_ref=NULL;
  cpl_table* tbl_atmext=NULL;
  cpl_table* tbl_sci=NULL;

  double exptime=600;
  double airmass=0;
  double airmass_start=0;
  double airmass_end=0;
  double dRA=0;
  double dDEC=0;
  double gain=0;
  double aimprim=0;
  double dEpsilon=0.1;
  double um2AA=1.e4;

  int nrow=0;
  int biny=1;

  const char* name_sci=NULL;
  const char* name_atm=NULL;

  name_sci=cpl_frame_get_filename(frm_sci);
  sinfo_msg("name_sci=%s",name_sci);     
  check_nomsg(plist=cpl_propertylist_load(name_sci,0));
  check_nomsg(tbl_sci=cpl_table_load(name_sci,1,0));
  check_nomsg(dRA=sinfo_pfits_get_ra(plist));
  dDEC=sinfo_pfits_get_dec(plist);
  airmass_start=sinfo_pfits_get_airmass_end(plist);
  airmass_end=sinfo_pfits_get_airmass_end(plist);
  airmass=0.5*(airmass_start+airmass_end);
  gain=2.42;
  biny=1;
  check_nomsg(exptime=sinfo_pfits_get_dit(plist));
  sinfo_free_propertylist(&plist);
  sinfo_msg("gain=%g airm=%g exptime=%g airmass=%g ra=%g dec=%g",
          gain,airmass,exptime,airmass,dRA,dDEC);

  sinfo_msg("table sci spectra=%s",name_sci);
  nrow=cpl_table_get_nrow(tbl_sci);

  check_nomsg(name_atm=cpl_frame_get_filename(frm_atmext));
  check_nomsg(tbl_atmext=cpl_table_load(name_atm,1,0));
 
  check_nomsg(sinfo_parse_catalog_std_stars(frm_cat,dRA,dDEC,dEpsilon,&tbl_ref));
 
  if(tbl_ref == NULL) {
    sinfo_msg_error("Provide std sar catalog frame");
    return NULL;
  //cpl_table_dump(tbl_ref,0,3,stdout);
  }

  check_nomsg(cpl_table_save(tbl_sci,NULL,NULL,"sci.fits",CPL_IO_DEFAULT));
  check_nomsg(tbl_eff=sinfo_utl_efficiency_internal(tbl_sci,tbl_atmext,tbl_ref,
                                                 exptime,airmass,aimprim,gain,
                                                 biny,um2AA,
                                                 "LAMBDA",
                                                 "LA_SILLA",
                                                 "LAMBDA",
                                                 "F_LAMBDA",
                                                 "BIN_WIDTH",
                                                 "wavelength",
                                                 "counts_bkg"));

  cleanup:
  sinfo_free_table(&tbl_ref);
  sinfo_free_table(&tbl_atmext);
  sinfo_free_propertylist(&plist);
 
  return tbl_eff;

}
/**@}*/
