Runge-Kutta(RK4)用于Java中的微分方程组

时间:2010-12-05 17:34:39

标签: java math ode automatic-differentiation runge-kutta

这个概念主要是这个帖子的结果:Differential Equations in Java 基本上,我试图遵循Jason S.建议并通过Runge-Kutta方法(RK4)实现微分方程的数值解。

  

大家好,   我试图在java中创建一个简单的SIR-epidemics模型的模拟程序。   基本上,SIR由三个微分方程组定义:
  S'(t)= - lamda(t)* S(t)
  I'(t)= lamda(t)* S(t)-γ(t)* I(t)
  R'(t)= gamma(t)* I(t)
  S - 易感人群,我 - 感染了人,R - 恢复了人。   lamda(t)= [c * x * I(t)] / N(T)   c - 接触次数,x - 感染性(与病人接触后生病的概率),N(t) - 总人口(不变)。
  gamma(t)= 1 /疾病持续时间(常数)

在第一次尝试不成功之后,我尝试用Runge-KUtta解决这个方程式,并尝试产生以下代码:

package test;

public class Main {
    public static void main(String[] args) {


        double[] S = new double[N+1];
        double[] I = new double[N+1];
        double[] R = new double[N+1];

        S[0] = 99;
        I[0] = 1;
        R[0] = 0;

        int steps = 100;
        double h = 1.0 / steps;
        double k1, k2, k3, k4;
        double x, y;
        double m, n;
        double k, l;

        for (int i = 0; i < 100; i++) {
            y = 0;
            for (int j = 0; j < steps; j++) {
                x = j * h;
                k1 = h * dSdt(x, y, S[j], I[j]);
                k2 = h * dSdt(x+h/2, y +k1/2, S[j], I[j]);
                k3 = h * dSdt(x+h/2, y+k2/2, S[j], I[j]);
                k4 = h * dSdt(x+h, y + k3, S[j], I[j]);
                y += k1/6+k2/3+k3/3+k4/6;
            }
            S[i+1] = S[i] + y;
            n = 0;
            for (int j = 0; j < steps; j++) {
                m = j * h;
                k1 = h * dIdt(m, n, S[j], I[j]);
                k2 = h * dIdt(m+h/2, n +k1/2, S[j], I[j]);
                k3 = h * dIdt(m+h/2, n+k2/2, S[j], I[j]);
                k4 = h * dIdt(m+h, n + k3, S[j], I[j]);
                n += k1/6+k2/3+k3/3+k4/6;
            }
            I[i+1] = I[0] + n;
            l = 0;
            for (int j = 0; j < steps; j++) {
                k = j * h;
                k1 = h * dRdt(k, l, I[j]);
                k2 = h * dRdt(k+h/2, l +k1/2, I[j]);
                k3 = h * dRdt(k+h/2, l+k2/2, I[j]);
                k4 = h * dRdt(k+h, l + k3, I[j]);
                l += k1/6+k2/3+k3/3+k4/6;
            }
            R[i+1] = R[i] + l;
        }
        for (int i = 0; i < 100; i ++) {
            System.out.println(S[i] + " " + I[i] + " " + R[i]);
        }
    }

    public static double dSdt(double x, double y, double s, double i) {
        return (- c * x * i / N) * s;
    }
    public static double dIdt(double x, double y, double s, double i) {
        return (c * x * i / N) * s - g * i;
    }
    public static double dRdt(double x, double y, double i) {
        return g*i;
    }

    private static int N = 100;

    private static int c = 5;
    private static double x = 0.5;      
    private static double g = (double) 1 / x;
}

这似乎不起作用,因为病人(I)的数量应首先增加,然后减少到大约0,并且应该严格增加被回收的人数。生病+健康+恢复的总数应为100,但我的代码会产生一些奇怪的结果:

99.0 1.0 0.0  
98.9997525 0.9802475 0.03960495  
98.99877716805084 0.9613703819491656 0.09843730763898331  
98.99661215494893 0.9433326554629141 0.1761363183872249  
98.99281287394908 0.9261002702516101 0.2723573345404987  
98.98695085435723 0.9096410034385773 0.3867711707625441  
98.97861266355956 0.8939243545756241 0.5190634940761019  
98.96739889250752 0.8789214477384787 0.6689342463444292  
98.95292320009872 0.8646049401404658 0.8360970974155659  
98.93481141227473 0.8509489367528628 1.0202789272217598  
98.91270067200323 0.8379289104653137 1.22121933523726  
98.8862386366277 0.8255216273600343 1.438670175799961
98.8550827193552 0.8137050767097959 1.672395117896858  

我找不到错误,请指教!非常感谢提前!

1 个答案:

答案 0 :(得分:1)

我找不到真正的编程问题,但无论如何我都会回答。

快速浏览一下,我会尝试两件事: 假设你的时间单位是几天,那么你似乎正在评估第1天之后情况是什么(如果我错了,请纠正我)。对于你提交的案例,我想你想知道几天的演变。所以你必须增加循环次数或者你的时间步长(但要小心)

其次,你似乎在这里犯了一个错误:c * x * i / N ......应该不是(c * x * i)/ N?检查是否有所作为。而且我认为你可以通过S'+ I'+ R'应该= 0 ...

的事实来检查

再一次,我没有仔细检查,但只是看一看,如果它有任何改变,请告诉我。