现代 Fortran 中的 CFD 抽象

计算科学 流体动力学 正则
2021-12-10 00:29:50

我是面向对象编程的新手,但这种设计技术对我来说似乎很有趣。我有一个 Fortran 90 CFD 包,不是很复杂,但是已经很难维护和添加新的物理特性或其他特性。正如我现在了解到的那样,它可以降低程序的复杂性,但从我的角度来看,最重要的是 - 数学抽象的内在面向对象。现在,我试图在 CFD 数学和 Fortran 2003 标准中引入的面向对象概念之间进行一些比较。CFD 从引入字段抽象开始。大多数情况下是三维张量场,可以描述为五维数组tensor_field(:,:,:,:,:)该数组存储张量场的节点值。同样,标量场scalar_field(:,:,:)vector_field(:,:,:,:)现在一切都清楚明了。但是当人们开始尝试为这种字段类型开发类时,它就变得棘手了。有一些问题出现:

  1. 如果该数组是相应类的一部分,那么如何实现graddiv操作?以优雅的数学方式,grad应该是scalar_field类中的过程,它给出vector_field作为其结果。但类似地,div应该在vector_field类中并且应该产生scalar_field如何在面向对象范式中实现对象之间的这种交互?
  2. 从数学的角度来看,tensor_field应该是向量和标量类的父类。但是只使用五维数组似乎有点不知所措。我考虑过使用标量类作为父类,但它似乎更像是向量类的元素,而不是父类。

总而言之,我的问题的主要思想是:是否有任何面向对象的 CFD 编程设计模式,可以被广泛接受和测试?也许你可以在这里用伪代码、Fortran 或 C++ 分享你的实现来讨论它们?

最好的问候,伊万 Y。

2个回答

我不知道在整个 CFD 领域是否存在有效的设计模式,因为有很多不同的方法可以解决这类问题(基于 PDE、基于粒子……)。要获得对所有这些方法有意义的概念,它们可能需要非常通用,而不是您编写的内容:标量字段将是某种东西(可能是对象的方法),在输入中获取坐标并返回一个标量值(向量/张量场相同,返回类型不同)。所有这一切都没有谈论“节点”或与所使用的方法相关的任何内容。

现在,如果您将自己限制在一种特定类型的方法(例如基于节点的方法),您可以按照自己的方式更多地指定您的接口。如果你设法坚持使用这种界面,你最终会得到一个非常强大的框架,可以让你处理各种各样的问题。但是,我要在您建议的界面中更改的第一件事是隐藏“数组”部分,而是使用虚拟(抽象)方法:您可能想要使用分析函数,在这种情况下您可能不需要存储所有节点中的函数值。

几年前我编写了一个类似的有限元框架,它在定义标量/向量/张量场时非常灵活:任何可以为给定正交节点(~位置)给出值(标量/向量/张量)的东西可以在框架中使用。非线性、精确解、方程之间的耦合……最终都可以很容易地混合使用。我是用 C++ 编写的,代码仍然可以在 LifeV 库的 ETA 模块中找到。这是一个相当困难的机器,因为它严重依赖 C++ 模板元编程(出于性能原因),但用户界面非常简单,并且可以使用更简单的代码来实现。

对于您的两个特定问题:

  1. 我会在字段类之外为 div 和 grad 创建函数,这样循环依赖就没有问题了。你只写 grad(my_field) 而不是 my_field.grad()
  2. 我会将类标量/向量/张量字段分开。有些接口只对标量有意义,对向量没有意义,反之亦然。如果您需要所有字段的基类,请不要在母类中指定存储(数组),而是为特定实现保留它。

[免责声明:我曾经是 LifeV 库的开发者]

您可以看到 Damian Rousen 的书(科学软件设计:面向对象的方式)。他广泛使用 Fortran 2003,并且是 Trilinos 项目的作者之一。您也可以在此处查看第 3 部分,但该书更好并且可以在此处获得。