利用ParametricNDSolveValue求解非线性微分方程组
mathematica吧
全部回复
仅看楼主
level 1
我在利用ParametricNDSolveValue求解非线性微分方程组时得不到我想要解,“h''[r] + (3 \[Rho]'[r]/\[Rho][r] h'[r] - dV[h[r]]) == 0, \[Rho]''[r] + k1*\[Rho][r]/3 (h'[r]^2 + V[h[r]]) == 0”这是我的方程组,其中“k1 = 1; V[h_] := 235.17737975645832 h^2 - 0.028362365242459223 h^4 + h^6/2976800; dV[h_] = D[V[h], h];”然后它的边界条件是“h'[10^-2] == 10^-2, \[Rho][10^-2] == 10^-2, \[Rho]'[10^-2] == 1, 0 <h[rmax] < 10^-3”这里的rmax是一个有限的距离,在rmax处h[r]无限趋于0。我以下的程序采用的是打靶法来解决这个问题。但他并不能实现h[r]在rmax处无限趋于0。但当我取”V[h_] := 0.1 + 0.175 h^2 - 0.45 h^3 + h^4/4; h0Start = 0.80621; h0Step = 0.00001; maxAttempts = 10;“时,他画出来的图可以得到满足我的需要的解。
程序如下:
$Assumptions = h > -1;
V[h_] :=
235.17737975645832` h^2 - 0.028362365242459223` h^4 + h^6/2976800;
dV[h_] = D[V[h], h]; rmin = 10^-3; k1 = 1;
sys = {h''[r] + (3 \[Rho]'[r]/\[Rho][r] h'[r] - dV[h[r]]) ==
0, \[Rho]''[r] + (k1/3) \[Rho][r] (h'[r]^2 + V[h[r]]) == 0,
h[rmin] == h0,
h'[rmin] == 10^-2, \[Rho][rmin] == 10^-2, \[Rho]'[rmin] == 1,
WhenEvent[h[r] < 10^-30, "StopIntegration"]};
pf = ParametricNDSolveValue[sys, {h, \[Rho]}, {r, rmin, 500}, {h0},
Method -> {"StiffnessSwitching"}, MaxSteps -> 10^6,
PrecisionGoal -> 10, AccuracyGoal -> 10, "MaxStepSize" -> 0.001]
CheckSolutionQuality[h0_?NumericQ] :=
Module[{sol, hsol, rmaxActual, testPoints, derivatives},
sol = Quiet@pf[h0];
hsol = sol[[1]];
rmaxActual = hsol["Domain"][[1, 2]];
If[rmaxActual >= 500 - 1,
Return[{"IntegrationFailed", h0, hsol, sol[[2]]}]];
If[hsol[rmaxActual] > 10^-3,
Return[{"FailAtRmax", h0, hsol, sol[[2]]}]];
testPoints = Subdivide[RH + 0.01, rmaxActual, 200];
derivatives = hsol' /@ testPoints;
Which[AllTrue[derivatives, # < -10^-20 &],
Return[{"StrictlyDecreasing", h0, hsol, sol[[2]]}],
AllTrue[derivatives, # <= 0 &],
Return[{"NonStrictDecreasing", h0, hsol, sol[[2]]}], True,
Return[{"NotMonotonic", h0, hsol, sol[[2]]}]]]
h0Start = 80;(*找适合边界条件h[rmax]趋于0的初始值,因为按物理情景来说他应该比较靠近h0=227这个方向*)
h0Step = 0.00001;
maxAttempts = 10;
strictMode = False;
h0failed = h0Start;
result = Catch[Do[currentH0 = h0Start + k*h0Step;
status = CheckSolutionQuality[currentH0];
(*记录最后一次失败的 h0*)
If[status[[1]] =!= "StrictlyDecreasing" &&
status[[1]] =!= "NonStrictDecreasing", h0failed = currentH0;];
Which[
status[[1]] ==
"StrictlyDecreasing" || (status[[1]] ==
"NonStrictDecreasing" && ! strictMode),
Throw[{"Success", currentH0, status[[1]]}],
status[[1]] == "IntegrationFailed",
Print["警告: h0=", currentH0, " 积分失败,尝试调整步长"];, True,
Print["尝试 h0=", currentH0, " 失败: ", status[[1]]];
solFailed = Quiet@pf[currentH0];
hSolFailed = solFailed[[1]];
rmaxFailed = hSolFailed["Domain"][[1, 2]];
If[rmaxFailed + 0.1 <= 100,
Print[" rmax 的值: ", rmaxFailed, " 解在 rmax 处的值: ",
hSolFailed[rmaxFailed], "解在 rmax+0.1 处的值: ",
hSolFailed[rmaxFailed + 0.1]],
Print["警告: rmax+0.1 超出范围,无法计算"]];], {k, 0, maxAttempts}];
{"Failed", "超过最大尝试次数"}];
(*结果处理与可视化*)
If[result[[1]] === "Final Success" || result[[1]] === "Success",
h0opt = result[[2]];
{hSolution, \[Rho]Solution} = pf[h0opt];
rmax = hSolution["Domain"][[1, 2]];
Print["========================================"];
Print["成功找到解!"];
Print["- 最佳 h0 = ", h0opt];
Print["- rmax = ", rmax];
Print["- 最终 h(rmax) = ", hSolution[rmax]];
Print["- 单调性模式: ", result[[3]]];
Print["- 最小h值: ", NMinimize[{hSolution[r], 10^-3 <= r <= rmax}, r]];
(*绘制成功的解*)
Grid[{{Plot[hSolution[r], {r, RH + 10^-6, rmax},
PlotLabel -> "场分布 h(r)", ImageSize -> 300, PlotRange -> All],
Plot[hSolution'[r], {r, RH + 10^-6, rmax},
PlotLabel -> "导数 h'(r)", ImageSize -> 300,
PlotRange -> All]}, {Plot[\[Rho]Solution[r], {r, RH + 10^-6,
rmax}, PlotLabel -> "质量分布 \[Rho](r)", ImageSize -> 300,
PlotRange -> All], SpanFromLeft}}, Frame -> All],
Print["========================================"];
Print["未能在 ", maxAttempts, " 次尝试内找到有效解"];
Print["最后尝试的 h0 = ", h0failed];
Print["失败原因: ", result[[2]]];
Print["解在rmax+1处的值: ", hSolFailed[rmaxFailed + 0.1]];
solFailed = Quiet@pf[h0failed];
hSolFailed = Quiet@pf[h0failed][[1]];
\[Rho]SolFailed = solFailed[[2]];
rmaxFailed = hSolFailed["Domain"][[1, 2]];
(*绘制失败的解*)
Grid[{{Plot[hSolFailed[r], {r, RH + 10^-6, rmaxFailed},
PlotLabel -> "失败解: 场分布 h(r)", ImageSize -> 300,
PlotRange -> All],
Plot[hSolFailed'[r], {r, RH + 10^-6, rmaxFailed},
PlotLabel -> "失败解: 导数 h'(r)", ImageSize -> 300,
PlotRange -> All]},
{Plot[\[Rho]SolFailed[r], {r, RH + 10^-6, rmaxFailed},
PlotLabel -> "失败解: \[Rho](r)", ImageSize -> 300,
PlotRange -> All], SpanFromLeft}}, Frame -> All]]
2025年03月21日 05点03分 1
level 1
查阅资料后,这个方程组或许能用松弛法求解?打靶法对初始条件要求过于严格?
2025年03月24日 13点03分 2
level 1
忘了定义 RH=0
2025年03月25日 01点03分 3
吧务
level 15
“打靶法对初始条件要求过于严格?”是会有这个问题,把它当纯边值问题去解有时候会容易一些。(采用有限元或者有限差分离散。)但是不管什么方法都无法避免找初值这一步,而如果问题非线性太强,这一步可能很难。这里只能简单提几条:
1. $Assumptions = h > -1;这行没意义,因为$Assumptions只影响具备Assumptions选项的函数,并且Mathematica是严格区分函数关系和函数值的,也就是说h和h[r]不是一回事。
2. 你说可以给出解的那组参数给出的依旧是失败解,是还需要别的调整吗?
3. \[Rho][rmin] == 10^-2这个条件看着有点奇怪,是否也是某种假设?
4. 在允许范围内尽量减小rmax应该可以降低求解难度。
5. 以下代码或许可以解决你的问题——如果你能找到一组足够恰当的InitialSeeding选项值的话:
k1 = 1; V[h_] :=
235.17737975645832 h^2 - 0.028362365242459223 h^4 + h^6/2976800;
dV[h_] = D[V[h], h];
eq = {(h''[r] + (3 \[Rho]'[r]/\[Rho][r] h'[r] - dV[h[r]])) \[Rho][r] ==
0 // Expand,
drho'[r] + k1*\[Rho][r]/3 (h'[r]^2 + V[h[r]]) == 0, \[Rho]'[r] ==
drho[r]};
rmin = 0; rmax = 500;
tst = NDSolveValue[{eq, {(*h[rmin]==h0,*)h[rmax] == 0(*h'[rmin]==
10^-2*), \[Rho][rmin] == 10^-2, drho[rmin] == 1}}, {\[Rho],
drho, h}, {r, rmin, rmax},
Method -> {"FiniteElement",
"MeshOptions" -> MaxCellMeasure -> 0.05},
InitialSeeding -> {\[Rho][r] == 0, h[r] == 200 - r/500 200,
drho[r] == 1}]; // AbsoluteTiming
2025年03月28日 18点03分 4
level 1
1.谢谢指出h和h[r]不同的这个问题。
2.当我取”V[h_] := 0.1 + 0.175 h^2 - 0.45 h^3 + h^4/4; h0Start = 0.80621; h0Step = 0.00001; maxAttempts = 10;“时,他画出来的图可以得到满足我的需要的解。即是可以视为成功解的。
3. \[Rho][rmin] == 10^-2这个条件本来是 \[Rho][rmin] ==rmin,这确实是一种假设,可以看到我原程序中rmin=10^-3,而 \[Rho][rmin] == 10^-2,应该保持一致性,但由于他们都是小值,对结果的影响应该不大。
4.确实如此但是有问题的是我不确定rmax究竟在什么量级。
5.这正是我觉得它不好求解的问题所在,我所说的V[h_] := 0.1 + 0.175 h^2 - 0.45 h^3 + h^4/4;初始值的搜索范围在0到1;而V[h_] :=
235.17737975645832 h^2 - 0.028362365242459223 h^4 + h^6/2976800它的搜索范围在NSolve[D[V[h], h] == 0, h]即0到227.551左右,这就增加了搜索难度。“找到一组足够恰当的InitialSeeding选项值”这感觉是困难的。以下我尝试了用可以视为成功解的势能来寻找。我先在原有函数基础上进行了拟合以找到“恰当的InitialSeeding”:(*V[h_]:=235.17737975645832` h^2-0.028362365242459223` \
h^4+h^6/2976800;*)V[h_] := 0.1 + 0.175 h^2 - 0.45 h^3 + h^4/4;
dV[h_] = D[V[h], h]; rmin = 10^-3; k1 = 1; RH = 0;
sys = {h''[r] + (3 \[Rho]'[r]/\[Rho][r] h'[r] - dV[h[r]]) ==
0, \[Rho]''[r] + (k1/3) \[Rho][r] (h'[r]^2 + V[h[r]]) == 0,
h[rmin] == h0,
h'[rmin] == rmin, \[Rho][rmin] == rmin, \[Rho]'[rmin] == 1,
WhenEvent[h[r] < 10^-30, "StopIntegration"]};
pf = ParametricNDSolveValue[sys, {h, \[Rho]}, {r, rmin, 500}, {h0},
Method -> {"StiffnessSwitching"}, MaxSteps -> 10^6,
PrecisionGoal -> 10, AccuracyGoal -> 10, "MaxStepSize" -> 0.001]
CheckSolutionQuality[h0_?NumericQ] :=
Module[{sol, hsol, rmaxActual, testPoints, derivatives},
sol = Quiet@pf[h0];
hsol = sol[[1]];
rmaxActual = hsol["Domain"][[1, 2]];
If[rmaxActual >= 500 - 1,
Return[{"IntegrationFailed", h0, hsol, sol[[2]]}]];
If[hsol[rmaxActual] > 10^-3,
Return[{"FailAtRmax", h0, hsol, sol[[2]]}]];
testPoints = Subdivide[RH + 0.01, rmaxActual, 200];
derivatives = hsol' /@ testPoints;
Which[AllTrue[derivatives, # < -10^-20 &],
Return[{"StrictlyDecreasing", h0, hsol, sol[[2]]}],
AllTrue[derivatives, # <= 0 &],
Return[{"NonStrictDecreasing", h0, hsol, sol[[2]]}], True,
Return[{"NotMonotonic", h0, hsol, sol[[2]]}]]]
(*h0Start=80;(*找适合边界条件h[rmax]趋于0的初始值,因为按物理情景来说他应该比较靠近h0=227这个方向*)
h0Step=1;
maxAttempts=10;*)h0Start = 0.80621; h0Step = 0.00001; maxAttempts = 10;
strictMode = False;
h0failed = h0Start;
result = Catch[Do[currentH0 = h0Start + k*h0Step;
status = CheckSolutionQuality[currentH0];
(*记录最后一次失败的 h0*)
If[status[[1]] =!= "StrictlyDecreasing" &&
status[[1]] =!= "NonStrictDecreasing", h0failed = currentH0;];
Which[
status[[1]] ==
"StrictlyDecreasing" || (status[[1]] ==
"NonStrictDecreasing" && ! strictMode),
Throw[{"Success", currentH0, status[[1]]}],
status[[1]] == "IntegrationFailed",
Print["警告: h0=", currentH0, " 积分失败,尝试调整步长"];, True,
Print["尝试 h0=", currentH0, " 失败: ", status[[1]]];
solFailed = Quiet@pf[currentH0];
hSolFailed = solFailed[[1]];
rmaxFailed = hSolFailed["Domain"][[1, 2]];
If[rmaxFailed + 0.1 <= 100,
Print[" rmax 的值: ", rmaxFailed, " 解在 rmax 处的值: ",
hSolFailed[rmaxFailed], "解在 rmax+0.1 处的值: ",
hSolFailed[rmaxFailed + 0.1]],
Print["警告: rmax+0.1 超出范围,无法计算"]];], {k, 0, maxAttempts}];
{"Failed", "超过最大尝试次数"}];
(*结果处理与可视化*)
If[result[[1]] === "Final Success" || result[[1]] === "Success",
h0opt = result[[2]];
{hSolution, \[Rho]Solution} = pf[h0opt];
rmax = hSolution["Domain"][[1, 2]];
Print["========================================"];
Print["成功找到解!"];
Print["- 最佳 h0 = ", h0opt];
Print["- rmax = ", rmax];
Print["- 最终 h(rmax) = ", hSolution[rmax]];
Print["- 单调性模式: ", result[[3]]];
Print["- 最小h值: ", NMinimize[{hSolution[r], 10^-3 <= r <= rmax}, r]];
(*绘制成功的解*)
Grid[{{Plot[hSolution[r], {r, RH + 10^-6, rmax},
PlotLabel -> "场分布 h(r)", ImageSize -> 300, PlotRange -> All],
Plot[hSolution'[r], {r, RH + 10^-6, rmax},
PlotLabel -> "导数 h'(r)", ImageSize -> 300,
PlotRange -> All]}, {Plot[\[Rho]Solution[r], {r, RH + 10^-6,
rmax}, PlotLabel -> "质量分布 \[Rho](r)", ImageSize -> 300,
PlotRange -> All], SpanFromLeft}}, Frame -> All],
Print["========================================"];
Print["未能在 ", maxAttempts, " 次尝试内找到有效解"];
Print["最后尝试的 h0 = ", h0failed];
Print["失败原因: ", result[[2]]];
Print["解在rmax+1处的值: ", hSolFailed[rmaxFailed + 0.1]];
solFailed = Quiet@pf[h0failed];
hSolFailed = Quiet@pf[h0failed][[1]];
\[Rho]SolFailed = solFailed[[2]];
rmaxFailed = hSolFailed["Domain"][[1, 2]];
(*绘制失败的解*)
Grid[{{Plot[hSolFailed[r], {r, RH + 10^-6, rmaxFailed},
PlotLabel -> "失败解: 场分布 h(r)", ImageSize -> 300,
PlotRange -> All],
Plot[hSolFailed'[r], {r, RH + 10^-6, rmaxFailed},
PlotLabel -> "失败解: 导数 h'(r)", ImageSize -> 300,
PlotRange -> All]}, {Plot[\[Rho]SolFailed[r], {r, RH + 10^-6,
rmaxFailed}, PlotLabel -> "失败解: \[Rho](r)", ImageSize -> 300,
PlotRange -> All], SpanFromLeft}}, Frame -> All]]
(*1. 采样数据点*)numSamples = 1000;
rSamples = Subdivide[RH + 10^-6, rmax, numSamples];
hSamples = hSolution /@ rSamples;
(*2. 定义拟合模型*)
fitModel = a0 + a1 r + a2 r^2 + a3 r^3 + a4 r^4 + a5 r^5;
(*3. 进行拟合,得到参数*)
fitResult =
FindFit[Transpose[{rSamples, hSamples}],
fitModel, {a0, a1, a2, a3, a4, a5}, r];
(*4. 拟合后的完整函数*)
fittedFunction[r_] = fitModel /. fitResult;
(*5. 输出拟合后的最终表达式*)
Print["拟合后的函数是:"];
fittedFunctionExpanded = Expand[fittedFunction[r]];
fittedFunctionExpanded
然后带入k1 = 1; V[h_] := 0.1 + 0.175 h^2 - 0.45 h^3 + h^4/4;
dV[h_] = D[V[h], h];
eq = {(h''[r] + (3 \[Rho]'[r]/\[Rho][r] h'[r] - dV[h[r]])) \[Rho][r] ==
0 // Expand,
drho'[r] + k1*\[Rho][r]/3 (h'[r]^2 + V[h[r]]) == 0, \[Rho]'[r] ==
drho[r]};
rmin = 10^-3; rmax = 16;
tst = NDSolveValue[{eq, {(*h[rmin]==h0,*)h[rmax] == 0(*h'[rmin]==
10^-2*), \[Rho][rmin] == rmin, drho[rmin] == 1}}, {\[Rho], drho,
h}, {r, rmin, rmax},
Method -> {"FiniteElement",
"MeshOptions" -> MaxCellMeasure -> 0.05},
InitialSeeding -> {\[Rho][r] == 0,
h[r] == 0.7926548794412709` + 0.028585400076749846` r -
0.0205050
18255621323
` r^2 + 0.0009091612898668904` r^3 +
0.00004732707151881457` r^4 - 2.6663192139792102`*^-6 r^5,
drho[r] == 1}]; // AbsoluteTiming得到的Plot[tst[[3]][r], {r, 0, rmax}] 才会正确,但Plot[tst[[1]][r], {r, 0, rmax}]不正确,把\[Rho]的结果拟合带入会出现报错FindRoot::dfmin: 已达到最小阻尼因子 1/10000.;NDSolveValue::fempsf: PDESolve 无法找到解.,直接猜测的InitialSeeding难度是很大的。
2025年04月29日 02点04分 5
1