为什么这段 scipy.root 代码无法收敛?

huangapple go评论67阅读模式
英文:

Why is this scipy.root code not converging?

问题

我正在运行一个测试问题,以设置更大的问题。通过有限差分法解决简单的非稳态热方程:

import matplotlib.pyplot as plt
import numpy as np
import sympy as sp
from scipy.optimize import fsolve
from scipy import optimize
import pandas as pd
from numba import njit

t_max = 25
x_max = 1
N_points_1 = 61
N_points_2 = 11
dt = t_max / (N_points_1 - 1)
dx = x_max / (N_points_2 - 1)
N_variables = N_points_1 * N_points_2
alpha = 0.01
T_x_0 = 60
T_x_L = 25
T_t_0 = 25

@njit
def EDP(v):
    T_N = np.ones((N_points_1, N_points_2))

    # 变量
    k = 0
    for i in range(N_points_1):
        for j in range(N_points_2):
            T_N[i, j] = v[k]
            k = k + 1

    # 模型
    sys = []
    ## 边界条件 x = 0
    for i in range(N_points_1):
        BC1 = T_N[i, 0] - T_x_0
        sys.append(BC1)

    ## 边界条件 x = L
    for i in range(N_points_1):
        BC2 = T_N[i, -1] - T_x_L
        sys.append(BC2)

    ## 初值条件
    for j in range(1, N_points_2 - 1):
        IC1 = T_N[0, j] - T_t_0
        sys.append(IC1)

    ## 能量平衡
    for i in range(N_points_1 - 1):
        for j in range(1, N_points_2 - 1):
            EB = alpha * (T_N[i, j + 1] - 2 * T_N[i, j] + T_N[i, j - 1]) / dx**2 - (T_N[i + 1, j] - T_N[i, j]) / dt
            sys.append(EB)

    sys = np.array(sys)

    return sys

initial_guess = np.linspace(25, 60, N_variables)
function_compile = EDP(initial_guess)

我测试了以下的scipy.root算法:

Solution_T = fsolve(EDP, initial_guess)
Solution_T = optimize.anderson(EDP, initial_guess, verbose=True, maxiter=1000)
Solution_T = optimize.newton_krylov(EDP, initial_guess, verbose=True, maxiter=1000)
Solution_T = optimize.broyden1(EDP, initial_guess, verbose=True, maxiter=1000)
Solution_T = optimize.broyden2(EDP, initial_guess, verbose=True, maxiter=1000)

只有fsolve 收敛(事实上是瞬间),但由于我只是在运行一个更大规模的问题的测试(将包含约50000个变量),fsolve 无法处理那么多变量,而且scipy文档建议使用上面提到的算法,但它们都不收敛。

它们要么发散,目标函数溢出,要么保持在相同的值上不收敛。至于为什么我不使用线性求解器,那是因为我打算稍后输入更复杂的非线性方程。

谢谢。

英文:

I'm running a test problem to set up larger problems. Solving the simple unsteady heat equation via finite differences:

import matplotlib.pyplot as plt
import numpy as np
import sympy as sp
from scipy.optimize import fsolve
from scipy import optimize
import pandas as pd
from numba import njit
t_max = 25
x_max = 1
N_points_1 = 61
N_points_2 = 11
dt = t_max/(N_points_1-1) 
dx = x_max/(N_points_2-1)
N_variables = N_points_1 * N_points_2
alpha = 0.01 
T_x_0 = 60 
T_x_L = 25
T_t_0 = 25
@njit
def EDP (v):
T_N =  np.ones((N_points_1, N_points_2))
#Variables
k=0
for i in range(N_points_1):
for j in range(N_points_2): 
T_N[i,j]=v[k]
k=k+1
#Model
sys = []
##Boundary Condition x = 0
for i in range(N_points_1):
BC1 = T_N[i,0] - T_x_0
sys.append(BC1)
##Boundary Condition x = L
for i in range(N_points_1):
BC2 = T_N[i,-1] - T_x_L
sys.append(BC2)
##Initial Condition
for j in range(1,N_points_2-1):
IC1 = T_N[0,j] - T_t_0
sys.append(IC1)
## Energy Balance 
for i in range(N_points_1-1):
for j in range (1,N_points_2 -1):
EB = alpha*(T_N[i,j+1]-2*T_N[i,j]+T_N[i,j-1])/dx**2 - (T_N[i+1,j]-T_N[i,j])/dt  
sys.append(EB)
sys=np.array(sys)
return sys
initial_guess = np.linspace(25,60,N_variables)        
function_compile = EDP(initial_guess)

I tested the following scipy.root algorithms:

Solution_T = fsolve(EDP,initial_guess)
Solution_T = optimize.anderson(EDP,initial_guess, verbose = True,maxiter = 1000)  
Solution_T = optimize.newton_krylov(EDP,initial_guess,verbose=True,maxiter = 1000)
Solution_T = optimize.broyden1(EDP,initial_guess,verbose=True,maxiter = 1000)
Solution_T = optimize.broyden2(EDP,initial_guess,verbose=True,maxiter = 1000)

And ONLY fsolve converges(instantly, in fact) but since i am just running a test for a larger run(which will contain about 50000 variables), fsolve won't be able to handle that and the scipy docs recommends the algorithms mentioned above, but none of them converge.

They either diverge with the objective function overflowing or remain stuck in the same value, not converging. As for why i am not using linear solvers, its because i intend to input more complex non-linear equations later.

Thanks

答案1

得分: 2

在处理数值方程时,通常更好的方式是将其表示为 min(||F(x)||),而不是试图找到 F(x)=0。这两种表达在存在解时是等价的,但如果无法获得精确解,这告诉您可以获得离解最近的是什么。

least_squares 对于您的示例非常有效,并且有一些参数可以调整以在某种程度上改善方法的性能。

sol = optimize.least_squares(EDP, initial_guess)
print(sum(EDP(sol.x)**2))
1.383176178225409e-26
英文:

When it comes to solve numerically equations like this, it is usually better to express it as min(||F(x)||) instead of trying to find F(x)=0 these two formulations are equivalent when a solution exist, but if it is not possible to get an exact solution this tell you what is the closest you can get from a solution.

least_squares works for your example, and it has a few parameters that you can tune to somewhat improve the method performance

sol = optimize.least_squares(EDP, initial_guess)
print(sum(EDP(sol.x)**2))
1.383176178225409e-26

huangapple
  • 本文由 发表于 2023年3月7日 03:43:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/75655166.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定