Matrix 求解大型耦合微分方程组
我有一个耦合的常微分方程组Matrix 求解大型耦合微分方程组,matrix,scipy,linear-algebra,sparse-matrix,numerical-methods,Matrix,Scipy,Linear Algebra,Sparse Matrix,Numerical Methods,我有一个耦合的常微分方程组 dx/dt=(A+Cúd(t)*B)*x, 其中A和B为常数矩阵,C_d为对角线系数矩阵,根据积分变量的当前值平滑变化 方阵A和B由较小的60*60上三角矩阵或零矩阵组成。整个系统的尺寸约为2500*2500。A和B是稀疏的,约有10%的非零元素。对角线元素为负或零。主要的(物理)约束是x(t)的元素在积分过程中不允许变为负值 目前,我使用了一个“天真”的步骤求解器 x_(i+1)=A*x_i*dt_i+B*(C_d(t_i)*x_i)*dt_i+x_i 或者在CPU
dx/dt=(A+Cúd(t)*B)*x
,其中A和B为常数矩阵,C_d为对角线系数矩阵,根据积分变量的当前值平滑变化 方阵A和B由较小的60*60上三角矩阵或零矩阵组成。整个系统的尺寸约为2500*2500。A和B是稀疏的,约有10%的非零元素。对角线元素为负或零。主要的(物理)约束是x(t)的元素在积分过程中不允许变为负值 目前,我使用了一个“天真”的步骤求解器
x_(i+1)=A*x_i*dt_i+B*(C_d(t_i)*x_i)*dt_i+x_i
或者在CPU/GPU版本中
def solve_CPU(nsteps, dt, c_d, x):
for step in xrange(nsteps):
x += (A.dot(x) + B.dot(x * c_d[step])) * dt[step]
def solve_GPU(m, n, nsteps, dt, c_d, cu_curr_x, cu_delta_x, cu_A, cu_B):
for step in xrange(nsteps):
cubl.gemv(trans='T', m=m, n=n, alpha=1.0, A=cu_A,
x=cu_curr_x, beta=0.0, y=cu_delta_x)
cubl.gemv(trans='T', m=m, n=n, alpha=c_d[step], A=cu_B,
x=cu_curr_x, beta=1.0, y=cu_delta_x)
cubl.axpy(alpha=dt[step], x=cu_delta_x, y=cu_curr_x)
并利用一个特性,即步长dt_i
,这可以通过一种方法计算出来,即在积分过程中x的元素总是>=0。根据近似量和设置,积分步数在25k和10M之间变化
我尝试了几种方法来优化通用硬件的性能:
- (未知)当使用ODEPACK的VODE解算器时,我不知道如何表达x>=0约束
- 使用英特尔MKL的(最慢)密集BLAS 2点积
- 在NVIDIA GPU上使用单精度立方体的(中等)密集BLAS
- (最快)使用CSR/CSC格式的SCIPY稀疏模块
有没有更优雅或更好的方法来解决这样的线性代数任务?步长dt_i是否比函数C_d(t_i)的变化率小得多?如果是的话,一个更复杂的集成方案,它包含了约束,并且可以使用更长的时间步长。第二个问题:为什么不在计算后将任何负值剪裁为零?如果由于数值不精确而出现负值,并且您通过事先选择时间步长来解决此问题,结果将不会告诉您解决方案接近零的程度(因为数值不精确更大)。非常感谢向我指出函数C_d(t_i)的性质。我还没有尝试去寻找它的特性。它是日志中的一条线,因此不会缓慢变化。您的第二个问题:我尝试在VODE的解算器函数中对x向量进行封顶。结果是速度变慢了。我猜是因为VODE的错误估计程序被搞糊涂了?或者:如果你的意思是“计算完成后”=“计算完成后”,那么问题是方程是耦合的,本征模是重的,你的方程是线性的,因此,我并没有立即发现一个数学上的原因来解释为什么避免负的
x
值很重要——方程是耦合的,等等,这与解的准确性无关。您可以尝试在完成积分器时对值进行封顶(这样就不会弄乱被积函数的平滑度),然后将精度与其他方法进行比较。另外,如果你对能量守恒或其他物理量感兴趣,研究辛或变分积分器可能会很有用,它们具有精确的守恒性质。我试着忽略负值和解发散。该系统是粒子产生和衰变的级联方程。因此,负值表示负粒子数。因此,如果有更多的粒子衰变,它们就开始创造它们的母亲,这有点奇怪:)我们可以把这个系统看作一个更复杂的捕食者-食饵模型。系统是线性化的,因此选择太大的dt会导致线性化范围失效。解耦系统的自治解将是指数的,它永远不会变为零。我来看看你建议的积分类型。如果你能在问题形成的论文中添加引文,那可能会有所帮助。