Fortran 计算科学中 ADT 的最佳实践

计算科学 数字 计算物理学 正则 时间积分
2021-12-02 02:12:41

我一直在用 Fortran 编写一个软件包,用于解决 2D2V 中的 Vlasov-Poisson 系统。我希望该软件在其当前应用之外有用(例如,具有不同数量的位置或速度维度的系统、使用的数值方法的变化、完整 Maxwell 系统的解决方案等),这导致我使用抽象数据类型 (ADT)对于一些底层结构,以提高通用性和可重用性。

在我目前的离散化中,我在空间中使用拉伸笛卡尔网格,在速度中使用 Hermite 基函数。这是我当前实现的草图:

type cartesian_grid
    ! dimension of grid
    int :: N 
  
    ! physical coordinates
    double precision, pointer :: x(:) 

    ! metric
    double precision, pointer :: xi_x(:) 

    ! step size of computational coordinates
    double precision :: delta_xi  
end type
type hermite_grid
    ! length of coordinate array
    int :: N  

    ! coordinate array
    double precision, pointer :: v(:)
  
    ! Moments of basis functions - used to compute moments of f.
    double precision, pointer :: I0(:), I1(:)  

    ! Scaling factor of Hermite basis functions
    double precision :: ux 
end type

对于我的时间积分,我需要计算 Vlasov 方程的 RHS:

tf=vrfqmEvf
目前,这是通过一个子程序来完成的,如下所示:

call vlapo_dfdt( f, cartesian_grid1, cartesian_grid2, hermite_grid1, hermit_grid2, dfdt)

最后一个组件是显式时间积分器,它集成ftt+h. 我写过很多时间积分器(RK4、RK Feldberg、AB2 等)。这些当前使用以下接口调用:

call time_integrator( t, h, f, cartesian_grid1, cartesian_grid2, hermite_grid1, hermite_grid2, vlapo_dfdt)

这是我遇到麻烦的地方。我想概括一下,以便网格表示不固定。这样,我可以将速度网格更改为(比如说)笛卡尔表示,而无需编写另一个时间积分例程。问题是我当前的积分器需要一个类型(hermite_grid)并且不接受速度网格的类型(cartesian_grid)。

我想概括这一点,以便我整合ftt+h如下:

call time_integrator( t, h, f, space_grid1, space_grid2, vel_grid1, vel_grid2, deriv_function)

其中 space_grid1、space_grid2、vel_grid1、vel_grid2 可以是 Hermite 或笛卡尔网格,而 deriv_function 是与 vlapo_dfdt() 具有相同接口的过程变量。这样我就可以更改导数的实现,而无需重新编写时间步进器。

问题似乎是我的 ADT 不够抽象,但是如何在将计算导数所需的数据传递到我的 deriv_function() 的同时进一步概括它们?对于笛卡尔坐标,我需要度量和计算坐标步长。对于 Hermite 坐标,我需要基函数和比例因子的矩。对于其他表示,我完全需要其他数据。

在现代 Fortran 中实现这一目标的最佳方法是什么?这似乎是计算科学中一个普遍存在的问题,我认为有一种标准(或最佳实践)方法可以做到这一点。

1个回答

听起来您想要的是一种抽象类型——笛卡尔网格和 Hermite 网格都继承自的通用网格类型。这种抽象网格类型本身实际上并没有做任何事情,而是定义了一个接口,调用者可以依靠实际实现(即笛卡尔网格和 Hermite 网格)来提供该接口。理想情况下,您将能够编写更高级别的例程,例如时间积分,这样低级别实体(如网格)的细节并不重要。这是所谓的模板方法模式的一个示例。

Fortran 2003 及更高版本是相当标准的面向对象类型语言的单一调度,类似于泛型之前的 Java。此处通过一些代码示例描述了您如何实际实现和使用抽象基类的机制。如果您想阅读更多内容,Damian Rouson 的这本书相当不错。我还建议阅读fortran90.org,它有很多很棒的信息。

抛开在 Fortran 中具体如何实现这一点的细节不谈,无论您使用哪种语言,如果您进行任何面向对象的编程,《设计模式》这本书都是必读的。模板方法是他们描述的模式之一但是对于科学计算,还有许多其他值得了解的内容,例如策略或工厂模式。这种面向对象的编程风格并不是编写好代码的真正方法,但仍然值得了解。