⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 threebody.c

📁 三体
💻 C
字号:
/* -*- linux-c -*- */
/* threebody.c

   Copyright (C) 2002-2003 John M. Fregeau

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <getopt.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_rng.h>
#include "fewbody.h"
#include "threebody.h"

/* print the usage */
void print_usage(FILE *stream)
{
	fprintf(stream, "USAGE:\n");
	fprintf(stream, "  threebody [options...]\n");
	fprintf(stream, "\n");
	fprintf(stream, "OPTIONS:\n");
	fprintf(stream, "  -m --m0 <m0/MSUN>            : set mass of single star [%.6g]\n", M0/FB_CONST_MSUN);
	fprintf(stream, "  -n --m10 <m10/MSUN>          : set mass 0 of binary [%.6g]\n", M10/FB_CONST_MSUN);
	fprintf(stream, "  -o --m11 <m11/MSUN>          : set mass 1 of binary [%.6g]\n", M11/FB_CONST_MSUN);
	fprintf(stream, "  -a --a1 <a1/AU>                : set semimajor axis of binary [%.6g]\n", A1/FB_CONST_AU);
	fprintf(stream, "  -e --e1 <e1>                   : set eccentricity of binary 0 [%.6g]\n", E1);
	fprintf(stream, "  -v --vinf <vinf/v_crit>      : set velocity at infinity [%.6g]\n", VINF);
	fprintf(stream, "  -b --b <b/(a_0+a_1)>         : set impact parameter [%.6g]\n", B);
	fprintf(stream, "  -t --tstop <tstop/t_dyn>     : set stopping time [%.6g]\n", TSTOP);
	fprintf(stream, "  -D --dt <dt/t_dyn>           : set approximate output dt [%.6g]\n", DT);
	fprintf(stream, "  -c --tcpustop <tcpustop/sec> : set cpu stopping time [%.6g]\n", TCPUSTOP);
	fprintf(stream, "  -A --absacc <absacc>         : set integrator's absolute accuracy [%.6g]\n", ABSACC);
	fprintf(stream, "  -R --relacc <relacc>         : set integrator's relative accuracy [%.6g]\n", RELACC);
	fprintf(stream, "  -N --ncount <ncount>         : set number of integration steps between calls\n");
	fprintf(stream, "                                 to fb_classify() [%d]\n", NCOUNT);
	fprintf(stream, "  -z --tidaltol <tidaltol>     : set tidal tolerance [%.6g]\n", TIDALTOL);
	fprintf(stream, "  -k --ks                      : turn K-S regularization on or off [%d]\n", KS);
	fprintf(stream, "  -s --seed                    : set random seed [%ld]\n", SEED);
	fprintf(stream, "  -d --debug                   : turn on debugging\n");
	fprintf(stream, "  -V --version                 : print version info\n");
	fprintf(stream, "  -h --help                    : display this help text\n");
}

/* set up the scattering */
int init_scattering(fb_obj_t *obj[2], double vinf, double b, double tidaltol)
{
	double m0, m1, M, mu, a1, e1, m10, m11, r, x, y, vx, vy, qa, qb, qc;

	/* some useful variables */
	m0 = obj[0]->m;
	m1 = obj[1]->m;

	M = m0 + m1;
	mu = m0 * m1 / M;

	a1 = obj[1]->a;
	e1 = obj[1]->e;
	m10 = obj[1]->obj[0]->m;
	m11 = obj[1]->obj[1]->m;

	/* the separation that gives the desired tidal perturbation */
	r = pow(2.0*m0*m1/tidaltol, 1.0/3.0) * pow(m10*m11, -1.0/3.0)*a1*(1.0+e1);

	/* solve for y */
	qa = M*M + fb_sqr(b*vinf*vinf);
	qb = 2.0*(M*r-fb_sqr(b*vinf))*b*vinf*vinf;
	qc = -2.0*fb_sqr(b*vinf)*M*r + fb_sqr(fb_sqr(b*vinf));
	y = (-qb+sqrt(qb*qb-4.0*qa*qc))/(2.0*qa);

	/* x should never be zero, so no need to worry about the square root here */
	x = sqrt(r*r - y*y);

	/* determine v_x from quadratic */
	qa = 1.0 + fb_sqr(y/x);
	qb = 2.0*y*b*vinf/(x*x);
	qc = fb_sqr(b*vinf/x) - 2.0*M/r - vinf*vinf;
	vx = (-qb-sqrt(qb*qb-4.0*qa*qc))/(2.0*qa);

	vy = (b*vinf+y*vx)/x;

	/* set the positions and velocities */
	obj[0]->x[0] = - x / (1.0 + m0/m1);
	obj[0]->x[1] = - y / (1.0 + m0/m1);
	obj[0]->x[2] = 0.0;

	obj[0]->v[0] = - vx / (1.0 + m0/m1);
	obj[0]->v[1] = - vy / (1.0 + m0/m1);
	obj[0]->v[2] = 0.0;

	obj[1]->x[0] = x / (1.0 + m1/m0);
	obj[1]->x[1] = y / (1.0 + m1/m0);
	obj[1]->x[2] = 0.0;

	obj[1]->v[0] = vx / (1.0 + m1/m0);
	obj[1]->v[1] = vy / (1.0 + m1/m0);
	obj[1]->v[2] = 0.0;

	return(0);
}

/* calculate the units used */
int calc_units(fb_obj_t *obj[2], fb_units_t *units)
{
	units->v = sqrt(FB_CONST_G*(obj[0]->m + obj[1]->m)/(obj[0]->m * obj[1]->m) * \
			(obj[1]->obj[0]->m * obj[1]->obj[1]->m / obj[1]->a));
	units->l = obj[1]->a;
	units->t = units->l / units->v;
	units->m = units->l * fb_sqr(units->v) / FB_CONST_G;
	units->E = units->m * fb_sqr(units->v);

	return(0);
}

/* normalize all variables to our system of units */
int normalize(fb_obj_t *obj[2], fb_units_t units)
{
	int i, j, k;

	for (j=0; j<2; j++) {
		obj[j]->a /= units.l;
		obj[j]->m /= units.m;

		for (i=0; i<3; i++) {
			obj[j]->x[i] /= units.l;
			obj[j]->v[i] /= units.v;
		}
	}

	for (k=0; k<2; k++) {
		obj[1]->obj[k]->m /= units.m;

		for (i=0; i<3; i++) {
			obj[1]->obj[k]->x[i] /= units.l;
			obj[1]->obj[k]->v[i] /= units.v;
		}
	}

	return(0);
}

/* the main attraction */
int main(int argc, char *argv[])
{
	int i, j;
	unsigned long int seed;
	double m0, m10, m11, a1, e1;
	double vinf, b, m1, M, mu, Ei, E, Li[3], l0[3], l1[3], L[3], r[3], t;
	fb_hier_t hier;
	fb_input_t input;
	fb_ret_t retval;
	fb_units_t units;
	char string1[1024], string2[1024];
	gsl_rng *rng;
	const gsl_rng_type *rng_type=gsl_rng_mt19937;
	const char *short_opts = "m:n:o:a:e:v:b:t:D:c:A:R:N:z:k:s:dVh";
	const struct option long_opts[] = {
		{"m0", required_argument, NULL, 'm'},
		{"m10", required_argument, NULL, 'n'},
		{"m11", required_argument, NULL, 'o'},
		{"a1", required_argument, NULL, 'a'},
		{"e1", required_argument, NULL, 'e'},
		{"vinf", required_argument, NULL, 'v'},
		{"b", required_argument, NULL, 'b'},
		{"tstop", required_argument, NULL, 't'},
		{"dt", required_argument, NULL, 'D'},
		{"tcpustop", required_argument, NULL, 'c'},
		{"absacc", required_argument, NULL, 'A'},
		{"relacc", required_argument, NULL, 'R'},
		{"ncount", required_argument, NULL, 'N'},
		{"tidaltol", required_argument, NULL, 'z'},
		{"ks", required_argument, NULL, 'k'},
		{"seed", required_argument, NULL, 's'},
		{"debug", no_argument, NULL, 'd'},
		{"version", no_argument, NULL, 'V'},
		{"help", no_argument, NULL, 'h'},
		{NULL, 0, NULL, 0}
	};

	/* set parameters to default values */
	m0 = M0;
	m10 = M10;
	m11 = M11;
	a1 = A1;
	e1 = E1;
	vinf = VINF;
	b = B;
	input.ks = KS;
	input.tstop = TSTOP;
	input.Dflag = 0;
	input.dt = DT;
	input.tcpustop = TCPUSTOP;
	input.absacc = ABSACC;
	input.relacc = RELACC;
	input.ncount = NCOUNT;
	input.tidaltol = TIDALTOL;
	seed = SEED;
	fb_debug = DEBUG;

	while ((i = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
		switch (i) {
		case 'm':
			m0 = atof(optarg) * FB_CONST_MSUN;
			break;
		case 'n':
			m10 = atof(optarg) * FB_CONST_MSUN;
			break;
		case 'o':
			m11 = atof(optarg) * FB_CONST_MSUN;
			break;
		case 'a':
			a1 = atof(optarg) * FB_CONST_AU;
			break;
		case 'e':
			e1 = atof(optarg);
			if (e1 >= 1.0) {
				fprintf(stderr, "e0 must be less than 1\n");
				return(1);
			}
			break;
		case 'v':
			vinf = atof(optarg);
			if (vinf < 0.0) {
				fprintf(stderr, "vinf must be non-negative\n");
				return(1);
			}
			break;
		case 'b':
			b = atof(optarg);
			if (b < 0.0) {
				fprintf(stderr, "b must be non-negative\n");
				return(1);
			}
			break;
		case 't':
			input.tstop = atof(optarg);
			break;
		case 'D':
			input.Dflag = 1;
			input.dt = atof(optarg);
			break;
		case 'c':
			input.tcpustop = atof(optarg);
			break;
		case 'A':
			input.absacc = atof(optarg);
			break;
		case 'R':
			input.relacc = atof(optarg);
			break;
		case 'N':
			input.ncount = atoi(optarg);
			break;
		case 'z':
			input.tidaltol = atof(optarg);
			break;
		case 'k':
			input.ks = atoi(optarg);
			break;
		case 's':
			seed = atol(optarg);
			break;
		case 'd':
			fb_debug = 1;
			break;
		case 'V':
			fb_print_version(stdout);
			return(0);
		case 'h':
			fb_print_version(stdout);
			fprintf(stdout, "\n");
			print_usage(stdout);
			return(0);
		default:
			break;
		}
	}

	/* check to make sure there was nothing crazy on the command line */
	if (optind < argc) {
		print_usage(stdout);
		return(1);
	}

	/* initialize a few things for integrator */
	t = 0.0;
	hier.nstar = 3;
	fb_malloc_hier(&hier);
	fb_init_hier(&hier);

	/* put stuff in log entry */
	sprintf(&(input.firstlogentry[strlen(input.firstlogentry)]), "  command line:");
	for (i=0; i<argc; i++) {
		sprintf(&(input.firstlogentry[strlen(input.firstlogentry)]), " %s", argv[i]);
	}
	sprintf(&(input.firstlogentry[strlen(input.firstlogentry)]), "\n");

	/* print out values of paramaters */
	fprintf(stderr, "PARAMETERS:\n");
	fprintf(stderr, "  ks=%d  seed=%ld\n", input.ks, seed);
	fprintf(stderr, "  m0=%.6g MSUN\n", m0/FB_CONST_MSUN);
	fprintf(stderr, "  a1=%.6g AU  e1=%.6g  m10=%.6g MSUN  m11=%.6g MSUN\n", \
		a1/FB_CONST_AU, e1, m10/FB_CONST_MSUN, m11/FB_CONST_MSUN);
	fprintf(stderr, "  vinf=%.6g  b=%.6g  tstop=%.6g  tcpustop=%.6g\n", \
		vinf, b, input.tstop, input.tcpustop);
	fprintf(stderr, "  tidaltol=%.6g  abs_acc=%.6g  rel_acc=%.6g  ncount=%d\n\n", \
		input.tidaltol, input.absacc, input.relacc, input.ncount);

	/* initialize GSL rng */
	gsl_rng_env_setup();
	rng = gsl_rng_alloc(rng_type);
	gsl_rng_set(rng, seed);

	/* create binary */
	hier.hier[hier.hi[2]+0].obj[0] = &(hier.hier[hier.hi[1]+1]);
	hier.hier[hier.hi[2]+0].obj[1] = &(hier.hier[hier.hi[1]+2]);
	hier.hier[hier.hi[2]+0].t = t;

	/* give the objects some properties */
	for (j=0; j<hier.nstar; j++) {
		hier.hier[hier.hi[1]+j].id = j;
		sprintf(hier.hier[hier.hi[1]+j].idstring, "%d", j);
		hier.hier[hier.hi[1]+j].n = 1;
		hier.hier[hier.hi[1]+j].obj[0] = NULL;
		hier.hier[hier.hi[1]+j].obj[1] = NULL;
	}

	hier.hier[hier.hi[1]+0].m = m0;
	hier.hier[hier.hi[1]+1].m = m10;
	hier.hier[hier.hi[1]+2].m = m11;

	hier.hier[hier.hi[2]+0].m = m10 + m11;

	hier.hier[hier.hi[2]+0].a = a1;
	hier.hier[hier.hi[2]+0].e = e1;

	hier.obj[0] = &(hier.hier[hier.hi[1]+0]);
	hier.obj[1] = &(hier.hier[hier.hi[2]+0]);
	hier.obj[2] = NULL;

	/* get the units and normalize */
	calc_units(hier.obj, &units);
	normalize(hier.obj, units);

	fprintf(stderr, "UNITS:\n");
	fprintf(stderr, "  v=v_crit=%.6g km/s  l=%.6g AU  t=t_dyn=%.6g yr\n", \
		units.v/1.0e5, units.l/FB_CONST_AU, units.t/FB_CONST_YR);
	fprintf(stderr, "  M=%.6g M_sun  E=%.6g erg\n\n", units.m/FB_CONST_MSUN, units.E);

	fb_dprintf("moving hierarchies analytically in from infinity...\n");

	m0 = hier.obj[0]->m;
	m1 = hier.obj[1]->m;
	M = m0 + m1;
	mu = m0 * m1 / M;

	Ei = 0.5 * mu * fb_sqr(vinf);

	/* move hierarchies analytically in from infinity along hyperbolic orbit */
	init_scattering(hier.obj, vinf, b, input.tidaltol);

	/* and check to see that we conserved energy and angular momentum */
	fb_cross(hier.obj[0]->x, hier.obj[0]->v, l0);
	fb_cross(hier.obj[1]->x, hier.obj[1]->v, l1);

	for (i=0; i<3; i++) {
		L[i] = (m0 * l0[i] + m1 * l1[i]);
		r[i] = hier.obj[1]->x[i] - hier.obj[0]->x[i];
	}

	E = - m0 * m1 / fb_mod(r) + 0.5 * (m0 * fb_dot(hier.obj[0]->v, hier.obj[0]->v) + \
					m1 * fb_dot(hier.obj[1]->v, hier.obj[1]->v));

	fb_dprintf("L0=%.6g DeltaL/L0=%.6g DeltaL=%.6g\n", mu*b*vinf, fb_mod(L)/(mu*b*vinf)-1.0, fb_mod(L)-mu*b*vinf);
	fb_dprintf("E0=%.6g DeltaE/E0=%.6g DeltaE=%.6g\n\n", Ei, E/Ei-1.0, E-Ei);

	/* trickle down the binary properties, then back up */
	fb_dprintf("obj[%d]->a=%e\n", 1, hier.obj[1]->a);
	fb_dprintf("obj[%d]->e=%e\n", 1, hier.obj[1]->e);
	fb_dprintf("obj[%d]->m=%e\n", 1, hier.obj[1]->m);
	fb_randorient(&(hier.hier[hier.hi[2]+0]), rng);
	fb_downsync(&(hier.hier[hier.hi[2]+0]), t);
	fb_upsync(&(hier.hier[hier.hi[2]+0]), t);
	fb_dprintf("obj[%d]->a=%e\n", 1, hier.obj[1]->a);
	fb_dprintf("obj[%d]->e=%e\n", 1, hier.obj[1]->e);
	fb_dprintf("obj[%d]->m=%e\n", 1, hier.obj[1]->m);

	/* store the initial energy and angular momentum*/
	Ei = fb_petot(&(hier.hier[hier.hi[1]]), hier.nstar) + fb_ketot(&(hier.hier[hier.hi[1]]), hier.nstar);
	fb_angmom(&(hier.hier[hier.hi[1]]), hier.nstar, Li);

	/* integrate along */
	fb_dprintf("calling fewbody()...\n");

	/* call fewbody! */
	retval = fewbody(input, &hier, &t);

	/* print information to screen */
	fprintf(stderr, "OUTCOME:\n");
	if (retval.retval == 1) {
		fprintf(stderr, "  encounter complete: %s (%s)\n\n", \
			fb_sprint_hier(hier.obj, hier.nobj, string1), \
			fb_sprint_hier_hr(hier.obj, hier.nstar, hier.nobj, string2));
	} else {
		fprintf(stderr, "  encounter NOT complete: %s (%s)\n\n", \
			fb_sprint_hier(hier.obj, hier.nobj, string1), \
			fb_sprint_hier_hr(hier.obj, hier.nstar, hier.nobj, string2));
	}

	fb_dprintf("there were %ld integration steps\n", retval.count);
	fb_dprintf("fb_classify() was called %ld times\n", retval.iclassify);

	fprintf(stderr, "FINAL:\n");
	fprintf(stderr, "  t_final=%.6g (%.6g yr)  t_cpu=%.6g s\n", \
		t, t*units.t/FB_CONST_YR, retval.tcpu);

	fprintf(stderr, "  L0=%.6g  DeltaL/L0=%.6g  DeltaL=%.6g\n", fb_mod(Li), retval.DeltaLfrac, retval.DeltaL);
	fprintf(stderr, "  E0=%.6g  DeltaE/E0=%.6g  DeltaE=%.6g\n", Ei, retval.DeltaEfrac, retval.DeltaE);
	fprintf(stderr, "  Rmin=%.6g (%.6g RSUN)  Rmin_i=%d  Rmin_j=%d\n", \
		retval.Rmin, retval.Rmin*units.l/FB_CONST_RSUN, retval.Rmin_i, retval.Rmin_j);

	/* free GSL stuff */
	gsl_rng_free(rng);

	/* free our own stuff */
	fb_free_hier(hier);

	/* done! */
	return(0);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -