Stepping through simpleFoam with VS Code — a guide to debugging solvers

Mustafa Bhotvawala
5 min readJun 20, 2020

--

This is a the second article in a series exploring utilities of OpenFOAM for viewers beginning with CFD — geared towards OpenFOAM beginners. The toolbox has a steep learning curve, but a see-through box offers far more control than a black one. Though we set up an environment to code our own solvers in the last article, we don’t have a debug environment to fix things when wrong, or to see how the code flows.

Debug mode allows you to do just this. We unpacked OpenFOAM directly into the /opt/ folder in our last article. This was the default “Opt” compilation. OpenFOAM needs to be compiled again in debug mode. Navigate to your .bashrc file in OpenFOAM’s etc/ folder and switch the flag:

WM_COMPILE_OPTION=Debug

Move back a directory and compile OpenFOAM:

./Allwmake

Debug mode is almost double the size of the normal compilation. This will take a while, atleast a few hours. Try running Allwmake in parallel to speed things up (for example, here with four processors):

./Allwmake -j 4

I recommend aliases to switch between your debug and Opt modes. Copy your OpenFOAM .bashrc file into .bashrc_debug. Source your .bashrc_debug file to activate debug mode.

alias of1912deb=”source /opt/OpenFOAM/OpenFOAM-v1912/etc/bashrc_debug”

A quick check to see if you’re in debug mode -

which icoFoam//should get--> /opt/OpenFOAM/OpenFOAM-v1912/platforms/linux64Gcc63DPInt32Debug/bin/icoFoam

Debug mode allows the gdb debugger to step through your code. You could do this in a terminal too, but I prefer working in an IDE, especially for code that’s as layered as OpenFOAM.

We’ll walk through simpleFoam in this example. simpleFoam uses the SIMPLE algorithm to solve the N-S equations for incompressible fluid flow, for a steady state solution. It’s a great starting point for most explanation on OpenFOAM.

Copy simpleFoam into your $WM_PROJECT_USER_DIR.

cp -r $FOAM_SOLVERS/incompressible/simpleFoam $WM_PROJECT_USER_DIR

To debug the solver, you need to supply it with the input files it needs from the OpenFOAM case structure. I simply copy a pitzDaily tutorial into the same folder as the solver code:

cp -r $FOAM_SOLVERS/incompressible/simpleFoam/pitzDaily/* $WM_PROJECT_USER_DIR/simpleFoam

The contents of your folder should look like this:

Start your VSCode environment:

code .

Navigate to the simpleFoam.C file. Place two breakpoints at the same locations as in the picture, after argList:addNote and at turbulence -> validate().

For those not familiar with debuggers — find the command Run — Start Debugging to execute.

Options to move along the code — Continue, Step Over, Step Into, Step Out

To move through the code, there are four options you need to use:

  1. Continue: will move to the next breakpoint
  2. Step Over: will proceed to the next line of code without entering the function on that line. If you step over turbulence->validate(), it will move to the next line after executing it, but you will not move through the contents of the method itself
  3. Step Into: will enter the method
  4. Step Out: returns control to the preceding stack frame — i.e. if you’ve entered turbulence->validate() with Step Into, it will finish execution of the method and return control to simpleFoam.C

Let’s run the debugger. If you want to work your way through the following header files too, I recommend adding a breakpoint at the argList::addNote line.

argList::addNote("Steady-state solver for incompressible, turbulent flows.");#include "postProcess.H"
#include "addCheckCaseOptions.H"
#include "setRootCaseLists.H"
#include "createTime.H"
#include "createMesh.H"
#include "createControl.H"
#include "createFields.H"
#include "initContinuityErrs.H"

We won’t enter the header files this way, but I can quickly desribe how the flow of code happens through these.

#include "postProcess.H"
#include "addCheckCaseOptions.H"
#include "setRootCaseLists.H"

The postProcess.H header file checks if the postProcess flag is issued and creates a list of all the function objects in the controlDict. setRootCaseLists.H parses through all the advanced switches that can be given to simpleFoam. For a list of these switches, see the documentation.

Header files are entered as though they’re part of the code. You can observe which file the debugger is currently paused at by looking at the call stack.

Let’s work our way down the code:

#include "createTime.H"
#include "createMesh.H"
#include "createControl.H"

createTime.H and createMesh.H, as their names suggests, create their respective runTime and mesh objects. createTime.H generates your first real output statement to your log file — “Create time”.

Foam::Info<< “Create time\n” << Foam::endl;Foam::Time runTime(Foam::Time::controlDictName, args);

createMesh.H is simple — it creates a mesh object (class fvMesh) for the corresponding runTime object.

Foam::autoPtr<Foam::fvMesh> meshPtr(nullptr);Foam::fvMesh& mesh = meshPtr();

createFields.H is present in your solver directory. The field objects p (pressure), U (velocity) are created here. Moreover, any new fields you want to evaluate — here’s where they need to be created for the solver to parse through.

createFields.H

The face flux phi is also created here through a header file inside createFields.H. Additionally, the transport model (based on your viscosity) as well as the turbulence model objects are created here.

Keep checking your terminal to see your outputs too — this is a sanity check to see that the flow of output is just like what we’d expect:

Your terminal

Voila, you’ve got through the setting up of the solver — your mesh, time, and fields, and models are now ready. The next article in the series will stick with this example, but move onto the actual code characteristic to simpleFoam — with a bit of math to explain how the SIMPLE algorithm is implemented.

--

--