#!/usr/bin/perl
#
#
# This program find peaks in a 2D fiber based spectral image
#
#

use Statistics::OLS;
use Math::FFT;
use Math::Stat;
use Math::Spline qw(spline linsearch binsearch);
use Math::Derivative qw(Derivative2);

use Math::Approx;


use Astro::FITS::CFITSIO qw( :longnames :constants );
use PDL;

use PDL::Fit::Polynomial; 
use PDL::Filter::Linear;
use PGPLOT;  # Load PGPLOT module
use PDL::Fit::Gaussian;
use PDL::Image2D;
use  PDL::Fit::Linfit;



use PDL::Core;
use PDL::Basic;
use PDL::Exporter;
@ISA    = qw( PDL::Exporter );
use PDL::Options ':Func';
use PDL::Slatec; # For matinv()




sub my_linfit1d {
   my $opthash = ref($_[-1]) eq "HASH" ? pop(@_) : {} ; 
   my %opt = parse( { Weights=>ones(1) }, $opthash ) ;
   barf "Usage: linfit1d incorrect args\n" if $#_<1 or $#_ > 3;
   my ($y, $fitfuncs, $wt) = @_;
   if ($#_ == 1) {
      ($y, $fitfuncs) = @_;
      $x = $y->xvals;
   }
   
#   my $wt = $opt{Weights};
   
   # Internally normalise data
   
   my $ymean = (abs($y)->sum)/($y->nelem);
   $ymean = 1 if $ymean == 0;
   my $y2 = $y / $ymean;
   
   # Do the fit
      
   my $M = $fitfuncs->xchg(0,1);
   my $C = $M->xchg(0,1) x ($M * $wt->dummy(0)) ;
   my $Y = $M->xchg(0,1) x ($y2->dummy(0) * $wt->dummy(0));

   # Fitted coefficients vector

   $a = matinv($C) x $Y;
   
   # Fitted data

   $yfit = ($M x $a)->clump(2); # Remove first dim=1
   
   $yfit *= $ymean; # Un-normalise
   if (wantarray) {
      my $coeff = $a->clump(2);
      $coeff *= $ymean; # Un-normalise
      return ($yfit, $coeff);
   }
   else{
      return $yfit;
   }  
   
}
*my_linfit1d = \&my_linfit1d;


$F3D=$ENV{FIT3D_PATH}; require("$F3D/scripts/my.pl"); # "/home/sanchez/sda1/perl/MY/my.pl";


if ($#ARGV<5) {
    print "USE: auto_ssp.pl CUBE.FITS BACK_LIST.fits OUTFILE MASK_LIST CONFIG_FILE PLOT [min max] [wmin wmax] [redshift_elines_to_mask]\n";
    print "CONFIG_FILE:\n";
    print "redshift delta_redshift min_redshift max_redshift\n";
    print "sigma delta_sigma min_sigma max_sigma\n";
    print "Av delta_Av min_Av max_Av\n";
    print "START_W END_W MASK_FILE CONFIG_FILE NPOLY MASK_FILE_POLY\n";
    print "MIN_DELTA_CHISQ MAX_NITER CUT_MEDIAN_FLUX\n";
    print "START_W_PEAK_LINE END_W_PEAK_LINE\n";
    print "START_W_CROSS END_W_CROSS\n";
    exit;
}

$cube_file=$ARGV[0];
$back_list=$ARGV[1];
$outfile=$ARGV[2];
$outfile_elines=$outfile;
$cut="auto_ssp_";
$outfile_elines =~ s/$cut//g;
$name=$outfile_elines;
$outfile_elines = "elines_".$outfile_elines;

$call="rm -r ".$outfile_elines;
system($call);
#print "$outfile_elines\n"; exit;
$mask_list=$ARGV[3];
$config_file=$ARGV[4];
$plot=$ARGV[5];

$smooth=1;



$out_file="junk.junk";
$factor=1;
$box=1;


$def=0;
if ($#ARGV==7) {
    $min=$ARGV[6];
    $max=$ARGV[7];
    $def=1;
}

if ($#ARGV==9) {
    $min=$ARGV[6];
    $max=$ARGV[7];
    $min_wave=$ARGV[8];
    $max_wave=$ARGV[9];
    $def=2;
}

if ($#ARGV==10) {
    $min=$ARGV[6];
    $max=$ARGV[7];
    $min_wave=$ARGV[8];
    $max_wave=$ARGV[9];
    $elines_mask=$ARGV[10];
    $def=2;
}

open(FH,"<$config_file");
$line=<FH>;
chop($line);
#($redshift,$d_redshift,$min_redshift,$max_redshift)=split(" ",$line);
($redshift_ini,$d_redshift_ini,$min_redshift_ini,$max_redshift_ini)=split(" ",$line);
$line=<FH>;
chop($line);
($sigma_ini,$d_sigma_ini,$min_sigma,$max_sigma)=split(" ",$line);
$line=<FH>;
chop($line);
($Av_ini,$d_Av_ini,$min_Av,$max_Av)=split(" ",$line);
$line=<FH>;
chop($line);
($start_w_e,$end_w_e,$mask_e,$config_e,$npoly_e,$mask_poly_e,$nmin_e,$nmax_e)=split(" ",$line);
$line=<FH>;
chop($line);
($MIN_DELTA_CHISQ,$MAX_NITER,$CUT_MEDIAN_FLUX)=split(" ",$line);
$line=<FH>;
chop($line);
($start_w_peak,$end_w_peak)=split(" ",$line);
$line=<FH>;
chop($line);
($start_w_cross,$end_w_cross)=split(" ",$line);
close(FH);

#print "$start_w_cross $end_w_cross\n"; exit;


#$call="cp ".$config_e." tmp_e.config";
#system($call);



#

if ($mask_list eq "none") {
    $nmask=0;
} else {
    open(FH,"<$mask_list");
    while($line=<FH>) {
	chop($line);
	@data=split(" ",$line);
	$start_mask[$nmask]=$data[0];
	$end_mask[$nmask]=$data[1];
	$nmask++;
    }
    close(FH);
    $n_mask_org=$nmask;
    open(FH,"<$elines_mask");
    while($line=<FH>) {
	chop($line);
	if ($line !~ "#") {
	    @data=split(" ",$line);
	    $w_eline[$nline]=$data[0];
	    $nline++;
	}
    }
    close(FH);
}

#
# We read the input spectrum
#

$pdl_flux_c_ini=rfits($back_list);
($n_c,$nf)=$pdl_flux_c_ini->dims;
$crpix=$pdl_flux_c_ini->hdr->{CRPIX1};
$cdelt=$pdl_flux_c_ini->hdr->{CDELT1};
if ($cdelt==0) {
    $cdelt=$pdl_flux_c_ini->hdr->{CD1_1};
}
$crval=$pdl_flux_c_ini->hdr->{CRVAL1};



$pdl_cube=rfits($cube_file);
($nx,$ny,$nz)=$pdl_cube->dims;
$crpix3=$pdl_cube->hdr->{CRPIX3};
$cdelt3=$pdl_cube->hdr->{CDELT3};
if ($cdelt3==0) {
    $cdelt3=$pdl_cube->hdr->{CD3_3};
}
$crval3=$pdl_cube->hdr->{CRVAL3};
$h=$pdl_cube->gethdr;

$mod_cube=zeroes($nx,$ny,$nz);
$res_cube=zeroes($nx,$ny,$nz);

$median_img=zeroes($nx,$ny);
$chi_img=zeroes($nx,$ny);
$age_img=zeroes($nx,$ny);
$met_img=zeroes($nx,$ny);
$Av_img=zeroes($nx,$ny);
$redshift_img=zeroes($nx,$ny);
$sigma_img=zeroes($nx,$ny);


open(OUT,">$outfile");

for ($ix=0;$ix<$nx;$ix++) {
    for ($iy=0;$iy<$ny;$iy++) {

	($redshift,$d_redshift,$min_redshift,$max_redshift)=($redshift_ini,$d_redshift_ini,$min_redshift_ini,$max_redshift_ini);
	$sigma=$sigma_ini;
	$d_sigma=$d_sigma_ini;
	$Av=$Av_ini;
	$d_Av=$d_Av_ini;
	

#	$d_redshift=$d_redshift_ini;
#	$d_sigma=$d_sigma_ini;
#	$d_Av=$d_Av_ini;
#	($redshift,$d_redshift,$min_redshift,$max_redshift)=($redshift_ini,$d_redshift_ini,$min_redshift_ini,$max_redshift_ini);
	$pdl_slice=$pdl_cube->slice("($ix),($iy),:");

	$y_min=1e12;
	$y_max=-1e12;
	$i_scale=0;
	for ($n_unc=0;$n_unc<$nz;$n_unc++) {

	    $index_unc[$n_unc]=$n_unc+1;
	    $wave_unc[$n_unc]=$crval3+$cdelt3*(($crpix3-1)+$n_unc);
	    $flux_unc[$n_unc]=$pdl_slice->at($n_unc);
	    if ($flux_unc[$n_unc] eq "nan") {
		$flux_unc[$n_unc]=0;
	    }
	    if ($flux_unc[$n_unc]<$y_min) {
		$y_min=$flux_unc[$n_unc];
	    }
	    if ($flux_unc[$n_unc]>$y_max) {
		$y_max=$flux_unc[$n_unc];
	    }
	    if ($n_unc>0) {
		if (($wave_unc[$n_unc-1]<=$wave_scale)&&($wave_unc[$n_unc]>$wave_scale)) {
		    $i_scale=$n_unc;	    
		}
	    }
	    $masked[$n_unc]=1;
	    $w_test=$wave_unc[$n_unc-1];
	    for ($j=0;$j<$nmask;$j++) {
		if (($w_test>$start_mask[$j])&&($w_test<$end_mask[$j])) {
		    $masked[$n_unc]=0;	    
#		    print "$w_test ($start_mask[$j],$end_mask[$j]) $masked[$n_unc]\n";
		}
	    }
	    
	    if ($def==2) {
		if ($w_test<$min_wave) {
		    $masked[$n_unc]=0;	    
		}
		if ($w_test>$max_wave) {
		    $masked[$n_unc]=0;	    
		}
	    }
	    
#	    print "$n_unc $wave_unc[$n_unc] $flux_unc[$n_unc] $masked[$n_unc]\n";

	    $flux_masked[$n_unc]=$flux_unc[$n_unc]*$masked[$n_unc];
	}

	
	if ($def==2) {
	    $y_min=$min;
	    $y_max=$max;
	} else {
	    $min_wave=$wave_unc[0];
	    $max_wave=$wave_unc[$n_unc-1];
	}
	
	if ($def==1) {
	    $y_min=$min;
	    $y_max=$max;
	}
#
# We check the median value
#
	$median=median(@flux_masked);
	$stddev=sigma(@flux_masked);
	$dpix_unc=$wave_unc[1]-$wave_unc[0];

	$y_min=$median-3*$stddev;
	$y_max=$median+5*$stddev;


	print "$ix, $iy, $median,$stddev ($CUT_MEDIAN_FLUX)\n ";


	if ($median>0) {
	    if ($plot==1) {
		pgbegin(0,"/xs",1,1);
		pgsfs(1.2);
		pgscf(2);             # Set character font
		pgslw(2);             # Set line width
		pgsch(1.2);           # Set character height
		pgenv($wave_unc[0],$wave_unc[$n_unc-1],$y_min,$y_max,0,0);
		pgsch(1.2);           # Set character height
		pglabel("Wavelength","Counts","$name $Av $chi_sq $age_min $met_min");
		pgsci(1);
		pgline($n_unc,\@wave_unc,\@flux_unc);    
		pgsci(3);
		pgline($n_unc,\@wave_unc,\@flux_masked);    
		pgsci(1);
		pgclose;
		pgend;
#    print "Press Enter"; <stdin>;
	    }
	}

	if (($median>$CUT_MEDIAN_FLUX)&&($median>2*$stddev)) {
	    print "We start to fit... ($ix,$iy) ($median,$stddev)\n";


#	print "MEDIAN=$median\n"; 

	



#
# We create a kernel
#


#print "We start the fit...\n";



@med_flux=median_filter(11,\@flux_unc);
for ($j=0;$j<$n_unc;$j++) {
    $e_flux_unc[$j]=1/(($flux_unc[$j]-$med_flux[$i])**2);
}




	$min_chi_sq=FIT($redshift,$sigma,$Av);
#print "($redshift,$sigma,$Av) $min_chi_sq\n";
#print "----------------------\n";

#
# We cross-correlate for the redshift!
#


	$delta_chi=10;
#while (($min_chi_sq>1)&&($delta_chi>0.1)) {
	$NITER=0;
#	while (($delta_chi>$MIN_DELTA_CHISQ)&&($NITER<$MAX_NITER)) {
#$MIN_CHISQ
	    while (($MIN_CHISQ>$MIN_DELTA_CHISQ)&&($NITER<$MAX_NITER)) {
#	    print " (($MIN_CHISQ>$MIN_DELTA_CHISQ)&&($NITER<$MAX_NITER))\n";
#	while (($delta_chi>0.001)&&($NITER<5)) {
	#($MIN_DELTA_CHISQ,$MAX_NITER,$CUT_MEDIAN_FLUX)=split(" ",$line);    
	    if ($d_redshift!=0) {
		$min_chi_sq=FIT($redshift,$sigma,$Av);
		$chi_test=FIT($redshift+$d_redshift,$sigma,$Av);
		if ($chi_test>$min_chi_sq) {
		    $d_redshift=-$d_redshift;
		}
#	print "REDSHIFT ($redshift,$sigma,$Av) $min_chi_sq\n";
		$niter_now=0;
		do {
		    $chi_now[0]=$min_chi_sq;
		    $redshift=$redshift+$d_redshift;
		    
		    for ($iter=1;$iter<3;$iter++) {
			$chi_now[$iter]=FIT($redshift+($iter)*$d_redshift,$sigma,$Av);
		    }
		    $min_chi_sq=$chi_now[1];
		    $niter_now++;
		} while (($chi_now[2]<$chi_now[1])&&($niter_now<5));
		
		$redshift=($redshift+2*$d_redshift)-$d_redshift*(($chi_now[2]-$chi_now[1])/($chi_now[2]-2*$chi_now[1]+$chi_now[0])+0.5);
#		print "$redshift min ($min_redshift,$max_redshift) $d_redshift\n";

		
		if ($redshift>$max_redshift) {
		    $redshift=0.5*($max_redshift+$min_redshift);
		    $d_redshift=-0.5*abs($d_redshift);
		}
		if ($redshift<$min_redshift) {
		    $redshift=0.5*($max_redshift+$min_redshift);
		    $d_redshift=-0.5*abs($d_redshift);
		}
#		print "$redshift latter ($min_redshift,$max_redshift) $d_redshift\n";
	    }
	    
	    
	    
	    
	    
	    
	    if ($d_sigma!=0) {
		
		$min_chi_sq=FIT($redshift,$sigma,$Av);
		$chi_test=FIT($redshift,$sigma+$d_sigma,$Av);
		if ($chi_test>$min_chi_sq) {
		    $d_sigma=-$d_sigma;
		}
#	print "SIGMA ($redshift,$sigma,$Av) $min_chi_sq\n";
		$niter_now=0;
		do {
		    $chi_now[0]=$min_chi_sq;
		    $sigma=$sigma+$d_sigma;
		    
		    for ($iter=0;$iter<1;$iter++) {
			$chi_now[$iter]=FIT($redshift,$sigma+($iter)*$d_sigma,$Av);
		    }
		    $min_chi_sq=$chi_now[1];
		    $niter_now++;
		} while (($chi_now[2]<$chi_now[1])&&($niter_now<5));
		
		$sigma=($sigma+2*$d_sigma)-$d_sigma*(($chi_now[2]-$chi_now[1])/($chi_now[2]-2*$chi_now[1]+$chi_now[0])+0.5);
		
		if ($sigma>$max_sigma) {
		    $sigma=0.5*($max_sigma+$min_sigma);
		    $d_sigma=-0.5*abs($d_sigma);
		}
		if ($sigma<$min_sigma) {
		    $sigma=0.5*($max_sigma+$min_sigma);
		    $d_sigma=-0.5*abs($d_sigma);
		}	
	    }
	    
	    if ($d_Av!=0) {
		
		$min_chi_sq=FIT($redshift,$sigma,$Av);
		$chi_test=FIT($redshift,$sigma,$Av+$d_Av);
		if ($chi_test>$min_chi_sq) {
		    $d_Av=-$d_Av;
		}
#	print "AV ($redshift,$sigma,$Av) $min_chi_sq\n";
		$niter_now=0;
		do {
		    $Av=$Av+$d_Av;
		    $chi_now[0]=$min_chi_sq;
		    
		    for ($iter=1;$iter<3;$iter++) {
			$chi_now[$iter]=FIT($redshift,$sigma,$Av+($iter)*$d_Av);
		    }
		    $min_chi_sq=$chi_now[1];
		    if ($Av<0) {
			$Av=abs($Av);
		    }
		    $niter_now++;
		} while (($chi_now[2]<$chi_now[1])&&($chi_now[1]-$chi_now[2]>0.05)&&($niter_now<5));
		$Av=($Av+2*$d_Av)-$d_Av*(($chi_now[2]-$chi_now[1])/($chi_now[2]-2*$chi_now[1]+$chi_now[0])+0.5);
		
		if ($Av>$max_Av) {
		    $Av=0.5*($max_Av+$min_Av);
		    $d_Av=-0.5*abs($d_Av);
		}
		if ($Av<$min_Av) {
		    $Av=0.5*($max_Av+$min_Av);
		    $d_Av=-0.5*abs($d_Av);
		}
	    }
	    $min_chi_sq_end=FIT($redshift,$sigma,$Av);
	    $delta_chi=abs(($min_chi_sq_end-$min_chi_sq)/$min_chi_sq);
#    print "END ($redshift,$sigma,$Av) $min_chi_sq $delta_chi\n";

	    
	    
	    
#($start_w_e,$end_w_e,$mask_e,$config_e,$npoly_e,$mask_poly_e)=split(" ",$line);
	    # We fit now the emission lines!
	    #
	    $SYS_VEL=300000*$redshift;
	    $SYS_VEL_MAX=300000*$redshift*1.3;
	    $SYS_VEL_MIN=300000*$redshift*0.7;


	    $wpeak=0;
	    $Fpeak=-1e12;
#	    $stddev=sigma(@res_spec);
	    open(RES,">sub_spec.txt");
	    for ($i=0;$i<$n_unc;$i++) {
		$ID=$i+1;
		$W=$wave_unc[$i];
		$F_OUT=$res_spec[$i];
		print RES "$ID  $W  $F_OUT\n";
		if (($W>$start_w_peak)&&($W<$end_w_peak)) {
#		    print "$F_OUT>$Fpeak $F_OUT>3*$stddev\n";
#		    if (($F_OUT>$Fpeak)&&($F_OUT>(2*$stddev))) {
		    if ($F_OUT>$Fpeak) {
			$wpeak=$W;
			$Fpeak=$F_OUT;
		    }
		}

		$NF++;
	    }
	    close(RES);	    

#	    exit;

	    @FLUX_UNC=@flux_unc;

	    #if ($Fpeak>0) {		


	    open(IN_CONF,"<$config_e");
	    open(OUT_CONF,">tmp_e.config");
	    $n_conf=0;
	    while($line=<IN_CONF>) {
		chop($line);
#		    if ($n_conf==2) {
#			if ($wpeak>0) {
#			    @data=split(" ",$line);
#			    $wpeak_res=$data[0];
#			    $SYS_VEL=300000*($wpeak/$wpeak_res-1);
#			$SYS_VEL_MAX=$SYS_VEL*1.1;
#			$SYS_VEL_MIN=$SYS_VEL*0.9;
#			}
#	    }
	    if ($n_conf==5) {
#			if ($SYS_VEL>0) {
#			    if ($SYS_VEL_MIN==0) {
#				$SYS_VEL_MIN=0.99*$SYS_VEL;
#			    }
#			    if ($SYS_VEL_MAX==0) {
#				$SYS_VEL_MAX=1.01*$SYS_VEL;
#			    }
#			} else {
#			    if ($SYS_VEL_MIN==0) {
#				$SYS_VEL_MIN=100;
#			    }
	#		    if ($SYS_VEL_MAX==0) {
	#			$SYS_VEL_MAX=1e12;
	#		    }
	#    }
		print OUT_CONF "$SYS_VEL   1   $SYS_VEL_MIN  $SYS_VEL_MAX  -1\n";	    
	    } else {
		print OUT_CONF "$line\n";
	    }
	    }
	    $n_conf++;
	    #}
	    close(OUT_CONF);
	    close(IN_CONF);
		
		
		
	    $call="spec2img.pl sub_spec.txt res_spec.fits 1";
	    system($call);
	    $call="polyfit_mask.pl res_spec.fits 9 res_poly.fits ".$mask_poly_e." ".$nmin_e." ".$nmax_e." /null";
	    system($call);
	    $call="imarith.pl res_spec.fits - res_poly.fits new_res.fits";
	    system($call);
	    $call="img2spec.pl new_res.fits 0 new_res.txt";
	    system($call);
	    if ($plot==1) {
		$call="fit_spec_back.pl new_res.txt none ".$start_w_e." ".$end_w_e." none 0 ".$mask_e." tmp_e.config";
	    } else {
		$call="fit_spec_back.pl new_res.txt none ".$start_w_e." ".$end_w_e." none 0 ".$mask_e." tmp_e.config /null";
	    }
#    $call="fit_spec_back.pl sub_spec.txt none ".$start_w_e." ".$end_w_e." none 0 ".$mask_e." tmp_e.config";
	    print "$call\n";
	    system($call);

	    
	    
	    #
	    # Now we subtract the emission lines
	    # 
	    
		open(MOD,"<out_mod_res.fit_spectra");
		$NF=0;
		@model_joint=@model_spec_min;
		@res_joint=@res_spec;
		while($line=<MOD>) {
		    chop($line);
		    @data=split(" ",$line);
		    $WMOD=$data[0];
		    $FMOD=$data[2];
		    while (abs($data[0]-$wave_unc[$NF])>0.1) {
			$NF++;
		    } 
		    $flux_now=$flux_unc[$NF]-$FMOD;	    
		    $flux_masked[$NF]=$flux_now*$masked[$NF];
		    $FLUX_UNC[$NF]=$flux_now;
		    $model_joint[$NF]=$model_spec_min[$NF]+$FMOD;
#		$res_joint[$NF]=$res_spec[$NF]-$FMOD;
		    $res_joint[$NF]=$flux_unc[$NF]-$model_joint[$NF];
		    
		}
		close(MOD);
		
		
#	    open(OUT_MOD,">mod_joint_spec.txt");
#	    open(OUT_RES,">res_joint_spec.txt");
#	    for ($j=0;$j<$n_unc;$j++) {
#		print OUT_MOD "$index_unc[$j] $wave_unc[$j] $model_joint[$j]\n";
#		print OUT_RES "$index_unc[$j] $wave_unc[$j] $res_joint[$j]\n";
#	    }
#	    close(OUT_RES);
#	    close(OUT_MOD);
		
		
	    
#    print "Press Enter"; <sdtin>;
	    #
	    #
	    
	    
#	    print " (($delta_chi>$MIN_DELTA_CHISQ)&&($NITER<$MAX_NITER))\n";   
	    #    print "END****\n";

#	    print "$redshift -> ";
		if ($NITER==0) {
		    if ($wpeak>0) {
			open(FIT,"<out.fit_spectra");
			$FIT=<FIT>;
			$FIT=<FIT>;
			@a_FIT=split(" ",$FIT);
			$red_now=$a_FIT[7];
			$e_red_now=$a_FIT[8];
			$rat_e=$e_red_now/$red_now;
			if ($rat_e<0.6) {
			    $redshift=$red_now/300000;
			    #$d_reshift=0.0005;
			}
			close(FIT);		
		    }
		}

#	}
#	    print "$redshift\n"; <stdin>;

		$d_redshift=-0.5*$d_redshift;
		$d_sigma=$d_sigma/2;
		$d_Av=$d_Av/2;
		$NITER++;
		if ($NITER>1) {
		    $d_Av=0;
		}
		if ($NITER>2) {
		    $d_sigma=0;
		}
		
		


	    $DIF_REDSHIFT=CROSS(\@wave_unc,\@FLUX_UNC,\@model_spec_min,-$d_redshift*10,$d_redshift*10,$d_redshift/10,$start_w_cross,$end_w_cross);
#	    $DIF_REDSHIFT=CROSS(\@wave_unc,\@FLUX_UNC,\@model_spec_min,-0.02,0.02,0.0001,$start_w_cross,$end_w_cross);
#	    $DIF_REDSHIFT=CROSS(\@wave_unc,\@FLUX_UNC,\@model_spec_min,-0.02,0.02,0.0001,3850,5400);
#	    print "Press Enter\n"; <stdin>;
		#print "CROSS_REDSHIFT = $redshift ";
		$redshift=$redshift+$DIF_REDSHIFT;
#	    $d_redshift=0;
#	    $min_chi_sq=FIT($redshift,$sigma,$Av);
		#print "$DIF_REDSHIFT $redshift\n";
		
#	    exit;









	}
	
	print "CHISQ=$MIN_CHISQ AGE=$age_min MET=$met_min AV=$Av REDSHIFT=$redshift SIGMA_DISP=$sigma\n";
	

	for ($j=0;$j<$n_unc;$j++) {
	    set($mod_cube,$ix,$iy,$j,$model_joint[$j]);
	    set($res_cube,$ix,$iy,$j,$res_joint[$j]);
	}	

	print OUT "$median $MIN_CHISQ $age_min $met_min $Av $redshift $sigma\n";


	    set($median_img,$ix,$iy,$median);	
	set($chi_img,$ix,$iy,$MIN_CHISQ);
	set($age_img,$ix,$iy,$age_min);
	set($met_img,$ix,$iy,$met_min);
	set($Av_img,$ix,$iy,$Av_min);
	set($redshift_img,$ix,$iy,$redshift);
	set($sigma_img,$ix,$iy,$sigma);
	    $chi_img->wfits("chi_img.fits");
	    $age_img->wfits("age_img.fits");
	    $Av_img->wfits("Av_img.fits");
	    $met_img->wfits("met_img.fits");
	    $redshift_img->wfits("redshift_img.fits");
	    $sigma_img->wfits("sigma_img.fits");    
	    
	    $median_img->wfits("median_img.fits");


#	$call="cat out.fit_spectra >> ".$outfile_elines;
#	system($call);




#	    if ($Fpeak>0) {
		$call="cat out.fit_spectra >> ".$outfile_elines;
		system($call);
#	    } else {
#		open(ELINES,">>$outfile_elines");
#		print ELINES "0\n";
#		close(ELINES);
#	    }



	print "DONE\n";
    } else {
	if ($median>0) {







		$wpeak=0.5*($start_w_peak+$end_w_peak);
		$Fpeak=-1e12;
		
#	    open(RES,">new_res.txt");
		open(RES,">sub_spec.txt");
		for ($i=0;$i<$n_unc;$i++) {
		    $ID=$i+1;
		    $W=$wave_unc[$i];
		    $F_OUT=$flux_unc[$i];
		    print RES "$ID  $W  $F_OUT\n";
		    
		    if (($W>$start_w_peak)&&($W<$end_w_peak)) {
#			if (($F_OUT>$Fpeak)&&($F_OUT>($median+$stddev))) {
			if ($F_OUT>$Fpeak) {
			    $wpeak=$W;
			    $Fpeak=$F_OUT;
			}
		    }
#	    print "$wpeak $F_OUT $median+2*$stddev\n";
		    $NF++;
		}
		close(RES);
		
		$cut_now=$median+2*$stddev;
#	    print "Fpeak $Fpeak ($cut_now)\n";
		
		@FLUX_UNC=@flux_unc;
		if ($Fpeak>0) {		
		    $SYS_VEL=300000*$redshift;
		    $SYS_VEL_MAX=300000*$redshift*1.3;
		    $SYS_VEL_MIN=300000*$redshift*0.7;
#	    print "CONF=$config_e\n";
		    open(IN_CONF,"<$config_e");
		    open(OUT_CONF,">tmp_e.config");
		    $n_conf=0;
		    while($line=<IN_CONF>) {
			chop($line);
			if ($n_conf==2) {
			    @data=split(" ",$line);
			    $wpeak_res=$data[0];
			    $SYS_VEL=300000*($wpeak/$wpeak_res-1);
			    $SYS_VEL_MAX=$SYS_VEL*1.01;
			    $SYS_VEL_MIN=$SYS_VEL*0.99;
#		    $SYS_VEL_MAX=300000*$max_redshift_ini*1.2;
#		    $SYS_VEL_MIN=300000*$min_redshift_ini*0.8;
#		    print "$SYS_VEL $wpeak $wpeak_res\n"; <stdin>;
		    }
		    if ($n_conf==5) {
			if ($SYS_VEL>0) {
			    if ($SYS_VEL_MIN==0) {
				$SYS_VEL_MIN=0.99*$SYS_VEL;
			    }
			    if ($SYS_VEL_MAX==0) {
				$SYS_VEL_MAX=1.01*$SYS_VEL;
			}
			} else {
			    if ($SYS_VEL_MIN==0) {
				$SYS_VEL_MIN=100;
			    }
			    if ($SYS_VEL_MAX==0) {
				$SYS_VEL_MAX=1e12;
			    }
			}
		    print OUT_CONF "$SYS_VEL   1   $SYS_VEL_MIN  $SYS_VEL_MAX  -1\n";	    
		    } else {
			print OUT_CONF "$line\n";
		    }
		    $n_conf++;
		}
		close(OUT_CONF);
		close(IN_CONF);
		
		
		
		    $call="spec2img.pl sub_spec.txt res_spec.fits 1";
		    system($call);
		    $call="polyfit_mask.pl res_spec.fits 9 res_poly.fits ".$mask_poly_e." ".$nmin_e." ".$nmax_e." /null";
		    system($call);
		    $call="imarith.pl res_spec.fits - res_poly.fits new_res.fits";
		    system($call);
		    $call="img2spec.pl new_res.fits 0 new_res.txt";
		    system($call);
		    
		    
		    
		    if ($plot==1) {
			$call="fit_spec_back.pl new_res.txt none ".$start_w_e." ".$end_w_e." none 0 ".$mask_e." tmp_e.config";
		    } else {
			$call="fit_spec_back.pl new_res.txt none ".$start_w_e." ".$end_w_e." none 0 ".$mask_e." tmp_e.config /null";
		    }
		    system($call);
#	    print "$call\n";
		    
		    
		    
		    open(MOD,"<out_mod_res.fit_spectra");
		    $NF=0;
		    @model_joint=@model_spec_min;
		    @res_joint=@res_spec;
		    while($line=<MOD>) {
			chop($line);
			@data=split(" ",$line);
			$WMOD=$data[0];
			$FMOD=$data[2];
			while (abs($data[0]-$wave_unc[$NF])>0.1) {
			    $NF++;
			} 
			$model_joint[$NF]=$FMOD;
			$res_joint[$NF]=$fluc_unc[$NF]-$FMOD;
		    }
		    close(MOD);
		    
		    for ($j=0;$j<$n_unc;$j++) {
			set($mod_cube,$ix,$iy,$j,$model_joint[$j]);
			set($res_cube,$ix,$iy,$j,$res_joint[$j]);
		    }		    
		    
		    
		    $call="cat out.fit_spectra >> ".$outfile_elines;
		    system($call);
		    
		    set($median_img,$ix,$iy,$median);	
		    $median_img->wfits("median_img.fits");
		} else {
		    open(ELINES,">>$outfile_elines");
		    print ELINES "0\n";
		    close(ELINES);
		    
		}
		print OUT "$median 0  0  0 0 0 0\n";
	    }   else {
		open(ELINES,">>$outfile_elines");
		print ELINES "0\n";
		close(ELINES);
		print OUT "$median 0  0  0 0 0 0\n";
	    }
    
	    
	}
    
	

    }
}

close(OUT);
#print "----------------------------\n";
$mod_cube->sethdr($h);
$res_cube->sethdr($h);
$mod_cube->wfits("mod.cube.fits");
$res_cube->wfits("res.cube.fits");



$chi_img->wfits("chi_img.fits");
$age_img->wfits("age_img.fits");
$Av_img->wfits("Av_img.fits");
$met_img->wfits("met_img.fits");
$redshift_img->wfits("redshift_img.fits");
$sigma_img->wfits("sigma_img.fits");    

$median_img->wfits("median_img.fits");

exit;

sub CROSS {
    my $pwave=$_[0];
    my $pflux=$_[1];
    my $pmodel=$_[2];
    my $min_z=$_[3];
    my $max_z=$_[4];
    my $d_z=$_[5];
    my $wave_min=$_[6];
    my $wave_max=$_[7];
    my $z_best;
    my $i,$j,$k,$n;
    my $z=$min_z;

    my @wave=@$pwave;
    my @flux=@$pflux;
    my @model=@$pmodel;

    my @cross;
    my $nc=0;
    my @z_dist;
    my $max_cross=-1e12;
    my $min_cross=1e12;

    my $z_best_min,$z_best_max;

#    print "$min_z $max_z $d_z\n";
#    print "WAVE=@wave\n"; <stdin>;

#    print "NW=$#wave\n";
    while ($z<$max_z) {

	my $wave_new;
	for ($i=0;$i<$#wave+1;$i++) {
	    $wave_new[$i]=$wave[$i]*(1+$z);
	}
#	print "$#wave $#wave_new\n";
	my $pdl_new_model = interpol(pdl(@wave), pdl(@wave_new), pdl(@model));
	$cross[$nc]=0;
	for ($i=0;$i<$#wave+1;$i++) {
	    $val=$pdl_new_model->at($i);
#	    print "$val $flux[$i]\n";
	    if (($wave[$i]>$wave_min)&&($wave[$i]<$wave_max)) {
		$cross[$nc]=$cross[$nc]+$val*$flux[$i];
	    }
	}
	if ($cross[$nc]>$max_cross) {
	    $max_cross=$cross[$nc];
	    $z_best_max=$z;
	}
	if ($cross[$nc]<$min_cross) {
	    $min_cross=$cross[$nc];
	    $z_best=$z;
	    $z_best_min=$z;
	}
	$z_dist[$nc]=$z;
	$z=$z+$d_z;

#	print "$z $max_z $cross[$nc] $max_cross\n";
	$nc++;
    }
    

    if ($plot==1) {
	pgbegin(0,"/xs",1,1);
	pgsfs(1.2);
	pgscf(2);             # Set character font
	pgslw(2);             # Set line width
	pgsch(1.2);           # Set character height
	pgenv($min_z-$d_z,$max_z+$d_z,$min_cross,$max_cross,0,0);
	pgsch(1.2);           # Set character height
	pglabel("\\gDredshift","Cross-Correlation","");
	pgsci(1);
	pgline($nc,\@z_dist,\@cross);    
	pgclose;
	pgend;
    }
#    print "Z=$z_best\n";
#    exit;


    return $z_best_max;
}



sub FIT {
    my $redshift=$_[0];
    my $sigma=$_[1];
    my $Av=$_[2];

    $MIN_CHISQ=1e12;	

#####################


#############




for ($j=0;$j<$n_c;$j++) {
    $wave_c[$j]=($crval+$cdelt*($j+1-$crpix))*(1+$redshift);
}
$dpix_c=$wave_c[1]-$wave_c[0];

$rsigma=$sigma/$dpix_c;

    if ($rsigma<=0) {
	$rsigma=0.1;
    }


for ($iii=0;$iii<$nf;$iii++) {
    $header="NAME".$iii;
    $name[$iii]=$pdl_flux_c_ini->hdr->{$header};
    $name_min=$name[$iii];
    $name_min =~ s/spec_ssp_//;
    $name_min =~ s/.spec//;
    ($AGE,$MET)=split("_",$name_min);
    if ($AGE =~ "Myr") {
	$age=$AGE;
	$age =~ s/Myr//;
	$age=$age/1000;
    } else {
	$age=$AGE;
	$age =~ s/Gyr//;
    }
    $met=$MET;
    $met =~ s/z/0\./;

    $age_mod[$iii]=$age;
    $met_mod[$iii]=$met;
#    print "$name[$iii] $age_mod[$iii] $met_mod[$iii]\n";


$box=int(3*$rsigma);
    if ($box<3) {
	$box=3;
    }
$kernel=zeroes(2*$box);
$norm=0;
$flux_c[$i]=0;
for ($j=0;$j<2*$box;$j++) {
    $gaus=exp(-0.5*((($j-$box)/$rsigma)**2));    
    set($kernel,$j,$gaus);
    $norm=$norm+$gaus;
}
$kernel=$kernel/$norm;

$pdl_flux_c_conv = conv2d $pdl_flux_c_ini,$kernel;


    $pdl_flux_c = $pdl_flux_c_conv->slice(",$iii");
    my $out_spec_pdl = interpol(pdl(@wave_unc), pdl(@wave_c), $pdl_flux_c);
    ($n_c_out)=$out_spec_pdl->dims;
#
# We store the result!
#
    for ($i=0;$i<$n_unc;$i++) {
#	print "$i/$n_c\n";
	$val=$out_spec_pdl->at($i);
	if ($val eq "nan") {
	    $val=0;
	}
	$model[$i][$iii]=$val*$masked[$i];
	$model_no_mask[$i][$iii]=$val;#*$masked[$i];
	if ($masked[$i]>0) {
	    $error[$i][$iii]=1/abs($val);
	  
#	    $error[$i][$iii]=10;
	} else {
	    $error[$i][$iii]=1e20;
	}

	for ($j=0;$j<$nline;$j++) {
	    if (abs($wave_unc[$i]-$w_eline[$j]*(1+$redshift))<(3*$rsigma)) {
		$error[$i][$iii]=1e10;
#		print "$wave_unc[$i] $error[$i][$iii]\n";
	    }
	}


    }
 #   print "$iii/$nf files\n";
}

    $pdl_model=zeroes($n_unc,$nf);
    $pdl_error=zeroes($n_unc,$nf);
    
    for ($j=0;$j<$nf;$j++) {
	for ($i=0;$i<$n_unc;$i++) {
	    $wave_res=$wave_unc[$i]/(1+$redshift);
	    $dust_rat=A_l(3.1,$wave_res);
	    $dust=10**(-0.4*$Av*$dust_rat);  
	    $val=$model[$i][$j]*$dust;
	    set($pdl_model,$i,$j,$val);
	    $e_val=$error[$i][$j];
	    set($pdl_error,$i,$j,1);
	}
    }
#
# We fit
#
#    print "We fit with Av=$Av ";
    $pdl_flux_masked=pdl(@flux_masked);
    ($yfit, $coeffs) = my_linfit1d $pdl_flux_masked,$pdl_model,$pdl_error;


#
# We remove the models that are negative
#
    $nf_new=0;
    $nf_neg=0;
    for ($k=0;$k<$nf;$k++) {
	$C=$coeffs->at($k,0);
	if ($C>0) {
	    $nf_new++;
	} else {
	    $nf_neg++;
	}
    }

#    print "\n";
    if ($nf_new>0) {
	while (($nf_neg>0)&&($nf_new>0)) {
#	    if ($nf_new>0) {
#	    print "$n_unc $nf_new $nf_neg ";
	    my $pdl_model_new=zeroes($n_unc,$nf_new);
	    my $pdl_error_new=zeroes($n_unc,$nf_new);
	    $nf_i=0;
#	    print "C= ";
	    for ($k=0;$k<$nf;$k++) {
		$C=$coeffs->at($k,0);
#		print " $C ";
		if ($C>0) {
		    for ($i=0;$i<$n_unc;$i++) {
			$val=$pdl_model->at($i,$k);
			set($pdl_model_new,$i,$nf_i,$val);
			$e_val=$pdl_error->at($i,$k);
			set($pdl_error_new,$i,$nf_i,$e_val);		    
		    }
		    $MOD[$nf_i]=$k;
		    $nf_i++;
		} else {
		    set($coeffs,$k,0,0);
		}
	    }
	    
#	    }
#	    print "\n";
	    ($yfit, $coeffs_new) = my_linfit1d $pdl_flux_masked,$pdl_model_new,$pdl_error_new;	
#	    print "FIT $coeffs_new\n";
	    
	    $nf_i=0;
	    $nf_neg=0;
	    $nf_new=0;
#	    print "C= ";
	    for ($k=0;$k<$nf;$k++) {
		$C=$coeffs->at($k,0);
#		print "$C ";
		if ($C>0) {
		    $val=$coeffs_new->at($nf_i,0);
		    $nf_i++;
		    if ($val>0) {
			set($coeffs,$k,0,$val);
			$nf_new++;
		    } else {
			set($coeffs,$k,0,0);
			$nf_neg++;
		    }
#		    print "$val , ";
		}
	    }
#	    print "\n";
	}
#	    print "$nf_new $nf_neg ";
#	    print "C= ";
	    for ($k=0;$k<$nf;$k++) {
		$C=$coeffs->at($k,0);
#		print " $C ";
	    }
#	print "\n";

    } else {
	$nf_new=$nf;
	$pdl_model_new=$pdl_model;
	$pdl_error_new=$pdl_error;
    }



#
# We determine the chi**2
#
    @J=$yfit->dims;
    @K=$coeffs->dims;
#    print "DONE ( $coeffs)\n"; <stdin>;
    $chi=0;
    for ($j=0;$j<$n_unc;$j++) {
#	print "$j/$n_unc\n";
	$out_spec[$j]=($yfit->at($j,0));#
	    if ($flux_unc[$j]!=0) {
		$chi=$chi+$masked[$j]*(($flux_unc[$j]-$out_spec[$j])**2)/abs($flux_unc[$j]);
	    }
    }





    $chi_sq=(($chi/($n_unc-$nf))**0.5);
    if ($chi_sq<$MIN_CHISQ) {
	$MIN_CHISQ=$chi_sq;
	$Av_MIN=$Av;
	for ($j=0;$j<$n_unc;$j++) {
	    $model_spec[$j]=0;
	    $wave_res=$wave_unc[$j]/(1+$redshift);
	    $dust_rat=A_l(3.1,$wave_res);
	    $dust=10**(-0.4*$Av*$dust_rat);  
	    $norm_C=0;
	    for ($k=0;$k<$nf;$k++) {
		$C=$coeffs->at($k,0);
		$norm_C=$norm_C+$C;
		$model_spec[$j]=$model_spec[$j]+$C*$model_no_mask[$j][$k]*$dust;
		$model_spec_min[$j]=$model_spec[$j];
	    }
	    $res_spec[$j]=$flux_unc[$j]-$model_spec[$j];	    
#	    print "$wave_unc[$j] $flux_unc[$j] $model_spec[$j] $res_spec[$j]\n";
	}
	$age_min=0;
	$met_min=0;
	for ($k=0;$k<$nf;$k++) {
	    $C=$coeffs->at($k,0);
	    if ($norm_C>0) {
		$age_min=$age_min+$C*$age_mod[$k]/$norm_C;
		$met_min=$met_min+$C*$met_mod[$k]/$norm_C;
	    }
#	    print "$k $C $age_min $age_mod[$k] $met_min $met_mod[$k]\n";
	}
	
    }
#    $name="multi";
    $scale="1";
#    $chi_sq=($chi)**0.5;

#    print "CHI_SQ=$chi_sq\n";
#    print "$name $chi_sq $scale\n";
#    print OUT "$name $chi_sq $scale $Av \n";
    
    if ($plot==1) {
	pgbegin(0,"/xs",1,1);
	pgsfs(1.2);
	pgscf(2);             # Set character font
	pgslw(2);             # Set line width
	pgsch(1.2);           # Set character height
	pgenv($wave_unc[0],$wave_unc[$n_unc-1],$y_min,$y_max,0,0);
	pgsch(1.2);           # Set character height
	pglabel("Wavelength","Counts","$name $Av $chi_sq $age_min $met_min");
	pgsci(1);
	pgline($n_unc,\@wave_unc,\@flux_unc);    
	pgsci(2);
	pgline($n_unc,\@wave_unc,\@out_spec);    
	pgsci(8);
	pgline($n_unc,\@wave_unc,\@model_spec_min);    
	pgsci(3);
	pgline($n_unc,\@wave_unc,\@flux_masked);    
	pgsci(1);
	pgclose;
	pgend;
#    print "Press Enter"; <stdin>;
    }






    return $chi_sq;
}
