Рассмотрим случай F(y)=y
. Тогда легко увидеть, что базисными решениями этого линейного ОДУ являются sin(k*x)/x
и cos(kx/x)
. Аналогично для F(y)=-y
получается sinh(k*x)/x
и cosh(k*x)/x
. Это означает, что большинство решений имеют особенность при x=0
. С такой особенностью практически невозможно справиться со стандартными решениями ODE. Нужно помочь решателю в сингулярности, обычная процедура применяется снова на некотором расстоянии от сингулярности.
Что вы можете сделать, это проанализировать ситуацию в x=0
и немного отойти. Вы получаете через предел разностных отношений
y''(0) + 2*y''(0) + k^2*F(y(0)) = 0
, который позволяет вычислить квадратичный c полином Тейлора. Таким образом, решите задачу на [a, 1]
с помощью решателя ODE, используя продолжение к сингулярности y(x)=y(0)-k**2/6*F(y(0))*x**2
на [0,a]
.
Граничное условие на x=a
проще всего установить sh с обработкой y0=y(0)
в качестве параметра. Функции ODE и B C тогда равны
def ode(x,y,y0): return [ y[1], -2*y[1]/x - k**2*F(y[0]) ]
def bc(ya,yb,y0): y2 = -k**2*F(y0)/6; return [ ya[0] - y0 - y2*a**2, ya[1] - 2*y2*a, yb[0]-1 ]
В случаях, обсуждаемых в вопросе, это дает
a = 1e-2
def F(y): return -y
for k in [0.01, 5]:
res = solve_bvp(ode, bc, [a,1], [[1,1], [0,0]], p=[1], tol=1e-5)
print(f'k={k}: {res.message}, y0={res.p[0]}, theory: {k/np.sinh(k)}')
if res.success:
y0 = res.p[0]
x = np.linspace(a,1,61);
plt.plot(x, res.sol(x)[0])
plt.plot([0], [y0],'o', res.x, res.y[0],'+', ms=4)
plt.title(f'k={k}'); plt.grid(); plt.show()
с результатом
k = 0,01: алгоритм сходится с требуемой точностью., y0 = 0,9999933335277726, теория: 0,99999833335277757
k = 5: алгоритм сходится к требуемая точность., y0 = 0,06738256929427147, теория: 0,06738252915294544