曲线拟合matplotlib中函数的函数

时间:2017-10-22 18:33:22

标签: matplotlib curve-fitting

我有3个功能:E(能量),P(压力)和H(焓)。

给定数据data.dat包含变量V(音量)和E(能量):

# Volume: V_C_I     Energy: E_C_I
     111.593876   -1.883070511360E+03
     113.087568   -1.883074916825E+03
     114.632273   -1.883078906679E+03
     116.184030   -1.883082373429E+03
     117.743646   -1.883085344696E+03
     119.326853   -1.883087860954E+03
     120.927806   -1.883089938181E+03
     122.538335   -1.883091557526E+03
     124.158641   -1.883092750745E+03
     125.789192   -1.883093540824E+03
     125.790261   -1.883093800747E+03
     127.176327   -1.883094160364E+03
     128.358654   -1.883094017730E+03
     128.542807   -1.883094255789E+03
     129.977279   -1.883094094751E+03
     131.390610   -1.883093689121E+03
     132.812287   -1.883093053342E+03
     134.242765   -1.883092185844E+03
     135.682211   -1.883091101112E+03
     137.130792   -1.883089807766E+03
     138.588565   -1.883088314435E+03

以下脚本执行:

1)curve_fit EV

2)使用P函数

计算def(P)(压力)

3)使用H函数计算def(H)(enthalpy)。 (H = E + PV)。

4)使用拟合曲线执行3个绘图:EPPVHP。< / p>

在绘制拟合曲线时,我使用了以下内容:

例如,对于EV曲线:

plt.plot(V_C_I_lin, E(V_C_I_lin, *popt_C_I)

其中V_C_I_lin是数据点之间的卷空间。

这看起来很好:

enter image description here

同样,对于PV曲线,类似的方案:

plt.plot(V_C_I_lin, P(V_C_I_lin, *popt_C_I), color='grey', label='E fit Data' )

产生所需的结果:

enter image description here

每个数据点的压力都由脚本保存在文件./E_V_P_H__C_I.dat中。

但是,对于HP曲线,类似的方案:

plt.plot(xp_C_I, H(V_C_I_lin, *popt_C_I), color='grey', label='H fit Data' )

其中xp_C_I是压力的空间,不能产生正确的拟合:

enter image description here

为什么在第三种情况下会发生这种情况?

代码:

import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
import sys
import os

# Intial candidates for fit
E0_init = -941.510817926696
V0_init = 63.54960592453
B0_init = 76.3746233515232
B0_prime_init = 4.05340727164527

def E(V, E0, V0, B0, B0_prime):
        return  E0+ (2.293710449E+17)*(1E-21)*( (9.0/16.0)*(V0*B0) * (  (((V0/V)**(2.0/3.0)-1.0)**3.0)*B0_prime  + ((V0/V)**(2.0/3.0)-1)**2  *  (6.0-4.0*(V0/V)**(2.0/3.0))  ))

def P(V, E0, V0, B0, B0_prime):
    f0=(3.0/2.0)*B0
    f1=((V0/V)**(7.0/3.0))-((V0/V)**(5.0/3.0))
    f2=((V0/V)**(2.0/3.0))-1
    pressure= f0*f1*(1+(3.0/4.0)*(B0_prime-4)*f2)
    return pressure

def H(V, E0, V0, B0, B0_prime):
    return E(V, E0, V0, B0, B0_prime) + P(V, E0, V0, B0, B0_prime) * V

# Data (Red triangles):
V_not_p_f_unit_C_I, E_not_p_f_unit_C_I = np.loadtxt('data.dat', skiprows = 1).T

# A minor conversion of the data:
nFU_C_I = 2.0
nFU_C_II = 4.0
E_C_I = E_not_p_f_unit_C_I/nFU_C_I
V_C_I = V_not_p_f_unit_C_I/nFU_C_I

######
# Fitting and obtaining the parameters:
init_vals = [E0_init, V0_init, B0_init, B0_prime_init]
popt_C_I, pcov_C_I = curve_fit(E, V_C_I, E_C_I, p0=init_vals)

# Calculation of P:
pressures_per_F_unit_C_I = P(V_C_I, *popt_C_I)

# Calculation of H:  H = E + PV
H_C_I = E_C_I + pressures_per_F_unit_C_I * V_C_I

# We save E, P and H into a file:
output_array_3 = np.vstack((E_C_I, V_C_I, pressures_per_F_unit_C_I, H_C_I)).T
np.savetxt('E_V_P_H__C_I.dat', output_array_3, header="Energy / FU (a.u.) \t Volume / FU (A^3) \t Pressure / F.U. (GPa) \t Enthalpy (a.u.)", fmt="%0.13f")


EnergyCI, VolumeCI, PressureCI, EnthalpyCI  = np.loadtxt('./E_V_P_H__C_I.dat', skiprows = 1).T

# Plotting E vs V:
fig = plt.figure()
V_C_I_lin = np.linspace(VolumeCI[0], VolumeCI[-1], 100)

# Linspace for plotting the fitting curve:
V_C_I_lin = np.linspace(VolumeCI[0], VolumeCI[-1], 100)

p2, = plt.plot(V_C_I_lin, E(V_C_I_lin, *popt_C_I), color='grey', label='E fit Data' )

# Plotting the scattered points: 
p1 = plt.scatter(VolumeCI, EnergyCI, color='red', marker="^", label='Data', s=100)

fontP = FontProperties()
fontP.set_size('small')
plt.legend((p1, p2 ), ("Data", 'E fit Data' ), prop=fontP)
plt.xlabel('V / Formula unit (Angstrom$^{3}$)')
plt.ylabel('E / Formula unit (a.u.)')
plt.ticklabel_format(useOffset=False)
plt.savefig('E_vs_V.pdf', bbox_inches='tight')

# Plotting P vs V: 
fig = plt.figure()

# Linspace for plotting the fitting curve:
xp_C_I = np.linspace(PressureCI[-1], PressureCI[0], 100)

# Plotting the fitting curves:
p2, = plt.plot(V_C_I_lin, P(V_C_I_lin, *popt_C_I), color='grey', label='E fit Data' )

# Plotting the scattered points: 
p1 = plt.scatter(VolumeCI, PressureCI, color='red', marker="^", label='Data', s=100)

fontP = FontProperties()
fontP.set_size('small')
plt.legend((p1, p2), ("Data", "E fit Data"), prop=fontP)
plt.xlabel('V / Formula unit (Angstrom$^{3}$)')
plt.ylabel('P (GPa)')
plt.ticklabel_format(useOffset=False)
plt.savefig('P_vs_V.pdf', bbox_inches='tight')

# Plotting H vs P:
fig = plt.figure()

xp_C_I = np.linspace(PressureCI[0], PressureCI[-1], 100)
V_C_I_lin = np.linspace(VolumeCI[0], VolumeCI[-1], 100)

# Linspace for plotting the fitting curve:
V_C_I_lin = np.linspace(VolumeCI[0], VolumeCI[-1], 100)

p2, = plt.plot(xp_C_I, H(V_C_I_lin, *popt_C_I), color='grey', label='H fit Data' )

# Plotting the scattered points: 
p1 = plt.scatter(pressures_per_F_unit_C_I, H_C_I, color='red', marker="^", label='Data', s=100)

fontP = FontProperties()
fontP.set_size('small')
plt.legend((p1, p2 ), ("Data", 'H fit Data' ), prop=fontP)
plt.xlabel('P / Formula unit (GPa)')
plt.ylabel('H / Formula unit (a.u.)')
plt.ticklabel_format(useOffset=False)
plt.savefig('H_vs_V.pdf', bbox_inches='tight')
plt.show()

1 个答案:

答案 0 :(得分:3)

你不能只绘制H(V)与一些完全不相关的压力xp_C_I

plt.plot(xp_C_I, H(V_C_I_lin, *popt_C_I), )

相反,您需要针对H(V)绘制P(V),以便将相同的V值用于压力和焓:

plt.plot(P(V_C_I_lin, *popt_C_I), H(V_C_I_lin, *popt_C_I), )