现代Fortran求解器的良好面向对象设计

5
我正在设计一个Fortran代码来解决PDE系统问题。
目前,我有一个类型为“Variable”的对象,其中包含多个属性,最重要的是存储数值的数组“val”。
同时,我还有一个“solver”类,用于对“variable”进行计算。我认为每次运行“solver”时将整个“variable”传递给它,并使用“variable%val”进行操作(在执行期间需要多次运行),效率会很低,因此我决定在“solver”类中定义指针字段,以将其绑定到适当的变量。例如:
program example
    use variable
    use solvers

    type(Variable) T 
    type(Solver) solver_temperature

    !Contructors
    call T%create()
    call solver_temperature%create(T)

    call solver_temperature%solve()
end program example

解决器模块
module solvers
type Solver
    real*8, pointer :: T(:,:)

contains 
    procedure :: create
    procedure :: solve
end type

contains
    subroutine create(this,T)
        type(Solver) :: this
        type(Variable) :: T

        this%T => T%val
    end subroutine
end module

在我的程序中,我为不同的物理特性和不同的解算器定义了不同的变量,并以我上面展示的方式将它们与这些变量相关联。
我对OOP还很陌生,所以我的问题是这是否是一个合理的设计?特别是从性能的角度来看。与仅将T作为数组并将其传递给子例程solve相比,速度如何?有没有一些常规的方法来做到这一点?

2
我认为变量指针没有太多意义。将其作为虚拟参数传递似乎更自然。这只是一个数组描述符,对性能没有什么不好的影响。 - Vladimir F Героям слава
1个回答

5
我已经使用Fortran的面向对象特性工作了一年左右,以下是一些扩展评论。
如果你只关心执行速度,那么通常最好避开面向对象的特性(基于论点和我的经验而非数据),但在许多情况下,同样的论点也适用于要在FORTRAN77之后添加到语言中的任何东西。
支持面向对象的论据更强调代码设计、可理解性、可扩展性等问题。如果这些对你有所影响,那么你应该考虑使用面向对象的特性。
正如 Vladimir 已经评论的那样,使用变量指针似乎没有太大意义。不要忘记,大多数Fortran实现都采用按引用调用,以避免复制(大量的)数据。
个人而言,我不喜欢你定义类型限定过程 create 的方式。我更喜欢将这种操作实现为函数,这样我就可以编写以下行:
t = solver%new()

而不是你的

call T%create()

注意,这只是我个人的偏好,更多是关于风格而非效率或正确性的问题。我注意到你没有声明子程序create的参数意图,可能是因为你只发布了代码片段。
由于面向对象在Fortran中相对较新(并且可以说在Fortran广泛使用的领域中大多数人都不太熟悉),因此没有太多有用的材料来指导我们采用它。我建议阅读Scientific Software Design。它对这个主题进行了适当的涵盖,并阐述了科学和工程程序员应该采用面向对象编程的论点。

+1 我也喜欢将初始化作为函数,因为它与构造函数的其他方法不同(尽管内存分配是在其他地方进行的)。有时候,即使标准派生类型初始化不足够,在solwer%new创建接口并使用名称solver也很方便,然后使用t = solver() - Vladimir F Героям слава
非常感谢提供书籍链接,我会尽力获取。 - tiam
在你的solver%new()示例中,solver是什么?一个Solver对象吗?还是你可以通过这种方式访问类型函数? - weymouth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接