执行求解器就像在Linux下发出任何其他命令一样简单:只需键入命令名并按enter键。一般来说,求解器和任何其他OpenFOAM应用程序都应该在case目录中执行。从其他目录执行求解器需要将-case参数传递给求解器,其后接案例的路径。对于使用icoFoam求解器模拟的cavity案例,命令如下所示:

icoFoam

根据网格大小、时间步长和要模拟的总时间,与通常的ls或cp命令一样,此命令确实需要更长的时间。此外,输出到终端的信息量很大,一旦终端关闭就会丢失。因此,应扩展执行求解器的语法:

nohup icoFoam >  log &
tail -f log

nohup命令指示shell保持作业运行,即使在shell窗口关闭或用户注销时也是如此。不是将所有内容都打印到屏幕上,而是将输出通过管道传输到名为log的文件中,然后将作业移到后台。由于作业在后台运行,并且所有输出都转发到日志文件,因此tail命令用于将文件结尾打印到屏幕上。通过将-f作为参数传递,这将一直更新,直到用户退出命令为止。另一个与正在运行的作业保持同步的选项是使用pyFoamPlotWatcher,其解析日志文件并从中生成gnuplot窗口。这些窗口会自动更新,并包含残差图,这便于监控模拟。

与在后台手动启动求解器并将输出重定向到日志文件不同,还可以使用foamJob脚本:

foamJob icoFoam

foamJob脚本非常强大,因为它为启动OpenFOAM作业提供了一个多功能一体的解决方案。下一节将介绍foamJob的一些特性。

3.4.1 controlDict配置

每个case都必须包含一个system/controlDict文件,该文件定义了所有与运行时相关的数据。包括停止求解器的时间、时间步长、时间步长数据写入间隔和方法。此字典的内容在求解器运行时自动重新读取,因此允许在模拟运行时进行更改。

OpenFOAM用户指南[5]全面介绍了参数和参数组合,因此此处不再重复此信息。这两个参数在这里有更详细的解释,正如本书其余部分所述。

writeControl:writeControl表示数据写入磁盘的时间。可以选择timeStep、runTime或adjustableRunTime。实际间隔由writeInterval定义,它只接受标量值。为了简单起见,从现在起这个间隔被命名为n。如果选择了timeStep,则每n个时间步都会写入磁盘,而选择runTime则每n秒写入case目录。最后一个常用的选项是adjustableRunTime,它每n秒向磁盘写入一次,但会调整时间步长,以使此间隔完全匹配。因此,case文件夹中只会出现名称很好的时间目录。使用默认设置,写入磁盘的数据量不受OpenFOAM的限制。特别是在许多用户访问同一存储单元并且运行时间较长的情况下,这可能会很快填满磁盘。

purgeWrite:purgeWrite可以通过使用过多的存储来避免上述问题。默认情况下此参数设置为0,并且不限制case写入磁盘的时间量。将其更改为2将指示OpenFOAM仅在磁盘上保留最新的2个时间实例,并在每次数据写入磁盘时删除其他实例。此选项不能用于将writeControl设置为adjustableRunTime的情况。

除了这些标准参数外,controlDict还包含在运行时链接到解算器的自定义库以及对函数对象的调用。

3.4.2 分解和并行执行

到目前为止,所有解算器都在单个处理器上执行。CFD算法的结构使其能够实现数据并行:计算域被划分为多个部分,相同的任务在计算域的每个部分上并行执行。每个进程与其邻居通信并共享相关数据。在现代多核体系结构和HPC集群中,将工作负载分布在多个计算单元上通常会导致执行时间加快。计算区域的分解决不能影响方法的数值性质:一致性、有界性、稳定性和守恒性。

在OpenFOAM中,数据并行是以一种非常优雅的方式实现的,它与底层FVM密切相关。实际上,第1章中用于阐述方程离散化的边界面也可能是处理器(进程)边界的面。在并行执行模拟之前,必须将计算域划分为与用于模拟的进程数量相同的子域。

提示:在单处理器内核上执行解算器通常被称为“串行执行”。

作为并行执行的一个示例,icoFoam解算器的cavity案例分布在开始作业的机器的两个核心上。必须确认机器至少有2个内核,否则模拟将比串行运行花费更长的时间。为了利用这两个核心,数据必须分布在它们之间。

提示:OpenFOAM中非结构化网格上的进程间通信(IPC)和FVM之间的交互由离散微分算子自动处理,其细节相对复杂,超出了本书的范围。

$FOAM_RUN文件夹可用于在$HOME文件夹中运行OpenFOAM仿真,但需要先创建它。

mkdir -p $FOAM_RUN

若要在$FOAM_RUN中运行算例,可以先拷贝cavity算例到路径下:

cp -r  $FOAM_TUTORIALS/incompressible/icoFoam/cavity/cavity $FOAM_RUN/
cd $FOAM_RUN/cavity

在下一步中,选择计算域的分解方式。OpenFOAM中存在各种分解域的方法。本教程使用scotch区域分解。域分解配置存储在字典文件system/decomposeParDict中。用户可以在OpenFOAM教程中使用下面的命令搜索此文件:

find $FOAM_TUTORIALS -type -iname decomposeParDict

默认情况下,cavity教程案例不包含此文件。只需将OpenFOAM教程中某个地方的任何decomposeParDict复制到当前目录下即可。

cp $FOAM_TUTORIALS/multiphase/interFoam/laminar/damBreak/damBreak/system/decomposeParDict ./system

decomposeParDict最重要的行如下:

numberOfSubdomains 4;
method simple;

第一行定义将使用多少子域(或MPI进程),第二行选择应用于分解域的方法。对于实际应用程序来说,使用simple方法通常是一个不好的选择,因为它将域分割为空间相等的部分。这样做不会最小化子域之间进程间通信边界的大小。考虑到网格一侧非常密集,另一侧非常粗糙,简单方法会将其切成两半,生成有限体积分布非常不均匀的子域。具有更多有限体积的网格需要更多的计算资源,使得模拟不平衡。不必要的大进程间通信边界导致进程间通信时间增加,这会严重降低并行执行的效率。

为了优化这一点,存在各种自动分解方法,例如:优化处理器边界,以使进程间通信开销最小化。通过如下更改system/DecomposePartict中的行,可以确保将域分解为两个子域,并使用scotch方法:

numberOfSubdomains        2;
method                 scotch;

在分解域之前须生成网格。此示例使用基于blockMesh的网格。生成网格后,必须使用decomposePar执行域分解:

blockMesh
decomposePar

案例目录中生成了两个新目录:processor0和processor1。其中每个都包含一个子域,包括网格(位于processor*/polyMesh目录中)和字段(位于processor*/0目录中)。并行启动模拟的实际命令比串行命令长一点,因为需要使用MPI:

mpirun -np 2 icoFoam -parallel >  log

这将调用带有2个子进程的mpirun来并行运行icoFoam,并将输出存储在日志中以供以后评估。mpirun的-parallel参数非常重要,因为它指示mpirun使用其特定子域运行每个进程。如果缺少此参数,将启动2个进程,但这两个进程都使用整个域,这不仅是冗余的,而且也是计算能力的浪费。

当模拟完成后,子域可以重建为一个单独的域。为此使用reconstructPar工具,默认情况下,该工具从每个处理器目录中获取所有时间实例并对其进行重建。当使用可选参数latestTime调用reconstructPar时,只能选择最后一个时间步骤。它指示reconstructPar仅重建最近的时间。当网格非常大并且重建需要大量时间和磁盘空间时,这很方便。无需重建子流程域,因为ParaView可以可视化分解的OpenFOAM案例。

虽然人们可能会观察到执行时间随着使用的处理器数量的增加而有很好的伸缩性,但低于某个总单元与子域的比率通常是个坏主意。进程本身会变慢,瓶颈不是可用的处理器能力,而是进程之间的通信。并行执行模拟结果,加速比s如下所示 其中分别是串行和并行执行时间。线性(理想)加速比等于使用的进程数。通常,由于进程间通信或子域局部的瓶颈(前面提到的局部计算),加速比的值将小于进程数。对于涉及更大网格算例的模拟,和评估的之间的差异将更大。然而,可能会出现超线性加速,其中:背后的原因通常特定于执行模拟的算法和架构。