我试图通过在python 2.7中使用scipy.optimize.fsolve
来找到方程组的解决方案。目标是计算化学系统的平衡浓度。由于问题的性质,一些常数非常小。现在,对于某些组合,我确实得到了一个合适的解对于某些参数,我找不到解决方案。要么解决方案是否定的,从物理角度来看这是不合理的,或者fsolve产生:
ier = 3,' xtol = 0.000000太小,无法在近似解决方案中进一步改进。')
ier = 4,'迭代没有取得良好的进展,正如前五次雅可比评估的改进所测量的那样。')
ier = 5,'迭代没有取得良好进展,通过最近十次迭代的改进来衡量。')
在我看来,根据我的研究,未能找到方程式系统的正确解决方案与数据类型float.64
的关联性不够准确。正如一位朋友所指出的那样,系统的调节条件并不完善,参数差异很大。
所以我尝试使用mpfr
模块提供的gmpy2
类型的fsolve但导致以下错误:
TypeError:根据规则&#39; safe&#39; <无法将数组数据从dtype(&#39; O&#39;)转换为dtype(&#39; float64&#39;) / p>
现在这是一个带参数的小例子,如果随机化的起始参数适合恰好,则会导致解决方案。但是,如果选择常数C_HCL为1e-4或更大,那么我永远找不到合适的解决方案。
from numpy import *
from scipy.optimize import *
K_1 = 1e-8
K_2 = 1e-8
K_W = 1e-30
C_HCL = 1e-11
C_NAOH = K_W/C_HCL
C_HL = 1e-6
if C_HCL-C_NAOH > 0:
Saeure_Base = C_HCL-C_NAOH+sqrt(K_W)
OH_init = K_W/(Saeure_Base)
elif C_HCL-C_NAOH < 0:
OH_init = C_NAOH-C_HCL+sqrt(K_W)
Saeure_Base = K_W/OH_init
# some randomized start parameters
G1 = random.uniform(0, 2)*Saeure_Base
G2 = random.uniform(0, 2)*OH_init
G3 = random.uniform(1, 2)*C_HL*(sqrt(K_W))/(Saeure_Base+OH_init)
G4 = random.uniform(0.1, 1)*(C_HL - G3)/2
G5 = C_HL - G3 - G4
zGuess = array([G1,G2,G3,G4,G5])
#equation system / 5 variables --> H3O, OH, HL, H2L, L
def myFunction(z):
H3O = z[0]
OH = z[1]
HL = z[2]
H2L = z[3]
L = z[4]
F = empty((5))
F[0] = H3O*L/HL - K_1
F[1] = OH*H2L/HL - K_2
F[2] = K_W - OH*H3O
F[3] = C_HL - HL - H2L - L
F[4] = OH+L+C_HCL-H2L-H3O-C_NAOH
return F
z = fsolve(myFunction,zGuess, maxfev=10000, xtol=1e-15, full_output=1,factor=0.1)
print z
所以问题是。这个问题是基于float.64和。的精度 如果是,(如何)可以用python解决?是解决方法吗?我是否需要更改fsolve函数以使其接受不同的数据类型?
答案 0 :(得分:4)
问题的根源是理论上的或数字的。
scipy.optimize.fsolve
函数基于MINPACK Fortran解算器(http://www.netlib.org/minpack/)。该求解器使用Newton-Raphson优化算法来提供解决方案。
使用此算法时,有关于函数平滑度的基本假设。例如,解点x
处的雅可比矩阵应该是可逆的。你更关心的是吸引力的盆地。
为了收敛,算法的起点需要接近实际解,即在吸引的盆地中。对于凸函数,总是满足这个条件,但是很容易找到这个算法表现不好的一些函数。您的功能就是其中之一,因为您只有一小部分输入参数。
要解决此问题,您应该更改起点。对于具有多个解决方案的函数,此起点也非常重要:来自维基百科文章的this picture向您显示根据起点找到的解决方案(五种解决方案的五种颜色);所以你应该小心你的解决方案,并实际检查&#34;物理&#34;解决方案的各个方面。
对于数值方面,Newton-Raphson算法需要具有雅可比矩阵的值(导数矩阵)。如果未将其提供给MINPACK求解器,则使用有限差分公式估计雅可比。需要提供有限差分公式的扰动步骤epsfcn=None
,None
仅在提供fprime
的情况下作为默认值(不需要jacobian估计)在这种情况下)。所以首先你应该加入它。你也可以通过手工推导你的函数来直接指定jacobian。
但是,步长的最小值将是机器精度,也称为machine epsilon。对于您的问题,您有非常小的输入值,这可能是一个问题。我建议将它们中的每一个乘以相同的值(如10 ^ 6),它相当于单位的变化,但会避免将错误和机器精度问题四舍五入。
当您查看您提供的参数xtol=1e-15
时,此问题也很重要。在您的错误消息中,它提供xtol=0.000000
,因为它低于机器精度,无法考虑。另外,如果您查看行F[2] = K_W - OH*H3O
,在给定机器精度的情况下,K_W
是1e-15
还是1e-30
并不重要。与机器精度相比,0
是这种情况的解决方案。要避免这个问题,只需将所有内容乘以更大的值即可。
总结一下: