/*                                                                            *
 *   This file is part of the ESO SINFO Pipeline                              *
 *   Copyright (C) 2004,2005 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: 2013-08-15 12:43:47 $
 * $Revision: 1.21 $
 * $Name: not supported by cvs2svn $
 */

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

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


#include <math.h>
#include <cpl_test.h>
#include <irplib_strehl.h>
#include <cpl.h>
#include <sinfo_new_psf.h>
#include <sinfo_error.h>
#include <sinfo_msg.h>
#include <sinfo_utils_wrappers.h>
/*-----------------------------------------------------------------------------
                                Defines
 ----------------------------------------------------------------------------*/
#define SINFO_TEST_STREHL_M1                      8.0
#define SINFO_TEST_STREHL_M2                       1.1
#define SINFO_TEST_STREHL_BOX_SIZE                 64 
#define SINFO_TEST_STREHL_WINDOW                   6
#define SINFO_TEST_PSF_SZ                          3
#define SINFO_TEST_PI   3.1415926535897932384626433832795028841971693993751058
#define SINFO_TEST_STREHL_ERROR_COEFFICIENT    SINFO_TEST_PI * 0.007 / 0.0271
#define SINFO_TEST_NOISE_NSAMPLES                100
#define SINFO_TEST_NOISE_HSIZE                     4

#define SINFO_TEST_FLUX0                        1.e6
#define SINFO_TEST_BKG                          1.e2
#define SINFO_TEST_EXP1                            1
#define SINFO_TEST_EXP2                            1 //3
#define SINFO_TEST_PS1                        0.025 //0.0125 half due 2K cam
#define SINFO_TEST_PS2                             0.100 //0.05
#define SINFO_TEST_NX                              64 // 64
#define SINFO_TEST_NY                              64 // 64
#define SINFO_TEST_SX                              4
#define SINFO_TEST_SY                              4

#define SINFO_TEST_WAV                             2.2
#define SINFO_TEST_DWAV                            1.00352//0.543410
//#define SINFO_TEST_DWAV                            0.543410
#define SINFO_TEST_R1                             27//27
#define SINFO_TEST_R2                             32//32
#define SINFO_BKG_CSX 8
#define SINFO_BKG_CSY 8




/*-----------------------------------------------------------------------------
                            Functions prototypes
 ----------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
/**
 * @defgroup sinfo_strehl_test  SINFO library unit tests
 */
/*---------------------------------------------------------------------------*/
/**@{*/


static void
test_small(void)
{

  const char* name="xshTHE_vis.fits";
  cpl_table* the=NULL;
  cpl_propertylist* plist=NULL;
  int nrow=0;
  float* pf=NULL;
  int* po=NULL;
  int i=0;


    check_nomsg(the=cpl_table_load(name,1,0));
    check_nomsg(plist=cpl_propertylist_load(name,0));
  
  check_nomsg(cpl_table_erase_column(the,"Wavelength"));
  check_nomsg(cpl_table_duplicate_column(the,"tmp",the,"IDENT"));
  check_nomsg(cpl_table_cast_column(the,"tmp","Wavelength",CPL_TYPE_FLOAT));
  check_nomsg(cpl_table_erase_column(the,"tmp"));

  check_nomsg(cpl_table_cast_column(the,"x_position","detector_x",
				    CPL_TYPE_DOUBLE));
  check_nomsg(cpl_table_erase_column(the,"x_position"));

  check_nomsg(cpl_table_cast_column(the,"y_position","detector_y",
				    CPL_TYPE_DOUBLE));
  check_nomsg(cpl_table_erase_column(the,"y_position"));

  cpl_table_new_column(the,"Pippo",CPL_TYPE_INT);
  po=cpl_table_get_data_int(the,"Pippo");
  pf=cpl_table_get_data_float(the,"ORDER");
  nrow=cpl_table_get_nrow(the);
  for(i=0;i<nrow;i++) {
    po[i]=1;
  }
  
  for(i=0;i<nrow;i++) {
    po[i]=(int)pf[i];
  }

  
  check_nomsg(cpl_table_save(the,plist,NULL,"xshTHE_vis_new.fits",
			     CPL_IO_DEFAULT));

 cleanup:
  sinfo_free_propertylist(&plist);
  sinfo_free_table(&the);

}

/**
   @brief      test PSF compuatation
 */
/*---------------------------------------------------------------------------*/
static void
test_flux(void)
{

  int mx=SINFO_BKG_CSX;
  int my=SINFO_BKG_CSY;
  int sx=SINFO_TEST_NX;
  int sy=SINFO_TEST_NY;
  cpl_image* mask=NULL;
  //cpl_image* img_w=NULL;
  int* pm=NULL;
  int i=0;
  int j=0;

  mask=cpl_image_new(sx,sy,CPL_TYPE_INT);
  pm=cpl_image_get_data_int(mask);

  //Fill 4 corners
  for(j=0;j<my;j++) {
    for(i=0;i<mx;i++) {
      pm[i+j*sx]=1;
    }
  }

  for(j=sy-my;j<my;j++) {
    for(i=0;i<mx;i++) {
      pm[i+j*sx]=1;
    }
  }



  for(j=sy-my;j<my;j++) {
    for(i=sx-mx;i<mx;i++) {
      pm[i+j*sx]=1;
    }
  }


  for(j=0;j<my;j++) {
    for(i=sx-mx;i<mx;i++) {
      pm[i+j*sx]=1;
    }
  }





}



/**
   @brief      test PSF compuatation
 */
/*---------------------------------------------------------------------------*/
cpl_error_code
test_psf(void)
{

  double peak=0;
  double m1=SINFO_TEST_STREHL_M1;
  double m2=SINFO_TEST_STREHL_M2;
  double w=2.2e-6;
  //double p1=0.0125;
  double p2=0.0250;
  double p3=0.0500;
  //double p4=0.100;
 
  //double pr=p2;

  sinfo_msg_warning("change pixel scale");
  /*
  check(sinfo_compute_psf(m1,m2/m1,w,p1,0.,0.,1.,&peak),"test psf");
  check(sinfo_compute_psf(m1,m2/m1,w,p2,0.,0.,1.,&peak),"test psf");
  check(sinfo_compute_psf(m1,m2/m1,w,p3,0.,0.,1.,&peak),"test psf");
  check(sinfo_compute_psf(m1,m2/m1,w,p4,0.,0.,1.,&peak),"test psf");


  sinfo_msg_warning("change PSF centroid position");
  check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,1.,&peak),"test psf");

  check(sinfo_compute_psf(m1,m2/m1,w,pr,-1.0,+0.0,1.,&peak),"test psf");
  check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,-1.0,1.,&peak),"test psf");
  check(sinfo_compute_psf(m1,m2/m1,w,pr,-1.0,-1.0,1.,&peak),"test psf");


  check(sinfo_compute_psf(m1,m2/m1,w,pr,+1.0,+0.0,1.,&peak),"test psf");
  check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+1.0,1.,&peak),"test psf");
  check(sinfo_compute_psf(m1,m2/m1,w,pr,+1.0,+1.0,1.,&peak),"test psf");


  check(sinfo_compute_psf(m1,m2/m1,w,pr,-2.0,-2.0,1.,&peak),"test psf");
  check(sinfo_compute_psf(m1,m2/m1,w,pr,+2.0,+2.0,1.,&peak),"test psf");


 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.5,+0.5,1.,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.5,+1.5,1.,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.5,+2.5,1.,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.5,+3.5,1.,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.5,+4.5,1.,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.5,+5.5,1.,&peak),"test psf");


 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.5,-0.5,1.,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+1.5,-0.5,1.,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+2.5,-0.5,1.,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+3.5,-0.5,1.,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+4.5,-0.5,1.,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+5.5,-0.5,1.,&peak),"test psf");
  */

  /*
 sinfo_msg_warning("change anamorphism");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,0.1,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,0.3,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,0.5,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,0.7,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,0.9,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,1.0,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,1.1,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,1.3,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,1.5,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,1.7,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,1.9,&peak),"test psf");



 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,-0.1,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,-0.3,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,-0.5,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,-0.7,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,-0.9,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,-1.0,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,-1.1,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,-1.3,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,-1.5,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,-1.7,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,pr,+0.0,+0.0,-1.9,&peak),"test psf");
  */

 sinfo_msg_warning("Test given values");
 check(sinfo_compute_psf(m1,m2/m1,w,p3,+3.78751,0.172931,1.,&peak),"test psf");
 check(sinfo_compute_psf(m1,m2/m1,w,p3,+0.46594,0.534966,1.,&peak),"test psf");



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



/**
   @brief      test Strehl compuatation
 */
/*---------------------------------------------------------------------------*/
/* TODO: make work this unit test (generate med_img1_num1.fits)
static void
test_strehl_one(void)
{
  const char* fname="med_img1_num1.fits";
  cpl_image* ima=NULL;
  double m1= SINFO_TEST_STREHL_M1;
  double m2= SINFO_TEST_STREHL_M2;
  double lam=2.2;

  double dlam=0.543410;
  double pscale=0.025;
  //double pscale=0.10;
  double xpos=0;
  double ypos=0;
  double r1=SINFO_TEST_R1*pscale;
  double r2=SINFO_TEST_R1*pscale;
  double r3=SINFO_TEST_R2*pscale;

  int size=SINFO_TEST_STREHL_BOX_SIZE;
  //int noise_box_sz=SINFO_TEST_STREHL_BOX_SIZE;
  //int noise_nsamples=SINFO_TEST_NOISE_NSAMPLES;
  double strehl=0;
  double strehl_err=0;
  double star_bkg=0;
  double star_peak=0;
  double star_flux=0;
  double psf_peak=0;
  double psf_flux=0;
  double bg_noise=0;
  cpl_bivector* iqe1=NULL;
  double* piqe=NULL;
  int sx=0;
  int sy=0;


  sinfo_msg_warning("ok11");
  check_nomsg(ima=cpl_image_load(fname,CPL_TYPE_FLOAT,0,0));

  sinfo_msg_warning("ok12");
  
  sx=cpl_image_get_size_x(ima);
  sy=cpl_image_get_size_y(ima);
  if(NULL != (iqe1=cpl_image_iqe(ima,1,1,64,64))) {


    piqe=cpl_bivector_get_x_data(iqe1);
    //*star_peak=piqe[5];
    xpos=piqe[0];
    ypos=piqe[1];
    sinfo_msg_warning("xc=%f yc=%f",piqe[0],piqe[1]); 
    sinfo_free_bivector(&iqe1);


  } else {
    xpos=sx/2;
    ypos=sy/2;

    sinfo_msg_warning("IQE fit failed"); 
    cpl_error_reset();

  }
  
  //check_nomsg(cpl_image_get_maxpos(ima,&xpos,&ypos));
  sinfo_msg_warning("ok13 xpos=%g ypos=%g",xpos,ypos);
  check_nomsg(sinfo_strehl_compute_one(ima,m1,m2,lam,dlam,pscale,
                                       (int)xpos,(int)ypos,
                                       r1,r2,r3,size,
                                       &strehl,&strehl_err,
                                       &star_bkg,&star_peak,&star_flux,
                                       &psf_peak,&psf_flux,&bg_noise));

  sinfo_msg_warning("ok14");

  sinfo_msg_warning("strehl=%g",strehl);
 cleanup:
  sinfo_free_image(&ima);
  sinfo_free_bivector(&iqe1);

  return;

}
*/

/* TODO: Make work the following unit test (generate med_img1_num4.fits and med_img2_num4.fits)
static void
test_strehl_two(void)
{
  const char* fname1="med_img1_num4.fits";
  const char* fname2="med_img2_num4.fits";
  double exptime1=240; //120-150-60-240-60
  double exptime2=60;  // 20- 30- 5- 60- 5
  cpl_image* ima1=NULL;
  cpl_image* ima2=NULL;
  double m1= SINFO_TEST_STREHL_M1;
  double m2= SINFO_TEST_STREHL_M2;
  double lam=2.2;

  //double dlam=0.543410;
  double pscale1=0.025;
  double pscale2=0.10;
  double xpos1=0;
  double ypos1=0;
  double xpos2=0;
  double ypos2=0;
  double r1=SINFO_TEST_R1*pscale1;
  double r2=SINFO_TEST_R1*pscale1;
  double r3=SINFO_TEST_R2*pscale1;

  //int size=SINFO_TEST_STREHL_BOX_SIZE;
  //int noise_box_sz=SINFO_TEST_STREHL_BOX_SIZE;
  //int noise_nsamples=SINFO_TEST_NOISE_NSAMPLES;
  double strehl=0;
  double strehl_err=0;
  double star_bkg=0;
  double star_peak=0;
  double star_flux=0;
  double psf_peak=0;
  double psf_flux=0;
  double bg_noise=0;
  cpl_bivector* iqe1=NULL;
  double* piqe=NULL;
  int sx=0;
  int sy=0;
  int d=16;


  sinfo_msg_warning("ok11");
  check_nomsg(ima1=cpl_image_load(fname1,CPL_TYPE_FLOAT,0,0));
  check_nomsg(ima2=cpl_image_load(fname2,CPL_TYPE_FLOAT,0,0));

  sinfo_msg_warning("ok12");
  
  sx=cpl_image_get_size_x(ima1);
  sy=cpl_image_get_size_y(ima1);
  if(NULL != (iqe1=cpl_image_iqe(ima1,sx/2-d,sy/2-d,sx/2+d,sy/2+d))) {


    piqe=cpl_bivector_get_x_data(iqe1);
    //*star_peak=piqe[5];
    xpos1=piqe[0];
    ypos1=piqe[1];
    sinfo_msg_warning("xc1=%f yc1=%f",piqe[0],piqe[1]); 
    sinfo_msg_warning("peak1=%f",piqe[5]); 
    sinfo_free_bivector(&iqe1);


  } else {
    xpos1=sx/2;
    ypos1=sy/2;

    sinfo_msg_warning("IQE fit failed"); 
    cpl_error_reset();

  }
  
  sinfo_msg_warning("ok13 xpos1=%g ypos1=%g",xpos1,ypos1);


  sx=cpl_image_get_size_x(ima2);
  sy=cpl_image_get_size_y(ima2);
  if(NULL != (iqe1=cpl_image_iqe(ima2,sx/2-d,sy/2-d,sx/2+d,sy/2+d))) {


    piqe=cpl_bivector_get_x_data(iqe1);
    //*star_peak=piqe[5];
    xpos2=piqe[0];
    ypos2=piqe[1];
    sinfo_msg_warning("xc2=%f yc2=%f",piqe[0],piqe[1]); 
    sinfo_msg_warning("peak2=%f",piqe[5]); 
    sinfo_free_bivector(&iqe1);


  } else {
    xpos2=sx/2;
    ypos2=sy/2;

    sinfo_msg_warning("IQE fit failed"); 
    cpl_error_reset();

  }
  


  //check_nomsg(cpl_image_get_maxpos(ima,&xpos,&ypos));
  sinfo_msg_warning("ok13 xpos2=%g ypos2=%g",xpos2,ypos2);
  check_nomsg(sinfo_strehl_compute_two(ima1,ima2,
                                       m1,m2,
                                       lam,
				       pscale1,pscale2,
                                       exptime1,exptime2,
				       xpos1,ypos1,
                                       xpos2,ypos2,
                                       r1,r2,r3,
                                       &strehl,&strehl_err,
                                    &star_bkg,&star_peak,&star_flux,
                                    &psf_peak,&psf_flux,&bg_noise));

  sinfo_msg_warning("ok14");

  sinfo_msg_warning("strehl=%g",strehl);
 cleanup:
  sinfo_free_image(&ima1);
  sinfo_free_image(&ima2);
  sinfo_free_bivector(&iqe1);

  return;

}
*/

/**
   @brief      test Strehl compuatation
 */
/*---------------------------------------------------------------------------*/
static void
test_strehl(const double accuracy)
{

  const int nx=SINFO_TEST_NX;
  const int ny=SINFO_TEST_NY;
  double xcen=nx/2;
  double ycen=ny/2;

  double sig_x=SINFO_TEST_SX;
  double sig_y=SINFO_TEST_SY;

  double norm=SINFO_TEST_FLUX0;
  double bkg_val=SINFO_TEST_BKG;
  double min_pix=-sqrt(bkg_val);
  double max_pix=+sqrt(bkg_val);


  cpl_image* ima_obj=NULL;
  cpl_image* ima_noise=NULL;

  cpl_size max_ima_x=0;
  cpl_size max_ima_y=0;

  double lam=SINFO_TEST_WAV;
  double dlam=SINFO_TEST_DWAV;

  double pscale=SINFO_TEST_PS1;
  double strehl_star_radius=SINFO_TEST_R1*pscale;
  double strehl_bg_r1=SINFO_TEST_R1*pscale;
  double strehl_bg_r2=SINFO_TEST_R2*pscale;

  double strehl=0;
  double strehlm=0;
  double strehl_err=0;
  double star_bkg=0;
  double star_peak=0;
  double star_flux=0;

  double flux=norm;
  double fluxm=0;
  double noise_min=min_pix;
  double noise_max=max_pix;
  double bkg=bkg_val;
  double bkgm=bkg_val;
  int bkg_sx=SINFO_BKG_CSX;
  int bkg_sy=SINFO_BKG_CSY;

  double psf_peak=0;
  double psf_flux=0;
  double bkg_noise=0;
  double bkg_stdevm=0;
  double* dx=NULL;
  //double fct=sqrt(2*log(2));
  cpl_bivector* ima_qual=NULL;
  cpl_image* psf=NULL;

  sinfo_msg_warning("Strehl Test1 pscale=%f",pscale);
  check_nomsg(ima_obj=cpl_image_new(nx,ny,CPL_TYPE_FLOAT));
  check_nomsg(ima_noise=cpl_image_new(nx,ny,CPL_TYPE_FLOAT));
  check_nomsg(cpl_image_fill_gaussian(ima_obj,xcen,ycen,flux,sig_x,sig_y));
  check_nomsg(cpl_image_fill_noise_uniform(ima_noise,noise_min,noise_max));

  fluxm=cpl_image_get_flux(ima_obj);

  assure(fabs((fluxm-flux)/flux) <accuracy, CPL_ERROR_UNSPECIFIED,
	 "Flux ima[e/m]=[%g/%g]",flux,fluxm);

  check_nomsg(cpl_image_add(ima_obj,ima_noise));
  check_nomsg(cpl_image_add_scalar(ima_obj,bkg));

  check_nomsg(sinfo_get_bkg_4corners(ima_obj,bkg_sx,bkg_sy,&bkgm,&bkg_stdevm));

  sinfo_get_flux_above_bkg(ima_obj,2,bkg_stdevm,&fluxm);
  sinfo_msg_warning("flux=%g",fluxm);
  assure(fabs((bkgm-bkg)/bkg) <accuracy,CPL_ERROR_UNSPECIFIED,
	 "Bkg  ima[e/m]=[%g/%g]", bkg,bkgm);


  check_nomsg(ima_qual=cpl_image_iqe(ima_obj,1,1,nx,nx));
  dx=cpl_bivector_get_x_data(ima_qual);


  assure(fabs((bkgm-bkg)/bkg) <accuracy,CPL_ERROR_UNSPECIFIED,
	 "Bkg  ima[e/m]=[%g/%g]", bkg,bkgm);


  assure(fabs((dx[0]-xcen)/xcen) <accuracy,CPL_ERROR_UNSPECIFIED,
               "Image quality: X [e/m]=[%f/%f]",
		    xcen,dx[0]);


  assure(fabs((dx[1]-ycen)/ycen) <accuracy,CPL_ERROR_UNSPECIFIED,
               "Image quality: Y [e/m]=[%f/%f]",
		    ycen,dx[1]);



  sinfo_msg_warning("Image quality: FWHM_X[m/'']=%f/%f FWHM_Y[m/'']="
		    "%f/%f pscale=%f",
		    dx[2],dx[2]*pscale,dx[3],dx[3]*pscale,pscale);
  //sinfo_msg_warning("Image quality: SIG_X=%f SIG_Y=%f",fct*dx[2],fct*dx[3]);
  sinfo_msg_warning("Image quality: ANGLE=%f Peak=%g BKG=%g",dx[4],dx[5],dx[6]);
  psf = irplib_strehl_generate_psf(SINFO_TEST_STREHL_M1,
				   SINFO_TEST_STREHL_M2,
				   lam, dlam, pscale,
				   SINFO_TEST_STREHL_BOX_SIZE);

  psf_peak = cpl_image_get_max(psf) ;

  cpl_image_delete(psf) ;

  sinfo_msg_warning("psf_peak=%f",psf_peak);


  assure(fabs((dx[1]-ycen)/ycen) <accuracy,CPL_ERROR_UNSPECIFIED,
               "Image quality: Y [e/m]=[%f/%f]",
		    ycen,dx[1]);


  strehl=((dx[5]-SINFO_TEST_BKG)/flux)/psf_peak;
  strehlm=((dx[5]-bkgm)/(cpl_image_get_flux(ima_obj)-bkgm*nx*ny))/psf_peak;

  assure(fabs((strehlm-strehl)/strehl) <accuracy,CPL_ERROR_UNSPECIFIED,
               "Strehl: [e/m]=[%f/%f]",strehl,strehlm);

  check_nomsg(cpl_image_save(ima_obj,"out_strehl.fits", CPL_BPP_IEEE_FLOAT, 
			     NULL,CPL_IO_DEFAULT));
 
  check_nomsg(cpl_image_get_maxpos(ima_obj,&max_ima_x,&max_ima_y));
  /*
  sinfo_msg("input par: ima=%p,M1=%f,M2=%f,lam=%f,dlam=%f,pscale=%f,"
	    "BOX_SIZE=%d,max_ima_x=%d,max_ima_y=%d,star_radius=%f,bg_r1=%f,"
            "bg_r2=%f,HSIZE=%d,NSAMPLES=%d",
             ima_obj,
                                            SINFO_TEST_STREHL_M1,
                                             SINFO_TEST_STREHL_M2,
                                             lam,
                                             dlam,
                                             pscale,
			                     SINFO_TEST_STREHL_BOX_SIZE,
                                             max_ima_x,
                                             max_ima_y,
			                     strehl_star_radius,
                                             strehl_bg_r1,
                                             strehl_bg_r2,
		 	                     SINFO_TEST_NOISE_HSIZE,
                                             SINFO_TEST_NOISE_NSAMPLES);
  */


  if(CPL_ERROR_NONE != sinfo_strehl_compute_one(ima_obj,
                                             SINFO_TEST_STREHL_M1,
                                             SINFO_TEST_STREHL_M2,
                                             lam,
                                             dlam,
                                             pscale,
                                             max_ima_x,
                                             max_ima_y,
			                     strehl_star_radius,
                                             strehl_bg_r1,
                                             strehl_bg_r2,
			                     SINFO_TEST_STREHL_BOX_SIZE,
			                     &strehl,
                                             &strehl_err,
                                             &star_bkg,
                                             &star_peak,
                                             &star_flux,
			                     &psf_peak,
                                             &psf_flux,
                                             &bkg_noise)) {


     sinfo_msg_warning("Problem computing strehl");
     strehl=-1;
     strehl_err=0;

  }

  sinfo_msg_warning("strehl=%f strehl_err=%f "
                    "star_bkg=%g star_peak=%g star_flux=%g "
                    "psf_peak=%g psf_flux=%g bkg_noise=%g",
                    strehl,strehl_err,
                    star_bkg,star_peak,star_flux,
                    psf_peak,psf_flux,bkg_noise);
  sinfo_msg_warning("--------END-----");


 cleanup:
  sinfo_free_bivector(&ima_qual);
  sinfo_free_image(&ima_obj);
  sinfo_free_image(&ima_noise);
  return;

}


/**
   @brief      test streehl compuatation
 */
/*----------------------------------------------------------------------------*/
static void
test_strehl2(const double accuracy)
{

  const int nx=SINFO_TEST_NX;
  const int ny=SINFO_TEST_NY;
  double xcen=nx/2;
  double ycen=ny/2;

  double norm=SINFO_TEST_FLUX0;

  cpl_image* ima1_obj=NULL;
  cpl_image* ima1_noise=NULL;
  cpl_image* ima2_obj=NULL;
  cpl_image* ima2_noise=NULL;


  double bkg_val=SINFO_TEST_BKG;
  double min_pix=-sqrt(bkg_val);
  double max_pix=+sqrt(bkg_val);
  cpl_size max_ima_x1=0;
  cpl_size max_ima_y1=0;
  cpl_size max_ima_x2=0;
  cpl_size max_ima_y2=0;

  double lam=SINFO_TEST_WAV;
  double dlam=SINFO_TEST_DWAV;

  double pscale1=SINFO_TEST_PS1;
  double pscale2=SINFO_TEST_PS2;
  double t1=SINFO_TEST_EXP1; //9
  double t2=SINFO_TEST_EXP2; //3

  double frat=sinfo_scale_flux(pscale1,pscale2,t1,t2);

  double sig1_x=SINFO_TEST_SX;
  double sig1_y=SINFO_TEST_SY;
  double sig2_x=SINFO_TEST_SX*pscale1/pscale2;
  double sig2_y=SINFO_TEST_SY*pscale1/pscale2;


  double strehl_star_radius=SINFO_TEST_R1*pscale2;
  double strehl_bg_r1=SINFO_TEST_R1*pscale2;
  double strehl_bg_r2=SINFO_TEST_R2*pscale2;

  double strehl=0;
  double strehl_err=0;
  double star_bkg=0;
  double star_peak=0;
  double star_flux=0;

  double psf_peak=0;
  double psf_peak1=0;
  double psf_peak2=0;
  double psf_flux=1;
  //double psf_flux1=1;
  //double psf_flux2=1;
  double bkg_noise=0;
  cpl_bivector* ima_qual=NULL;
  double* dx=NULL;

  double bkg1=bkg_val;
  double bkg2=bkg_val*frat;
  double flux1=norm;
  double flux2=norm*t2/t1;
  double fluxm1=0;
  double fluxm2=0;
  double prat=pscale2/pscale1;
  double prat2=prat*prat;
		   



  double noise_min1=min_pix;
  double noise_min2=min_pix*frat;

  double noise_max1=max_pix;
  double noise_max2=max_pix*frat;
  double peak1=0;
  double peak2=0;
  cpl_image* psf1=NULL;
  cpl_image* psf2=NULL;
  //double fct=sqrt(2*log(2));


  double bkg1m=bkg_val;
  double bkg2m=bkg_val;
  double bkg_stdev1m=0;
  double bkg_stdev2m=0;

  int bkg_sx=SINFO_BKG_CSX;
  int bkg_sy=SINFO_BKG_CSY;

  sinfo_msg_warning("Strehl Test2: Flux1=%g Bkg1=%g Flux2=%g Bkg2=%g frat=%g",
	    flux1,bkg1,flux2,bkg2,frat);
  check_nomsg(ima1_obj=cpl_image_new(nx,ny,CPL_TYPE_FLOAT));
  check_nomsg(ima1_noise=cpl_image_new(nx,ny,CPL_TYPE_FLOAT));
  check_nomsg(ima2_obj=cpl_image_new(nx,ny,CPL_TYPE_FLOAT));
  check_nomsg(ima2_noise=cpl_image_new(nx,ny,CPL_TYPE_FLOAT));

  check_nomsg(cpl_image_fill_gaussian(ima1_obj,xcen,ycen,flux1,sig1_x,sig1_y));
  check_nomsg(cpl_image_fill_noise_uniform(ima1_noise,noise_min1,noise_max1));

  check_nomsg(cpl_image_fill_gaussian(ima2_obj,xcen,ycen,flux2,sig2_x,sig2_y));
  check_nomsg(cpl_image_fill_noise_uniform(ima2_noise,noise_min2,noise_max2));


  fluxm1=cpl_image_get_flux(ima1_obj);
  fluxm2=cpl_image_get_flux(ima2_obj);

  assure(fabs((fluxm1-flux1)/flux1) <accuracy, CPL_ERROR_UNSPECIFIED,
   "Flux1 ima[e/m]=[%g/%g]",flux1,fluxm1);

  //assure(fabs((fluxm2-flux2)/flux2) <accuracy, CPL_ERROR_UNSPECIFIED,
  // "Flux2 ima[e/m]=[%g/%g]",flux2,fluxm2);

   


  check_nomsg(cpl_image_add(ima1_obj,ima1_noise));
  check_nomsg(cpl_image_add_scalar(ima1_obj,bkg1));

  check_nomsg(ima_qual=cpl_image_iqe(ima1_obj,1,1,nx,ny));
  dx=cpl_bivector_get_x_data(ima_qual);


  //assure(fabs((dx[0]-xcen)/xcen) <accuracy,CPL_ERROR_UNSPECIFIED,
  //           "Image1 quality: X [e/m]=[%f/%f]",xcen,dx[0]);

  //assure(fabs((dx[1]-ycen)/ycen) <accuracy,CPL_ERROR_UNSPECIFIED,
  //             "Image1 quality: X [e/m]=[%f/%f]",ycen,dx[1]);


  sinfo_msg_warning("Image1 quality: FWHM_X[m/'']=%f/%f FWHM_Y[m/'']=%f/%f",
		    dx[2],dx[2]*pscale1,dx[3],dx[3]*pscale1);

  //sinfo_msg_warning("Image1 quality: SIG_X=%f SIG_Y=%f",fct*dx[2],fct*dx[3]);
  sinfo_msg_warning("Image1 quality: ANGLE=%f",dx[4]);
  sinfo_msg_warning("Image1 quality: Peak=%g BKG=%g",dx[5],dx[6]);

  peak1=cpl_image_get_max(ima1_obj);

  check_nomsg(sinfo_get_bkg_4corners(ima1_obj,bkg_sx,bkg_sy,
				     &bkg1m,&bkg_stdev1m));



  sinfo_msg_warning("4 corners Bkg1  [e/m]=[%g/%g]", bkg1,bkg1m);
  sinfo_msg_warning("Image1 peak=%g BKG=%g",peak1,bkg1m);
  sinfo_free_bivector(&ima_qual);

  sinfo_get_flux_above_bkg(ima1_obj,2,bkg_stdev1m,&fluxm1);





  check_nomsg(cpl_image_add(ima2_obj,ima2_noise));
  check_nomsg(cpl_image_add_scalar(ima2_obj,bkg2));

  check_nomsg(ima_qual=cpl_image_iqe(ima2_obj,1,1,nx,ny));
  dx=cpl_bivector_get_x_data(ima_qual);

  //assure(fabs((dx[0]-xcen)/xcen) <accuracy,CPL_ERROR_UNSPECIFIED,
  //             "Image1 quality: X [e/m]=[%f/%f]",xcen,dx[0]);

  //assure(fabs((dx[1]-ycen)/ycen) <accuracy,CPL_ERROR_UNSPECIFIED,
  //             "Image1 quality: X [e/m]=[%f/%f]",ycen,dx[1]);

  sinfo_msg_warning("Image2 quality: FWHM_X[m/'']=%f/%f FWHM_Y[m/'']=%f/%f",
		    dx[2],dx[2]*pscale2,dx[3],dx[3]*pscale2);
  //sinfo_msg_warning("Image2 quality: SIG_X=%f SIG_Y=%f",fct*dx[2],fct*dx[3]);
  sinfo_msg_warning("Image2 quality: ANGLE=%f",dx[4]);
  sinfo_msg_warning("Image1 quality: Peak=%g BKG=%g",dx[5],dx[6]);

  
  peak2=cpl_image_get_max(ima2_obj);

  check_nomsg(sinfo_get_bkg_4corners(ima2_obj,bkg_sx,bkg_sy,
				     &bkg2m,&bkg_stdev2m));

  sinfo_msg_warning("4 corners Bkg2  [e/m]=%g/%g", bkg2,bkg2m);
  sinfo_msg_warning("Image1 peak=%g BKG=%g",peak2,bkg2m);

  sinfo_get_flux_above_bkg(ima2_obj,2,bkg_stdev2m,&fluxm2);
 



  sinfo_msg_warning("Scaled Bkg1 [e/m]=%g/%g",bkg1,bkg2m/frat);

  bkg1m=bkg2m/frat;

  psf1 = irplib_strehl_generate_psf(SINFO_TEST_STREHL_M1,
				   SINFO_TEST_STREHL_M2,
				   lam, dlam, pscale1,
				   SINFO_TEST_STREHL_BOX_SIZE);

  psf_peak1 = cpl_image_get_max(psf1) ;

  sinfo_free_image(&psf1) ;

  sinfo_msg_warning("psf peak1=%g",psf_peak1);

  sinfo_msg_warning("Strehl1 [e/m]=%g/%g",
	    (peak1-bkg1)/flux1/psf_peak1,
	    (peak1-bkg1m)/
            ((cpl_image_get_flux(ima1_obj)-bkg1m*nx*ny))/psf_peak1);

  psf2 = irplib_strehl_generate_psf(SINFO_TEST_STREHL_M1,
				   SINFO_TEST_STREHL_M2,
				   lam, dlam, pscale2,
				   SINFO_TEST_STREHL_BOX_SIZE);

  psf_peak2 = cpl_image_get_max(psf2) ;

  sinfo_free_image(&psf2) ;

  sinfo_msg_warning("psf peak2=%g",psf_peak2);

  sinfo_msg_warning("Strehl2 [e/m]=%g/%g",
	   (peak2-bkg2)/flux2/psf_peak1,
	    (peak2-bkg2m)/(cpl_image_get_flux(ima2_obj)-bkg2m*nx*ny)/
             psf_peak1);

  sinfo_free_bivector(&ima_qual);

  check_nomsg(cpl_image_save(ima1_obj,"out_strehl1.fits", CPL_BPP_IEEE_FLOAT, 
			     NULL,CPL_IO_DEFAULT));

  check_nomsg(cpl_image_save(ima2_obj,"out_strehl2.fits", CPL_BPP_IEEE_FLOAT, 
			     NULL,CPL_IO_DEFAULT));
 
  check_nomsg(cpl_image_get_maxpos(ima1_obj,&max_ima_x1,&max_ima_y1));
  check_nomsg(cpl_image_get_maxpos(ima2_obj,&max_ima_x2,&max_ima_y2));
  /*
  sinfo_msg("input par: ima=%p,M1=%f,M2=%f,lam=%f,dlam=%f,pscale=%f,"
	    "BOX_SIZE=%d,max_ima_x=%d,max_ima_y=%d,star_radius=%f,bg_r1=%f,"
            "bg_r2=%f,HSIZE=%d,NSAMPLES=%d",
             ima_obj,
                                            SINFO_TEST_STREHL_M1,
                                             SINFO_TEST_STREHL_M2,
                                             lam,
                                             dlam,
                                             pscale,
			                     SINFO_TEST_STREHL_BOX_SIZE,
                                             max_ima_x,
                                             max_ima_y,
			                     strehl_star_radius,
                                             strehl_bg_r1,
                                             strehl_bg_r2,
		 	                     SINFO_TEST_NOISE_HSIZE,
                                             SINFO_TEST_NOISE_NSAMPLES);
  */

  if(CPL_ERROR_NONE != sinfo_strehl_compute_two(ima1_obj,ima2_obj,
                                             SINFO_TEST_STREHL_M1,
                                             SINFO_TEST_STREHL_M2,
                                             lam,
                                             pscale1,
                                             pscale2,
					     t1,
                                             t2,
                                             max_ima_x1,
                                             max_ima_y1,
                                             max_ima_x2,
                                             max_ima_y2,
			                     strehl_star_radius,
                                             strehl_bg_r1,
                                             strehl_bg_r2,
			                     &strehl,
                                             &strehl_err,
                                             &star_bkg,
                                             &star_peak,
                                             &star_flux,
			                     &psf_peak,
                                             &psf_flux,
                                             &bkg_noise)) {


     sinfo_msg_warning("Problem computing strehl");
     strehl=-1;
     strehl_err=0;

  }

  sinfo_msg_warning("strehl=%g strehl_err=%g star_bkg=%g "
                    "star_peak=%g star_flux=%g "
		    "psf_peak=%g psf_flux=%g bkg_noise=%g",
		    strehl,strehl_err,star_bkg,star_peak,star_flux,psf_peak,
		    psf_flux,bkg_noise);



  sinfo_msg_warning("Combined Strehl1 [e/m]=%10.8g/%10.8g",
		    (peak1-bkg2/frat)/(flux2/frat)/psf_peak1,
		    (peak1-bkg2m/frat)/
                    ((cpl_image_get_flux(ima2_obj)-bkg2m*nx*ny)/frat)/
		    psf_peak1);


 sinfo_msg_warning("Correct Combined Strehl1 [e/m]=%10.8g/%10.8g",
		   (peak1-bkg2/frat)/(flux2/frat)/psf_peak1/prat2,
		    (peak1-bkg2m/frat)/
                    ((cpl_image_get_flux(ima2_obj)-bkg2m*nx*ny)/frat)/
		   psf_peak1/prat2);

  sinfo_msg_warning("peak_psf1=%g psf_peak2=%g",psf_peak1,psf_peak2);
  sinfo_msg_warning("prat2=%g",prat2);

  sinfo_msg_warning("Combined Strehl2 [e/m]=%g/%g",
		    (peak2-bkg1*frat)/(flux1*frat)/psf_peak1,
		    (peak2-bkg1m*frat)/
                    ((cpl_image_get_flux(ima1_obj)-bkg1m*nx*ny)*frat)/
		    psf_peak1);


 sinfo_msg_warning("Correct Combined Strehl2 [e/m]=%g/%g",
		    (peak2-bkg1*frat)/(flux1*frat)/psf_peak1*prat2,
		    (peak2-bkg1m*frat)/
                    ((cpl_image_get_flux(ima1_obj)-bkg1m*nx*ny)*frat)/
		    psf_peak1*prat2);


 cleanup:

  sinfo_free_bivector(&ima_qual);
  sinfo_free_image(&ima1_obj);
  sinfo_free_image(&ima1_noise);
  sinfo_free_image(&ima2_obj);
  sinfo_free_image(&ima2_noise);
  sinfo_free_image(&psf1) ;
  sinfo_free_image(&psf2) ;
  ;
  return;

}



   
/*----------------------------------------------------------------------------*/
/**
  @brief   SINFONI pipeline unit test for skycor

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


int main()
{
  cpl_test_init(PACKAGE_BUGREPORT, CPL_MSG_WARNING);
  cpl_errorstate initial_errorstate = cpl_errorstate_get();

  /* Initialize CPL + SINFO messaging */
  printf("Hello World!\n");
  check(test_strehl(0.003),"Fail testing strehl");
  check(test_strehl2(0.003),"Fail testing strehl");
  //check(test_strehl4(),"Fail testing strehl");
  check(test_psf(),"Fail testing psf");
  /* TODO: make work the following unit test
  check(test_strehl_one(),"Fail test_strehl_one");
  */

  /* TODO: make work the following unit test
  check(test_strehl_two(),"Fail test_strehl_two");
  */
  /* TODO: make work the following test
  check(test_small(),"Fail test_small");
  */


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

    cleanup:

  return cpl_test_end(0);
}


/**@}*/
