如何编写数值模拟软件的集成测试?

计算科学 有限元 数字 测试
2021-11-25 03:18:09

更准确地说,我将举一个我的典型用例的有价值的例子。

假设我正在开发一个 FEM 软件,它可以生成多个时间解决方案并将它们与一堆相关数据一起插入到 HDF5 文件中。

如果我使用一种天真的方法来编写集成测试,我可以这样做:

  1. 编写代码
  2. 在一个简单的案例上手动测试它
  3. 确定它有效并保存正确的解决方案
  4. 编写一个自定义测试,将新版本代码的解决方案与我已经为简单案例找到的正确解决方案进行比较。

这显然行不通,因为即使更改我的 BLAS 实现也可能会稍微改变我解决方案的每个 DOF。在特定规范内对解决方案之间的相似性进行测试可能会更有效,但这并非微不足道,而且仅仅编写测试感觉就像过冲。

如何为这个软件编写集成测试以在 Jenkins 上自动运行?是否有一些工具可以帮助我处理解决方案的正常不确定性?

3个回答

我认为您无法避免对浮点比较使用容差。由于使用浮点数的舍入、离散化等导致的错误是不可避免的。

我通常用来测试我编写的 FEM 代码的方法是:

  • 测试单个元素上的刚度和质量矩阵,以确保我得到正确的局部元素组装,与已知结果进行比较
  • 在一个简单的网格上再次测试,以确保我得到正确的全局装配,与已知结果进行比较
  • 测试在具有已知结果的函数上组装负载向量
  • 在应该“精确”的制造解决方案上测试整个求解器(工作精度,有足够的细化;一个例子是泊松问题,在P1离散化)
  • 在不精确的制造解上测试求解器,反复细化解,计算误差,并根据网格尺寸回归误差以确定求解器的收敛顺序

对于泊松问题,这些测试会锻炼大部分求解器。对于更复杂的问题,您的里程可能会有所不同;为某些问题编写测试用例比为其他问题编写测试用例更容易,并且为某些程序(例如,您自己编写的串行代码)编写测试比为其他程序(例如,并行代码,其中处理器排序可以影响减少的结果)。

在选择公差时,所有这些测试都需要一些判断,但是通过制造的解决方案,您将清楚地知道什么时候是严重错误的,什么时候是正确的。通常,我从类似的东西开始107作为特征值约为 1 的解的绝对容差,并相应地向上或向下调整。

测试收敛顺序需要最多的判断,因为您不仅需要选择容差,还需要选择用于回归的网格间距。最好先进行试验,然后绘制误差与网格大小的关系图(实际上,因为它是幂律,误差范数的对数与网格大小的对数;您还将回归误差范数的对数与网格大小的对数)。一旦你有了有意义的数据,然后将绘制收敛行为的代码转换为一个测试,该测试将从回归获得的收敛顺序与理论的收敛顺序进行比较。例如,如果我期望收敛阶数为 3,并且我得到介于 2.7 和 3.3 之间的任何值,或者类似的结果,那么我会说测试“通过”。

Geoff 已经给出了很好的概述,但我想提供另一个真实世界的外观。在 deal.II 项目 ( http://www.dealii.org/ ) 中,我们在多个平台上对代码库的每次更改运行了大约 7,000 次测试。

Geoff 描述的测试主要是“集成测试”,即它们贯穿代码库的重要部分。您需要的这些代码相对较少,但事实证明它们很难调试:如果它们失败,并且您没有立即提交破坏它们,则需要查看大量代码以找出哪个一块改变了功能。为了避免这种情况,我们进行了一些集成测试,但有大量(数千个)小型单元测试,它们只是测试库的一小部分。更改破坏功能的典型情况是几个集成测试失败加上几个小单元测试,最简单的单元测试是用于调试的单元测试。

至于这些测试是如何工作的:是的,我们将输出存储在参考平台上,然后比较运行测试的平台上的输出。我们使用numdiff适当设置容差来避免舍入的微小变化问题。我们花了很长时间来调整容差,以确保所有 7,000 个左右的测试都能在我们使用的每个平台上成功运行。在此之前,我们只是简单地将一台特定的机器指定为“参考平台”,并将测试保存在那里并在那里运行测试。

我想在其他答案中补充几点。

  1. 角落测试用例应该是回归测试套件的一部分 - 病态问题,病态 - 不良纵横比,正交各向异性和非各向同性材料属性,不适当的约束模型。
  2. 确保反作用力匹配。
  3. Sturm 检查特征值问题,尤其是在存在多个特征值时。
  4. 在迭代求解器的情况下,可能会得到正确的答案,但数值错误或不正确的预处理器构造/分解可能会使求解器收敛缓慢。因此,需要将性能与相同停止容差设置的旧代码进行比较。

  5. 需要逐步收紧停止公差并记录迭代次数。

  6. 并行和 GPU:线程数、缓存大小等的性能扩展需要交叉检查,并且应该符合预期。

PS:

  1. 写一个简短的矩阵向量乘法并检查范数||Ax*-b|| 其中 x* 是求解器返回的答案。这必须简单而简短,以便可以在一两个小时内通过在几个同事的帮助下进行代码演练来验证其正确性。