// rootstartup.cpp : Defines the entry point for the console application.
//
//startup steps: make new Win32 console projekt
//with configuration manager clone configuration of release and debug to releasedll and debugdll
//set configuration type of releasedll and debugdll to dll
//(For all projects do not use precompiled headers or add #include "stdafx.h")
//add LinkDef.h
//and add empty dict.h and dict.cpp
//set custom build steps of LinkDef.h as:
//CommandLine: $(ROOTSYS)bin\rootcint -f dict.cpp -c  TestClass.h LinkDef.h
//Output: dict.cpp dict.h
//Additional Dependencies: TestClass.h
//set additional Linkeer Dependencies: "$(ROOTSYS)/lib/libCore.lib" "$(ROOTSYS)/lib/libCint.lib" "$(ROOTSYS)/lib/libHist.lib" "$(ROOTSYS)/lib/libGraf.lib" "$(ROOTSYS)/lib/libGraf3d.lib" "$(ROOTSYS)/lib/libGpad.lib" "$(ROOTSYS)/lib/libTree.lib" "$(ROOTSYS)/lib/libRint.lib" "$(ROOTSYS)/lib/libPostscript.lib" "$(ROOTSYS)/lib/libMatrix.lib" "$(ROOTSYS)/lib/libPhysics.lib" "$(ROOTSYS)/lib/libGui.lib" "$(ROOTSYS)/lib/libGeom.lib" "$(ROOTSYS)/lib/libRIO.lib"
//if std::ofstream &Cout=std::cout; is exported to root you must set
//C++/code generation/runtimelibrary to Multi-threaded Release/Debug
//also download the same binary compiled with the same compiler!

//additional settings for this project switch off precompiled headers
//#include <vld.h>

 

#ifdef __CINT__
#include <complex>
using namespace std;
typedef std::complex<double> cdouble;
enum timepropagationmethod { cranknicholson = 0 , splitopchebyshev = 1 , splitop = 2 };
typedef double (* functionPtr) (double x, void * params);
cdouble exp(cdouble i){
	double ir=i.real();
	double ii=i.imag();
	cdouble I(0,1);
	return exp(ir)*(cos(ii)+I*sin(ii));

}
int testoct()  //put here the name of the file
{gSystem->Load("octtool.dll");return main(-1,NULL);}
//{gSystem->Load("libocttool.so");return main(-1,NULL);}
#else
#include <TApplication.h>
#include <TString.h>
#include <TSystem.h>
#include <math.h>
#include "TRandom.h"

#include "octtool.h"
#include "ExpLog.h"
#include <string.h>
#include <time.h>

#ifndef WIN32
#include <stdlib.h>
#else
#include <conio.h>
#endif

#endif
#define CNT 3000
#define pi 3.1415926
#define ELCNT 5
double *pot[ELCNT];
double *pot2[ELCNT];
double *axis;
double *axis2;
double offset=1;

TApplication *theApp2;




void readPot(){
	TString fname;
	logfile.SetReadPath("./bemsolver.gen/");
	axis=new double[CNT];
	pot[0]=new double[CNT];
	pot[1]=new double[CNT];
	pot[2]=new double[CNT];
	pot[3]=new double[CNT];
	pot[4]=new double[CNT];
	logfile.ReadTSV("./axialpot0.tsv",axis,pot[0],CNT);
	logfile.ReadTSV("./axialpot1.tsv",axis,pot[1],CNT);
	logfile.ReadTSV("./axialpot2.tsv",axis,pot[2],CNT);
	logfile.ReadTSV("./axialpot3.tsv",axis,pot[3],CNT);
	logfile.ReadTSV("./axialpot4.tsv",axis,pot[4],CNT);
}
void Squeeze(){
	for(int i=0;i<CNT;i++)
		pot[0][i]*=3.;
}
void makeHarmonicPot(double mass,double hbar,double omega_trap,bool displace=false){
	TString fname;
	logfile.SetReadPath("./bemsolver.gen/");
	static bool firsttime=true;
	if (firsttime){
		axis=new double[CNT];
		pot[0]=new double[CNT];
		pot[1]=new double[CNT];
		pot[2]=new double[CNT];
		pot[3]=new double[CNT];
		pot[4]=new double[CNT];
		firsttime=false;
	}
	double x0=sqrt(hbar/2./mass/omega_trap);
	double shift=0.;
	if(displace) shift=x0;
	for(int i=0;i<CNT;i++){
		axis[i]=-10*x0+double(i)*20.*x0/double(CNT);
		pot[0][i]=mass/2.*omega_trap*omega_trap*(axis[i]-shift)*(axis[i]-shift)-0.5*hbar*omega_trap;
		pot[1][i]=0;
		pot[2][i]=0;
		pot[3][i]=0;
		pot[4][i]=0;

	}
}

double Energy;
double U[]={10,0,0,0,0};
double Dx;
double Dx2;
double mass;
double hbar;

void reduceResolution(double *bigarr,int sizearr,double *smallarr,int steps){
	int i;
	int j=0;
	for(i=0;i<sizearr;i+=steps){
		smallarr[j++]=bigarr[i];
	}
}

double numerovDiff(double Energy,void *param){
	double *g=new double[CNT];
	int i,j;
	for(i=0;i<CNT;i++){
		double summedpot;
		summedpot=offset;
		for(j=0;j<ELCNT;j++){
			summedpot+=U[j]*pot[j][i];
		}
		g[i]=-2.*mass/hbar/hbar*(Energy-summedpot);
	}
	double *Y1=new double[CNT];
	double *Y2=new double[CNT];
	

	
	numerov(g,CNT,Dx,Y1);
	numerov(g,CNT,-Dx,Y2);
	double diff=0;
	for(i=0;i<CNT;i++){
		diff+= fabs(fabs(Y2[i])-fabs(Y1[i]));
	}
	if(false) {
		logfile.Graph("wfn1",axis,Y1,3000,"x","wfn");
		logfile.Graph("wfn2",axis,Y2,3000,"x","wfn");
	}
	return diff;
	delete[] Y1;
	delete[] Y2;
	delete[] g;

}

double findminimum (functionPtr fptr,double start,double stop,int max_iter )
{
	double eps=1./pow(2.,max_iter+1.);
	double l=start,r=stop,m;
	double lv,rv,mv;
	int j;
	for(j=0;j<max_iter;j++){
		m=(l+r)/2.;
		lv=fptr(l+eps,NULL)-fptr(l,NULL);
		rv=fptr(r,NULL)-fptr(r-eps,NULL);
		mv=fptr(m+eps/2.,NULL)-fptr(m-eps/2.,NULL);
		if(mv*lv<0) r=m;
		else l=m;
	}
	return (l+r)/2.;;
}

void getwfn(double energy,double *Y1,char *title,bool backwards=false,bool secure=true){
	double *g=new double[CNT];
	int i,j;
	for(i=0;i<CNT;i++){
		double summedpot;
		summedpot=offset;
		for(j=0;j<ELCNT;j++){
			summedpot+=U[j]*pot[j][i];
		}
		g[i]=-2.*mass/hbar/hbar*(energy-summedpot);
	}

	

	if(!backwards)	numerov(g,CNT,Dx,Y1,secure);
	else numerov(g,CNT,-Dx,Y1,secure);
	if(secure){
	double norm=0;
		for(i=0;i<CNT;i++){
			norm+=Y1[i]*Y1[i]*fabs(Dx);
		}
		norm=sqrt(norm);
		for(i=0;i<CNT;i++){
			Y1[i]/=norm; 
		}
	}

	
	logfile.Graph(title,axis,Y1,3000,"x","wfn");
	delete[] g;
}

double shapefn(int elnum,int elcnt,int t,int timesteps){
	//if(elnum==0) return 10;
	//else return 0;

	double phase=(double(t*(elcnt-1)) / double(timesteps*2)-0.5*double(elnum));
	if(phase<-0.5) return 0;
	else if( phase>0.5) return 0;
	else return (1.+cos( phase*2*pi ))/2.*10.;
}

int singlewavefnoct(){
	int reductionStep;//for chebyshev method you must use as minimum x points as possible. Only every "reductionStep"th point is used.
                         //for cranck nicholson it is the other way around.
                         //use highest reduction step. otherwise it takes
                         //longer and you need more coefficients

	int timesteps;
	offset=1;//bias of the whole world
	timepropagationmethod method=cranknicholson;
	//timepropagationmethod method=splitop;
	//timepropagationmethod method=splitopchebyshev;

	switch(method){
		case cranknicholson:
			reductionStep=20;
			timesteps=2000;//2000
			break;
		case splitop:
			reductionStep=20;
			timesteps=2000;
			break;
		case splitopchebyshev:
			reductionStep=40;
			timesteps=2000;
			break;
	}
	bool atomicunits=true;

	double xanzzoomedscale=0.8;//if 1 then the whole x range is used. otherwise it defines the window which moves with the minimum of the potential
	int steps=20;//negatice steps makestime evolution video, positive steps optimizes if we should make video
	int moviesteps=500;//500
	double endtime=125;//125.
	double timescale=0.4;//0.5The smaller timescale the faster the potentials are changed
	
	double energylow=0.0,energyhi=0.3;//n=1

	
	int xanzzoomed=CNT*xanzzoomedscale/double(reductionStep);

	if(xanzzoomedscale==1.)  xanzzoomed=-1;

	logfile.SetLogFileName();
	logfile.Append(false); 
	logfile.Overwrite(true); 
	logfile.Logging(false);
	readPot();
	
	hbar=1.05457148e-34;
	double el = 1.602e-19;         
	mass = 40.078*1.66e-27;
	double mass_el=9.1095e-31;
	if (atomicunits){
		mass=mass/mass_el;
		mass=1;
		hbar=1;
		el=1;
	}


	logfile.Graph("potential 0",axis,pot[0],3000,"x","V");
	
	Dx=axis[1]-axis[0];
	


	double xxx[10000];
	double yyy[10000];
	int cnt;
	double x;
	for(x=-10,cnt=0;x<1;x+=0.01,cnt++){
		xxx[cnt]=x;
		yyy[cnt]=numerovDiff(x,NULL);
	}

	logfile.Graph("numerov difference",xxx,yyy,cnt-1,"x","V");
	double en0=findminimum (numerovDiff,-2.25,-2,16 );//change here to another range if you want a different eigenstate as inital state
	cout <<en0<<endl;
	double *phi_ini=new double[CNT];
	getwfn(en0,phi_ini,"phi ini");
	bool explainnumerov=false;
	if(explainnumerov){
		logfile.SetLogFileName("c:\\tmp\\");
		logfile.WriteTSV("./wfn_ok",axis,phi_ini,3000);

		
		logfile.WriteTSV("./potential",axis,pot[0],3000);
		getwfn(en0*1.001,phi_ini,"./phi_ini",false,false);
		logfile.Graph("wfn1",axis,phi_ini,3000);
		logfile.WriteTSV("./wfn_mismatched_left",axis,phi_ini,3000);
		getwfn(en0*1.001,phi_ini,"phi ini",true,false);
		logfile.Graph("wfn2",axis,phi_ini,3000);
		logfile.WriteTSV("./wfn_mismatched_right",axis,phi_ini,3000);
	}

	
	U[0]=0;
	U[4]=10;
	double en1=findminimum (numerovDiff,-2.25,-2,16 );//change here to another range if you want a different eigenstate as target state, eg. take as limits -1.6,-1.1 for second excited state
	cout <<en1<<endl;
	double *phi_final=new double[CNT];
	getwfn(en1,phi_final,"phi final");
//reduce resolution

	int CNT2=int(double(CNT)/double(reductionStep)+0.5);
	int i;
	for(i=0;i<ELCNT;++i){
		pot2[i]=new double[CNT2];
		reduceResolution(pot[i],CNT,pot2[i],reductionStep);
	}
	double *phi_ini2=new double[CNT2];
	reduceResolution(phi_ini,CNT,phi_ini2,reductionStep);
	double *phi_final2=new double[CNT2];
	reduceResolution(phi_final,CNT,phi_final2,reductionStep);
	double *axis2=new double[CNT2];
	reduceResolution(axis,CNT,axis2,reductionStep);
	Dx2=axis2[1]-axis2[0];
//generate time dependent voltages
	int t;
	double *timearray=new double[timesteps];
	double *scale[ELCNT];

	for(i=0;i<ELCNT;i++){
		scale[i]=new double[timesteps];
	}

	for(t=0;t<timesteps;t++){
		timearray[t]=(double(t)*endtime*timescale)/double(timesteps);
		for(i=0;i<ELCNT;i++){
			scale[i][t]=shapefn(i,ELCNT,t,timesteps);
		}
	}

	//logfile.Graph("voltage0",timearray,scale[0],timesteps,"x","V");
	//logfile.Graph("voltage1",timearray,scale[1],timesteps,"x","V");
	//logfile.Graph("voltage2",timearray,scale[2],timesteps,"x","V");
	//logfile.Graph("voltage3",timearray,scale[3],timesteps,"x","V");
	//logfile.Graph("voltage4",timearray,scale[4],timesteps,"x","V");

	double Dt=timearray[1]-timearray[0];

//define lambda function
	double lambdalow=1;
	double lambdacut=10000;
	double lambdamul=200./timesteps;
		
	double *oneOverLambda[ELCNT];

	for(i=0;i<ELCNT;i++){
		oneOverLambda[i]=new double[timesteps];
	}

	for(t=0;t<timesteps;t++){
		for(i=0;i<ELCNT;i++){
			oneOverLambda[i][t]=1./(lambdalow+(exp((1.-t)*lambdamul)+exp((t-timesteps)*lambdamul))*lambdacut);
		}
	}
	logfile.Graph("lambda",timearray,oneOverLambda[0],timesteps,"x","V");
//show unoptimized movie
	double *scale_optimized_vid=new double[xanzzoomed*moviesteps];
	double *phi_r_vid=new double[xanzzoomed*moviesteps];
	double *phi_i_vid=new double[xanzzoomed*moviesteps];
	double *overlap=new double[steps];
	int *phi_reached_offset_arr=new int[moviesteps];
	double xaxis[2]={axis2[0],axis2[CNT2-1]};
	double yaxis[2]={-3.2,1};
	/*logfile.WriteTSV("u1",timearray,scale[0],timesteps);
	logfile.WriteTSV("u2",timearray,scale[1],timesteps);
	logfile.WriteTSV("u3",timearray,scale[2],timesteps);
	logfile.WriteTSV("u4",timearray,scale[3],timesteps);
	logfile.WriteTSV("u5",timearray,scale[4],timesteps);*/
	
	makevideo(phi_ini2,phi_final2,pot2,Dx2,scale,Dt,-moviesteps,hbar,mass,oneOverLambda,
			CNT2,timesteps,ELCNT,
			scale_optimized_vid,phi_r_vid,phi_i_vid,overlap,
			phi_reached_offset_arr,xanzzoomed,method,1);
	double *phi_abs_vid=new double[xanzzoomed*moviesteps];
	for(i=0;i<xanzzoomed*moviesteps;i++){
		phi_abs_vid[i]=phi_r_vid[i]*phi_r_vid[i]+phi_i_vid[i]*phi_i_vid[i];
	}
	for(i=0;i<moviesteps;i++){
		logfile.Graph("potfwn",xaxis,yaxis,2,"x","pot wfn","A*",0);
		logfile.Graph("pot","potfwn",&axis2[phi_reached_offset_arr[i]],&scale_optimized_vid[i*xanzzoomed],xanzzoomed,"C",1,2);
		logfile.Graph("wfn","potfwn",&axis2[phi_reached_offset_arr[i]],&phi_r_vid[i*xanzzoomed],xanzzoomed,"CP",2,2);
		logfile.Graph("abs","potfwn",&axis2[phi_reached_offset_arr[i]],&phi_abs_vid[i*xanzzoomed],xanzzoomed,"CP",3,2);
		if(i==moviesteps-1){
				/*logfile.WriteTSV("pot",&axis2[phi_reached_offset_arr[i]],&scale_optimized_vid[i*xanzzoomed],xanzzoomed);
				logfile.WriteTSV("wfn",&axis2[phi_reached_offset_arr[i]],&phi_r_vid[i*xanzzoomed],xanzzoomed);
				logfile.WriteTSV("abs",&axis2[phi_reached_offset_arr[i]],&phi_abs_vid[i*xanzzoomed],xanzzoomed);*/
		}

	}

//do optimization

	double *scale_optimized[ELCNT];
	for(i=0;i<ELCNT;i++){
		scale_optimized[i]=new double[timesteps];
	}

	cdouble *phi_reached=new cdouble[CNT2];//TODO use offsets for phi_reached;

	int phi_reached_offset;
	optimalcontrol(phi_ini2,phi_final2,pot2,Dx2,scale,Dt,steps,hbar,mass,oneOverLambda,
		CNT2,timesteps,ELCNT,
		scale_optimized,phi_reached,overlap,phi_reached_offset,xanzzoomed,method);

	double *iteration=new double[steps];
	
	for(i=0;i<steps;i++) iteration[i]=i;
	logfile.Graph("fidelity",iteration,overlap,steps,"iteration","overlap","AC");
	//logfile.WriteTSV("fidelity",overlap,steps);
//show optimized movie
	makevideo(phi_ini2,phi_final2,pot2,Dx2,scale_optimized,Dt,-moviesteps,hbar,mass,oneOverLambda,
			CNT2,timesteps,ELCNT,
			scale_optimized_vid,phi_r_vid,phi_i_vid,overlap,
			phi_reached_offset_arr,xanzzoomed,method,1);
	for(i=0;i<xanzzoomed*moviesteps;i++){
		phi_abs_vid[i]=phi_r_vid[i]*phi_r_vid[i]+phi_i_vid[i]*phi_i_vid[i];
	}
	/*logfile.WriteTSV("u1opt",timearray,scale_optimized[0],timesteps);
	logfile.WriteTSV("u2opt",timearray,scale_optimized[1],timesteps);
	logfile.WriteTSV("u3opt",timearray,scale_optimized[2],timesteps);
	logfile.WriteTSV("u4opt",timearray,scale_optimized[3],timesteps);
	logfile.WriteTSV("u5opt",timearray,scale_optimized[4],timesteps);*/
	for(i=0;i<moviesteps;i++){
		logfile.Graph("potfwn opt",xaxis,yaxis,2,"x","pot wfn","A*",0);
		logfile.Graph("pot","potfwn opt",&axis2[phi_reached_offset_arr[i]],&scale_optimized_vid[i*xanzzoomed],xanzzoomed,"C",1,2);
		logfile.Graph("wfn","potfwn opt",&axis2[phi_reached_offset_arr[i]],&phi_r_vid[i*xanzzoomed],xanzzoomed,"CP",2,2);
		logfile.Graph("abs","potfwn opt",&axis2[phi_reached_offset_arr[i]],&phi_abs_vid[i*xanzzoomed],xanzzoomed,"CP",3,2);
		if(i==moviesteps-1){
				/*logfile.WriteTSV("potoct",&axis2[phi_reached_offset_arr[i]],&scale_optimized_vid[i*xanzzoomed],xanzzoomed);
				logfile.WriteTSV("wfnoct",&axis2[phi_reached_offset_arr[i]],&phi_r_vid[i*xanzzoomed],xanzzoomed);
				logfile.WriteTSV("absoct",&axis2[phi_reached_offset_arr[i]],&phi_abs_vid[i*xanzzoomed],xanzzoomed);*/
		}
	}

	return 0;

}


double randGen(double noiserange,double alpha){
	//double sum=0;
	//sum+=alpha*(gRandom->Uniform(-noiserange,noiserange)-sum);
	return gRandom->Uniform(-noiserange,noiserange);
}
	
void updateHamiltonian(int t,double Dt,cdouble *Hamiltonian,int CNT2,double Dx2,double Omega,double kz,double delta,double *phase,double noise=0){
	int i;
	double noiseval;
	if(noise==0) noiseval=0;
	else noiseval=randGen(noise,0.3);
	cdouble I(0,1);
	for(i=0;i<CNT2;i++) {
		Hamiltonian[i+CNT2]=hbar*Omega/2.*I*(exp(-(kz*i*Dx2-delta*t*Dt-phase[t]-noiseval)*I));
		Hamiltonian[i+CNT2*2]=-hbar*Omega/2.*I*(exp((kz*i*Dx2-delta*t*Dt-phase[t]-noiseval)*I));
	}
}


void gatemovie(double *phase,int timesteps,double Dt,int reductionStep,bool plotmovie,double omega_trap,double Omega,double kz,double delta,int plotonly=-1,bool plotmomentum=false,double eta=0,bool dopumping=false,TString titel="",bool squeeze=false){

	U[0]=1;	
	timepropagationmethod method=splitopchebyshev;
	
	offset=0;double xanzzoomedscale=1;//if 1 then the whole x range is used. otherwise it defines the window which moves with the minimum of the potential

	int xanzzoomed=CNT*xanzzoomedscale/double(reductionStep);
	if(xanzzoomedscale==1.)  xanzzoomed=-1;

	logfile.SetLogFileName();
	logfile.Append(false); 
	logfile.Overwrite(true); 
	logfile.Logging(false);

	
	
	
	 makeHarmonicPot(mass,hbar,omega_trap);

	//logfile.Graph("potential 0",axis,pot[0],3000,"x","V");
	
	Dx=axis[1]-axis[0];
	


	double *xxx=new double[1000];
	double *yyy=new double[1000];
	int cnt;
	double x;
	for(x=0,cnt=0;x<5.*hbar*omega_trap;x+=5.*hbar*omega_trap/200.,cnt++){
		xxx[cnt]=x;
		yyy[cnt]=numerovDiff(x,NULL);
	}

	//logfile.Graph("potential ini",xxx,yyy,cnt-1,"x","V");

	//double en2=findminimum(numerovDiff,1.1,2,50 );
	double en0=0;
	cout <<en0<<endl;
	double *phi_real[3];
	phi_real[0]=new double[CNT];
	phi_real[1]=new double[CNT];
	phi_real[2]=new double[CNT];

	getwfn(en0,phi_real[0],"phi ini 0");
	getwfn(hbar*omega_trap*1,phi_real[1],"phi ini 1");
	getwfn(hbar*omega_trap*2,phi_real[2],"phi ini 1");
	
	if(dopumping){
		for(int i=0;i<CNT;i++){
			phi_real[1][i]=(phi_real[0][i]+phi_real[1][i]+phi_real[2][i])/sqrt(3.);
		}
	}
	makeHarmonicPot(mass,hbar,omega_trap);
	if(squeeze) Squeeze();

	int CNT2=int(double(CNT)/double(reductionStep)+0.5);
	int i;
	int j;
	for(i=0;i<ELCNT;++i){
		pot2[i]=new double[CNT2];
		reduceResolution(pot[i],CNT,pot2[i],reductionStep);
	}

	double *phi_real2[2];
	phi_real2[0]=new double[CNT2];
	phi_real2[1]=new double[CNT2];
	reduceResolution(phi_real[0],CNT,phi_real2[0],reductionStep);
	reduceResolution(phi_real[1],CNT,phi_real2[1],reductionStep);
	double *axis2=new double[CNT2];
	reduceResolution(axis,CNT,axis2,reductionStep);
	Dx2=axis2[1]-axis2[0];
//generate time dependent voltages
	TimePropagator *timepropagate;
	int dim=2;
		
	cdouble *summedV=new cdouble[CNT2*dim*dim];
	cdouble *Hamiltonian=new cdouble[CNT2*dim*dim];
	cdouble *phi[4];
	double *phiplot[4];
	double *phiplotreal[4];
	
	for(i=0;i<4;i++) {
		phi[i]=new cdouble[CNT2*dim];
		phiplot[i]=new double[CNT2*dim];
		phiplotreal[i]=new double[CNT2*dim];
	}
	cdouble I(0,1);

	double maxy=0;

	
	for(i=0;i<CNT2;i++) {
		double val=phi_real2[0][i]*phi_real2[0][i];
		if(val>maxy) maxy=val;
		Hamiltonian[i]=pot2[0][i];//at time t
		Hamiltonian[i+CNT2*3]=pot2[0][i];//at time t
		phi[0][i]=phi_real2[0][i];
		phi[0][i+CNT2]=0;//sqrt(1./2.)*phi_real2[i];	
		phi[1][i]=0;
		phi[1][i+CNT2]=phi_real2[0][i];	
		phi[2][i]=phi_real2[1][i]*exp(double(timesteps)*Dt*omega_trap*I);
		phi[2][i+CNT2]=0;//sqrt(1./2.)*phi_real2[i];	
		phi[3][i]=0;
		phi[3][i+CNT2]=phi_real2[1][i]*exp(double(timesteps)*Dt*omega_trap*I);//sqrt(1./2.)*phi_real2[i];	
	}

	if(squeeze) maxy*=1.8;
	if(hbar==1)
		timepropagate=new SplitOpChebyshev(CNT2,CNT2,Dx2,Dt,hbar,mass,dim,0,20);	
	else
		timepropagate=new SplitOpChebyshev(CNT2,CNT2,Dx2,Dt,hbar,mass,dim,0,18.e-27);	
	QMOperators *op=new QMOperators(timepropagate);
	double *spec=new double[CNT2];
	op->FFTPowerSpectrum(phi[0],spec);

	double maxky=0;
	for(i=0;i<CNT2;++i) {
		if (spec[i]>maxky) maxky=spec[i];
	}

	int t=0;

	cout <<"Dt :"<<Dt<<endl;
	

	double starkShift;
	double starkShiftOld=0;
	cout <<delta;
	if(delta!=0){
		for(i=0;i<10;i++){
			starkShift=1./2.*(sqrt(Omega*Omega+delta*delta)-fabs(delta));
			if(delta>0) delta-=starkShift-starkShiftOld;
			else delta+=starkShift-starkShiftOld;
			cout <<delta<<endl;
			starkShiftOld=starkShift;
		}
	}
	double kstep=2.*pi/(double(CNT2)*Dx2);
	double *kaxis=new double[CNT2];
	for(i=0;i<=CNT2/2;++i){
		if((i+CNT2/2)==CNT2) break;
		kaxis[i+CNT2/2] =i*kstep;
	}
	for(i=CNT2/2+1;i<CNT2;++i){
		kaxis[i-CNT2/2-1] = (i-CNT2)*kstep;
	}

	double currentphase=0,phasebefore=0;
	while(true){
		int j;
		if( plotmovie) {
			for(j=0;j<4;j++){
				char numstr[10];
				itoa2(j,numstr,10);
				if(plotonly!=-1){
					j=plotonly;
					TString titel2;
					if(titel=="") titel2=TString("phi")+TString(numstr);
					else titel2=titel;
					double width=1024,height=700;
					if(plotmomentum){
						width=512;
					}
					logfile.Graph(titel2,axis2,0,CNT2,"x","phi","APC|>",1,2,1,1,8,true,0,0,-maxy*1.1,maxy*1.1,phi[j],true,30000,000,000,width,height);
					logfile.Graph(TString("phi2")+TString(numstr),titel2,axis2,0,CNT2,"PC|>",2,2,1,1,8,true,0,0,-maxy*1.1,maxy*1.1,&phi[j][CNT2],false,30000,00,00,1024,700);
					//logfile.Print(TString("phi")+TString(numstr),"gif");
	
					if(!plotmomentum) break;
	
					op->FFTPowerSpectrum(phi[j],spec);
					for(i=0;i<CNT2;++i) spec[i]=-spec[i];
					logfile.Graph("phi momentum",kaxis,spec,CNT2,"k","phi momentum","APC",1,2,1,1,8,true,0,0,-1.1*maxky,1.1*maxky,0,false,30000,500,0,512,700);
					op->FFTPowerSpectrum(&phi[j][CNT2],spec);
					
					logfile.Graph("phi momentum2","phi momentum",kaxis,spec,CNT2,"PC",2,2,1,1,8,true,0,0,-1.1*maxky,1.1*maxky,0,false,30000,500,0,512,700);
					break;
				}

				
				int xpos[4]={0,600+20,0,600+20};
				int ypos[4]={0,0,400+30,400+30};
				logfile.Graph(TString("phi")+TString(numstr),axis2,0,CNT2,"x","phi","APC|>",1,2,1,1,8,false,0,0,-maxy*1.1,maxy*1.1,phi[j],true,30000,xpos[j],ypos[j],600,400);
				logfile.Graph(TString("phi2")+TString(numstr),TString("phi")+TString(numstr),axis2,0,CNT2,"PC|>",2,2,1,1,8,false,0,0,-maxy*1.1,maxy*1.1,&phi[j][CNT2],false,30000,xpos[j],ypos[j],600,400);
				
			}

			if (t==timesteps) break;
#ifdef WIN32
if(kbhit()) break;
#endif
			if(dopumping){
				currentphase=Dt*t*Omega*eta/pi;
				//cout <<currentphase<<endl;
			
				if(int(currentphase)!=int(phasebefore)){
					double norm[4]={0,0,0,0};
					for(j=0;j<4;j++)	{
						if(plotonly!=-1) j=plotonly;
						cdouble randomphase;
						randomphase=(exp(I*gRandom->Uniform(-pi,pi)));
						
						for(i=0;i<CNT2;++i) {
							phi[j][i]=abs(phi[j][i])+randomphase*abs(phi[j][i+CNT2]);
							phi[j][i+CNT2]=0;
							norm[j]+=real(phi[j][i]*conj(phi[j][i]))*Dx2;
						}
						norm[j]=sqrt(norm[j]);
						for(i=0;i<CNT2;++i) phi[j][i]/=norm[j];
						if(plotonly!=-1) break;
					}
				}
				phasebefore=currentphase;
			}
			//cout <<currentphase<<" of "<<2*pi+sqrt(2.)*pi<<endl;
			//offdiagonal potentials
			if(!squeeze) updateHamiltonian(t,Dt,Hamiltonian,CNT2,Dx2,Omega,kz,delta,phase);
			
			t++;
			double max=0;
			int maxpos;
			if(plotonly!=-1) timepropagate->forward(phi[plotonly],Hamiltonian);
			else
			for(j=0;j<4;j++){
				timepropagate->forward(phi[j],Hamiltonian);
			}	
		}
	}
	
	delete[] spec;
	delete op;
	delete[] axis2;
	delete[] kaxis;
	delete timepropagate;
	for(i=0;i<4;i++) {
		delete[] phi[i];
		delete[] phiplot[i];
		delete[] phiplotreal[i];
	}
	delete[] Hamiltonian;
	delete[] summedV;
	
	delete[] phi_real2[1];
	delete[] phi_real2[0];
	for(i=0;i<ELCNT;i++){
		delete pot2[i];
		
	}
	delete[] phi_real[2];
	delete[] phi_real[1];
	delete[] phi_real[0];
	delete[] yyy;
	delete[] xxx;


}


double CompositeSimpson38ruleIntegrator(double *f,int cnt,double h){
	double sum=0;
	int cnt2;
	int i;
	if(cnt%3==0) cnt2=cnt;
	else cnt2=cnt-1;
	for(i=0;i<cnt2;i+=3){
		sum+=f[i]+3*f[i+1]+3*f[i+2]+f[i+3];
	}
	for(i=cnt2;i<cnt;i++) sum+=f[i];
	return 3.*h/8.*sum;
}

void gateoct(double *phase,int timesteps,double Dt,int reductionStep,bool plotmovie,double omega_trap,double Omega,double kz,double delta,int iterations,bool doNoiseAnalysis=false,int noiseloopcnt=1,double noiselimit=1.2,bool doInitialNoiseAnalysis=false,bool doOnlyNoiseAnalysis=false,TString noisefname="noisestability0"){
	U[0]=1;	
	double *phasenew=new double[timesteps];
	timepropagationmethod method=splitopchebyshev;
	
	offset=0;double xanzzoomedscale=1;//if 1 then the whole x range is used. otherwise it defines the window which moves with the minimum of the potential

	int xanzzoomed=CNT*xanzzoomedscale/double(reductionStep);
	if(xanzzoomedscale==1.)  xanzzoomed=-1;

	logfile.SetLogFileName();
	logfile.Append(false); 
	logfile.Overwrite(true); 
	logfile.Logging(false);

	
	bool displace=false;
	makeHarmonicPot(mass,hbar,omega_trap,displace);

	logfile.Graph("potential 0",axis,pot[0],3000,"x","V");
	
	Dx=axis[1]-axis[0];
	


	double xxx[10000];
	double yyy[10000];
	int cnt;
	double x;
	for(x=0,cnt=0;x<5.*hbar*omega_trap;x+=5.*hbar*omega_trap/200.,cnt++){
		xxx[cnt]=x;
		yyy[cnt]=numerovDiff(x,NULL);
	}

	logfile.Graph("potential ini",xxx,yyy,cnt-1,"x","V");

	//double en2=findminimum(numerovDiff,1.1,2,50 );
	double en0=0;
	cout <<en0<<endl;
	double *phi_real[2];
	phi_real[0]=new double[CNT];
	phi_real[1]=new double[CNT];

	getwfn(en0,phi_real[0],"phi ini 0");
	getwfn(hbar*omega_trap*1,phi_real[1],"phi ini 1");
	makeHarmonicPot(mass,hbar,omega_trap);


	int CNT2=int(double(CNT)/double(reductionStep)+0.5);
	int i;
	int j;
	for(i=0;i<ELCNT;++i){
		pot2[i]=new double[CNT2];
		reduceResolution(pot[i],CNT,pot2[i],reductionStep);
	}

	double *phi_real2[2];
	double *phi_final2[2];
	phi_real2[0]=new double[CNT2];
	phi_real2[1]=new double[CNT2];
	reduceResolution(phi_real[0],CNT,phi_real2[0],reductionStep);
	reduceResolution(phi_real[1],CNT,phi_real2[1],reductionStep);
	double *axis2=new double[CNT2];
	reduceResolution(axis,CNT,axis2,reductionStep);
	Dx2=axis2[1]-axis2[0];
//generate time dependent voltages
	TimePropagator *timepropagate;
	int dim=2;
		
	cdouble *summedV=new cdouble[CNT2*dim*dim];
	cdouble *Hamiltonian=new cdouble[CNT2*dim*dim];
	cdouble *phi[4];
	cdouble *chi[4];

	cdouble *phi_ini[4];
	cdouble *phi_final[4];
	double *phiplot[4];
	double *phiplotreal[4];
	
	for(i=0;i<4;i++) {
		phi[i]=new cdouble[CNT2*dim];
		chi[i]=new cdouble[CNT2*dim];
		phi_ini[i]=new cdouble[CNT2*dim];
		phi_final[i]=new cdouble[CNT2*dim];
		phiplot[i]=new double[CNT2*dim];
		phiplotreal[i]=new double[CNT2*dim];
	}
	cdouble I(0,1);

	double maxy=0;
	
	
	for(i=0;i<CNT2;i++) {
		double val=phi_real2[0][i]*phi_real2[0][i];
		if(val>maxy) maxy=val;
		Hamiltonian[i]=pot2[0][i];//at time t
		Hamiltonian[i+CNT2*3]=pot2[0][i];//at time t
		phi_ini[0][i]=phi_real2[0][i];
		phi_ini[0][i+CNT2]=0;//sqrt(1./2.)*phi_real2[i];	
		phi_ini[1][i]=0;
		phi_ini[1][i+CNT2]=phi_real2[0][i];	
		phi_ini[2][i]=phi_real2[1][i]*exp(double(timesteps)*Dt*omega_trap*I);
		phi_ini[2][i+CNT2]=0;//sqrt(1./2.)*phi_real2[i];	
		phi_ini[3][i]=0;
		phi_ini[3][i+CNT2]=phi_real2[1][i]*exp(double(timesteps)*Dt*omega_trap*I);//sqrt(1./2.)*phi_real2[i];	

		phi_final[0][i]=-phi_real2[0][i];
		phi_final[0][i+CNT2]=0;//sqrt(1./2.)*phi_real2[i];	
		phi_final[1][i]=0;
		phi_final[1][i+CNT2]=phi_real2[0][i];	
		phi_final[2][i]=-phi_real2[1][i];
		phi_final[2][i+CNT2]=0;//sqrt(1./2.)*phi_real2[i];	
		phi_final[3][i]=0;
		phi_final[3][i+CNT2]=-phi_real2[1][i];//sqrt(1./2.)*phi_real2[i];	

	}
	
	int t=0;

	cout <<"Dt :"<<Dt<<endl;
	if(hbar==1)
		timepropagate=new SplitOpChebyshev(CNT2,CNT2,Dx2,Dt,hbar,mass,dim,0,20);	
	else
		timepropagate=new SplitOpChebyshev(CNT2,CNT2,Dx2,Dt,hbar,mass,dim,0,18.e-27);	

	QMOperators op(timepropagate);

	double starkShift;
	double starkShiftOld=0;
	cout <<delta;
	for(i=0;i<10;i++){
		starkShift=1./2.*(sqrt(Omega*Omega+delta*delta)-fabs(delta));
		if(delta>0) delta-=starkShift-starkShiftOld;
		else delta+=starkShift-starkShiftOld;
		cout <<delta<<endl;
		starkShiftOld=starkShift;
	}

		
	
	double lambdalow=2000000./2.;//2000000
	double lambdacut=100000000000.;
	double lambdamul=200./timesteps;
		
	double *oneOverLambda;
	double *time;

	oneOverLambda=new double[timesteps];
	time=new double[timesteps];

	for(t=0;t<timesteps;t++) {
		oneOverLambda[t]=1e-6;//1./(lambdalow+(exp((1.-t)*lambdamul)+exp((t-timesteps)*lambdamul))*lambdacut);
		time[t]=t*Dt;
	}
	logfile.Graph("One Over Lambda",time,oneOverLambda,timesteps,"t","One Over Lambda");
	memcpy(phasenew,phase,sizeof(double)*timesteps);


	//plot phasenoise
	double noise;
	double noiserange=noiselimit*2;
	int noisecnt=10;
	double fidelarr[20];
	double noisearr[20];

	int ii=0;
	if(doInitialNoiseAnalysis){
		
		for(noise=0;noise<noiserange;noise+=noiserange/noisecnt){
			noisearr[ii]=noise;
			
			for(j=0;j<4;j++) 
				for(i=0;i<CNT2*2;i++) phi[j][i]=phi_ini[j][i];
			for(t=0;t<timesteps;t++){
				updateHamiltonian(t,Dt,Hamiltonian,CNT2,Dx2,Omega,kz,delta,phase,noise);
				for(j=0;j<4;j++) timepropagate->forward(phi[j],Hamiltonian);
			}

			double fidel=0;
			for(j=0;j<4;j++) 
				for(i=0;i<CNT2*2;i++) fidel+=1./8.*real(conj(phi_final[j][i])*phi[j][i])*Dx2;
			fidel+=0.5;
			fidelarr[ii]=fidel;
		
			ii++;
			cout <<"Phase noise amplitude: "<<noise<<"Fidelity: "<<fidel<<endl;
		}
		logfile.WriteTSV(TString("./")+noisefname,noisearr,fidelarr,noisecnt);
		logfile.Graph("Noise stability",noisearr,fidelarr,noisecnt,"noise amplitude","Fidelity");
	}
	if(doOnlyNoiseAnalysis) return;
	//get inital fidelity
	for(j=0;j<4;j++) 
			for(i=0;i<CNT2*2;i++) phi[j][i]=phi_ini[j][i];
	for(t=0;t<timesteps;t++){
		updateHamiltonian(t,Dt,Hamiltonian,CNT2,Dx2,Omega,kz,delta,phase,0);
		for(j=0;j<4;j++) timepropagate->forward(phi[j],Hamiltonian);
	}

	double fidel=0;
	for(j=0;j<4;j++) 
		for(i=0;i<CNT2*2;i++) fidel+=1./8.*real(conj(phi_final[j][i])*phi[j][i])*Dx2;
	fidel+=0.5;
	cout <<"Fidelity:"<<fidel<<endl;
	double *Karr=new double[CNT2];
	double lastFidel=fidel;
	double stepsize=1;
	double *fideliter=new double[iterations];
	for(int n=1;n<iterations;n++){
		cout <<"Iteration :"<<n<<endl;
		//set phi=phi_ini
		for(j=0;j<4;j++) 
			for(i=0;i<CNT2*2;i++) phi[j][i]=phi_ini[j][i];

		//generally you should now timepropagate phi forward to t=T, 
		//for the current fidelity measure this is not needed as,
		//the equation for chi at t=T is chi=phi_final

		//set chi(t=T)=phi_final
		for(j=0;j<4;j++) 
			for(i=0;i<CNT2*2;i++) {
				if(j==2)	chi[j][i]=1.*phi_final[j][i];
				else chi[j][i]=phi_final[j][i];
			}

		//now time propagate chi backwards to obtain  chi(t=0)
		for(t=timesteps-1;t>=0;--t){
			updateHamiltonian(t,Dt,Hamiltonian,CNT2,Dx2,Omega,kz,delta,phase);
			for(j=0;j<4;j++) timepropagate->backward(chi[j],Hamiltonian);
		}

		//now we update the control parameters
	
		for(t=0;t<timesteps;t++){
			for(i=0;i<4;i++){
				int noiseloop;
				
				for(noiseloop=0;noiseloop<noiseloopcnt;noiseloop++){
					double noiseval;
					if(noiseloopcnt==1) noiseval=0;
					else noiseval =randGen(noiselimit,0.3);
					int x;
					for(x=0;x<CNT2;x++){
						
						cdouble dH_dPhase=-/*hbar*/Omega/2. *  exp(-(kz*x*Dx2-delta*t*Dt-phase[t]-noiseval)*I);// top right Value in H matrix coresponding to Hamiltonian[i+CNT2]
						cdouble dHConj_dPhase=-/*hbar*/Omega/2. *  exp((kz*x*Dx2-delta*t*Dt-phase[t]-noiseval)*I);// bottom left Value in H matrix coresponding to Hamiltonian[i+CNT2*2]
				
						Karr[x]=imag(conj(phi[i][x])*dH_dPhase*chi[i][x+CNT2]+
						   conj(phi[i][x+CNT2])*dHConj_dPhase*chi[i][x]);

					}
					double K=CompositeSimpson38ruleIntegrator(Karr,CNT2,Dx2);
					phasenew[t]+=2.*oneOverLambda[t]*K /*/hbar*/ /double(noiseloopcnt)*stepsize;
				}
				
			}
		
			updateHamiltonian(t,Dt,Hamiltonian,CNT2,Dx2,Omega,kz,delta,phase);
			for(j=0;j<4;j++) timepropagate->forward(chi[j],Hamiltonian);
			updateHamiltonian(t,Dt,Hamiltonian,CNT2,Dx2,Omega,kz,delta,phasenew);
			for(j=0;j<4;j++) timepropagate->forward(phi[j],Hamiltonian);
			
		}
		double fidel=0;
		for(j=0;j<4;j++) 
			for(i=0;i<CNT2*2;i++) fidel+=1./8.*real(conj(phi_final[j][i])*phi[j][i])*Dx2;
		fidel+=0.5;
		if(true) for(j=0;j<4;j++){
			char numstr[10];
			itoa2(j,numstr,10);
			int xpos[4]={0,600+20,0,600+20};
			int ypos[4]={0,0,400+30,400+30};
			logfile.Graph(TString("phi")+TString(numstr),axis2,0,CNT2,"x","phi","APC|>",1,2,1,1,8,false,0,0,-maxy*1.1,maxy*1.1,phi[j],true,30000,xpos[j],ypos[j],600,400);
			logfile.Graph(TString("phi2")+TString(numstr),TString("phi")+TString(numstr),axis2,0,CNT2,"PC|>",2,2,1,1,8,false,0,0,-maxy*1.1,maxy*1.1,&phi[j][CNT2],false,30000,xpos[j],ypos[j],600,400);


		}
		cout <<"Fidelity:"<<fidel<<endl;

		if(fidel>lastFidel){
			lastFidel=fidel;
			memcpy(phase,phasenew,sizeof(double)*timesteps);
		}else{
			stepsize*=0.5;
			memcpy(phasenew,phase,sizeof(double)*timesteps);
			cout <<"Stepsize reduced: "<<stepsize<<endl;
		}
		
		logfile.Graph("phase",time,phase,timesteps,"","","L");
	}
	//compare phase noise stability
	if(doNoiseAnalysis){
		ii=0;
	
		for(noise=0;noise<noiserange;noise+=noiserange/noisecnt){
			noisearr[ii]=noise;
			
			for(j=0;j<4;j++) 
				for(i=0;i<CNT2*2;i++) phi[j][i]=phi_ini[j][i];
			for(t=0;t<timesteps;t++){
				updateHamiltonian(t,Dt,Hamiltonian,CNT2,Dx2,Omega,kz,delta,phase,noise);
				for(j=0;j<4;j++) timepropagate->forward(phi[j],Hamiltonian);
			}

			double fidel=0;
			for(j=0;j<4;j++) 
				for(i=0;i<CNT2*2;i++) fidel+=1./8.*real(conj(phi_final[j][i])*phi[j][i])*Dx2;
			fidel+=0.5;
			fidelarr[ii]=fidel;
			ii++;
			cout <<"Phase noise amplitude: "<<noise<<"Fidelity: "<<fidel<<endl;
		}
		logfile.Graph("Noise stability opt",noisearr,fidelarr,noisecnt,"noise amplitude","Fidelity");
		if( noiseloopcnt==1) logfile.WriteTSV("./noisestability1",noisearr,fidelarr,noisecnt);
		else logfile.WriteTSV("./noisestability1_noise",noisearr,fidelarr,noisecnt);
	}
	delete[] phasenew;
}

void laserAtomInteraction(){
	//cout <<__FILE__ << __LINE__<<end;
	int reductionStep=80;//for chebyshev method you must use as minimum x points as possible. Only every "reductionStep"th point is used.
                         //for cranck nicholson it is the other way around.
                         //use highest reduction step. otherwise it takes
                         //longer and you need more coefficients

	int iterations=50;
	bool atomicunits=false;
	bool plotmovie=true;
	#ifdef asdfasf
	double omega_trap=2.*pi*1.e6;//2.*pi*1.e6;
	double lambda729=729e-9;//729e-9
	double Omega=2.*pi*0.07e6;//2.*pi*0.07e6//el*fieldampl*polvec*kz/4.*quadrupoleSD
#endif

	double omega_trap=2.*pi*1.e6;//2.*pi*1.e6;
	double lambda729=200e-9;//729e-9 100
	double Omega=2.*pi*0.1e6;//2.*pi*0.07e6//el*fieldampl*polvec*kz/4.*quadrupoleSD  0.1
//double Omega=2.*pi*0.8e6;//2.*pi*0.07e6//el*fieldampl*polvec*kz/4.*quadrupoleSD  0.1
	
int timesteps=1000;//2000,200   ,1000(good)
	hbar=1.05457148e-34;
	double el = 1.602e-19;       
	mass = 40.078*1.66e-27;
	double mass_el=9.1095e-31;
	if (atomicunits){
		mass=mass/mass_el;
		mass=1;
		hbar=1;
		el=1;
		omega_trap=1;
	}
	double x0=sqrt(hbar/2./mass/omega_trap);

	double kz=2.*pi/lambda729;

	double eta=kz*x0;
	//cout <<"Lambdicke parameter :" <<eta<<endl;
	double Dt=(pi+pi/sqrt(2.)+pi+pi/sqrt(2.))/(double(timesteps)*Omega*eta);
	double *phase=new double[timesteps];
	double *taxis=new double[timesteps];
	double na=0.0,al=0.000001;
	bool doOnlyNoiseAnalysis=false;
	for(int t=0;t<timesteps;t++){
		
		double currentphase=Dt*double(t)*Omega*eta;
	
		if(currentphase<pi/sqrt(2.)){
			phase[t]=0.+randGen(na,al);;
		}
		else if(currentphase<pi/sqrt(2.)+pi){
			phase[t]=pi/2.+randGen(na,al);;
		}
		else if(currentphase<pi/sqrt(2.)+pi+pi/sqrt(2.)){
			phase[t]=0+randGen(na,al);;
		}
		else  if(currentphase<pi/sqrt(2.)+pi+pi/sqrt(2.)+pi){
			phase[t]=pi/2.+randGen(na,al);;
		}
		taxis[t]=t*Dt;
		phase[t]=0;
	}

	bool dobreak=false;
	while(1){	
		int num;
		cout <<"0: quit"<<endl;
		cout <<"1: n=0 Carrier"<<endl;
		cout <<"2: n=1 Carrier"<<endl;
		cout <<"3: n=0 red sideband"<<endl;
		cout <<"4: n=1 red sideband"<<endl;
		cout <<"5: superposition red sideband + depumping"<<endl;
		cout <<"6: blue sideband n=0 |S>"<<endl;
		cout <<"7: blue sideband n=0 |D>"<<endl;
		cout <<"8: n=0 squeezed"<<endl;
		cout <<"9: transport"<<endl;
			
	
		cin >>num;
		switch(num){
		case 1:
			gatemovie( phase,timesteps, Dt, reductionStep, plotmovie, omega_trap, Omega, kz,0,0,false,eta,false,"n=0 Carrier");
			break;
		case 2:
			gatemovie( phase,timesteps, Dt, reductionStep, plotmovie, omega_trap, Omega, kz,0,2,false,eta,false,"n=1 Carrier");
			break;
		case 3:
			gatemovie( phase,timesteps, Dt, reductionStep, plotmovie, omega_trap, Omega, kz,-omega_trap,0,false,eta,false,"n=0 red sideband");//red
			break;
		case 4:
			gatemovie( phase,timesteps, Dt, reductionStep, plotmovie, omega_trap, Omega, kz,-omega_trap,2,false,eta,false,"n=1 red sideband");//red
			break;
		case 5:
			gatemovie( phase,timesteps, Dt, reductionStep, plotmovie, omega_trap, Omega, kz,-omega_trap,2,false,eta,true,"superposition red sideband + depumping");//red
			break;
		case 6:
			gatemovie( phase,timesteps, Dt, reductionStep, plotmovie, omega_trap, Omega, kz,omega_trap,0,false,eta,false,"blue sideband n=0 |S>");
			break;
		case 7:
			gatemovie( phase,timesteps, Dt, reductionStep, plotmovie, omega_trap, Omega, kz,omega_trap,1,false,eta,false,"blue sideband n=0 |D>");
			break;
		case 8:
			gatemovie( phase,timesteps, Dt/10, reductionStep, plotmovie, omega_trap, Omega, kz,0,1,true,eta,false,"n=0 squeezed",true);
			break;
		case 9:
			dobreak=true;
			break;
		default:
			theApp2->Terminate();//root memory error workaround call before destructor of ExpJob can be called!;
		}
		if(dobreak) break;
		cout <<endl<<num<<endl;
		
	}
	delete[] taxis;
	delete[] phase;
	
}

void gate(){
	int reductionStep=80;//for chebyshev method you must use as minimum x points as possible. Only every "reductionStep"th point is used.
                         //for cranck nicholson it is the other way around.
                         //use highest reduction step. otherwise it takes
                         //longer and you need more coefficients

	int iterations=50;
	bool atomicunits=false;
	bool plotmovie=true;
	#ifdef asdfasf
	double omega_trap=2.*pi*1.e6;//2.*pi*1.e6;
	double lambda729=729e-9;//729e-9
	double Omega=2.*pi*0.07e6;//2.*pi*0.07e6//el*fieldampl*polvec*kz/4.*quadrupoleSD
#endif

	double omega_trap=2.*pi*1.e6;//paper: 2.*pi*1.e6;
	double lambda729=100e-9;//paper: 200e-9;//fast 729e-9 100
	double Omega=2.*pi*0.07e6;//paper: 2.*pi*0.02e6;//fast: 2.*pi*0.07e6//el*fieldampl*polvec*kz/4.*quadrupoleSD  0.1

	int timesteps=200;//paper: 4000;//2000,fast: 200   ,1000(good)
	hbar=1.05457148e-34;
	double el = 1.602e-19;       
	mass = 40.078*1.66e-27;
	double mass_el=9.1095e-31;
	if (atomicunits){
		mass=mass/mass_el;
		mass=1;
		hbar=1;
		el=1;
		omega_trap=1;
	}
	double x0=sqrt(hbar/2./mass/omega_trap);

	double kz=2.*pi/lambda729;

	double eta=kz*x0;
	cout <<"Lambdicke parameter :" <<eta<<endl;
	double Dt=(pi+pi/sqrt(2.)+pi+pi/sqrt(2.))/(double(timesteps)*Omega*eta);
	double *phase=new double[timesteps];
	double *taxis=new double[timesteps];
	
	double na=0.0,al=0.000001;
	bool doOnlyNoiseAnalysis=false;
	for(int t=0;t<timesteps;t++){
		
		double currentphase=Dt*double(t)*Omega*eta;
	
		if(currentphase<pi/sqrt(2.)){
			phase[t]=-(0.+randGen(na,al)-pi/4.);
		}
		else if(currentphase<pi/sqrt(2.)+pi){
			phase[t]=-(pi/2.+randGen(na,al)-pi/4.);
		}
		else if(currentphase<pi/sqrt(2.)+pi+pi/sqrt(2.)){
			phase[t]=-(0+randGen(na,al)-pi/4.);
		}
		else  if(currentphase<pi/sqrt(2.)+pi+pi/sqrt(2.)+pi){
			phase[t]=-(pi/2.+randGen(na,al)-pi/4.);
		}
		taxis[t]=t*Dt;
		//phase[t]=0;
	}
	if(doOnlyNoiseAnalysis){
		//gateoct( phase,timesteps, Dt, reductionStep, false, omega_trap, Omega, kz,omega_trap,iterations,true,1,1,true,true,"noisestabilityComposite");
		logfile.SetReadPath("C:/Users/k/Documents/uni/ks/dev/c/EssentialNumericalTools/Release/octtool.gen/");
		//logfile.ReadTSV("./phase1.tsv",phase,timesteps);
		gateoct( phase,timesteps, Dt, reductionStep, false, omega_trap, Omega, kz,omega_trap,iterations,true,1,1,true,true,"noisestabilityphase1");
		logfile.SetReadPath("C:/Users/k/Documents/uni/ks/dev/c/EssentialNumericalTools/Release/octtool.gen/");
		logfile.ReadTSV("./phase2.tsv",phase,timesteps);
		gateoct( phase,timesteps, Dt, reductionStep, false, omega_trap, Omega, kz,omega_trap,iterations,true,1,1,true,true,"noisestabilityphase2");	
		return;
	}
	
	logfile.Graph("noisedphase",taxis,phase,timesteps,"","","AL");

	
	gatemovie( phase,timesteps, Dt, reductionStep, plotmovie, omega_trap, Omega, kz,omega_trap);

	if(true){
		//gateoct( phase,timesteps, Dt, reductionStep, false, omega_trap, Omega, kz,omega_trap,iterations,true,1);
		
		for(int t=0;t<timesteps;t++){
			
			double currentphase=Dt*double(t)*Omega*eta;
		
			if(currentphase<pi/sqrt(2.)){
				phase[t]=0.+randGen(na,al);;
			}
			else if(currentphase<pi/sqrt(2.)+pi){
				phase[t]=pi/2.+randGen(na,al);;
			}
			else if(currentphase<pi/sqrt(2.)+pi+pi/sqrt(2.)){
				phase[t]=0+randGen(na,al);;
			}
			else  if(currentphase<pi/sqrt(2.)+pi+pi/sqrt(2.)+pi){
				phase[t]=pi/2.+randGen(na,al);;
			}
			taxis[t]=t*Dt;
			//phase[t]=0;
		}
		gateoct( phase,timesteps, Dt, reductionStep, false, omega_trap, Omega, kz,omega_trap,iterations,true,100,1.6,true);
		logfile.WriteTSV("./phase3with1.6",phase,timesteps);
		int noisecnt=20;
		double fidelarr[3][20];
		double noisearr[20];


		
		//logfile.ReadTSV("./noisestability0.tsv",noisearr,fidelarr[0],noisecnt);
		//logfile.ReadTSV("./noisestability1.tsv",noisearr,fidelarr[1],noisecnt);
		//logfile.ReadTSV("./noisestability1_noise.tsv",noisearr,fidelarr[2],noisecnt);

		logfile.Graph("noise",noisearr,fidelarr[2],noisecnt,"phasenoise","fidelity","AL",3);
		logfile.Graph("noise1","noise",noisearr,fidelarr[0],noisecnt,"L",1);
		logfile.Graph("noise3","noise",noisearr,fidelarr[1],noisecnt,"L",2);
	}
	
//	gatemovie( phase,timesteps, Dt, reductionStep, plotmovie, omega_trap, Omega, kz,omega_trap);
	
	delete[] taxis;
	delete[] phase;
}
int main(int argc, char* argv[]){
#ifndef __CINT__
	char *str=argv[0];TApplication theApp("App", &argc, argv);
	theApp2=&theApp;
#endif
	//gate();
	laserAtomInteraction();
	
	singlewavefnoct();
	
	
#ifndef __CINT__
   while(true){
		gSystem->ProcessEvents();
		gSystem->Sleep(10);
	}
	theApp.Terminate();//root memory error workaround call before destructor of ExpJob can be called!
#endif
}
