SEIR流行病动力学模型的C++实现

SEIR简要描述

        对于SEIR动力学,即易感-潜伏-感染-康复动力学过程,与易感-感染-康复(SIR)动力学不同的是,该动力学中多了潜伏态过程,即个体被感染疾病后,需要经过一定的时间才能表现疾病症状,在此期间我们称为潜伏态。

        该动力学过程可以描述为:易感态个体接触周围患病个体后,通过感染速率β感染疾病,并且进入疾病潜伏态,随后通过速率λ转变为感染态个体,而感染个体会以μ的康复速率恢复为康复者,见下图。

        SEIR的疾病过程可以用来描述很多带有潜伏期的疾病,如梅毒、狂犬病以及最近肆虐全球的COVID-19等。由于其及其模型变体在预测新冠传播方面有非常多的应用,因此这个模型也成为了现今的研究热点。我最近在与医科同学交流时,了解到狂犬病的症状与SEIR模型较为相似,因此想来做一些这方面的工作,所以写下了这个程序供大家参考。对于SEIR模型的性质,及数学模型,大家可以在很多文献或书籍中得到一个更全面的认知,我也不做介绍,直接上代码。

 C++代码实现

        采用Gillespie算法进行实现,具体来说:

        (1)在任意时刻 𝑡,我们算每个个体的转移率 𝜆𝑖(𝑡),即状态分别为 0 ,1,2,3(易感,感染,康复,潜伏)的个体, 速率𝜆𝑖(𝑡) 分别为βkinf(i),μ,0,λ,其中kinf(i)为节点的感染者邻居数。

        (2) 然后计算出系统的总速率 𝜔(𝑡) = ∑𝑖 𝜆𝑖(𝑡),其中系统状态保持时间 𝜏 = 1/𝜔(𝑡)。

        (3) 在下一时刻 𝑡 + 𝜏 时,以概率 𝜆𝑖(𝑡)/𝜔(𝑡) 采样选择节点发生状态改变,选择节点为易感态S时,转变为潜伏态E;选择节点为潜伏态E时,转变为感染态I;选择节点为感染态I时,转变为康复态R;选择康复态R时,跳过该节点,选择其他节点。

        (4) 重复 (1) 到 (3) 过程,直到整个系统达到稳定状态或系统中 𝐼 个体为零时停止迭代。

#include <iostream>
#include <ctime>
#include <stdlib.h>
#include <fstream>
#include <cmath>
#include "mt19937ar.c"
#include<algorithm>
#include <vector>

using namespace std;


int main()
{
    int Network_Size = 100000;
    double r = 0.4;                //感染速率
    double g = 0.2;               //恢复速率
    double k = 0.4;              //潜伏态转变速率
    int I0 = 100;
    double tend = 50;
    double counter = 10;
    vector<int> degree(Network_Size,0);
    vector<vector<int> > adjlist(Network_Size);

    unsigned long idum;
    idum=(unsigned long)time(NULL);
    init_genrand(idum);
    ofstream outfile_S;
    outfile_S.open("SEIR_S.txt");
    ofstream outfile_E;
    outfile_E.open("SEIR_E.txt");
    ofstream outfile_I;
    outfile_I.open("SEIR_I.txt");
    ofstream outfile_R;
    outfile_R.open("SEIR_R.txt");
    ifstream infile;
    infile.open("ER_degree1.txt");
    ifstream infile2;
    infile2.open("ER_adjlist1.txt");
    double Sum_degree = 0;

    for(int i = 0; i < Network_Size; i++)          //导入节点度与网络结构
    {
        infile >> degree[i];
        Sum_degree = Sum_degree + degree[i];
        adjlist[i].resize(degree[i]);
    }
    for(int i = 0; i < Network_Size; i++)
    {
        for(int j = 0; j < degree[i]; j++)
        {
            infile2 >> adjlist[i][j];
        }
    }


    vector<vector<int> > X_vec_S;
    vector<vector<int> > X_vec_E;
    vector<vector<int> > X_vec_I;
    vector<vector<int> > X_vec_R;
    int n_intervals = tend;
    double interval = tend/(1.0*n_intervals);
    vector<int> X_vec_ind_S(n_intervals + 1);
    vector<int> X_vec_ind_E(n_intervals + 1);
    vector<int> X_vec_ind_I(n_intervals + 1);
    vector<int> X_vec_ind_R(n_intervals + 1);
    vector<double> rate(Network_Size,0);
    vector<int> I_node(Network_Size,0);
    vector<double> sum(Network_Size,0);
    vector<double> nk(Network_Size,0);
    vector<int> kinf(Network_Size,0);

    for(int n = 0; n < counter; n++)
    {
        double wt = 0;
        double dt;
        double t = 0;
        double I;
        double R = 0;
        double E = 0;
        int random_1;    //用来初始化感染者节点
        int count1;
        for(int i = 0; i < Network_Size; i++)
        {
            rate[i] = 0;
            I_node[i] = 0;
            kinf[i] = 0;
        }
        I = I0;
        for(;;)         //随机取初始感染者节点
        {
            if(I == 0)
            {
                break;
            }
            random_1 = genrand_int32()%Network_Size;
            if(I_node[random_1] == 0)
            {
                I_node[random_1] = 1;
                I--;
            }
            else
                continue;
        }
        for(int i = 0; i < Network_Size; i++)
        {
            for(int j = 0; j < adjlist[i].size(); j++)
            {
                if(I_node[adjlist[i][j]] == 1)
                {
                    kinf[i]++;
                }
            }
        }
        for(int i = 0; i < Network_Size; i++)
        {
            if(I_node[i] == 1)
            {
                rate[i] = g;
            }
            if(I_node[i] == 2)
            {
                rate[i] = 0;
            }
            if(I_node[i] == 3)
            {
                rate[i] = k;
            }
            if(I_node[i] == 0)
            {
                rate[i] = r*kinf[i];
            }
            wt = wt + rate[i];
        }
        double v = genrand_real2();
        dt = -log(1 - v)/wt;
        I = I0;
        count1 = 1;
        X_vec_ind_I[0] = I;
        X_vec_ind_S[0] = Network_Size-E-I-R;
        X_vec_ind_E[0] = E;
        X_vec_ind_R[0] = R;
        t = dt;
        for(;;)
        {
            //cout << t << '\t' << E << '\t' << I << '\t' << R << endl;
            double u;
            v = genrand_real2();
            for(int i = 0; i < Network_Size; i++)
            {
                nk[i] = 0;
                sum[i] = 0;
            }
            while((t > count1*interval)&&(count1 <= n_intervals))
            {
                X_vec_ind_E[count1] = E;
                X_vec_ind_I[count1] = I;
                X_vec_ind_R[count1] = R;
                X_vec_ind_S[count1] = Network_Size-I-R-E;
                count1 ++;
            }
            if(t > tend)
            {
                break;
            }

            for(int i = 0; i < Network_Size; i++)
            {
                if(i == 0)
                {
                    sum[i] = rate[i];
                }
                else
                {
                    sum[i] = sum[i-1] + rate[i];
                }
                nk[i] = sum[i]/wt;
            }
            u = genrand_real2();
            for(int i = 0; i < Network_Size; i++)
            {

                if( u < nk[i])
                {
                    if(I_node[i] == 1)
                    {
                        I_node[i] = 2;
                        I--;
                        R++;
                        for(int j = 0; j < adjlist[i].size(); j++)
                        {
                            kinf[adjlist[i][j]]--;
                        }
                        break;
                    }
                    if(I_node[i] == 2)
                    {
                        continue;
                    }
                    if(I_node[i] == 3)
                    {
                        I_node[i] = 1;
                        E--;
                        I++;
                        for(int j = 0; j < adjlist[i].size(); j++)
                        {
                            kinf[adjlist[i][j]]++;
                        }
                    }
                    if(I_node[i] == 0)
                    {
                        I_node[i] = 3;
                        E++;
                        break;
                    }
                }
                if(I == 0)
                {
                    while (count1 <= n_intervals)
                    {
                        X_vec_ind_I[count1] = 0;
                        X_vec_ind_E[count1] = E;
                        X_vec_ind_R[count1] = R;
                        X_vec_ind_S[count1] = Network_Size-E-I-R;
                        count1 ++;
                    }
                    break;
                }

            }

            wt = 0;
            for(int i = 0; i < Network_Size; i++)
            {
                if(I_node[i] == 1)
                {
                    rate[i] = g;
                }
                if(I_node[i] == 2)
                {
                    rate[i] = 0;
                }
                if(I_node[i] == 3)
                {
                    rate[i] = k;
                }
                if(I_node[i] == 0)
                {
                    rate[i] = r*kinf[i];
                }
                wt = wt + rate[i];
            }
            dt = -log(1 - v)/wt;
            t = t + dt;
        }
     X_vec_E.push_back(X_vec_ind_E);
     X_vec_I.push_back(X_vec_ind_I);
     X_vec_R.push_back(X_vec_ind_R);
     X_vec_S.push_back(X_vec_ind_S);
    }

    double EXt1,EXt2,EXt3,EXt4;
    for(int i=0; i <= n_intervals; i++)
    {
        EXt1 = 0;
        EXt2 = 0;
        EXt3 = 0;
        EXt4 = 0;
        for(int j=0; j < counter; j++)
        {
            EXt1 += X_vec_S[j][i];
            EXt2 += X_vec_E[j][i];
            EXt3 += X_vec_I[j][i];
            EXt4 += X_vec_R[j][i];
        }

        EXt1 /= 1.0*counter*Network_Size;
        EXt2 /= 1.0*counter*Network_Size;
        EXt3 /= 1.0*counter*Network_Size;
        EXt4 /= 1.0*counter*Network_Size;
        outfile_S << EXt1 << "\n";
        outfile_E << EXt2 << "\n";
        outfile_I << EXt3 << "\n";
        outfile_R << EXt4 << "\n";
    }
    outfile_S << endl;
    outfile_E << endl;
    outfile_I << endl;
    outfile_R << endl;


}

结果

        模拟采用平均度为4的ER随机网络,网络规模为100000,其中感染速率β=0.4,恢复速率μ=0.2,潜伏转变速率λ=0.2,初始感染总数为100。

        若程序或动力学理解有错,希望有大佬能指正,感谢! 

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
你可以使用MATLAB来实现SEIR传染病模型SEIR模型是一种常见的流行病模型,用于描述传染病在人群中的传播情况。下面是一个简单的MATLAB代码示例: ```matlab % 参数设置 N = 1000; % 总人口数 beta = 0.2; % 感染率 gamma = 0.1; % 恢复率 sigma = 0.1; % 潜伏期转化率 % 初始条件 I0 = 1; % 初始感染者数 E0 = 0; % 初始潜伏者数 R0 = 0; % 初始康复者数 S0 = N - I0 - E0 - R0; % 初始易感者数 % 模型求解 [t, y] = ode45(@(t, y) seir_model(t, y, N, beta, gamma, sigma), [0, 100], [S0, E0, I0, R0]); % 绘图 figure; plot(t, y(:, 1), 'r-', 'LineWidth', 2); hold on; plot(t, y(:, 2), 'b-', 'LineWidth', 2); plot(t, y(:, 3), 'g-', 'LineWidth', 2); plot(t, y(:, 4), 'k-', 'LineWidth', 2); legend('易感者', '潜伏者', '感染者', '康复者'); xlabel('时间'); ylabel('人数'); title('SEIR传染病模型'); % SEIR模型的ODE函数 function dydt = seir_model(t, y, N, beta, gamma, sigma) S = y(1); E = y(2); I = y(3); R = y(4); dSdt = -beta * S * I / N; dEdt = beta * S * I / N - sigma * E; dIdt = sigma * E - gamma * I; dRdt = gamma * I; dydt = [dSdt; dEdt; dIdt; dRdt]; end ``` 在这个示例中,我们首先设置了参数N(总人口数)、beta(感染率)、gamma(恢复率)和sigma(潜伏期转化率)。然后,我们定义了初始条件和SEIR模型的ODE函数。最后,使用ode45函数求解ODE,并绘制了易感者、潜伏者、感染者和康复者随时间的变化曲线。 你可以根据自己的需求修改参数和初始条件,并对结果进行进一步的分析和可视化。希望对你有帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值