using System;
namespace ConsoleApplication1
{
///
/// 相空間(位置+運動量)上のベクトル。
///
///
/// 曲面上の運動のシミュレーション用なので、2次元。
/// 4次のルンゲクッタ法を使った数値計算関数付き。
///
public class PhaseVector
{
public double q1;
public double q2;
public double p1;
public double p2;
public PhaseVector(double q1, double q2, double p1, double p2)
{
this.q1 = q1;
this.q2 = q2;
this.p1 = p1;
this.p2 = p2;
}
public static PhaseVector operator +(PhaseVector x, PhaseVector y)
{
return new PhaseVector(
x.q1 + y.q1, x.q2 + y.q2,
x.p1 + y.p1, x.p2 + y.p2);
}
public static PhaseVector operator /(PhaseVector x, double a)
{
return new PhaseVector(
x.q1 / a, x.q2 / a,
x.p1 / a, x.p2 / a);
}
public static PhaseVector operator *(double a, PhaseVector x)
{
return new PhaseVector(
a * x.q1, a * x.q2,
a * x.p1, a * x.p2);
}
public delegate void Callback(double t, PhaseVector x);
public delegate PhaseVector PhaseFunc(PhaseVector x);
///
/// 微分方程式
/// (d/dt)q = f(q)
/// の解を数値計算で求める。
///
/// 時刻の初期値
/// 時刻の最終値
/// 時刻の刻み幅
/// 結果出力の間隔
/// q の初期値
/// f
/// 結果出力用のコールバック関数
///
/// 4次のルンゲクッタ法で計算。
///
public static void Simulate(
double t0, double t1, double dt, int display_interval,
PhaseVector initial,
PhaseFunc f, Callback cb)
{
PhaseVector q = initial;
int n = 1;
for (double t = t0; t < t1; t += dt, ++n)
{
PhaseVector k1 = dt * f(q);
PhaseVector k2 = dt * f(q + k1 / 2);
PhaseVector k3 = dt * f(q + k2 / 2);
PhaseVector k4 = dt * f(q + k3);
q = q + (k1 + 2 * (k2 + k3) + k4) / 6;
if (n > display_interval)
{
cb(t, q);
n = 1;
}
}
}
}
///
/// サンプルプログラム。
/// 球面上の運動をシミュレーション。
///
class Program
{
static void Main(string[] args)
{
const double dt = 0.01;
const double t_end = 10;
const int DISPLAY_INTERVAL = 5;
const double q1 = 0;
const double q2 = Math.PI / 2;
const double p1 = 0.1;
const double p2 = 0;
PhaseVector.Simulate(
0, t_end, dt, DISPLAY_INTERVAL,
new PhaseVector(q1, q2, p1, p2),
F, Show
);
}
static PhaseVector F(PhaseVector q)
{
const double M = 0.1;
const double G = 10;
double s2 = Math.Sin(q.q2);
double c2 = Math.Cos(q.q2);
return new PhaseVector(
q.p1 / (M * s2),
q.p2 / M,
0,
(q.p1 * q.p1 * c2)
/ (M * s2 * s2 * s2)
- M * G * s2
);
}
static void Show(double t, PhaseVector q)
{
double y = Math.Sin(q.q2);
double x = Math.Cos(q.q1) * y;
y = Math.Sin(q.q1) * y;
double z = -Math.Cos(q.q2);
Console.Write("{0},{1},{2},{3}\n",
t, x, y, z);
}
}
}