计算数学
常微分方程数值解法
保辛积分
力学系统的哈密顿方程可以通过对力学系统的拉格朗日函数进行勒让德变换得到, 更简便导出正则方程的方法是由相空间的变分原理直接得到。积分曲线
n个自由度力学系统的哈密顿方程如下
[封闭性] 辛映射的复合依然是辛映射。即a与b是任意的辛映射, 则有唯一确定的辛映射
[满足结合律] 即对于辛映射a,b,c,满足
[有单位元素存在] 存在单位映射1,有
[辛映射存在逆映射] 即对于映射f,总存在逆映射
因此辛映射(或辛矩阵)构成一个群,且有子群,如行列式为1的辛矩阵构成子群。 偶次微分流形的辛结构(symplectic struture中文有人译为辛构造)是一个闭的非退化的微分2形式
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
class cHamilton
{
/*--------------------------------------class comment
Version : V1.0
Coded by : syz
Date : 2011-06-28 16:19:05 *星期二*
----------------------------------------------------
parameters :
* k--弹簧劲度系数
* m--谐振子质量
*
Methods :
* Hamilton ----辛格式计算谐振子问题
* RK4----------4阶RK方法解算谐振子
* func---------谐振子的正则方程(哈密顿方程)
--------------------------------------------------*/
public double k = 1.0;
//弹簧劲度系数,无量纲化
public double m = 1.0;
//振子质量,无量纲化
public void Hamilton(long NN, double t0, double p0, double q0, double h)
{
StreamWriter ob1 = new StreamWriter("fout.txt");
// ob1.WriteLine("辛RK方法");
double afa = 1.0 / (2.0 - Math.Pow(2.0, 1.0 / 3));
double beta = 1 - 2.0 * afa;
double c1 = 0.0;
double c2 = afa;
double c3 = beta;
double c4 = afa;
double d1 = afa / 2.0;
double d2 = (afa + beta) / 2.0;
double d3 = d2;
double d4 = d1;
double x1, x2, x3, y1, y2, y3, p, q, p1, q1;
//积分初值
p = p0;
q = q0;
for (int i = 0; i < NN; i++)
{
x1 = p - c1 * h * k*q;
y1 = q + d1 * h * p / m;
x2 = x1 - c2 * h * k * y1;
y2 = y1 + d2 * h * x2 / m;
x3 = x2 - c3 * h * k * y2;
y3 = y2 + d3 * h * x3 / m;
p1 = x3 - c4 * h * k * y3;
q1 = y3 + d4 * h * p1 / m;
p = p1;
q = q1;
//输出广义坐标与广义动量
ob1.WriteLine("{0:F8} {1:F8}", p, q);
}
ob1.Close();
}
public void RK4(int N, int M, double t0, double h, double[] y0)
{
/* ----------------------------------------------------
Desciption :
parameters :
* N----------积分步数
* t0----积分初始时刻
* h-----积分步长
* y0[M]------积分初值
* M----------方程维数
Methods :
* solve----RK4方法函数
* func-----求解的方程函数
*
--------------------------------------------------*/
//生成输出文件
StreamWriter ob2 = new StreamWriter("fRK.txt");
// ob2.WriteLine("RK4方法解微分方程组");
int i;
//积分的第i步
double[] k1 = new double[M];
double[] k2 = new double[M];
double[] k3 = new double[M];
double[] k4 = new double[M];
//注意这里不能再初始化,否则y0就会被重新设置为0
// y0=new double[M];
//初值向量
//计算结果,用文件输出
double[] y = new double[M];
// double h, t;
// h = (tt - t0) / N;
//步长
//积分初值
y = y0;
double t = t0;
double[] vec1 = new double[M];
double[] vec2 = new double[M];
double[] vec3 = new double[M];
int j; //分量指标
for (i = 0; i < N; i++)
{
//第一次调用函数
func(out k1, y, t);
for (j = 0; j < M; j++)
vec1[j] = y[j] + 0.5 * h * k1[j];
//第二次调用函数
func(out k2, vec1, t + 0.5 * h);
for (j = 0; j < M; j++)
vec2[j] = y[j] + 0.5 * h * k2[j];
//第三次调用函数
func(out k3, vec2, t + 0.5 * h);
for (j = 0; j < M; j++)
vec3[j] = y[j] + h * k3[j];
//第四次调用函数
func(out k4, vec3, t + h);
for (j = 0; j < M; j++)
y[j] = y[j] + (k1[j] + k2[j] * 2 + k3[j] * 2 + k4[j]) * h / 6.0;
t = t + h;
//输出计算结果
ob2.WriteLine("{0:F8} {1:F8}", y[0], y[1]);
}
ob2.Close();
//关闭文件
}
public void func(out double[] f, double[] y, double t)
{
//右函数
//y应变量
//t自变量
//f方程函数
//不能对y重新执行以下语句,否则参数传递进来的y将被置于0
//y = new double[2];
f = new double[2];
f[0] = y[1]/m;
f[1] = -k*y[0];
}
}
namespace Hamilton
{
class Program
{
static void Main(string[] args)
{
cHamilton ob;
ob=new cHamilton();
//用辛算法解谐振子问题
ob.Hamilton(100000,0.0, 20.0, 8.0, 0.5);
//Hamilton(long NN, double t0,double p0,double q0, double h)
double[] y0 = new double[2];
y0[0] = 20.0;
y0[1] = 8.0;
ob.RK4(10000, 2, 0.0, 0.5, y0);
//RK4(int N, int M, double t0, double h, double[] y0)
}
}
}