此代码包含3个嵌套循环,在Matlab中需要30秒才能运行,而在Python中则需要5分钟以上。任何有关如何使Python更快的建议都受到高度赞赏!该代码使用Newmark数值解决方案创建响应谱。 我知道矢量化将解决挑战,但我找不到实现它的空间。
from numba import jit
import numpy as np
import matplotlib.pyplot as plt
import scipy as sp
import timeit
start = timeit.default_timer()
sig=np.loadtxt('LXR1N.txt')
t=sig[:,0]
ag=0.01*sig[:,1]
h=t[1]-t[0]
f=-ag
alfa=1/6; delta=0.5
alfa0=1/(alfa*h**2)
alfa1=delta/(alfa*h)
alfa2=1/(alfa*h)
alfa3=1/(2*alfa)-1
alfa4=delta/alfa-1
alfa5= h/2*(delta/alfa-2)
alfa6= h*(1-delta)
alfa7= delta*h;
D=np.array([0.01,0.04,0.06,0.1])
T=np.zeros(1198,float)
d=np.zeros([len(t)])
len(d)
v=np.zeros([len(t)])
a=np.zeros([len(t)])
fb=np.zeros([len(t)-1])
sd=np.empty((len(D),len(T)))
sa=np.empty((len(D),len(T)))
sv=np.empty((len(D),len(T)))
aex=np.empty((len(D),len(T)))
vex=np.empty((len(D),len(T)))
for i in range(0,len(T)):
T[i]=0.015+0.005*i
i=None
s=-1
for q in D:
s+=1
for i in range(0,len(T)):
omega=2*np.pi/T[i]
c=2*q*omega
k=omega**2
kb=k+alfa0+alfa1*c
d[0]=0
v[0]=0
a[0]=0
for j in range(0,len(t)-1):
fb[j]=f[j]+alfa0*d[j]+alfa2*v[j]+alfa3*a[j]+c*alfa1*d[j]+c*alfa4*v[j]+c*alfa5*a[j]
d[j+1]=fb[j]/kb
a[j+1]=alfa0*d[j+1]-alfa0*d[j]-alfa2*v[j]-alfa3*a[j]
v[j+1]=v[j]+alfa6*a[j]+alfa7*a[j+1]
atot=a+ag
atot1=-omega**2*d-2*q*omega*v
sd[s,i]=max(abs(d))
sa[s,i]=omega**2*sd[s,i]
sv[s,i]=omega*sd[s,i]
aex[s,i]=max(abs(atot))
vex[s,i]=max(abs(v))
del i
del j
plt.figure(1,figsize=(10, 4))
for i in range(sd.shape[0]):
plt.plot(T,sd[i,:],label=str(D[i]*100)+"%")
plt.xlabel("Period [s]")
plt.ylabel("Sd [m]")
plt.xlim([0,6])
plt.ylim([0,0.6])
plt.legend()
plt.savefig('Sd.jpg')
plt.show()
plt.figure(2,figsize=(6, 3))
for j in range(sa.shape[0]):
plt.plot(T,1/9.81*sa[j,:],label=str(D[j]*100)+"%")
plt.xlabel("Period [s]")
plt.ylabel("Sa [g]")
plt.xlim([0,6])
plt.ylim([0,2.5])
plt.legend()
plt.savefig('Sa.png')
plt.show()
stop = timeit.default_timer()
execution_time = stop - start
print("Program Executed in: ",execution_time, 'seconds')
答案 0 :(得分:0)
您是否尝试过分析?它应该能够告诉您时间成本在哪里。尝试使用cProfile模块,然后使用snakeViz进行可视化。分析完代码后,您可以根据IO绑定或CPU绑定来优化某些部分。
1个示例可能会用迭代器替换循环。即
for i in range(0,len(T)):
T[i]=0.015+0.005*i
到
T = [0.015+0.005*i for i in range(len(T))]
使用time.time()为len(T)= 10000计时,在我的PC上,第二个代码的运行速度加快了0.0009秒。
您可能还想看看多线程或多处理解决方案。通常,这会使代码更加复杂,但将允许python使用更多可用的处理能力。如果受IO限制,请使用多线程;如果受CPU限制,请使用多处理。
尽管没有概要分析和/或不知道数据集的大小,但是很难提出任何可以保证性能提高的更改。
PS。请查看有关Python多处理和线程的文档。
答案 1 :(得分:0)
对代码进行的微小更改也不应在纯Python代码中使用,例如np.zeros([len(t)])
,仅使用Numpy函数的函数部分很容易使用Numba进行编译。
hpaulj已经在注释中解释说,在这种情况下,Matlab的性能优势与jit编译有关。有一些限制(仅支持大多数Numpy函数),这在Python中也很容易做到。
实施
import numba as nb
import numpy as np
@nb.njit(error_model="numpy")
def func_nb(sig):
t=sig[:,0]
ag=0.01*sig[:,1]
h=t[1]-t[0]
f=-ag
alfa=1/6; delta=0.5
alfa0=1/(alfa*h**2)
alfa1=delta/(alfa*h)
alfa2=1/(alfa*h)
alfa3=1/(2*alfa)-1
alfa4=delta/alfa-1
alfa5= h/2*(delta/alfa-2)
alfa6= h*(1-delta)
alfa7= delta*h
D=np.array([0.01,0.04,0.06,0.1])
T=np.zeros(1198)
d=np.zeros(len(t))
v=np.zeros(len(t))
a=np.zeros(len(t))
fb=np.zeros((len(t)-1))
sd=np.empty((len(D),len(T)))
sa=np.empty((len(D),len(T)))
sv=np.empty((len(D),len(T)))
aex=np.empty((len(D),len(T)))
vex=np.empty((len(D),len(T)))
for i in range(0,len(T)):
T[i]=0.015+0.005*i
for s in range(D.shape[0]):
q=D[s]
for i in range(0,len(T)):
omega=2*np.pi/T[i]
c=2*q*omega
k=omega**2
kb=k+alfa0+alfa1*c
d[0]=0
v[0]=0
a[0]=0
for j in range(0,len(t)-1):
fb[j]=f[j]+alfa0*d[j]+alfa2*v[j]+alfa3*a[j]+c*alfa1*d[j]+c*alfa4*v[j]+c*alfa5*a[j]
d[j+1]=fb[j]/kb
a[j+1]=alfa0*d[j+1]-alfa0*d[j]-alfa2*v[j]-alfa3*a[j]
v[j+1]=v[j]+alfa6*a[j]+alfa7*a[j+1]
atot=a+ag
atot1=-omega**2*d-2*q*omega*v
sd[s,i]=np.max(np.abs(d))
sa[s,i]=omega**2*sd[s,i]
sv[s,i]=omega*sd[s,i]
aex[s,i]=np.max(np.abs(atot))
vex[s,i]=np.max(np.abs(v))
return sd,sa,sv,aex,vex
时间
sig=np.loadtxt("LXR1N.txt")
%timeit sd,sa,sv,aex,vex=func(sig)
#1.33 s ± 4.89 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
#I simply don't want to wait for multiple runs
import time
t1=time.time()
sd,sa,sv,aex,vex=orig()
print(time.time()-t1)
#229.00757384300232