有关matlab / python转换的建议

时间:2015-11-22 20:07:19

标签: python matlab

我试图将下面的matlab代码翻译成python代码。该代码计算氘分子的对位状态的数值,然后绘制结果。当我尝试将其转换为python时,似乎我陷入了嵌套的for循环中,它计算了一个总和。过去几天我一直在网上搜索但没有成功。

因为它是物理代码我会从代码中提到一些方面。所以首先我们计算分区函数(Z)。之后计算能量,它是ln(Z)对β的偏导数。由此我们可以计算比热(大约)作为能量与温度的导数。

所以matlab代码如下所示:

epsilon = 0.0038*1.60217662*10^-19;
k = 1.38*10^-23;
T = 1:.1:2000;
beta = 1./(k*T);

%partitionfunction
clear Z Zodd;
for i = 1:length(T)  
    clear p;    
    for s = 1:2:31;
        a = 2*s+1;
        b = s^2+s;
        p(s) = 3*a*exp(-b*epsilon*beta(i));
    end
    Zodd(i) = sum(p);
end

%energy
ln_Zodd = log(Zodd); 

for i = 1 : (length(T)-1)
    Epara(i) = -(ln_Zodd(i+1)-ln_Zodd(i))/(beta(i+1)-beta(i));
end

%heat capacity
for i = 1 : (length(T)-2)
    Cpara(i) = (Epara(i+1)-Epara(i))/(T(i+1)-T(i));
end   

%plot
x = k*T/epsilon;
plot(x(1:6000),Cpara(1:6000)/k, 'r');
axis([0 7 0 1.5]);
ylabel('C_v/k');
xlabel('kT/eps');

相应的python代码:

import numpy as np
import matplotlib.pyplot as plt
import math

epsilon=0.0038*1.60217662*10**-19
k = 1.38*10**-23
T = np.arange(1,2000,0.1)
beta = 1/(k*T)

#partitionfunction
for i in np.arange(1,len(T)): 
    for s in np.arange(1,31,2):
    p[s] = 3*(2*s+1)*math.exp(-(s**2+s)*epsilon*beta(i))
    Zodd[i] = sum(p)

#energy
ln_Zodd = math.log(Zodd)

for i in np.arange(1,(len(T) - 1)):
    Epara[i]=- (ln_Zodd(i + 1) - ln_Zodd(i)) / (beta(i + 1) - beta(i))

#heat capacity
for i in np.arange(1,(len(T) - 2)):
    Cpara[i]=(Epara(i + 1) - Epara(i)) / (T(i + 1) - T(i))

#plot
x = k*T/epsilon
plt.plot(x(np.arange(1,6000)),Cpara(np.arange(1,6000)) / k,'r')
plt.axis([0, 7, 0, 1.5]) 
plt.ylabel('C_v/k')
plt.xlabel('kT/eps')   
plt.show()

这应该是计算(近似)此问题的最简单方法,因为分析表达式更复杂。我是python的新手,所以任何建议或更正都会受到赞赏。

1 个答案:

答案 0 :(得分:2)

我同意@rayryeng这个问题是偏离主题的。但是,由于我对matlab,python,理论物理感兴趣,我花了很多时间来查看你的代码。

它有多个语法问题,也有多个语义问题。数组中的[]总是应该访问数组,通常你会尝试使用()。与matlab不同,数组的自然索引从0开始。

这是原始代码的语法和语义修正版本:

import numpy as np
import matplotlib.pyplot as plt
#import math  #use np.* if you have it already imported

epsilon=0.0038*1.60217662*10**-19
k = 1.38*10**-23
T = np.arange(1,2000,0.1)
beta = 1.0/(k*T) #changed to 1.0 for safe measure; redundant

#partitionfunction
svec=np.arange(1,31,2)
p=np.zeros(max(svec)) #added pre-allocation
Zodd=np.zeros(len(T)) #added pre-allocation
for i in np.arange(len(T)): #changed to index Zodd from 0
    for s in svec:  #changed to avoid magic numbers
        p[s-1] = 3*(2*s+1)*np.exp(-(s**2+s)*epsilon*beta[i])   #changed to index p from 0; changed beta(i) to beta[i]; changed to np.exp
    Zodd[i] = sum(p)

#energy
ln_Zodd = np.log(Zodd)  #changed to np.log

Epara=np.zeros(len(T)-2)  #added pre-allocation
for i in np.arange(len(T) - 2): #changed to index Epara from 0
    Epara[i]=- (ln_Zodd[i + 1] - ln_Zodd[i]) / (beta[i + 1] - beta[i])   #changed bunch of () to []

#heat capacity
Cpara=np.zeros(len(T)-3)  #added pre-allocation
for i in np.arange(len(T) - 3): #changed to index Cpara from 0
    Cpara[i]=(Epara[i + 1] - Epara[i]) / (T[i + 1] - T[i])

#plot
x = k*T/epsilon
plt.plot(x[:6000],Cpara[:6000] / k,'r')  #fixed and simplified array indices
plt.axis([0, 7, 0, 1.5])
plt.ylabel('C_v/k')
plt.xlabel('kT/eps')
plt.show()

花时间浏览我所做的评论,他们会在那里指导你。如果问题不明确,请要求澄清:)

但是,这段代码效率很低。特别是你的双循环需要很长时间才能运行(这可能解释了为什么你认为它挂了)。所以我也非常基于numpy

结果如下:

import numpy as np
import scipy.constants as consts
import matplotlib.pyplot as plt

epsilon=0.0038*consts.eV  #changed eV
k = consts.k  #changed
T = np.arange(1,2000,0.1)
beta = 1.0/(k*T) #changed to 1.0 for safe measure; redundant

#partitionfunction
s=np.arange(1,31,2)[:,None]
Zodd = (3*(2*s+1)*np.exp(-(s**2+s)*epsilon*beta)).sum(axis=0)

#energy
ln_Zodd = np.log(Zodd)  #changed to np.log
#Epara = - (ln_Zodd[1:]-ln_Zodd[:-1])/(beta[1:]-beta[:-1])  #manual version
Epara = - np.diff(ln_Zodd)/np.diff(beta)

#heat capacity
Cpara=np.diff(Epara)/np.diff(T)[:-1]

#plot
x = k*T/epsilon
plt.plot(x[:len(Cpara)],Cpara / k,'r')  #fixed and simplified array indices
plt.axis([0, 7, 0, 1.5])
plt.ylabel('C_v/k')
plt.xlabel('kT/eps')
plt.show()

再次,请查看所做的更改。我使用scipy.constants模块将物理常量导入到高精度。我还使用了数组广播,它允许我将双循环转换为沿其中一个维度的矩阵之和(就像你应该在matlab中完成它一样;你原来的matlab代码也远没有效率)。

这是常见的结果:

heat capacity vs T

你可以看到它似乎是正确的:在高温下你得到了Dulong - Petit行为,在T->0我们根据热力学第三定律获得了零限制。热容量呈指数衰减,但这应该是有意义的,因为你的能隙有限。