下面的代码在Mathematica中建模了一个简单的SIR模型(用于疾病控制)。 (我直接从笔记本上复制了它。)
可以使用NDSolve
求解方程式,并将解决方案插入到三个不同的函数中以供进一步使用。
可以看出,第一行的Beta术语取决于Inf [t]的值,这是NDSolve
函数的三个解之一。
此代码工作正常,我已将其包括在内,以便更好地解释下面的问题。
Beta = Piecewise[{{0.01, Inf[t] > 20}, {.06, Inf[t] <= 20}}];
Mu = 0.1;
Pop = 100;
ans = NDSolve[{S'[t] == -Beta S[t] Inf[t],
Inf'[t] == Beta S[t] Inf[t] - Mu Inf[t],
R'[t] == Mu Inf[t],
S[0] == Pop - 1, Inf[0] == 1,
R[0] == 0}, {S[t], Inf[t], R[t]}, {t, 0, 10}];
Sus[t_] = S[t] /. ans[[1, 1]];
Infected[t_] = Inf[t] /. ans[[1, 2]];
Rec[t_] = R[t] /. ans[[1, 3]];
我现在想要更新代码,以便基于Beta
值而不是Inf[t]
参数的任何一个/或值,我将使Beta值等于输出一个函数,其中Inf[t]
是输入。这可以在下面看到UpdateTransmission[]
是函数。
当我尝试运行下面的代码时,Beta
值保持为0并且不会增加。问题不在于UpdateTransmission
函数,因为我已经独立测试了它。
Beta = UpdateTransmission[SpinMatrix, ThresholdMatrix, Inf[t]];
Mu = 0.1;
Pop = 100;
ans = NDSolve[{S'[t] == -Beta S[t] Inf[t],
Inf'[t] == Beta S[t] Inf[t] - Mu Inf[t],
R'[t] == Mu Inf[t], S[0] == Pop - 1, Inf[0] == 1,
R[0] == 0},
{S[t], Inf[t], R[t]}, {t, 0, 10}];
Sus[t_] = S[t] /. ans[[1, 1]];
Infected[t_] = Inf[t] /. ans[[1, 2]];
Rec[t_] = R[t] /. ans[[1, 3]];
Plot[{Sus[t], Infected[t], Rec[t]}, {t, 0, 5}]
有人可以解释为什么这可能无法正常运行吗?
编辑:这是更新的功能
UpdateTransmission[S_, Th_, Infect_] := Module[{BetaOverall},
P = S;
For[i = 1, i <= Pop, i++,
P[[i]] = Sign[Infect - Th[[i]]];];
BetaOverall = ((Count[P, 1]*.02) + (Count[P, -1]*.5))/Pop
]
以下是上述代码中引用的两个列表:
SpinMatrix = Table[-1, {Pop}]
val := RandomReal[NormalDistribution[.5, .1]]
ThresholdMatrix = Table[Pop*val, {Pop}]
修改编辑
好的我把所有东西放在一起并试图绘制我的三条曲线。现在可以看出,它们都是扁平衬里。 Sus [t]线保持在100,而另外两条似乎保持在1.这里应该发生的是Sus [t]线应该大幅下降而其他两条线应该增加。
(我试图插入和图像,但我不能,因为我没有所需的声望点,所以我只是在代码中过去,你可以在自己的机器上看到你的情节)
Pop = 100;
SpinMatrix = Table[-1, {Pop}];
val := RandomReal[NormalDistribution[.5, .1]];
ThresholdMatrix = Table[Pop*val, {Pop}];
updateTransmission[S_, Th_, Infect_] := Module[{}, P = S;
For[i = 1, i <= Pop, i++, P[[i]] = Sign[Infect - Th[[i]]];];
Return[((Count[P, 1]*.02) + (Count[P, -1]*.5))/Pop]];
beta[t_] := updateTransmission[SpinMatrix, ThresholdMatrix, Inf[t]];
mu = 0.1;
ans = NDSolve[{S'[t] == -beta[t] S[t] Inf[t],
Inf'[t] == beta[t] S[t] Inf[t] -
mu Inf[t], R'[t] == mu Inf[t], S[0] == Pop - 1, Inf[0] == 1,
R[0] == 0}, {S[t], Inf[t], R[t]}, {t, 0, 10}];
Sus[t_] = S[t] /. First@ans;
Infected[t_] = Inf[t] /. First@ans;
Rec[t_] = R[t] /. First@ans;
Plot[{Sus[t], Infected[t], Rec[t]}, {t, 0, 10}]
我期待的输出应该类似于下面给出的代码:
Beta = Piecewise[{{0.5, Inf[t] > 20}, {.02, Inf[t] <= 20}}];
Mu = 0.1;
Pop = 100;
ans = NDSolve[{S'[t] == -Beta S[t] Inf[t],
Inf'[t] == Beta S[t] Inf[t] - Mu Inf[t],
R'[t] == Mu Inf[t], S[0] == Pop - 1, Inf[0] == 1,
R[0] == 0}, {S[t], Inf[t], R[t]}, {t, 0, 10}];
Sus[t_] = S[t] /. ans[[1, 1]];
Infected[t_] = Inf[t] /. ans[[1, 2]];
Rec[t_] = R[t] /. ans[[1, 3]];
Plot[{Sus[t], Infected[t], Rec[t]}, {t, 0, 10}]
答案 0 :(得分:3)
我不知道为什么,但我将问题追溯到在NDSolve内部无法正常工作的Sign []函数!
删除它:
Pop = 100;
SpinMatrix = Table[-1, {Pop}];
val := RandomReal[NormalDistribution[.5, .1]];
ThresholdMatrix = Table[Pop*val, {Pop}];
updateTransmission[Th_, Inf_] :=
Total[Table[If[Inf >= Th[[i]], 2/100, 1/2]/Pop , {i, Pop}]];
beta[t_] := updateTransmission[ThresholdMatrix, Inf[t]];
mu = 0.1;
ans = NDSolve[{
S'[t] == -beta[t] S[t] Inf[t],
Inf'[t] == beta[t] S[t] Inf[t] - mu Inf[t],
R'[t] == mu Inf[t],
S[0] == Pop - 1,
R[0] == 0,
Inf[0] == 1}, {S[t], Inf[t], R[t]}, {t, 0, 10}];
Sus[t_] = S[t] /. First@ans;
Infected[t_] = Inf[t] /. First@ans;
Rec[t_] := R[t] /. First@ans;
Plot[{Sus[t], Infected[t], Rec[t]}, {t, 0, 10}]
给予:
可能有更好的Mma知识的人可以解释代码中发生的事情。
HTH!
答案 1 :(得分:1)
在某些方面,您遇到Set
(=
)和SetDelayed
(:=
)之间的差异。例如,如果您撰写了f = 7
,则f
在初始化后的所有7
内都会变为f
。但是,如果您改为编写f = 7 t
,并试图像使用函数f[8]
那样使用它,那么您将获得(7 t)[8]
,因为Set
表示值f
SetDelayed
不变。但是,f
意味着Beta = Piecewise[{{0.01, Inf[t] > 20}, {.06, Inf[t] <= 20}}]
的值会发生变化,每次发生时都必须重新评估。不过,你最初的情况很特别。
当你写
时Inf[t]
Beta
未定义,因此仍未评估。但是,你的微分方程中Set
的每一次出现都被上面的公式所取代,NDSolve
提供,所以Piecewise
只看到Beta = UpdateTransmission[Inf[t]]
函数。在你的第二个案例中,你写了
UpdateTransmission
问题在于Beta
仅在最初定义Piecewise
时执行,而UpdateTransmission
仍然未评估,Beta
很可能仍会给出纯粹的结果象征性的输入。我会尝试三件事之一,
UpdateTransmission[Inf[t]]
,Beta
使用SetDelayed
重新定义Beta := UpdateTransmission[Inf[t]]
,例如
UpdateTransmission
以便每次遇到它时都会重新评估,或者
重新定义UpdateTransmission[x_?(Head[#]=!=Symbol&)] := ...
不通过
UpdateTransmission[x_] /; Head[x]=!= Symbol := ...
或
UpdateTransmission[Inf[t]]
选项3的工作方式是强制Beta
保持未评估状态,并有效地执行与选项1相同的操作。但是,它需要最少的更改。就个人而言,我赞成选项1或3,因为我不知道NDSolve
需要重新评估多少次{{1}}。