我正在Fortran中编写一个伪谱CFD代码,它基本上是平面层中Navier-Stokes方程的时间步长。在我的情况下它实际上是一个3d代码,但在2d中可以很好地理解这个问题,所以我会坚持这个案例。几何上,我的2d平面图层由y=0
和y=1
限定,并沿另一个方向x
是周期性的。在不进入杂草的情况下,有效的离散化是沿着y
和x
上的傅里叶模式分解切比雪夫多项式上的场(例如,速度)。切比雪夫多项式基本上是在一个变形网格上伪装的余弦。 Navier-Stokes方程在谱空间中具有简单形式,但非线性项除外。因此,大多数计算都是在光谱空间中进行的,偶尔会有物理空间偏移来计算非线性项:需要将复杂Chebyshev-Fourier系数的2d阵列变换为相应的2d场(即实数值的数组)在网格上)。没有其他约束,这种转换相对容易实现。例如,从复杂的频谱系数开始 - 让我们称之为c_in(NX, NY/2+1)
- 对于x
的每个值,可以沿着y
采用复数到真实的,相关的傅里叶变换来获得真实切比雪夫系数的2d阵列。然后,可以对所有FFTW_REDFT
和 voila 沿着y
执行离散余弦变换(FFTW中的x
),最后得到真实场{,{{ 1}}。
所有麻烦的根源在于,由于某些原因,我需要来首先计算DCT。这是一个问题,因为余弦变换仅针对FFTW中的实际数据实现。各种约束导致我不希望将我的复杂频谱系数阵列分成两个真实阵列用于实部和虚部。鉴于数据结构的这些约束,问题是:如何有效地使FFTW沿着复数数组的第一个索引计算几个DCT。
到目前为止,我的解决方案在于使用r_out(NX,NY)
高级界面来定义一个跨越虚构值的变换:我将plan_many_r2r
设置为2.因此,如果我使用此计划使用与idist
的实部相关联的指针ptr2real_in
,计算所有实部的余弦变换。然后,我使用与c_in(1,1)
的虚构部分关联的指针ptr2imag_in
重复执行计划。之后,沿着第二维计算复杂到真实的DFT很容易。
所以这种方法的关键是定义c_in(1,1)
,这实际上是ptr2imag_in
的内存地址,移动了c_in(1,1)
的内存大小。我在下面包含一个最小的例子,但是对我来说看起来很笨拙。特别是,我以这种方式定义了指向复数数组的虚部的指针
C_double
在我看来,我需要做的就是将cptr = C_loc(c_in(1,1))
Call C_F_Pointer(cptr, ptr2imag_in, [2*NX, (NY/2+1)])
cptr = C_loc(ptr2imag_in(2,1))
Call C_F_Pointer(cptr, ptr2imag_in, [2*NX, (NY/2+1)])
换成8个字节。我怎么能这样做?以下代码失败:
cptr
采用DCT,然后是复数到实际DFT的完整最小示例如下:
cptr = C_loc(c_in(1,1))
cptr = cptr + 8
Call C_F_Pointer(cptr, ptr2imag_in, [2*NX, (NY/2+1)])
答案 0 :(得分:0)
您可以尝试以下试用1-Dim示例的意义 (我不确定编译代码的效率如何......)。
program mapctor
implicit none
integer, parameter :: n = 10
integer :: i
complex :: cx(n) ! the couplex array
real :: rx(2,n) ! mapped to real
EQUIVALENCE(cx(1), rx(1,1)) ! some old fortran stuff !
! fill in some test values
do i=1,n
cx(i) = cmplx(i,-i)
enddo
write(6,*)"REAL PART:"
call xfft(rx(1,:),n)
write(6,*)"IMAG PART:"
call xfft(rx(2,:),n)
end program mapctor
subroutine xfft(x,n) ! mock-up fft routine, or whatever
implicit none
real, intent(in) :: x(n)
integer, intent(in) :: n
write(6,'(f12.6)') x
end subroutine xfft