Example #1
0
u8 * calc_page_ecc(u8 *data)
{
	static u8 ecc[16];

	calc_ecc(data, ecc);
	calc_ecc(data + 512, ecc + 4);
	calc_ecc(data + 1024, ecc + 8);
	calc_ecc(data + 1536, ecc + 12);
	return ecc;
}
int main(int argc, char *argv[])
{


/* Clear Screen */
	system("clear");
	printf("\nBEMRI simulator!\n");
	
/* Variable Declarations */	
    BEMRI *b;
    flags f;
    iParams iPars;
    double dt1, dt, tmax, e[3], t, t0, r_min, t_RK4 = 0.0,tau, t_node, sim_time, E0, PbN, dt_test;
    double r_bemri, r_current, r_node, r_1, r_2, theta_N, ecc_N, theta0h, r_tid, r0;
    double E1h,E2h,l1h,l2h,e1h,e2h,dAdt, dt_temp, dt_min, fmax[2], alpha = 1e-5, chi, node_phase, E_last, a1h, a2h;
    double Ph_init,eh_init, Q[3][3], Qtt[3][3], T_pm[4];
	double R[3], m[3], timer=1e300;
    double test_rad, test_angle, del_ia, del_aop, frac = 1.0, max_hard_count, eh0;
    int xed, a = 0, N=1, single, minned, status, entered_node, passed_node, times_around, max_orbits, num_params;
    int m1NegY=0, hard_count, agent, amax, astep, nvar, zeroed, angle_counter = 0, inner_runs, ipsval = 1, past;
    double t_broken, Pb0, Esys0,Lsys0, eb0, Hrat = 3, ri, r_cm, percentage_as_double, gam_now, eb_prev, ab_prev, k1, k2;
    double e1h_prev, e2h_prev, timer0;
    long seed, iseed;
	double y[22],yscal[22],dydx[22], dscale, mconv, tconv;	//these are the vectors used for BS integration, 22 = 7*N+1
	double lan0, ia0, aop0, ab0;
	char fname[80];
	


/* for BS ODE integrator setup */
	for(int i=0;i<22;i++)
		yscal[i] = 1;
	
/* Vector from observer to system center of mass */	
	R[0] = 0; R[1] = 0; R[2] = 2.45027686e20;	//distance to Sgr A*

/* timing variables */	
    time_t start;
    time_t stop;
    struct timeval t1;

/* command line argument check */
	//possible flags:
	//	-c				run to completion
	//	-s [value]		use value for seed
	//	-t [value]		run to tmax = value*Ph
	//	-nd				do not stop sim when BEMRI is disrupted
	//	-N [value]		run simulation N times, do not output position or quadrupole data
	//	-so				suppress any screen output
    //  -PbN [value]	set Pb = value*tnode
    //	-th0 [value]	set theta0 = value
    //	-RK4			use RK4 integrator instead of BS2
    //	-fname [string]	use string as file name instead of BEMRI.dat
    //	-fpars [string] use string as filename to find input parameters
    //	-beta [value]	use beta = value
	//	-gam [value]	use gamma = value
    //	-ips [value]	run [value] runs per set of parameters, sampling initial phases
    //	-eh [value]		set BH orbit eccentricity
	//	-Htest			Test Heggie values
	//	-Hrat [value]	Use [value] for rp/a ratio in Heggie test
	//	-geo			Use geometricized units -- G = c = 1
	//	-ang			Randomize binary orientation angles
	
    b = (BEMRI *) malloc( sizeof(BEMRI) );
	if(args(argc,argv,&iPars,&f,&N,&frac,&seed,&PbN,fname,&eh,&ipsval,&Hrat))
		return 1;
	

/* initialize BEMRI parameters */
    init_params(b,f);

/* file pointer declarations */	
    FILE *results_fp, *Q_fp, *pos_fp;
    if(f.fnameflag == 0)
    	results_fp = fopen("BEMRI.dat","w");
    else
    	results_fp = fopen(fname,"w");

	if(f.cflag != 1 && f.Nflag != 1)
	{
		Q_fp = fopen("QP.dat","w");
		pos_fp = fopen("pos.dat","w");
	}

/* Chain declaration */
	C = (CHAIN *) malloc( sizeof(CHAIN) );
	
/* set seed if not given on command line */
	if(f.sflag == 0)
	{gettimeofday(&t1,NULL); seed = t1.tv_usec;}
	iseed = seed;		//save initial seed to output
	
	
	
/* master loop, changes parameters */
/* this is the total number of unique (gamma,inc,lan) values that will be run */
for(int ii=0;ii<N;ii++)
    {
		
		/* randomly assign angles if -ang flag is used */
		if(f.angflag)							// angle variation
		{
			iPars.lanA = 2*PI*ran2(&seed);
			iPars.incA = acos(2*ran2(&seed)-1);
		}
		/* if not using random angles OR a parameter file, then assign angles of zero */
		else if(!f.fParflag)
			iPars.lanA = iPars.incA = 0.0;
		
		/* assign random gamma value unless certain flags are used */ 
		if(!f.fParflag && !f.betaflag && !f.gamflag){
			iPars.gamma = (0.35 + 4.65*ran2(&seed));  // randomly assigning beta from being uniform over gamma
			iPars.beta = 1.0/iPars.gamma;
		}

/* starting the loop over all theta0 initial binary phase values */
  for(angle_counter = 0; angle_counter<ipsval; angle_counter++)
    {

/* set G and c, which will be reset if -geo is used */		
	c = 299792458e0;
	G = 6.673e-11;
		
/* reset timer and m1NegY */
	timer = 1e300;
	m1NegY = 0;

/* parameter setup */
    	init_params(b,f);	// initialize BEMRI parameters
	eb = 0.0;
	aop = 0.0;			// aop is redundant for circular orbits, always set to 0	
	lan = iPars.lanA;	// set dynamic value lan
	ia = iPars.incA;	// set dynamic value ia
	if(!f.th0flag && !f.fParflag && f.ipsflag)	// assign appropriate value of th0 if using -ips flag
		iPars.th0 = 2*PI * (float)angle_counter/ipsval;		//only set theta0 if th0flag has NOT been set

	
/* Setup for testing results from Heggie and Rasio paper */			
	if(f.Htflag == 1)
		{
			G = c = 1;
			ia = 0;
			lan = 0;
			aop = 0;
			m1 = m2 = 1;
			m3 = 1;
			ab = 1;
			eb = 0.0;
			eh = 1.0;
			rph = Hrat*ab;
			r0 = 100*rph;
			theta0h = -acos(2*rph/r0 - 1);
			Pb = 2*PI*sqrt(ab*ab*ab/(G*(m1+m2)));
		}
	
/* setup for elliptical BEMRI */
	else if(eh < 1)
		theta0h = PI;
		

/* Setup for parabolic orbit evolution */	
	else if(eh >= 1)
	{
		if(f.geoflag)								// if using geometricized units
		{
			mconv = G/(c*c);						// conversion factor for masses
			tconv = c;
			G = c = 1.0;							// set constants to 1
			//ab /= dscale;
			m1 *= mconv;							// convert mass values to meters
			m2 *= mconv;
			m3 *= mconv;
			Pb *= tconv;							// recalculate the binary period with new ab and masses
		}

		r_tid = ab*pow(m3/(m1+m2),1.0/3.0);			// calculate tidal radius r_tid
		rph = r_tid/iPars.beta;						// calculate pericenter distance for BEMRI orbit
		r0 = 200.0*rph;								// calculate r0 = initial separation
		theta0h = -acos(2.0*rph/r0 - 1.0);			// calculate corresponding true anomaly
		if(isnan(theta0h) || fabs(theta0h) < 2.0)	// see if the anomaly was in acceptable range
			theta0h = -2.0;							// if not, just set to -2.0 radians
		//theta0h = -3.0;
	}


/* recalculate BEMRI parameters using new values */		
	recalc_params(b);
	
/* initial conditions and node passage time */
    lh = sqrt(rph*(1+eh)*G*(m3*m3*m4*m4)/(m3+m4));		//initial angular momentum of SMBH orbit
    advance_orbit(&(b->binary_h),lh,theta0h);			//begin cm-SMBH orbit at theta0h
   
/* timestep tau and max simulation time tmax */ 
	if(f.Htflag == 1)
	{
		tau = Pb/pow(2,7);
		tmax = 1e100;
	}
    else if(eh<1)
    {
		tau = Pb/pow(2,7);
		tmax = 1*Pb;
    }
    else
    {
    	tau = Pb/pow(2,7);
		tmax = 1e100;		  
    }


    recalc_params(b);
// update little binary positions and velocities for orbit around hole
    lb = sqrt(rpb*(1+eb)*G*(m1*m1*m2*m2)/(m1+m2));		//initial angular momentum of BEMRI
    advance_orbit(&(b->binary_b),lb,iPars.th0);						//begin BEMRI at theta0
	BEMRI_CM_update(b);
    load_vectors(rr,vv,m,b);		//load initial values into working vectors
    dt = tau;
    dt1 = dt;
			   
/* Chain setup and testing */
	setup_chain(C,m,3);
	nvar = 6*(C->N-1);
		
/* BEMRI lifetime check */			
    if ( peters_lifetime(eb,ab,m1,m2) < 100*Ph )			//BEMRI lifetime too short, abort current run
    {status = 3;times_around = -1;}

		
/* other setup */
    eh0 = eh;
    t0 = 0;
    zeroed = 0;
    t_broken = 0.0;
	xed = 0;
	minned = 0;
	t_RK4 = 0.0;
	status = 0;
	entered_node = 0;
	passed_node = 0;
	times_around = 0;
	max_orbits = 1;
    a = -1;
	if(eh < 1)
		amax = (int)(abs((tmax-t0)/dt1));
	else
		amax = 1e6;
	astep = 1;//(int)ceil((amax/200000.0));		//output management
    start = time(NULL);
	max_hard_count = 20;
	hard_count = 0;
	Pb0 = Pb;
	ri = sqrt( pow(X4-X3,2) + pow(Y4-Y3,2) + pow(Z4-Z3,2) );	// initial distance from binary cm to SMBH
	k1 = G*m3*m1;
	k2 = G*m3*m2;
		
		
/* initial energy setup */			
	calc_energies(b,&E1h,&E2h);
    E0 = Eb;
	eb0 = eb;
	ab0 = ab;
    E_last = E0;			//initialize E_last
    calc_total_energy(b);					// compute total system energy
    calc_total_angular_momentum(b);			// compute total system ang. mom.
   	Esys0 = b->energy;
	Lsys0 = b->L;
		
/* print out some diagnostic info */
	if(!f.Nflag)
	{
		printf("\nbeta = %.3f",iPars.beta);
		printf("\ngamma = %.3f",iPars.gamma);
		printf("\nt_max = %.3e",tmax);
		printf("\ntheta0h = %.3e",theta0h);
		printf("\ntheta0 = %.10e",iPars.th0);
		printf("\nab = %.4e",ab);
		printf("\nPb = %.4e",Pb);
		printf("\nr_cm0 = %.4e",ri);
		printf("\nG = %.3e\nc = %.3e",G,c);
		printf("\nia = %.3f\tlan = %.3f\n",ia*180/PI,lan*180/PI);
		
		if(angle_counter==0) anykey();
	}

		
/* main simulation loop */
	while( f.cflag*times_around < 100 && times_around >= 0 && t_RK4 <= tmax )	//something should happen before this, but if not...
		{
		/* this while loop will run under one of two conditions:
			if the -c flag is used, then completion = 1 and tmax = HUGE, so it will run until
			times_around < 100. If the -t or no flag is used, then completion = 0 and the sim
			will run until t_RK4 = tmax. */
			
			gam_now = ah*(1-eh)/(ab*pow(m3/(m1+m2),1.0/3.0));	
			if( !f.Nflag )
			{
				printf("t_RK4 = %.3e\r",t_RK4);
				//printf("Y1 = %.3e\r",Y1);
				fflush(stdout);
			}

	/* upkeep */	
		a += 1;
       	E_last = Eb;		//store old BEMRI energy
		eb_prev = eb;
		e1h_prev = e1h;
		e2h_prev = e2h;
		ab_prev = ab;
			
	/* actual integration call */
		if(!f.bs2flag)
		{
			pack_y_vector_C(C,y);
			leap_derivs2(t_RK4,y,dydx);
			for(int i=0;i<nvar;i++)
				yscal[i]=FMAX(fabs(y[i])+fabs(dydx[i]*dt)+TINY,1);
			//bs_const_step(y,nvar,&t_RK4,dt1,&dt,1e-12,1e-6,yscal,1,leap_derivs2);
			bsstep(y,nvar,&t_RK4,&dt1,1e-12,1e-9,yscal,1,leap_derivs2);
			unpack_y_vector_C(C,y);
			if(a%10 == 0)
				check_chain(C);
			update_momenta(C);		
			update_positions(C);
		}
		else{
			//t_RK4 += N_body_main(rr,vv,m,dt1,3,&dt,1e-8,&minned);	//evolves orbit from time t to t+dt1 with initial step size dt
			pack_y_vector(rr,vv,m,y);
			RK4A_const_step(y,22,&t_RK4,dt1,&dt,1e-9,1e-6,Nbody_derivs1);
			unpack_y_vector(rr,vv,m,y);
		}		
			
        update_binaries(b,rr,vv);								//copies values from v and r into the structures
        CM_values(b);										//calculate values for the center of mass
        if(dt > dt1)										//keeps integration step size at maximum of dt1
			dt = dt1;
		timer -= dt1;										// update timer value	
			
	/* calculate desired values */	
		calc_angles(&(b->binary_b));			// calculate current orbital angles
        past = true_anomaly(&(b->binary_h));	// calculate current true anomaly of BH orbit
        calc_energies(b,&E1h,&E2h);				// compute current binding energies
        calc_angular_momenta(b,&l1h,&l2h);		// compute current pairwise angular momenta
        calc_ecc(b,&e1h,&e2h,E1h,E2h,l1h,l2h);	// compute current pairwise eccentricities
        calc_total_energy(b);					// compute total system energy
        calc_total_angular_momentum(b);			// compute total system ang. mom.
        r_bemri = sqrt( pow(X1-X2,2) + pow(Y1-Y2,2) + pow(Z1-Z2,2));	//BEMRI separation
        r_1 = sqrt( pow(X1-X3,2) + pow(Y1-Y3,2) + pow(Z1-Z3,2) );		// m1-SMBH separation
        r_2 = sqrt( pow(X2-X3,2) + pow(Y2-Y3,2) + pow(Z2-Z3,2) );		// m2-SMBH separation
		r_current = min(r_1,r_2);										//current distance from SMBH to closest BEMRI component
		r_cm = sqrt( pow(X4-X3,2) + pow(Y4-Y3,2) + pow(Z4-Z3,2) );
    	ab = E_to_a(Eb,m1,m2); 					//update semi-major axis of the BEMRI
    	ah = E_to_a(Eh,m3,m1+m2);  				//update semi-major axis of the BH orbit
    	Pb = 2*PI*sqrt(pow(ab,3)/(G*(m1+m2)));	//current orbital periods
    	Ph = 2*PI*sqrt(pow(ah,3)/(G*(m1+m2+m3)));
		b->binary_b.rp = ab*(1-eb);				// compute new binary periapse
		b->binary_h.rp = ah*(1-eh);				// compute new BEMRI periapse
		point_mass_QP(m,rr,3,R,Q,Qtt);			// compute GW output
		if(eh<1) r_node = ah*(1-eh*eh);			//SMBH-BEMRI separation when BEMRI is at the node

			
	/* stopping conditions */
	if(eh0 < 1 || f.ipsflag==0)				// for elliptical BEMRIs or single runs
	{
		if( passed_node && theta_h >= PI )	//if BEMRI has passed the node AND passed apoapse
		{
			passed_node = 0;				//reset passed_node
			times_around += 1;				//increment times_around
           	if( (Eb/E_last) > 1 )			//compare current Eb to last orbit's initial Eb
          		hard_count++;				//the BEMRI has hardened, increment hard_count
           	else
           		hard_count = 0;				//the BEMRI has softened, reset hard_count
           	if( hard_count == max_hard_count)
           	{
           		status = 2;
           		break;
           	}
          	E_last = Eb;
		}
		if(r_current < r_node && entered_node == 0)	//updates values for overall while loop condition, don't want to update while BEMRI is in the node.
		{
			entered_node = 1;	//then the node has been entered
    		theta_N = theta_b;		//save the phase when BEMRI entered the node
    		ecc_N = eb;
		}
		if(r_current > r_node && entered_node == 1)	//if BEMRI has just left the node
		{
			passed_node = 1;						//set passed_node
			entered_node = 0;						//reset entered_node
		}
	}
			

	/* if m1 has gone into negative y territory, start the clock */
	if(Y1<=0 && !m1NegY){
		m1NegY = 1;
		timer0 = t_RK4;
		timer = t_RK4;
		printf("\nTimer started!\n");
	} 

	
	

	/* if timer has gone off, then break */
	if(timer<=0) 
        {
//	printf("TIMER! eb=%.3e | e1h = %.3e | e2h = %.2e\n",eb,e1h,e2h);
         	if(fabs(eb_prev-eb)/eb <1e-9 && k1/r_1 > Eb && k2/r_2 > Eb)
                {
                	status = 0;
                        printf("No change condition met\n");
                        break;
                }
		else if(fabs(e1h_prev-e1h)/e1h < 1e-9 || fabs(e2h_prev-e2h)/e2h < 1e-9)
		{
                	status = 0;
                        printf("No change condition met\n");
                        break;
                }	
        }		
			
	if(f.Htflag == 1 && r_cm > ri )	// if 
        {
           	status = 0;
           	break;
        }			
        if(r_bemri < 2*R_NS && G < 1)
        {
           	status = -1;
           	break;
        }
		
		//Energy conservation check
        if( fabs(Esys0 - b->energy) / fabs(Esys0) > 1e-6 )
        {
        	status = -3;
			printf("\nenergy violation\nEsys0 = %.10e\nEsys(t) = %.10e\n",Esys0,b->energy);
        	break;
        }
        
		// angular momentum conservation check 
		if( fabs(Lsys0 - b->L) / fabs(Lsys0) > 1e-6 )
        {
        	status = -4;
			printf("\nAng. mom violation\nLsys0 = %.10e\nLsys(t) = %.10e\n",Lsys0,b->L);
        	break;
        }


/* print progress */	
		if(f.cflag == 1 && f.soflag==0)
		{
			printf("Current Theta: %.3f\tOrbits Completed: %d\r",theta_h,times_around);
			fflush(stdout);
		}
		else if(f.soflag==0 && eh0 < 1)
		{
			if(print_percentage(a,ii,t_RK4,tmax,ipsval))
			{
				xed = 1;
				status = -2;
				fflush(stdout);
				break;
			}
		}


	/* Full Data Output */
		if(a%astep == 0 && f.cflag != 1 && f.Nflag != 1)
		{	
			output_time(t_RK4+dt1,pos_fp);
			output_positions(rr,b,pos_fp);
			fprintf(pos_fp,"%.10e,%.10e,%.10e,%.10e,%.10e,",Eb,Eh,b->energy,b->L,eb);
			fprintf(pos_fp,"\n");
			output_QP(Qtt, Q_fp);
		}


	} // END OF CURRENT SINGLE RUN

/* initial clean up */					
	stop = time(NULL);
	sim_time = difftime(stop,start)/60.0;

	a1h = E_to_a(E1h,m1,m3);
	a2h = E_to_a(E2h,m2,m3);

/* print percentage if eh0 >= 1 */		
if(f.soflag==0 && eh0 >= 1)
{
	print_percentage(0,ii,angle_counter,ipsval,N);
	printf("\nde = %.10e\n",eb - eb0);
}


/* assign proper status if came out with a zero */
if(status==0)
{
	if(Eb>0)	// binary disrupted
		status=0;
	else if(Eh < 0)	// binary survived, bound to SMBH
		status=1;
	else
		status=2;
}


/* final state output */
	if(Eb < 0)
	{ e1h = e2h = -1; }
	fprintf(results_fp,"%d,%ld,",status,iseed);
	fprintf(results_fp,"%.4e,%.4e",t_RK4,timer0);
	fprintf(results_fp,"%.10e,%.10e,%.10e,%.10e,%.10e,",eb0,eb,eh,e1h,e2h);
	fprintf(results_fp,"%.10e,%.10e,%.10e,%.10e,%.10e,",ab0,ab,ah,a1h,a2h);
	fprintf(results_fp,"%.10e,%.10e,%.10e,%.10e,%.10e,",Eh,E1h,E2h,E0,Esys0);
	fprintf(results_fp,"%.10e,%.10e,%.10e,%.10e,",lh,l1h,l2h,Lsys0);
   	fprintf(results_fp,"%.10e,%.10e,%.10e,%.10e",iPars.incA,iPars.lanA,iPars.th0,iPars.gamma);
    fprintf(results_fp,"\n");
		
/* status codes: */
	//-4: ang. mom. conservation violation
    //-3: energy conservation violation
	//-2: run manually canceled
	//-1: simulation halted due to BEMRI proximity
    //0 : good simulation, BEMRI disrupted
    //1 : good simulation, BEMRI survived but bound to SMBH
    //2 : good simulation, BEMRI survived and remained unbound
    //3 : lifetime for given parameters was too short

}	// END OF CURRENT ANGLE_COUNTER LOOP 

/* 100% print */
	if(xed == 0 && f.cflag == 0 && f.soflag==0)
	{
		fflush(stdout);
		printf("Running %d of %d... (100%%)\n\r",ii+1,N);
		printf("\n\r");
	}

}	// END OF OVERALL N LOOP
	
/* file clean up */
	fclose(results_fp);
	if(f.cflag != 1 && f.Nflag != 1)
	{
		fclose(pos_fp);
		fclose(Q_fp);
	}
	printf("\nfcount = %d\n",fcount);
	free(b);
 	free(C);	
	return 0;
}