我正在将用Octave / Matlab编写的二维CFD代码移植到fortran。域是周期性的,因此该方案基于FT。以下矩阵,'laplacian':
0 -1 -4 -9 -4 -1
-1 -2 -5 -10 -5 -2
-4 -5 -8 -13 -8 -5
-9 -10 -13 -18 -13 -10
-4 -5 -8 -13 -8 -5
-1 -2 -5 -10 -5 -2
代表6乘6网格上FT的拉普拉斯算子。我想要逆矩阵,即使拉普拉斯算子是奇异的。在matlab / octave中,'inv(laplacian)'返回所有'Inf',但是'1./laplacian'返回正确的答案(尽管是(1,1)元素,返回为Inf,必须设置为零)。
问题是如何使用LAPACK翻译第二个表单。我通常的矩阵求逆序列'DGETRF / DGETRI'失败,信息= 4,毫不奇怪。还有其他二十个DxxTRF。有谁知道什么可能有机会做Octave的工作?
答案 0 :(得分:2)
如果你正在做我认为你的事情,那么你想要用不同的系数乘以傅立叶变换的不同波数,这些系数是从拉普拉斯算子的特征值导出的。
像
这样的东西lambda(kx, ky, kz) = (kx**2 + ky**2 + kz**2)
注意“矩阵”中的1,4和9。它们是这些正方形kx**2
。
这不是矩阵求逆,实际上只是将1.0除以以表格形式写入的数字。该表看起来像一个矩阵,因为您的代码是2D,因此您只有lambda(kx, ky)
。
拉普拉斯算子的整个实际矩阵将非常大(N倍N,其中N = nx*ny
在2D中,N = nx*ny*nz
在3D中)并且将具有lambda
s在对角线上,其他地方都是零。逆矩阵在对角线上具有1./labda
s。所以你的操作在某种意义上是矩阵求逆,但与你想的不同。
你做的是
FT(kx,ky,kz) = FT(kx,ky,kz) / (kx**2 + ky**2 + kz**2)
也可以写成
FT = FT * inv_laplacian
,其中
inv_laplacian = 1. / laplacian
其中laplacian
是系数(特征值)数组。
这不是矩阵求逆,它只是将数字除以1.0。
现在,用0特征值做什么?如果你没有启用浮点异常捕获,我建议你不要启用它们,那么你只需执行:
FT = FT * inv_laplacian
因为inv_laplacian(0,0,0)
为0,所以FT(0,0,0)除以0并且未定义(NaN或类似)。您可以将其设置为您想要的任何内容。 FT(0,0,0)
的含义是你的字段的平均值,它是任意的。只做
FT(0,0,0) = 0 !or any number you want
就是这样。
BTW我在现实世界的科学代码中看到了极端的做法,例如:
for i =0, nkx-1
for j =0, nkx-1
for k =0, nkx-1
FT(i, j, k) = FT(i, j, k) / (cos(i*ax) + cos(j*ay) + cos(k*az)
end
end
end
需要AGES来计算。它与你的情况非常相似,你的特征值不是余弦而是正方形。
关键是系数在时间上是恒定的并且是可分离的。
可以计算一次:
lambdax(i) = i**2 !or cos(ax*i)
lambday(i) = j**2 !or cos(ay*j)
lambdaz(i) = k**2 !or cos(az*k)
然后再做
FT(kx,ky,kz) = FT(kx,ky,kz) / (lambdax(kx) + lambday(ky) + lambdaz(kz))
您可以查看我的快速泊松求解器PoisFFT的源代码,以查看示例https://github.com/LadaF/PoisFFT/blob/master/src/poisfft-solvers-inc.f90并找到合适的边界条件。您的案例可能是第152行的PoisFFT_Solver2D_FullPeriodic。