/*
 S.F.Sanchez (08.08.2003)

*/


#include <stdlib.h>
#include <stdio.h>
#include <ctype.h> //For Type check
#include <string.h> //For String manipulation
#include <math.h> //For Math functions


#include "my_math.h"
#include "my_struct.h"


#ifndef EXIT_FAILURE
#define EXIT_FAILURE 1
#endif

#ifndef EXIT_SUCCESS
#define EXIT_SUCCESS 1
#endif

#define PARAMETERS 3
#define MAX_MODELS 2000
#define MAX_BACK 500

int write_error_par(double **covar, struct MODPAR *modpar, int n_mod);

int copy_modpar(struct MODPAR *newpar, struct MODPAR *modpar, int n_mod);

double poly_n(double x, double a[], int na) {
    int i;
    double t = x;      
    double Yi = 0;
    for (i=0;i<na;i++) {
	Yi+=a[i]*pow(t,i);
    }
    return Yi;
}


double gauss1d(double x, double I_m,double r_m, double sigma) {
      double e1,Yi;
      e1 = exp(-0.5*pow((x-r_m)/sigma,2));      
      Yi = I_m*e1/(sigma*sqrt(2*3.1416));      
      return Yi;
}

double DUST(double l, double Av, double Rv) {
      double e1,Yi;
      double x,y,ax,bx;	  
      l=l/10000; 
      x=1/l;
      y=(x-1.82);
      ax=1+0.17699*y-0.50447*pow(y,2)-0.02427*pow(y,3)+0.72085*pow(y,4)+0.01979*pow(y,5)-0.77530*pow(y,6)+0.32999*pow(y,7);
      bx=1.41338*y+2.28305*pow(y,2)+1.07233*pow(y,3)-5.38434*pow(y,4)-0.62251*pow(y,5)+5.30260*pow(y,6)-2.09002*pow(y,7);
      Yi=Av*(ax+bx/Rv);
      return Yi;
}

double model(double x, double y, struct MODPAR *modpar, int n_mod, struct BACKGROUND back[], int n_back) {
    int k,j;
    double flux_tmp,flux;
    double *a;
    double x_c,y_c,pre_pa,pa,q;
    double Im,r_m,beta;
    double xp,yp,r;
    double c;
    int nnx;

    int n_back_now;
    double d_wave_min;
    int n_wave_min,n_wave1,n_wave2;
    double wave_back,wave_back1,wave_back2,wave_back3,wave_back4;
    double f1,f2,f3,f4;
    double aa,bb;
    double vel_back;
    double flux_back,factor;
    double crval_back,cdelt_back;

    double speed_of_light=299792.458;
    double vel_line;
    double suma;
    double redshift;

    flux=0;
//    printf("AQUI %f %d\n",x,n_mod);
    for (k=0;k<n_mod;k++) {
	x_c=modpar[k].a[1];
	y_c=modpar[k].a[2];
	Im=modpar[k].a[3];
	r_m=modpar[k].a[4];
	beta=modpar[k].a[5];
	pre_pa=modpar[k].a[6];
	pa=(3.14159/180.0)*modpar[k].a[6];
	while (pa>2*3.14159) {
	    pa-=2*3.14159;
	}
	while (pa<0) {
	    pa+=2*3.14159;
	}
	q=modpar[k].a[7];
	c=modpar[k].a[8];
	xp=(x-x_c)*cos(pa)+(y-y_c)*sin(pa);
	yp=(y-y_c)*cos(pa)-(x-x_c)*sin(pa);
	r=pow((pow(xp,(c+2))+pow(yp/q,(c+2))),1/(c+2));

	if(strcmp(modpar[k].model, "gauss1d") == 0)
	    flux_tmp=gauss1d(x,modpar[k].a[2],modpar[k].a[1],modpar[k].a[3]);
	else if(strcmp(modpar[k].model, "moffat") == 0)
	    flux_tmp=Im/(pow((1+pow((r/r_m),2)),beta));
	else if(strcmp(modpar[k].model, "gauss") == 0)
	    flux_tmp=Im*exp(-pow((r/(2*r_m)),2));
	else if(strcmp(modpar[k].model, "disk") == 0)
	    flux_tmp=Im*exp(-(r/r_m));
	else if(strcmp(modpar[k].model, "vauc") == 0)
	    flux_tmp=Im*exp(-7.67*(pow(r/r_m,0.25)-1));
	else if(strcmp(modpar[k].model, "flat") == 0)
	    flux_tmp=Im;
	else if (strcmp(modpar[k].model, "poly1d") == 0) {
	    fflush(stdout);
	    flux_tmp=0.0;
	    for (j=1;j<9;j++) {
		flux_tmp+=modpar[k].a[j]*pow((x/1000),j-1);
	    }
	}
	else if (strcmp(modpar[k].model, "eline") == 0) {
	    redshift=modpar[k].a[6];
	    vel_line=modpar[k].a[4];
	    factor=(1+vel_line/speed_of_light+redshift);
	    flux_tmp=gauss1d(x,modpar[k].a[2],modpar[k].a[1]*factor,modpar[k].a[3]);
	}
	else if (strcmp(modpar[k].model, "back") == 0) {
	    fflush(stdout);
	    n_back_now=floor(modpar[k].a[1]);
	    flux_back=modpar[k].a[2];
	    vel_back=modpar[k].a[4];
	    redshift=modpar[k].a[6];
	    factor=(1+vel_back/speed_of_light+redshift);	    


//	    factor=(1+vel_back/speed_of_light);
	    crval_back=factor*back[n_back_now].wave[0];
	    cdelt_back=factor*back[n_back_now].wave[1]-crval_back;
	    n_wave_min=floor((x-crval_back)/cdelt_back);
	    
	    d_wave_min=back[n_back_now].wave[n_wave_min]-x;

	    if (modpar[k].a[3]==0) {

		if ((d_wave_min==0)||(n_wave_min==0)||(n_wave_min==(back[n_back_now].n-1))) {
		    flux_tmp=flux_back*back[n_back_now].flux[n_wave_min];
		} else {
		/* Linear Interpolation */
/*
		wave_back1=factor*back[n_back_now].wave[n_wave_min];
		wave_back2=factor*back[n_back_now].wave[n_wave_min+1];

		aa=(wave_back2-x)/(wave_back2-wave_back1);
		bb=1-aa;
		flux_tmp=flux_back*(aa*back[n_back_now].flux[n_wave_min]+bb*back[n_back_now].flux[n_wave_min+1]);
		*/
	
	
		    wave_back1=factor*back[n_back_now].wave[n_wave_min-1];
		    wave_back2=factor*back[n_back_now].wave[n_wave_min];
		    wave_back3=factor*back[n_back_now].wave[n_wave_min+1];
		    wave_back4=factor*back[n_back_now].wave[n_wave_min+2];
		    
		    f1=((x-wave_back2)*(x-wave_back3)*(x-wave_back4))/((wave_back1-wave_back2)*(wave_back1-wave_back3)*(wave_back1-wave_back4));
		    f2=((x-wave_back1)*(x-wave_back3)*(x-wave_back4))/((wave_back2-wave_back1)*(wave_back2-wave_back3)*(wave_back2-wave_back4));
		    f3=((x-wave_back1)*(x-wave_back2)*(x-wave_back4))/((wave_back3-wave_back1)*(wave_back3-wave_back2)*(wave_back3-wave_back4));
		f4=((x-wave_back1)*(x-wave_back2)*(x-wave_back3))/((wave_back4-wave_back1)*(wave_back4-wave_back2)*(wave_back4-wave_back3));
		
		
		flux_tmp=flux_back*(f1*back[n_back_now].flux[n_wave_min-1]+f2*back[n_back_now].flux[n_wave_min]+f3*back[n_back_now].flux[n_wave_min+1]+f4*back[n_back_now].flux[n_wave_min+2]);
		
		}
	    } else {
/*
 * We smooth the data:
 */ 
		n_wave1=floor((x-4*modpar[k].a[3]-crval_back)/cdelt_back);
		n_wave2=floor((x+4*modpar[k].a[3]-crval_back)/cdelt_back);
		if (n_wave1<0) {
		    n_wave1=0;
		}
		if (n_wave2<1) {
		    n_wave2=1;
		}
		if (n_wave1>=back[n_back_now].n) {
		    n_wave1=back[n_back_now].n-1;
		}
		if (n_wave2>=back[n_back_now].n) {
		    n_wave2=back[n_back_now].n-1;
		}
		flux_tmp=0.0;
		suma=0;
		for (j=n_wave1;j<=n_wave2;j++) {
//		    flux_tmp=flux_tmp+flux_back*back[n_back_now].flux[j]/(n_wave2-n_wave1+1);
		    flux_tmp=flux_tmp+gauss1d(factor*back[n_back_now].wave[j],flux_back*back[n_back_now].flux[j],x,modpar[k].a[3]);
		    suma=suma+gauss1d(factor*back[n_back_now].wave[j],1,x,modpar[k].a[3]);
		}
		flux_tmp=flux_tmp/suma;
	    }
	    if (modpar[k].a[5]>0) {
		factor=DUST(x,modpar[k].a[5],5.5);
		flux_tmp=flux_tmp/pow(10,0.4*factor);
	    }
	} else {
	    flux_tmp=0.0;
	}
	flux+=flux_tmp;
	if (strcmp(modpar[k].model, "dust") == 0) {
	    factor=DUST(x,modpar[k].a[1],modpar[k].a[2]);
	    flux=flux/pow(10,0.4*factor);
	}

    }
//    printf("END %f %d %d %d\n",x,n_mod,n_back_now,n_back);
    return flux;
}


double dmodel(double x, double y, struct MODPAR *modpar, int n_mod, int i_d , struct BACKGROUND back[], int n_back) {
    int i,k,j;
    double flux1,flux2,flux;
    double d;
    double *a;
    int ndim;
    struct MODPAR newpar[n_mod];
    d=0.001;
    copy_modpar(newpar,modpar,n_mod);
    read_modpar(a,modpar,n_mod,&ndim);
    i=0;
    for (k=0;k<n_mod;k++) {
	for(j=1;j<=modpar[k].na;j++) {
	    if (modpar[k].ia[j]==1) {
		if (modpar[k].fixa[j]==-1) {
		    if (i==i_d) {
			newpar[k].a[j]+=d;
		    }
		    i++;
		}
	    }
	}
    }
    flux1=model(x,y,newpar,n_mod,back,n_back);
    flux2=model(x,y,modpar,n_mod,back,n_back);
    flux=(flux1-flux2)/d;

    return flux;
}

void error_eline(struct MODPAR *modpar, int n_mod, double mean_res, double sigma_res) {
    int k,j;
    double Im;
    double error,sig;
    for (k=0;k<n_mod;k++) {
	if (strcmp(modpar[k].model, "eline") == 0) {
	    Im=modpar[k].a[2];
	    sig=modpar[k].a[3];
	    error=sigma_res*sig*sqrt(2*3.1415);//*sqrt(1+Im/mean_res);
	    //error=sigma_res*sqrt(2*sig*2.345);//*sqrt(1+Im/mean_res);
	    printf("error = %f %f %f %f %f \n",Im,mean_res,sig,sigma_res,error);
	    modpar[k].e_a[2]=error;
	}
	
    }
    fflush(stdout);
}

//int write_error_par(double **covar, struct MODPAR *modpar, int n_mod);

int write_model_res(char config[80], int n, float *w, float *y, float *y_mod, float *y_res, float *y_cont, char *flag);

int read_back(int n_back, char* filename, struct BACKGROUND *back) {
        FILE *fichero,*fichero2;	
	float temp_float;    
	int count_f,n,i,temp_int;
	char specfile[80];
	char tmpchar[80];
	int ns,j;
	count_f=0; 
	ns=0;
	
	n=n_back;
//	printf("PASO %d\n",n);
	printf("Background list: '%s', ",filename);
	if ((fichero=fopen(filename,"r"))==NULL) {
	    printf("Error opening file: %s\n",filename);
	    return(-1);
	} else {
//	    printf("PASO %d\n",n);

	    for(i=0;i<n;i++) {
//	    fscanf(fichero, "%s", tmpchar);
		    fscanf(fichero, "%s", specfile);	
		    strcpy(back[i].name,specfile);
		    //printf("BACK FILE[%i]='%s'\n",i,back[i].name);
		    ns=0;
		    if ((fichero2=fopen(specfile,"r"))==NULL) {
			printf("Error opening file: %s\n",filename);
			return(-1);
		    } else {
			while( fscanf(fichero2, "%f", &temp_float) != EOF) {	       			   
			    count_f++;
			    if (count_f>2) {
				count_f=0;
				ns++;
			    }		
			}
		    }	 
		    rewind(fichero2);
		    back[i].n=ns;
		    back[i].id= (int *)malloc(ns*sizeof(int));  
		    back[i].wave= (float *)malloc(ns*sizeof(float));  
		    back[i].flux= (float *)malloc(ns*sizeof(float));  
		    
		    for(j=0;j<ns;j++) {
			fscanf(fichero2, "%d", &temp_int);
			back[i].id[j]=temp_int;
			fscanf(fichero2, "%f", &temp_float);
			back[i].wave[j]=temp_float;
			fscanf(fichero2, "%f", &temp_float);
			back[i].flux[j]=temp_float;
//			printf("%d %d %d %f %f\n",i,j,back[i].id[j],back[i].wave[j],back[i].flux[j]);
		    }   
		}

	}
	return(0);

}

int read_data(char* filename, struct IMG *img_out) {
    FILE *fichero;
    float temp_float;    
    int count_f,n,i,temp_int,loop;
    struct IMG img;
    double flux_sum;
    count_f=0; 
    printf("Reading data...\n");
    n=0;
    loop=0;
    //    do {
      if ((fichero=fopen(filename,"r"))==NULL) {
	printf("Error opening file: %s\n",filename);
	return(-1);
      } else {
	while( fscanf(fichero, "%f", &temp_float) != EOF) {	       			   
	  count_f++;
	  if (count_f>2) {
	    count_f=0;
	    n++;
	  }
	}
      }
      rewind(fichero);
      img.nx= n;
      img.x= (double *)malloc(n*sizeof(double));  
      img.y= (double *)malloc(n*sizeof(double));  
      img.flux= (double *)malloc(n*sizeof(double));  
      img.sigma= (double *)malloc(n*sizeof(double));  
      
      flux_sum=0.0;
      for(i=0;i<n;i++) {
	fscanf(fichero, "%d", &temp_int);
	fscanf(fichero, "%f", &temp_float);
	img.x[i]=temp_float;
	img.y[i]=1.0;
	fscanf(fichero, "%f", &temp_float);
	img.flux[i]=temp_float;
	flux_sum=flux_sum+temp_float;
	//	printf("%f %f\n",img.x[i],img.flux[i]);
    }
      flux_sum=flux_sum/n;
      
      for(i=0;i<n;i++) {
	img.sigma[i]=sqrt(fabs(flux_sum));
      }
      
      loop++;
      //    } while ((n==0)&&(loop<10));
    printf("File readed (N=%d, loop=%d)\n",n,loop);

    *img_out=img;
    return(0);
}


int read_modpar(double *a, struct MODPAR *modpar, int n_mod, int *ndim) {
    int k,i,j;
    i=0;
    for (k=0;k<n_mod;k++) {
	for(j=1;j<=modpar[k].na;j++) {
	    if (modpar[k].ia[j]==1) {
		if (modpar[k].fixa[j]==-1) {
		    i++;
		}
	    }
	}
    }
    a= (double *)malloc(i*sizeof(double));  
    i=0;
    for (k=0;k<n_mod;k++) {
	for(j=1;j<=modpar[k].na;j++) {
	    if (modpar[k].ia[j]==1) {
		if (modpar[k].fixa[j]==-1) {
		    a[i]=modpar[k].a[j];
		    i++;
		}
	    }
	}
    }
    *ndim=i;
    return(0);
}


int write_modpar(double *a, struct MODPAR *modpar, int n_mod, int *ndim) {
    int k,i,j;
    i=0;
    for (k=0;k<n_mod;k++) {
	for(j=1;j<=modpar[k].na;j++) {
	    if (modpar[k].ia[j]==1) {
		if (modpar[k].fixa[j]==-1) {
		    modpar[k].a[j]=a[i];
		    i++;
		} else {			    

		    if (modpar[k].p_a2[j]==0) {
			modpar[k].a[j]=modpar[modpar[k].fixa[j]-1].a[j]+modpar[k].p_a[j]; 		    
		    } 
		    if (modpar[k].p_a2[j]==1) {
			modpar[k].a[j]=modpar[modpar[k].fixa[j]-1].a[j]*modpar[k].p_a[j]; 		    
		    } 
//		    modpar[k].a[j]=modpar[modpar[k].fixa[j]-1].a[j]+modpar[k].p_a[j]; 		    
		}
	    }
	}
    }
    *ndim=i;
    return(0);
}


int write_p_modpar(double *a, struct MODPAR *modpar, int n_mod, int *ndim) {
    int k,i,j;
    i=0;
    for (k=0;k<n_mod;k++) {
	for(j=1;j<=modpar[k].na;j++) {
	    if (modpar[k].ia[j]==1) {
		if (modpar[k].fixa[j]==-1) {
		    modpar[k].p_a[j]=a[i];
		    i++;
		} else {			    
		    modpar[k].p_a[j]=modpar[modpar[k].fixa[j]-1].p_a[j];
		}
	    }
	}
    }
    *ndim=i;
    return(0);
}



int copy_modpar(struct MODPAR *newpar, struct MODPAR *modpar, int n_mod) {
    int k,j;
    int np=9;
    for (k=0;k<n_mod;k++) {
	
	strcpy(newpar[k].model,modpar[k].model);
//	printf("NEWPAR='%s', '%s'\n",newpar[k].model,modpar[k].model);
//	newpar[k].model=modpar[k].model;
	newpar[k].na=modpar[k].na;
	newpar[k].a=dvector(1,np);
	newpar[k].e_a=dvector(1,np);
	newpar[k].p_a=dvector(1,np);
	newpar[k].ia=ivector(1,np);
	newpar[k].fixa=ivector(1,np);
	for(j=1;j<=modpar[k].na;j++) {
	    newpar[k].a[j]=modpar[k].a[j];
	    newpar[k].e_a[j]=modpar[k].e_a[j];
	    newpar[k].p_a[j]=modpar[k].p_a[j];
	    newpar[k].ia[j]=modpar[k].ia[j];
	    newpar[k].fixa[j]=modpar[k].fixa[j];
	}
    }
    return(0);
}




int read_config(char config[80], struct MODPAR *modpar, int *n_modpar, int *add_psf_out, double *ssq_out, double *min_delta_chisq);
int write_config(char config[80], struct MODPAR *modpar, int n_mod, int add_psf, double ssq, double min_delta_chisq, char *flag);
int write_int(char config[80], int n_row, char *flag);
int print_config(struct MODPAR *modpar, int n_mod, int add_psf, double ssq, double min_delta_chisq);

int write_out_file(char config[80],struct MODPAR *modpar, int n_mod, char *flag);



void function(double x, double y, double *flux, double dp[], struct MODPAR modpar[],int n_mod,int ma, struct BACKGROUND back[], int n_back);

void my_mrqcof_xy(double x[], double x1[], double y[], double sig[], int ndata, 
		  double **alpha, double beta[], double *chisq,
	    void (*funcs)(double, double, double *, double [], struct MODPAR modpar[], int n_mod), 
		  struct MODPAR modpar[], int n_mod);

void my_mrqmin_xy( double x[], double x1[], double y[], double sig[], int ndata, 
		   double **covar, double **alpha, double *chisq,
		   void (*funcs)(double, double, double *, double [], struct MODPAR modpar[], int n_mod),
		   double *alamda, struct MODPAR modpar[], int n_mod);

int print_par(struct MODPAR *modpar, int n_mod);

int main (int nargs,char* args[]){

  double mean_res,sigma_res;

    int niter_max=80; // put that as an imput in the config??
    int n_back=0;

    struct BACKGROUND back[MAX_BACK];

    struct MODPAR modpar[MAX_MODELS];
    int n_mod,i;
    FILE *fichero;
    char filename[100];
    int count_f=0;
    float temp_float;
    int j;
    
    struct IMG img;
    int add_psf;
    double ssq,min_delta_chisq,chisq;
    int n;
    double chi_sq,real_chi_sq;

    float *xp,*yp,*yp_lines,*yp_all,*yp_cont,*yp_model,*yp_res,*sigma_p;
    float r_min,r_max,y_min,y_max;




    double **covar,**alpha;
    double alamda;
    double *a;
    int ndim;
  
    
    int niter=0;

    double flux_sum;

  if (nargs<3) {
      printf("USE: fit_spec_back SPECTRUM.TXT CONFIG_FILE [BACKGROUND_LIST NBACK]\n");
      return(0);
  } 

  //  set_user_dataformat();
  strcpy(filename,args[1]);

  if (nargs>4) {
      n_back=(int)atoi(args[4]);
      if (n_back>0) {
	  printf("%d backgrounds\n",n_back);
	  read_back(n_back,args[3],back);
	  printf("included\n");
      } else {
	  printf("No background included\n");
      }
   } else {
      n_back=0;
      printf("No background included\n");
  }


  
  //  read_data(args[1],&img);
  printf("filename=%s\n",filename);
  read_data(filename,&img);

  xp= (float *)malloc(img.nx*sizeof(float));  
  yp= (float *)malloc(img.nx*sizeof(float));  
  yp_model= (float *)malloc(img.nx*sizeof(float));  
  yp_lines= (float *)malloc(img.nx*sizeof(float));  
  yp_all= (float *)malloc(img.nx*sizeof(float));  
  yp_cont= (float *)malloc(img.nx*sizeof(float));  
  yp_res= (float *)malloc(img.nx*sizeof(float));  
  r_min=100000;
  r_max=-100000;
  y_min=100000;
  y_max=-100000;
  n=img.nx;
  for (i=0;i<img.nx;i++) {
      xp[i]=(float)img.x[i];
      yp[i]=(float)img.flux[i];      
      if (xp[i]>r_max) r_max=xp[i];
      if (yp[i]>y_max) y_max=yp[i];
      if (xp[i]<r_min) r_min=xp[i];
      if (yp[i]<y_min) y_min=yp[i];
  }

  read_config(args[2],modpar,&n_mod,&add_psf,&ssq,&min_delta_chisq);
//  print_config(modpar,n_mod,add_psf,ssq,min_delta_chisq);  
  printf("Config readed\n");
  fflush(stdout);
//  return(0);
  read_modpar(a,modpar,n_mod,&ndim);
  covar=dmatrix(1,ndim+1,1,ndim+1);
  alpha=dmatrix(1,ndim+1,1,ndim+1);
  alamda=-1.0;
  chisq=10e6;
  chi_sq=11e6;
  while ((((chisq>ssq)&&(fabs(chi_sq-chisq)>min_delta_chisq))||(niter<4))&&(niter<niter_max)) {
      alamda=-1.0;
      chi_sq=chisq;
      fflush(stdout);
      my_mrqmin_back(img.x,img.y,img.flux,img.sigma,img.nx-1,covar,alpha,&chisq,&function,&alamda,modpar,n_mod,back,n_back);
      printf("Iter=%d Chisq=%f (%f), %f (%f)\n",niter,chisq,ssq,chi_sq-chisq,min_delta_chisq);
      niter++;
  }
  fflush(stdout);

  for (i=0;i<img.nx;i++) {
    yp_model[i]=model(img.x[i],img.y[i],modpar,n_mod-1,back,n_back);    
      yp_all[i]=model(img.x[i],img.y[i],modpar,n_mod,back,n_back);    
      yp_cont[i]=yp_all[i]-yp_model[i];
      yp_res[i]=yp[i]-yp_all[i];
      if (yp_res[i]>y_max) y_max=yp_res[i];
      if (yp_res[i]<y_min) y_min=yp_res[i];
      if (yp_all[i]>y_max) y_max=yp_all[i];
      if (yp_all[i]<y_min) y_min=yp_all[i];
  }



  printf("Fitted\n");
  fflush(stdout);
  real_chi_sq=chisq/(img.nx-n_mod-1);
  printf("CHI_SQ=%f\n",real_chi_sq);
  write_error_par(covar,modpar,n_mod);


  mean_res=fmean(yp_res,img.nx);
  sigma_res=fsigma(yp_res,img.nx,mean_res);

  error_eline(modpar,n_mod,mean_res,sigma_res);


  print_par(modpar,n_mod);

/*
 * WE copy the results to a log file
 */

  write_out_file("out.fit_spectra",modpar,n_mod,"w");
  write_config("out_config.fit_spectra",modpar,n_mod,add_psf,ssq,min_delta_chisq,"w");
  write_model_res("out_mod_res.fit_spectra",n,xp,yp,yp_all,yp_res,yp_cont,"w");
}


void function(double x, double y, double *flux, double dp[], struct MODPAR modpar[],int n_mod, int ma, struct BACKGROUND back[], int n_back) {
    double *a;
    int ndim,j;
//    printf("MODEL %f %f\n",x,y);
    fflush(stdout);
    *flux=model(x,y,modpar,n_mod,back,n_back); 
//    printf("DONE\n");
    for (j=1;j<=ma;j++) {
	dp[j]=dmodel(x,y,modpar,n_mod,j-1,back,n_back);     
	if (fabs(dp[j])>1e5) {
	    dp[j]=0;
	}
    }
//    printf("PASO %f %d \n",x,j);
    fflush(stdout);


}


int read_config(char config[80], struct MODPAR *modpar, int *n_modpar, int *add_psf_out, double *ssq_out, double *min_delta_chisq) {

  
  FILE *fichero;
  int i,k;
  int j;
  int np;
  double alamda;
  double **p_in,*y_in;
  double *p_test,*p_p_test;
  int ndim;
  double ftol;
  int nfunk;
  int niter;
  int add_psf;
  
  double ssq;
  double min_delta_chisq_in;
  double tmp_d;
  float tmp_f;

  int tmp_i;
  int aceptable;
  int n_mod;

  printf("Config File : %s\n",config);
  if ((fichero=fopen(config,"r"))==NULL) {
    printf("Error opening file: %s\n",config);
    return(-1);
  } else {    
    printf("File Opened...\n");
    fscanf(fichero, "%d", &add_psf);
    if ((add_psf!=0)&&(add_psf!=1)) {
      add_psf=0;
    }
    printf("Add PSF=%d\n",add_psf);
    fflush(stdout);
    fscanf(fichero, "%d", &n_mod);
    printf("Num. Models= %d\n",n_mod);
    fflush(stdout);
    fscanf(fichero, "%f", &tmp_f);
    ssq=(double)tmp_f;
    printf("Chisq Lim= %f\n",ssq);
    fscanf(fichero, "%f", &tmp_f);
    min_delta_chisq_in=(double)tmp_f;
    printf("Min Delta_Chisq= %f\n",min_delta_chisq_in);
    fflush(stdout);
    np=9;
    ndim=0;  
    for(i=0;i<n_mod;i++) {
      modpar[i].a=dvector(1,np);
      modpar[i].e_a=dvector(1,np);
      modpar[i].p_a=dvector(1,np);
      modpar[i].p_a2=dvector(1,np);
      modpar[i].ia=ivector(1,np);
      modpar[i].fixa=ivector(1,np);
      fscanf(fichero,"%s",modpar[i].model); 
      for (j=0;j<np;) {
	j++;
	fscanf(fichero,"%g",&tmp_f); 
	modpar[i].a[j]=(double)tmp_f; 
	modpar[i].e_a[j]=0.0;
	fscanf(fichero,"%d",&tmp_i); 
	modpar[i].ia[j]=tmp_i; 
	fscanf(fichero,"%g",&tmp_f); 
	modpar[i].p_a[j]=(double)tmp_f; 
	fscanf(fichero,"%g",&tmp_f); 
	modpar[i].p_a2[j]=(double)tmp_f; 
	fscanf(fichero,"%d",&tmp_i); 
	modpar[i].fixa[j]=tmp_i; 
	if (modpar[i].ia[j]==1) {
	  ndim++;
	}
      }
     
      modpar[i].ia[np]=0;
      modpar[i].na=np;    
      
    }
  }
  fclose(fichero);
  printf("File Closed\n");
  fflush(stdout);    

  
  *n_modpar=n_mod;
  *add_psf_out=add_psf;
  *ssq_out=ssq;
  *min_delta_chisq=min_delta_chisq_in;

  return(0);
}


int write_config(char config[80], struct MODPAR *modpar, int n_mod, int add_psf, double ssq, double min_delta_chisq, char *flag) {

  
  FILE *fichero;
  int i,k;
  int j;
  int np;
  double alamda;
  double **p_in,*y_in;
  double *p_test,*p_p_test;
  int ndim;
  double ftol;
  int nfunk;
  int niter;

  
  printf("Config File : %s\n",config);
  if ((fichero=fopen(config,flag))==NULL) {
    printf("Error opening file: %s\n",config);
    return(-1);
  } else {    
    printf("File Opened...\n");
    fprintf(fichero, "%d\n", add_psf);
    fprintf(fichero, "%d\n", n_mod);
    fprintf(fichero, "%f\n", ssq);
    fprintf(fichero,"%f\n",min_delta_chisq);
    np=9;
    for(i=0;i<n_mod;i++) {
      fprintf(fichero,"%s\n",modpar[i].model); 
      for (j=0;j<np;) {
	j++;
	fprintf(fichero,"%g\t",modpar[i].a[j]); 
	fprintf(fichero,"%d\t",modpar[i].ia[j]); 	
	fprintf(fichero,"%g\t",modpar[i].p_a[j]); 	
	fprintf(fichero,"%g\t",modpar[i].p_a2[j]); 	
	fprintf(fichero,"%d\n",modpar[i].fixa[j]); 
      }
    }
  }
  fclose(fichero);
  printf("File Closed\n");
  fflush(stdout);    
  return(0);
}

int print_config(struct MODPAR *modpar, int n_mod, int add_psf, double ssq, double min_delta_chisq) {

  
  int i,k;
  int j;
  int np;
  double alamda;
  double **p_in,*y_in;
  double *p_test,*p_p_test;
  int ndim;
  double ftol;
  int nfunk;
  int niter;

  
    printf( "%d\n", add_psf);
    printf( "%d\n", n_mod);
    printf( "%f\n", ssq);
    printf("%f\n",min_delta_chisq);
    np=9;
    for(i=0;i<n_mod;i++) {
      printf("%s\n",modpar[i].model); 
      for (j=0;j<np;) {
	j++;
	printf("%g\t",modpar[i].a[j]); 
	printf("%d\t",modpar[i].ia[j]); 	
	printf("%g\t",modpar[i].p_a[j]); 	
	printf("%g\t",modpar[i].p_a2[j]); 	
	printf("%d\n",modpar[i].fixa[j]); 
      }
    }

  return(0);
}


int write_int(char config[80], int n_row, char *flag) {  
  FILE *fichero;
  int i,k;
  int j;
  int np;
  double alamda;
  double **p_in,*y_in;
  double *p_test,*p_p_test;
  int ndim;
  double ftol;
  int nfunk;
  int niter;

  if ((fichero=fopen(config,flag))==NULL) {
    printf("Error opening file: %s\n",config);
    return(-1);
  } else {    
    fprintf(fichero, "%d\n", n_row);
  }
  fclose(fichero);
  fflush(stdout);    
  return(0);
}



int write_model_res(char config[80], int n, float *w, float *y, float *y_mod, float *y_res, float *y_cont, char *flag) {
    int k,i,j;
    FILE *fichero;
    printf("OUT File : %s\n",config);
    if ((fichero=fopen(config,flag))==NULL) {
	printf("Error opening file: %s\n",config);
	return(-1);
    } else {    
	for (k=0;k<n;k++) {
	    fprintf(fichero,"%f %f %f %f %f\n",w[k],y[k],y_mod[k],y_res[k],y_cont[k]);
	}
    }
    fclose(fichero);
}

int write_out_file(char config[80],struct MODPAR *modpar, int n_mod, char *flag) {
    int k,i,j;
    FILE *fichero;
    printf("OUT File : %s\n",config);
    if ((fichero=fopen(config,flag))==NULL) {
	printf("Error opening file: %s\n",config);
	return(-1);
    } else {    
	i=1;
	fprintf(fichero,"%d ",n_mod);
	for (k=0;k<n_mod;k++) {
	    fprintf(fichero,"\n%s ",modpar[k].model);
	    for(j=1;j<=modpar[k].na;j++) {
		fprintf(fichero," %4.4f %4.4f",modpar[k].a[j],modpar[k].e_a[j]);
	    }
	}
	fprintf(fichero,"\n");
    }
    fclose(fichero);

    printf("File Closed\n");
    fflush(stdout);    
    return(0);
}
