本节涵盖了OpenFOAM求解器与动态网格功能的扩展和新的动态网格类的开发。

13.3.1 在求解器中添加动网格

扩展具有动态网格功能的OpenFOAM解算器是一个相当简单的过程,scalarTransportFoam就是一个例子。由于动态网格处理的扩展需要修改特定的求解器应用程序文件,因此必须复制需要修改的文件。

注:在扩展OpenFOAM解算器时,以及通常在编程时,尽可能减少复制的源代码数量。

复制源代码会增加维护所需的时间。如果原始文件中存在错误,则必须在副本中解决该错误。随着OpenFOAM的发展,不必要的源代码副本使得跟踪上游更改变得困难。此外,复杂的OpenFOAM求解器包含用于初始化全局变量和耦合PDE求解算法的文件。假设复制了整个求解器文件夹,对求解器的修改很小并放置在单个文件中。在这种情况下,很难找出新求解器和原始求解器之间的差异。因此,在编写新的OpenFOAM求解器时盲目复制整个求解器文件夹的“常见”做法从长远来看是低效的。

因此,编程新OpenFOAM求解器的第一步是创建求解器文件夹,并仅将必要的文件复制到求解器文件夹:

?>  mkdir scalarTransportDyMFoam && cd scalarTransportDyMFoam
?>  cp $FOAM_SOLVERS/basic/scalarTransportFoam/scalarTransportFoam.C .
?>  cp -r $FOAM_SOLVERS/basic/scalarTransportFoam/Make .

即使对于相对简单的scalarTransportFoam解算器,也可以重用createFields. H文件。对于更复杂的“真实世界”解算器,可以重复使用更多的解算器文件,从而实现更简洁的实现。通过将路径附加到Make/options,OpenFOAM构建配置文件中的原始求解器,可以启用文件重用:

EXE_INC = \
    -I$(FOAM_SOLVERS)/basic/scalarTransportFoam \
    -I$(LIB_SRC)/finiteVolume/lnInclude \
    -I$(LIB_SRC)/fvOptions/lnInclude \
    -I$(LIB_SRC)/meshTools/lnInclude \
    -I$(LIB_SRC)/dynamicMesh/lnInclude \
    -I$(LIB_SRC)/dynamicFvMesh/lnInclude \
    -I$(LIB_SRC)/sampling/lnInclude
EXE_LIBS = \
    -lfiniteVolume \
    -lfvOptions \
    -lmeshTools \
    -ldynamicMesh \
    -ldynamicFvMesh \
    -lsampling

第一个“include”行使用FOAM_SOLVER环境变量指向OpenFOAM的solver文件夹。 如果原始求解器的文件夹包含包含其他必要文件的子文件夹,也可以包括这些子文件夹。 上面代码段中列出的其他行用于包含动态网格头文件和加载动态网格库。

由于此示例创建了一个新解算器,因此应将scalarTransportFoam.C文件重命名为scalarTransportDyMSolver.C,并遵循具有动态网格支持的解算器的OpenFOAM约定。然后,应将Make/files中出现的所有scalarTransportFoam替换为scalarTransportDyMFoam。在Make/files中,将求解器可执行文件编译到$FOAM_USER_APPBIN中,而不是标准$FOAM_APPBIN中,这一点很重要。

与原始解算器相比,处于当前状态的新scalarTransportDyMFoam解算器没有任何新功能。这可以使用第13章/scalarTransportAutoRefine的模拟案例进行测试。

图13.8显示了本例中使用的测试用例的初始条件和域几何。测试用例由一个立方体域组成,初始场预设为域角处的球体,以及用于在空间对角线方向上传输场的恒速场。

图13.8 网格细化标量传输的测试用例。红色单元格初始化为值100,蓝色单元格初始化为值0,线框球体是等值线为50的等值面

验证scalarTransportDyMSolver是否按预期工作后,下一步是在新的解算器中实现动态网格功能。为此,必须在文本编辑器中打开scalarTransportDyMSolver.C,并且必须在simpleControl.H之后包含dynamicMesh.H:

#include "fvCFD.H"
#include "fvOptions.H"
#include "simpleControl.H"
#include "dynamicFvMesh.H"

在主函数中,必须包含createDynamicFvMesh.H而不是createMesh.H,以便启用动态网格:

int main(int argc, char *argv[])
{
    #include "setRootCase.H"
    #include "createTime.H"
    #include "createDynamicFvMesh.H"
    #include "createFields.H"
    #include "createFvOptions.H"

如果仔细查看scalarTransportFoam的源代码,就会发现没有调用mesh.update(),而mesh.update()负责执行动态网格函数。因此,必须在时间循环结束时添加以下内容:

    mesh.update();
    runTime.write();
}
Info<< "End\n" << endl;
return 0;

动态网格头文件与相应得库二进制代码必须在构建过程中可用,以便新求解器工作.要包含头文件并链接库,需要通过添加以下“include”行来修改Make/options文件:

-I(LIB_SRC)/dynamicMesh/lnInclude \
-I$(LIB_SRC)/dynamicFvMesh/lnInclude \

通过向Make/options添加以下“链接”行,应用程序与动态网格库链接:

-ldynamicMesh \
-ldynamicFvMesh \

dynamicRefineFvMesh::update成员函数更正网格细化过程生成的新面的体积通量值。此过程称为通量映射,可由用户通过修改放置在常量/dynamicMeshDict中的通量映射表进行管理。有关网格细化的信息,请参见第13.1节。然而,所映射的体积通量是用于流动解算法的足够好的初始猜测,其强制实施体积守恒的体积通量值。对于该示例中的标量输运方程,不需要流动求解算法,因为场是使用恒定的规定速度平流的。

此时编译并运行求解器会得到数值无界解。为了解决这一问题,我们将最后一行代码插入求解器应用程序中,该应用程序模拟了流动求解算法的存在,并计算体积守恒的体积通量值。该行插入到对update成员函数的调用的正下方:

mesh.update();
phi = fvc::interpolate(U) &amp; mesh.Sf();

代码现在可以编译了--通过调用solver文件夹中的wmake。新的求解器可以在

ases/chapter13/scalarTransportAutoRefine

案例文件夹中。图13.9显示了图13.8所示的具有动态自适应网格细化的传输球形标量场T。T的平流是扩散的,网格加密和去加密解决了扩散区域并跟随输送场。

图13.9 使用动态网格细化传输的标量场

注:通过细化网格,创建了新的单元面,这需要修改体积通量场。体积守恒性、数值有界性以及解的稳定性强烈依赖于体积通量值。

练习:用于该测试用例的细化标准均匀地细化所传输球体的内部。一个有趣的练习是应用一个细化标准,该标准将跟随T值的跳跃。这将降低计算成本并提高精度。