/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* .COPYRIGHT   (C) 1993-2009 European Southern Observatory     */
/* .IDENT       mosdisp.c                                  */
/* .AUTHORS     Pascal Ballester (ESO/Garching)            */
/*              Cristian Levin   (ESO/La Silla)            */
/* .KEYWORDS    Spectroscopy, Long-Slit, MOS               */
/* .PURPOSE                                                */

/* .VERSION     1.0  Package Modification 21-SEP-1993      */

/* 090507		last modif			   */
/* ------------------------------------------------------- */

/* Purpose:
   This module is related to the dispersion relation and its representation.
   The upper modules (moscalib.c, mosrebin.c) do not know which representation
   is used (Legendre polynomials, or any other), nor how it is stored (which
   descriptor, meaning of coefficients). This design enables to replace 
   this module mosdisp.c by any other based on a different representation.
*/

/* Note:
`
   the general rule is that arrays start at index 1. However
   the module can accomodate any starting index, which is specified at 
   initialisation time (function initdisp).
*/


#include <midas_def.h>
#include <tbldef.h>
#include <fitnol.h>
#include <proto_mos.h>
#include <cpl_matrix.h>
#include <nrutil.h>

#include <ctype.h>
#include <stdio.h>
#include <math.h>


#ifndef PI 
#define PI 3.141592653589793
#endif

#define MAXNCOE 100
/* void     (*function) (), function = fpoly;   */
/* Another way to define a variable pointing to a function */

double   pixbin;              /* Pixel bin in wavelength units */
double   coef[100];           /* Array of coefficients  */
int	 fdeg, ncoef, refdeg, maxcoef; /* Number of coefficients, Degree */
int      degy,degxy; /* order of polynoms in y-dir and of the mixed term */
int	 tide, colslit, colline, coly, colrms, colcoef[100];
int	 start_index, nbline;


/* -------------------------------------------------------------------------- */
#ifdef _STDC__
  void setrefdeg_2D(int deg, int deg1, int deg2)
#else
  void setrefdeg_2D(deg, deg1, deg2) 
  int deg, deg1, deg2;
#endif
{

refdeg = deg;
degy = deg1;
degxy = deg2;
maxcoef = refdeg + degy + degxy + 1;
}

/* -------------------------------------------------------------------------- */
#ifdef _STDC__
  void setdisp_2D(int deg, double coefs[])
#else
  void setdisp_2D(deg, coefs)
  int deg;
  double  coefs[];
#endif
{

int i;

fdeg = deg;
refdeg = deg;
ncoef = deg + degy + degxy + 1;
maxcoef = deg + degy + degxy + 1;

for (i=1; i<=ncoef; i++) 
  coef[i] = coefs[i-1];
}


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


#ifdef _STDC__
  double mos_fit_disp_2D(int *ndata, int *deg, double x[], double y[],
		       double l[])
#else
  double mos_fit_disp_2D(ndata, deg, x, y, l)
  int *ndata, *deg;
  double x[],y[],l[];
#endif
{

  double   *sig, *xsh, *ysh, *lsh;
  int i;
  int maxdeg,actvals;
  char poltyp[12];

  /* printf("NData : %d   ---   Deg value : %d\n",*ndata,*deg); */

  refdeg = *deg;
  maxdeg = *ndata ;
  if (refdeg > maxdeg) fdeg = maxdeg;
  else                 fdeg = refdeg;
  ncoef   = fdeg + degy + degxy + 1;
  maxcoef = fdeg + degy + degxy + 1;

  if (*ndata < ncoef) {
    printf("Not enough lines (minimum is 2). \nNo dispersion relation computed\n");
    return(-2.);
  }
  
  if (fdeg < 1)  {
    printf("Degree : %d. No dispersion relation fitted\n",*deg);
    return(-1.);
  }
  

  sig  =(double*) dvector(1,*ndata);
  
  /*  for  (i=1;i<=*ndata;i++) printf(" xid = %9.3f yid=%9.3f lid=%9.3f\n", x[i],y[i],l[i]);*/
  xsh  =x+start_index-1;
  ysh  =y+start_index-1;
  lsh  =l+start_index-1;
  
  for (i=1; i<=*ndata; i++) sig[i]=1.;

  SCKGETC("POLTYP", 1, 8, &actvals, poltyp);
  if (toupper(poltyp[0]) == 'L')
    lsqfit2d_nr(x,y,l,sig,*ndata,coef,ncoef,fleg_2D);
  else if (toupper(poltyp[0]) == 'C')
    lsqfit2d_nr(x,y,l,sig,*ndata,coef,ncoef,fcheb_2D);
  else if (toupper(poltyp[0]) == 'P')
    lsqfit2d_nr(x,y,l,sig,*ndata,coef,ncoef,fpoly_2D);
  else 
    printf("ERROR - You have tried an invalid polynom type \n"); 

  free_dvector(sig,1,*ndata);
  
  pixbin = coef[2];
  return(pixbin);
  
}


/* -------------------------------------------------------------------------- */
#ifdef __STDC__
void mos_eval_disp_2D (double x[], double y[], double l[], int n)
#else
void mos_eval_disp_2D (x, y, l, n)
     double x[], y[], l[];
     int n;
#endif

{

  int actvals, i, icoef;
  double xp[MAXNCOE];
  char   poltyp[12];

  SCKGETC("POLTYP", 1, 8, &actvals, poltyp);
  for (i = start_index; i < (n + start_index); i++)
    {
      l[i] = 0.;

      if (toupper(poltyp[0]) == 'L')
        fleg_2D (x[i], y[i], xp, ncoef);
      else if (toupper(poltyp[0]) == 'C')
        fcheb_2D (x[i], y[i], xp, ncoef);
      else if (toupper(poltyp[0]) == 'P')
        fpoly_2D (x[i], y[i], xp, ncoef);
      else
	printf("ERROR - You have tried an invalid polynom type \n"); 

      for (icoef = 1; icoef <= ncoef; icoef++)
	l[i] += coef[icoef] * xp[icoef];
    }
}

/* -------------------------------------------------------------------------- */
#ifdef __STDC__
  void mos_writedisp_2D(int line, int slit, int ypix, 
		      double y, int numrow, double rms) 
#else
  void mos_writedisp_2D(line, slit, ypix, y, numrow, rms)  
  int  line, slit, ypix, numrow;
  double y, rms;
#endif
{
  int icoef,iexp;
  double coef2D[MAXNCOE], poly;
  


  /* make 1D coeficients from 2D coeficients -- last 5 depend on (y-ystart)*/
  for (icoef = 1; icoef <= (maxcoef-(degy+degxy)); icoef++)
    coef2D[icoef-1] = coef[icoef];
  poly = y;
  for (iexp = 1; iexp <= degy; iexp++)
    {
      coef2D[0] = coef2D[0] + coef[(maxcoef-degy)-degxy+iexp]*poly;
      poly = poly * y;
    }
  poly = y;
  for (iexp = 1; iexp <= degxy; iexp++)
    {
      coef2D[1] = coef2D[1] + coef[maxcoef-degxy+iexp] * poly;
      poly = poly * y;
    }
  TCEWRI(tide, line, colslit, &slit);
  TCEWRI(tide, line, colline, &ypix);
  TCEWRD(tide, line, coly,    &y);
  TCEWRD(tide, line, colrms,  &rms); 
  
  /*      if (nbline<line) nbline=line;   */
  /*if (nbline<line) nbline=numrow;*/
  
  for (icoef=1; icoef<=maxcoef-(degy+degxy); icoef++)
    TCEWRD(tide, line, colcoef[icoef], &coef2D[icoef-1]);
}

#ifdef __STDC__
  void fleg_2D( double x1, double x2, double pl[], int nl)
#else
  void fleg_2D(x1,x2,pl,nl)
  int nl;
  double x1,x2,pl[];
#endif  
{
  /* Legendre polynom in x1 - polynom in y and one mixed polynom x1*x2*/
  int j;
  float twox,f2,f1,d;
  
  pl[1]=1.0;
  pl[2]=x1;
  if (nl > 2) 
    {
      twox=2.0*x1;  /*Legendre in x*/
      f2=x1;
      d=1.0;
      for (j=3;j<=nl-(degy+degxy);j++) 
	{
	  f1=d;
	  d += 1.0;
	  f2 += twox;
	  pl[j]=(f2*pl[j-1]-f1*pl[j-2])/d;
	}

      pl[nl-(degy+degxy)+1]=x2;  /*polynom in y*/
      for (j=nl-(degy+degxy)+2;j<=(nl-degxy);j++)
	pl[j] = x2*pl[j-1];
      
      pl[nl-degxy+1] = x1*x2;    /*mixed polynom*/  
      for (j=nl-degxy+2;j<=nl;j++)
	pl[j] = x2*pl[j-1];
    }
}

#ifdef __STDC__
  void fcheb_2D( double x1, double x2, double pl[], int nl)
#else
  void fcheb_2D(x1,x2,pl,nl)
  int nl;
  double x1,x2,pl[];
#endif  
{
  /* Chebichev polynom in x1 - polynom in y and one mixed polynom x1*x2*/
  int j;
  float twox;
  
  pl[1]=1.0;
  pl[2]=x1;
  if (nl > 2) 
    {
      twox=2.0*x1;  /*Chebichev in x*/
      for (j=3;j<=nl-(degy+degxy);j++) 
	pl[j]=twox*pl[j-1]-pl[j-2];
  
      pl[nl-(degy+degxy)+1]=x2;  /*polynom in y*/
      for (j=nl-(degy+degxy)+2;j<=(nl-degxy);j++)
	pl[j] = x2*pl[j-1];
      
      pl[nl-degxy+1] = x1*x2;    /*mixed polynom*/  
      for (j=nl-degxy+2;j<=nl;j++)
	pl[j] = x2*pl[j-1];
    }
}

#ifdef __STDC__
  void fpoly_2D( double x1, double x2, double pl[], int nl)
#else
  void fpoly_2D(x1,x2,pl,nl)
  int nl;
  double x1,x2,pl[];
#endif  
{
  /* standard polynom in x1 (nl) && in x2 (degy) and 
     mixed polynom x1*x2 (degxy) */
  int j;
  
  pl[1]=1.0;
  if (nl > 1) 
    {
      for (j=2;j<=nl-(degy+degxy);j++)  /*polynom in x*/
	pl[j]=x1*pl[j-1];

      pl[nl-(degy+degxy)+1] = x2;  /*polynom in y*/
      for (j=nl-(degy+degxy)+2;j<=(nl-degxy);j++)
	pl[j] = x2*pl[j-1];

      pl[nl-degxy+1] = x1*x2;    /*mixed polynom*/  
      for (j=nl-degxy+2;j<=nl;j++)
	pl[j] = x2*pl[j-1];
    }
}
