本文是SBFFT学习笔记的第三篇,这一篇中主要介绍在这一算法中用到的各种网格所使用的数据结构,以及与不同网格数据相互转换的子程序。
根据本系列第一篇中的相关理论,在计算中需要用到四种网格,全局的稠密网格(DGBX)、小块的稠密网格(DSBX)、全局的稀疏网格(SGBX)和小块的稀疏网格(SSBX)。在具体代码实现中定义了一个BOX数据类型(BOX.f90文件中的SetupBOX模块),来实现对于这四种网格的封装,具体的数据结构定义如下:
type :: BOX
! 基本信息
character(len=4) id ! 标记四种类型的网格,可能的值为"DGBX"、"DSBX"、"SGBX"、"SSBX"
integer level ! 标记是否使用:0表示未使用,1表示已初始化
integer indbox ! 当前小块的一维编号,用于 MPI_SPLIT
integer, dimension( 3 ) indbox3d ! 当前小块的在各个方向上的序号
integer, dimension( 3 ) nbox ! 每个方向上小块的数目
integer, dimension( 3 ) buff ! 各方向上缓冲区的格点数
integer nproc ! 当前小块使用的核数
integer nproc_c ! 当前小块核心区域使用的核数
integer nptot ! 计算使用的总核数
! 核心区和缓冲区
integer n1, n2, n3 ! 当前核使用的各方向格点数目
integer n123 ! n123 = n1 * n2 * n3
integer n1off, n2off, n3off ! 各方向上的位移值
integer m1, m2, m3 ! 各方向上的总格点数
! 倒空间
integer k1, k2, k3 ! 当前核使用的倒空间网格各方向格点数
integer k123= ! k123 = k1 * k2 * k3
integer k3off ! Gz方向上的位置
! 核心区域
integer c1, c2, c3 ! 当前核使用的各方向格点数目(核心区域)
integer c123=0 ! c123 = c1 * c2 * c3
integer c10, c11 ! 当前核的网格中核心区域格点在x方向的起始和结束位置
integer c20, c21 ! 当前核的网格中核心区域格点在y方向的起始和结束位置
integer c30, c31 ! 当前核的网格中核心区域格点在整个块中的起始和结束位置
integer b1, b2, b3 ! 当前小块中核心区域各方向格点数目
integer b123 ! 核心区的总格点数
integer b1off, b2off ! 当前小块中核心区域在网格中下x,y方向的位置
integer b3off ! 当前小块中核心区域在网格中的位置
! 稀疏度
integer sparX, sparY, sparZ ! 各个方向的稀疏度,1表示是稠密网格
! MPI
integer MPI_INTRA_WORLD ! 当前小块使用的MPI网络
integer rankBox ! 当前核在当前小块MPI网络中的编号
integer rankBox0, rankBox1 ! 核心区域使用核的编号的下界和上界
integer MPI_CORE_WORLD ! 所有计算核心区域的有核构成的MPI网络
integer rankCore ! 在上一网络中的编号
type(FFT_CONFIG) FFT_STATE ! FFT相关信息
logical active_proc ! 只有在第一个小块使用的核被标记为active
logical buffer_proc ! 为.TRUE.表示当前核处理缓冲区
logical core_proc ! 为.TRUE.表示当前核处理核心区
! 电荷密度
real*8, dimension( *, *, * ) rhoC ! 核心区域的电荷密度
real*8, dimension( *, *, * ) qTable ! q向量的长度
real*8, dimension( *, *, * , * ) qVectors ! 实际的q向量
logical, dimension( *, * , * ) qMask ! mask函数
! 块的几何参数
real*8, dimension( 3, 3 ) cellReal ! 当前块的格矢,以Bohr为单位
real*8, dimension( 3, 3 ) cellRecip ! 当前块的倒格矢
real*8, dimension( 3 ) length ! 当前块三个格矢的长度
real*8, dimension( 3 ) ecut ! 各方向的截断能
end type BOX
在程序中使用了四个BOX类型的变量DGBX、DSBX、SGBX和SSBX,分别对应计算使用的四个网格。程序中首先使用Inputs中的ReadOptions子程序(Inputs.f90文件)读取输入参数后对这几个变量的网格大小等参数进行赋值(相关文件1244-1319),再调用SetupBOX模块中InitBOX子程序对这些变量进行初始化
call InitBOX(box, m1G, m2G, m3G, cellRealIn)
这里bx是需要初始化的BOX类型变量,m1G、m2G、m3G三个整数表示x、y、z三个方向全局网格长度,cellRealIn对应bx%cellReal表示格矢。关于具体的调用,可以参考SYS模块中SetupAllBoxes子程序(System.f90文件中)。
由于计算过程中涉及到涉及到不同类型网格的数据转换,在程序中用到了四种实空间中网格转换的子程序:
- DGBX_2_DSBX
- DSBX_2_DGBX
- DSBX_2_SGBX
- SGBX_2_SSBX
这些子程序对应计算流程中的赋值和拼合操作,只涉及到数据的传递(使用MPI_ISend和MPI_IRecv),因此没有从稀疏网格到稠密网格转换的子程序(对应插值操作)。这些子程序的调用方式是类似的,以DGBX_2_DSBX为例,其位于DataExchange_DG2DS.f90的同名模块中,其定义为:
subroutine DGBX_2_DSBX(
real*8, dimension( *, *, * ) array_DG,
real*8, dimension( *, *, * ) array_DS
)
此外在DataExchange_SS2DS.f90文件的同名模块中定义的SSBX_2_DSBX子程序,对应的是在倒空间而非实空间中的数据转换,这里从稀疏网格到稠密网格的变换只是在高频部分加上0,其定义为:
subroutine SSBX_2_DSBX(
complex*16, dimension( *, *, * ) array_SS,
complex*16, dimension( *, *, * ) array_DS
)
这些子程序的实现细节比较琐碎,还需要参考其源代码。