C++中的三体问题

计算科学 有限差分 C++ 模拟
2021-12-08 12:27:03

我正在上初学者编程课程,我们有一个小项目。我选择使用欧拉方法来模拟三体问题。即使系统是混乱的,也有一些特殊情况会产生对称的轨迹。我得到了大部分,但最重要的一个没有出来。它被称为图 8,应该是稳定的。

我确信初始条件很好。程序也应该如此,因为我得到了其他预期的结果。所以问题是我的程序是否有错误,或者欧拉方法不适用于这种特定情况。(然后我会更改为 Runge-Kutta 方法)

我很感激任何帮助!

#include <iostream>
#include <cmath>
#include <fstream>

using namespace std; 

double const  ms=1.0000000000000000;
double const  me=1.0000000000000000;
double const  mm=1.0000000000000000;
double const  G=1.000000000000000000;
double const  dt=0.0001000000000000;

/* 1=Sonne,2=Erde, 3=Mond */

double fsx(double x1, double y1, double x2, double y2, double x3, double y3){
  double dv;
dv=G*(me/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1)))*((x2-x1)/sqrt((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1)))+G*(mm/((y3-y1)*(y3-y1)+(x3-x1)*(x3-x1)))*((x3-x1)/sqrt((y3-y1)*(y3-y1)+(x3-x1)*(x3-x1))); 
/*Projektion der Gravitationskraft auf Körper 1 auf x-Richtung */
  return dv;
}

double fsy(double x1, double y1, double x2, double y2, double x3, double y3){
  double dv=G*(me/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1)))*((y2-y1)/sqrt((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1)))+G*(mm/((y3-y1)*(y3-y1)+(x3-x1)*(x3-x1)))*((y3-y1)/sqrt((y3-y1)*(y3-y1)+(x3-x1)*(x3-x1))); /*Projektion der Gravitationskraft auf Körper 1 auf y-Richtung */
  return dv;
}

double fex(double x1, double y1, double x2, double y2, double x3, double y3){
  double dv;
dv=G*(ms/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1)))*((x2-x1)/sqrt((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1)))+G*(mm/((y3-y1)*(y3-y1)+(x3-x1)*(x3-x1)))*((x3-x1)/sqrt((y3-y1)*(y3-y1)+(x3-x1)*(x3-x1))); 
/*Projektion der Gravitationskraft auf Körper 1 auf x-Richtung */
  return dv;
}

double fey(double x1, double y1, double x2, double y2, double x3, double y3){
  double dv=G*(ms/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1)))*((y2-y1)/sqrt((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1)))+G*(mm/((y3-y1)*(y3-y1)+(x3-x1)*(x3-x1)))*((y3-y1)/sqrt((y3-y1)*(y3-y1)+(x3-x1)*(x3-x1))); /*Projektion der Gravitationskraft auf Körper 1 auf y-Richtung */
  return dv;
}

double fmx(double x1, double y1, double x2, double y2, double x3, double y3){
  double dv;
dv=G*(me/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1)))*((x2-x1)/sqrt((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1)))+G*(ms/((y3-y1)*(y3-y1)+(x3-x1)*(x3-x1)))*((x3-x1)/sqrt((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1))); 
/*Projektion der Gravitationskraft auf Körper 1 auf x-Richtung */
  return dv;
}

double fmy(double x1, double y1, double x2, double y2, double x3, double y3){
  double dv=G*(me/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1)))*((y2-y1)/sqrt((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1)))+G*(ms/((y3-y1)*(y3-y1)+(x3-x1)*(x3-x1)))*((y3-y1)/sqrt((y3-y1)*(y3-y1)+(x3-x1)*(x3-x1))); /*Projektion der Gravitationskraft auf Körper 1 auf y-Richtung */
  return dv;
}


double euler(double (f)(double,double,double,double,double,double), double x1, double y1, double x2, double y2, double x3, double y3, double vi){
  double vf=vi + f(x1, y1, x2, y2, x3, y3)*(dt);
  return vf;
}



int main() {
float xf3, yf3, tmax;
  ofstream out("project1.dat");

  ti=0.00000000000000000, xi1=-0.97000436, yi1=0.24308753, vxi1=0.466203685, vyi1=0.43236573, tmax=3.000000000000, xi2=-xi1, vxi2=vxi1, yi2=-yi1, vyi2=vyi1, xi3=0.0000000000000, vxi3=-2*vxi1, yi3=0.0000000000000000, vyi3=-2*vyi1;
  for(tf=0.0;tf<=tmax;tf=tf+dt){
    vxf1=euler(fsx,xi1,yi1,xi2,yi2,xi3,yi3,vxi1);
    vyf1=euler(fsy,xi1,yi1,xi2,yi2,xi3,yi3,vyi1);
    vxf2=euler(fex,xi2,yi2,xi1,yi1,xi3,yi3,vxi2); /* Gravitationskraft und damit auch fx und fy sind symmetrisch -> es reichen 2 Funktionen */
    vyf2=euler(fey,xi2,yi2,xi1,yi1,xi3,yi3,vyi2);
    vxf3=euler(fmx,xi3,yi3,xi2,yi2,xi1,yi1,vxi3);
    vyf3=euler(fmy,xi3,yi3,xi2,yi2,xi1,yi1,vyi3);
    xf1=xi1+(vxf1)*(dt);
    yf1=yi1+(vyf1)*(dt);
    xf2=xi2+(vxf2)*(dt);
    yf2=yi2+(vyf2)*(dt);
    xf3=xi3+(vxf3)*(dt);
    yf3=yi3+(vyf3)*(dt);

    out << tf << " "<< xf1 << " " << yf1 <<" "<< vxf1 << " " << vyf1<<  " "<< xf2 << " " << yf2 <<" "<< vxf2 << " " << vyf2<< " "<< xf3 << " " << yf3 <<" "<< vxf3 << " " << vyf3 << endl;
    ti=tf;
vxi1=vxf1;
    vyi1=vyf1;
    vxi2=vxf2;
    vyi2=vyf2;
    vxi3=vxf3;
    vyi3=vyf3;

    xi1=xf1;
    yi1=yf1;
    xi2=xf2;
    yi2=yf2;
    xi3=xf3;
    yi3=yf3;
  }
out.close();
}

grafic(它应该是一个完美的8):在此处输入图像描述

1个回答

所以你的代码一定有问题。我知道这一点是因为当我刚刚编写了一个 C++ 代码来使用我的模拟框架解决这个问题时,我使用 Explicit Euler 得到了以下结果:

在此处输入图像描述

我建议将频繁的计算分解为函数,尤其是可以进行向量相关数学运算的函数。您可以考虑用数组表示每个物体的位置和速度,例如:

double p1[2], v1[2]; // These represent position and velocity of body 1

然后您可以编写函数来计算向量幅度和单位向量,例如:

double hypot( double x, double y ){
  double t; // modified based on code from wikipedia on "Hypot" page
  x = abs(x);
  y = abs(y);
  if( x == 0.0 ){ return y; }
  if( y == 0.0 ){ return x; }
  t = min(x,y);
  x = max(x,y);
  t = t/x;
  return x*sqrt(1.0+t*t);
}

double mag( double * vec ){
  return hypot(vec[0],vec[1]);
}

void toUnit( double * vec ){
  double mag_ = mag(vec);
  vec[0] /= mag_; vec[1] /= mag_;
}

只需执行以下操作即可使用这些功能:

double r[2] = {p1[0]-p2[0],p1[1]-p2[1]};
double magr = mag(r);
toUnit(r);
double accel_mag = G*m1/(magr*magr);
double dv2dt[2] = {accel_mag*r[0],accel_mag*r[1]};

养成将经常使用的计算构建成独立函数的习惯不仅可以减少构建新代码的时间,而且调试问题也会更容易,因为如果你在某些数学上有错误,你只需要修复一个功能,即使这个功能在很多地方都使用过。