• CFD, Fluid Flow, FEA, Heat/Mass Transfer
  • +91 987-11-19-383
  • amod.cfd@gmail.com

Step-by-step guide to OpenFOAM which is now a mature open-source product with reliability matching that of commercial products.

OpenFOAM: A Beginner's Diary

Disclaimer:

This content is not approved or endorsed by OpenCFD Limited, the producer of the OpenFOAM software and owner of the OpenFOAM and OpenCFD trademarks.
At the outset, start with few excerpts from User Guide: "OpenFOAM is first and foremost a C++ library, used primarily to create executables, known as applications. The applications fall into two categories: solvers, that are each designed to solve a specific problem in continuum mechanics; and utilities, that are designed to perform tasks that involve data manipulation. One of the strengths of OpenFOAM is that new solvers and utilities can be created by its users with some pre-requisite knowledge of the underlying method, physics and programming techniques involved. OpenFOAM is supplied with pre- and post-processing environments. The interface to the pre- and post-processing are themselves OpenFOAM utilities, thereby ensuring consistent data handling across all environments."
The code is released under GPL GNU Public License), the product is free, powerful but comes with its own 'inconvenience'. Though the authors and programmers try their best to document everything, it still requires additional things to be learnt other than CFD itself, such as:
  • complier and build-platform (such as "Windows XP Professional, Service Pack 2, 64-bit") used to prepare the binaries
  • 'make' utility to compile the source codes, associated intermediate programs like Qt, Cygwin
  • Windows versions of required programs such as "Visual Studio 2008 x86 9.0.30729.1 SP"
  • Jargons like Kubuntu (Ubuntu + KDE) are by no mean kind to those either not familiar with Linux or not up-to-date with this OS!
  • Yet, one can do with it whatever (s)he likes, including unlimited commercial use, serial or parallel computing.
The effort of this page is to provide all resources 'collocated': start (installation) -> finish (getting CFD results), in a concise but complete manner.

Installation:

OpenFOAM, by its design is meant for Linux platform. However, there are few companies which provide installers for Microsoft Windows free of cost (other than providing other paid services). Some of them are:

Few key attributes

  • OpenFOAM stands for: Open Field Operations And Manipulation.
  • It is primarily, similar to CFX, a 3D-solver, hence all 2D meshes need to be extruded in third dimension. 2D problems are solved using special patches "empty". Excerpts from user guide: "OpenFOAM always operates in a 3 dimensional Cartesian coordinate system and all geometries are generated in 3 dimensions. OpenFOAM solves the case in 3 dimensions by default but can be instructed to solve in 2 dimensions by specifying a special empty boundary condition on boundaries normal to the (3rd) dimension for which no solution is required."
  • It is a collection of Utilities, Solvers and Libraries based on programming language C++.
  • Ulities are specific functions needed to be performed in any CFD simulations such as "Mesh Generation and Checking", "Mesh Conversion", Post-processing ...
  • It is primarily a command line based solver, with less emphasis on GUI. It uses ParaView or paraFoam as post-processor.
  • Paraview is a general-purpose post-processing tool to process a vast variety of formats.
  • ParaFoam is a customized-version of Paraview to post-process results produced by OpenFOAM in its native format (i.e. without any interim conversion of data)
  • Unit of variables in OpenFOAM are specified as row vector of size 1x7 comprising of indexes [a b c d e f g] designated as [Massa Lengthb Timec Temperatured Quantitye Currentf Luminous Intensityg] which in SI unit is [kga mb sc Kd kilo-molee Af Cdg]. For example, the unit of dynamic viscosity, kg/m-s or Pa.s can be specified as [1 -1 -1 0 0 0 0].
  • The solvers are named based on certain features and can easily be decoded and remembered after working through once or twice: For example, icoFoam is InCOmpressible Foam (icoFoam), simpleFoam is Semi-Implicit Method for Pressure-Linked Equations Foam...
  • "SanppyHex Mesh" in OpenFOAM is similar to "Cartesian Meshing" in ICEM CFD, "Trim Mesh" in STAR CCM+ and "Cut-cell method" in some other pre-processors.
  • Simulation of axi-symmetric flow problems, patch name 'wedge' is used. The wedge (also called prism mesh in other programs) is created by collapsing a pair of nodes - to convert a cuboid into a wedge - as described in the user manual shipped with OpenFOAM.
  • Files have free form, no need to indicate continuation across lines, no constraints on start column and end column
  • // is used to put comment in OpenFOAM dictionary files, inline with C++ programming syntax. Comment encompassing multiple lines need to be enclosed between /* and */ delimiters.
  • The OpenFOAM solver supports polyhedral meshes. It is believed that OpenFOAM had it first than any other program!
  • Pre-processor Harpoon can directly export data in the native format of OpenFOAM (no data conversion required).

Some of the troubleshooting and best practices can be found out at:

  • OpenFOAM: Troubleshooting
  • Few excellent videos on YouTube, by Jozsef Nagy, are: blockMeshDict and OpenFOAM results in ParaView. Many thanks Jozsef!
  • OpenFOAM uses its own makefile 'wmake' which is based on standard 'make' utility. However, the common 'makefile' command 'make' will not work with compilation of OpenFOAM codes.
  • If you know what to look for, it is a great tool. If you don't, you might get lost in the hugeness of the OpenFOAM! The trick is to go through as many tutorials as possible and as many repeats you can make. You will find it worth doing.

One of the complexity a new user faces is the files (with no pre-defined extensions, most of us are so used to now) and folder-structure used by OpenFOAM. A bare minimum requirement for geometry, assuming that OpenFOAM case is stored and run in a folder named "BaseDir", then the following items must exist, all with read and write access:
  1. FOAM_CASE refers to the complete folder path of current case and can be access using $ macro substitution. For example: to include a dictionary boundaryConditions, use: #include "${FOAM_CASE}/constant/boundaryConditions" where ${FOAM_CASE} refers to the absolute path of the case folder.
  2. BaseDir/system/controlDict: the system directory contains information about run-time control and solver numerics (such as discretization scheme, multi-grid solver type, relaxation factors ...)
  3. BaseDir/constant/polyMesh: This directory contains information about polyhedral mesh using 5 sub-dictionaries described below.
  4. BaseDir/constant/polyMesh/points or points.gz
  5. BaseDir/constant/polyMesh/faces or faces.gz
  6. BaseDir/constant/polyMesh/owner or owner.gz
  7. BaseDir/constant/polyMesh/neighbour or neighbour.gz
  8. BaseDir/constant/polyMesh/boundary or boundary.gz: contains information about name and type of the surface patches. Patch name defined in this file should match with patch names (boundary names) used in field variables dictionaries inside ${FOAM_CASE}/0/ folder.
  9. BaseDir/0/p
  10. BaseDir/0/U
  11. Key short-cuts to installation folders are: $FOAM_SOLVER (list of categorised solvers such as icoFoam, simpleFoam, $FOAM_UTILITIES (utiliities such as blockMesh, chechMesh, postProcess...), $FOAM_SRC (source codes for entire OpenFOAM program), $FOAM_TUTORIALS (tutorial cases supplied with installation), $FOAM_RUN (user folder)
  12. Folders containing executables: $FOAM_APPBIN (list of all executables and dll files), $FOAM_USER_APPBIN (folder to keep new executables created by users), $FOAM_LIBBIN (library for binaries)
The example folder structure is explained pictorially below. The name of the folder is the name of the case and any case needs to have following content.

OpenFOAM Folder Structure

There are few additional files which is just to make simulations easier:
  1. BaseDir/Allrun: This file describes all the things that need to be executed in order to run a case
  2. BaseDir/Allclean: Keeps file required for future re-use. All other files are deleted.
The content of the files / dictionaries used in OpenFOAM are:
  • controlDict: Excerpts from user guide: "Input data relating to the control of time and reading and writing of the solution data are read in from the controlDict dictionary. The user should view this file; as a case control file, it is located in the system directory."
  • blockMeshDict: the file describing the geometry (and not the mesh, 'blockMesh' is the utility or command that creates the mesh from this geometry). This operation, 'blockmesh' creates the 5 files described below.
  • points or pints.gz: the file containing node numbers and locations (X, Y, Z coordinates)
  • faces or faces.gz: the file containing the face connectivity of the "points" or nodes defined in points file
  • owner or owner.gz: the file containing the collection of faces which make up an 3D element
  • neighbour or neighbour.gz: the file containing connectivity between the faces (each internal faces have an owner and neighbour, apart from boundary faces who have owner only). Note that it uses '..ou..' in neighbour.
  • .../0/p and .../0/U are boundary condition setting and flow field initialization files. Be careful with the units! In OpenFOAM incompressible solvers, the solved pressure is plocal / ρ. Hence, unit in p dictionary should be m2/s2 i.e. [0 2 -2 0 0 0 0] and not kg/m-s2 i.e. [1 -1 -2 0 0 0 0].
  • system/fvSchemes: This dictionary in the system directory sets the numerical schemes for terms, such as derivatives equations, that appear in applications being run.
  • U / p / T dictionaries : boundary names can be combined using "(boundary-1 | boundary-2 | ...)". Note that there should not be any space before and after separator "|". Refer to tutorial case simpleFoam/simpleCar. E.g.
    "(left|right)"  {
      type zeroGradient;
    } 
  • DT: diffusivity which resides in transportProperties dictionary, phi is a flux scalar field = U.Sf where Sf is the area of the cell faces.
  • There are two different algorithms to solve Navier-Stokes equations. SIMPLE (simpleFoam...) - only steady state solution [pseudo-transient] and PISO (icoFoam, pisoFoam...) - both transient and steady state solution.

Step-by-step Guide for OpenFOAM simulation

Generation of computational geometry and mesh is one of the most time consuming activity. An comparison between pre-processing activity used in OpenFOAM simulation process and any other commercial program with fully-developed GUI is summarized below.
Step-1Commercial ProgramOpenFOAM
Pre-processingGeometry creation in CAD, import into CFD simulation program as IGES, STEP, PARASOLIDCreate geometry inside OpenFOAM using blockMesh utility, create geometry in any 3D CAD environment, import geometry in STL for meshing using snappyHexMesh (sHM) utility
Mesh generation in a meshing program such as ICEM CFD, ANSA, GridPro, PointWise and import into a solver dependent format such as *.msh, *.cfx5, *.ccmGenerate mesh using blockMesh, generate mesh in any other program (GMSH) and use converter utilities such as gmsh2foam, fluentMeshToFoam
Naming of zone for easy selection and application of boundary condition is done in mesh generation environmentThe method is equally applicable to OpenFOAM as boundary condition needs to be applied on a set of contiguous faces.
If you have created a mesh in other software and not defined zone, use following utility to define patches in OpenFOAM.
  • autoPatch: split the boundary into set of contiguous set of face elements, defined by specified feature angle.
  • createPatch: Utility to create patches out of selected boundary faces. Source of faces can either be existing patches or from a faceSet
  • checkMesh: Use this utility to ensure mesh pass through the criteria set for OpenFOAM solver

Step-2: Viscous model and boundary conditions - the definition of material properties, and selection of turbulence model are done through the files stored in folder 'constant' namely 'transportProperties' and 'turbulenceProperties'. The application of boundary conditions for velocity is done through file located in folder '0' as explained above.

  • Reduce the bandwidth of the mesh using renumberMesh utility
  • Use readFields utility to read data obtained from experiment or from previous simulation or mapFields - to map the coarse mesh results to the initial conditions for the fine mesh.
  • Specify turbulence value at inlet and in the interior using dictionaries k, epsilon...

Step-3: Solver setting - files stored in folder 'system' can be used to select a solver, specify convergence criteria, chose relaxation factor, time steps for psuedo-transient or physically transient simulations.

  • Use setFields (requires setFieldsDict) utility to initialize different value in various zones
  • Use utility system/decomposePar to partition the mesh for parallel processing.
  • Set monitor points: for example to write average temperature to the terminal during simulation, add following lines of code in system/controlDict:
    functions (
      avgT     {
        functionObjectLibs ("libutilityFunctionObjects.so");
        type coded;
        redirectType average;
        outputControl outputTime;
        code
        #{
          const volScalarField& T = mesh().lookupObject("T");
          Info<<"T avg:" << average(T) << endl;
        #};
      }
    ); 
  • Control write intervals: the intervals to write output can be controlled through controlDict file. In order to determine write interval during run time, use following code inside the controlDict dictionary:
    startTime   0;
    endTime     100;
    n           5;
    ...
    writeInterval   #codeStream
    {
      code
      #{
        label dt = ($endTime - $startTime);
        label i = $n;
        os  << (dt / i);
      #};
    };
    
  • Monitor the run through non-OpenFOAM utlities such as PyFOAM.
  • To terminate the execution at any time without saving the data for current iteration (time-step), press control-c. If you want to save the current iteraton also, edit the controlDict file by to "runTimeModifiable yes;" if required and then add the keyword "stopAt writeNow;". Other options to 'writeNow' are nextWrite, writeNow, noWriteNow, endTime.
  • Use sampleDict to create a sampling of solution over a line of a surface for subsequent post-processing.

Step-4: Post-processing - ParaView is a native post-processor for OpenFOAM result. Create a file foam.foam in the case folder and read it in ParaView. All the necessary result files will get loaded. Alternatively, use conversion utilities such as foamMeshToFluent and foamDataToFluent to post-process the result in other commercial programs. Use utility postProcess to generate intermediate outputs from OpenFOAM for subsequent post-processing in GNUPlot or ParaView: e.g. postProcess -func sampleDict -latestTime. Refer in the later sections of this page on dictionaries requires for postProcess utility.

  • simpleFoam -postProcess -func yPlus: write yPlus values on the walls. It creates a file named yPlus in each time directory and can be used to create contour plots in ParaView.
  • postProcess –func vorticity –noZero: compute and write the vorticity field for all the saved solutions excluding 0. The –noZero option means do not compute the vorticity field for the directory 0. Do not use '–noZero' option to compute and write the vorticity field for '0' time-step.
  • postprocess –func 'grad(U)' –endTime: compute and write the velocity gradient or grad(U) in the whole domain (including at the walls). The –endTime option instructs to compute the velocity gradient only for the last time-step of the solution. Similarly, postprocess –func 'grad(p)' and postProcess -func 'div(T)' can be used to compute and write the divergence of the pressure and temperature fields respectively for all time steps.
  • pisoFoam -postProcess -func CourantNo: compute and write the Courant number.
  • pisoFoam -postProcess -func wallShearStress: compute and write the wall shear stresses at the walls. Since no arguments are given, it will save the wall shear stresses for all time steps in '0' directory.

Note: All the incompressible solvers implemented in OpenFOAM namely icoFoam, simpleFoam, pisoFoam and pimpleFoam use "specific engergy [J/kg] or modified pressure P = p/ρ [J/kg] where p is actual static pressure in [Pa]. Hence, during post processing the results need to be multiplied by the density to get the pressure in [Pa].


A layout of the files is shown below:

File Structure in OpenFOAM

File Hierarchy in OpenFOAM

Dictionary and keywords are two important concepts in OpenFOAM. For example:
fvSolution               <-- Dictionary file	
  solvers {              <-- Dictionaries					
  p	{                <-- Sub-Dictionaries or Keywords				
    solver PCG;				
    preconditioner DIC;  <-- Values assigned to Keywords	
    tolerance 1e-06;     <-- Values assigned to Keywords	
    relTol 0;
 }

Summary of OpenFOAM Programs and Utilities

Most of the applications in OpenFOAM requires instruction from a plain text file called dictionaries. These are equivalent command line operation to the GUI features available in commercial softwares. Though, most of the dictionaries are commented well, the learning curve might still be steep for most of the beginners.

Headers of the dictionaries convey information about class and object (note that OpenFOAM has been written in C++ which is an object-oriented programming language). For example:

FoamFile {
    version     2.0;
    format      ascii;
    class       volVectorField; //dictionary, volScalarField, volTensorField
    object      U;              //p, T, gradU, sigma, k, epsilon, nut, omega, caseProperties, caseSummary
                                //controlDict, sampleDict, fvSchemes, fvSolution, transportProperties ...
}

In the example above, object 'U is of class type 'volVectorField' and should always be specified / initialized as vector such as "internalField uniform (0 0 0);". Similarly, an object of class type 'volTensorField' will need to be specified as 3×3 matrix.

A dictionary in OpenFOAM can contain multiple data entries as well as many sub-dictionaries. For a dictionary entry, the name is follow by the keyword entries in curly braces '{'.E.g.

solvers  {               //Dictionary 'solver'
  p {                    //Sub-dictionary 'p' as it is nested inside dictionary 'solver'
    solver         PCG;
    preconditioner DIC;
    tolerance      1e-06;
    relTol         0;
  }
}
Macro expansion can be used to duplicate and access variables in dictionaries. For example:
$p;                //Create a copy of dictionary 'p'
$p.tolerance;      //Access variable 'tolerance' in the dictionary 'p'
Another example of dictionary nested inside a dictionary:
boundaryField {    //Dictionary 'boundaryField'
  inlet   {        //Sub-dictionary 'inlet' as it is nested inside dictionary 'boundaryField'
    type            zeroGradient;
  }
  outlet     {     //Sub-dictionary 'outlet' as it is nested inside dictionary 'boundaryField'
    type            fixedValue;
    value           uniform 0;
  }
}  
Lists or list entries on the other hand are following by parentheses '('. For example:
vertices (         //Name of the the 'list'
  (0 0 5)
  (0 5 5)
)

Summary OpenFOAM

Example 'blockMeshDict' files and mesh generated in OpenFOAM.
  • The mesh generated by blockMeshDict file available with OpenFOAM distribution.

    Block Mesh for Cylinder

    The blockMeshDict file is here .
  • The mesh generated with simple biasing over cylinder body is shown below.
    Block Mesh for Cylinder

    The blockMeshDict file is here.
  • The mesh generated for a pipe flow, pipe diameter of 50 [mm] and length of 1000 [mm] is shown below.
    Block Mesh for Pipe Flow

    The blockMeshDict file is here.
  • A recommended blocking for a quater-symmetric cylindrical domain is shown below.
    Block Mesh for Pipe Flow

Variables or Parametric blockMeshDict

It is possible to use variables or parameters to define meshing features in blockMeshDict. If #calc function is used, blockMesh creates a runtime folder dynamicCode (first run of blockMesh) in the case folder. Refer to the screen-shots for sample use of variables in blockMeshDict and what works and what does not [tested in Version: v1606+ on Microsoft Windows 10].

parametric blockMeshDict

example of parametric blockMeshDict

Use of include feature: OpenFOAM dictionaries can read B.C. information stored in other files using directive 'include' as demonstrated below. This is applicable not just blockMeshDict but any other dictionary like U, p, T... For example: initialization of velocity filed, the information stored in a file called 'initCondition' is
  flowVelocity         (10 0 0);
  pressure             10000;
  turbulentKE          0.1;
  turbulentOmega       0.3;
  #inputMode           merge 
This file has been included in 'U' dictionary as
  #include        "initConditions"
  dimensions      [0 1 -1 0 0 0 0];
  internalField   uniform $flowVelocity; 
Other example of 'include' directive for definition of variables in blockMeshDict is explained below.

parametric using include file


Dirichlet B.C. – prescribes the value of the dependent variable on the boundary and is specified with keyword "fixedValue" in OpenFOAM. Neumann B.C.- prescribes the gradient of the variable normal to the boundary and is specified with keyword "fixedGradient or zeroGradient" in OpenFOAM. In OpenFOAM, boundary fields are calculated as per following equation where "refValue", φREF and "refGrad" are the value and the gradient taken as reference values. Here f is a fraction that switches the boundary condition between a Dirichlet BC (f = 1) and a Neumann BC (f = 0). δ is the center patch face to center cell distance and φi is the field variable at cell center.

φB = f × φREF + (1 - f) × (φi + refGrad × δ)

Inlet Boundary Condition from Volumetric / Mass Flow Rate: This method specifies uniform velocity at inlet face. For volumetric heat flow, use the following settings.

  inletZone  {
    type                 flowRateInletVelocity;   //Calculate velocity field from volumetric flow rate
    volumetricFlowRate   1.0;                     //volume flow rate in [m3/s]
    value   uniform      (1 0 0);                 //Initial value: does not affect the B.C. 
  } 
To calculate velocity from mass flow rate, the solver needs to know the density. Hence, DataEntry type 'rho' needs to be specified in this case.
  inletZone  {
    type                 flowRateInletVelocity;   //Calculate velocity field from volumetric flow rate
    massFlowRate         1.0;                     //volume flow rate in [m3/s]
    rho                  rho;                     //Name of density field
    rhoInlet             1.185;                   //Density at inlet in [kg/m3]	
  } 

Boundary conditions in cylindrical coordinate system
  inletZone  {
    type            cylindricalInletVelocity;    //specify that it is in cyl CS.
    axis            (0 1 0);                     //z-axis of cylindrical CS
    centre          (1 0 0);                     //centre of CS w.r.t global CS
    axialVelocity   constant  10;                //velocity along axial direction
    radialVelocity  constant -5;  
    rpm constant    1000;
  } 

Boundary conditions: Total Pressure - phi used in the dictionary totalPressure below is a flux scalar field = U.Sf where Sf is the area vector of the cell faces and U is velocity field obtained by interpolating velocities at cell centers. mesh.Sf() creates a vector field - surface normal for each surface of the mesh. phi field is calculated by dot product: linearInterpolate(U) & mesh.Sf where '&' denotes the dot product of two vectors.
  outletZone  {
    type   totalPressure;
    U      U;
    phi    phi;                                 //Name of flux field
    rho    rho;                                 //Name of density field
    psi    none;                                //1/R/T: R = Gas constant
    gamma  1.4;                                 //Adiabatic exponent = Cp / Cv
    p0     uniform 1e5;                         //Total pressure value
  }
  • For subsonic conditions (Ma < 0.3): p0 = p + 1/2 * ρ * U * U.
  • For transonic conditions (γ ≤ 1.0) - p0 = p * [1 + 1/2 * ψ * U * U], p/RT = ρ, Thus: p0 = p + 1/2 * ρ * U * U.
  • For transonic conditions (γ > 1.0) - p0 = p * [1 + (γ-1)/2 * Ma](γ-1)/γ

Boundary conditions: Parabolic Velocity Profile in Y-direction at Inlet

Excerpt from a post on cfd-online.com: "codedFixedValue boundary condition method attempts to load a shared library using case-supplied C++ code, so you need to allow your FOAM to execute user written code. You should switch "allowSystemOperations" in .../etc/controlDict from 0 to 1." The implementation of codeStream for diction 0/U is described below.

dimensions [0 1 -1 0 0 0 0];
internalField uniform 10;

inletZone {
  type         codedFixedValue;         //B.C. - designated by term 'Fixed'
  value        $internalField;          //Initial value
  redirectType parabolicInlet;          //Unique name for this boundary patch
	
  // Note about initial value - it is specified so the utility always has 
  // a starting value to work with (e.g. when plotting boundary values using 
  // ParaView at time 0). In this case the "uniform 10" value is substituted 
  // for time '0'. At later times, boundary values are evaluated by solver.

  // codeStream reads 3 entries: 'code', 'codeInclude' (optional), 'codeOptions'
  // (optional) and uses those to generate library sources inside codeStream/
  // Note the #{ ... #} syntax is a 'verbatim' input mode that allows inputting 
  // strings with embedded newlines. Method to read mesh if different for the
  // internal field and boundary faces.
	
  code
  #{
    const IOdictionary& d = static_cast (
      dict.parent().parent()            // access current dictionary
    );
    const fvMesh& mesh = refCast(d.db());
    const label zoneId = mesh.boundary().findPatchID("inletZone");
    const fvPatch& patch = mesh.boundary()[zoneId];
    
    //Initialize velocity components -  patch.size() = number of faces
    vectorField U(patch.size(), vector(0, 0, 0));
    
	#codeStream recognisea regular macro substitutions using the '$' syntax
	
    //Create boundary condition without loop
    vector dir = vector(0, 1, 0);       //Get unit vector along x-direction
    scalarField var = patch().Cf()&dir; //& = dot product, Cf = face centre
    scalarField value = 10.0*(1.0 - pow(var, 2) / pow(0.5, 2));
    vector(1, 0, 0) * value;            //Velocity components as vector field
    
	V0 = 10.0;
    //Create boundary condition with loop
    forAll(U, i)  {
      const scalar y = patch.Cf()[i][1];
      U[i] = vector($V0 * (1 - pow(var,2) / pow(0.5, 2));
    }
    U.writeEntry("", os);              //Write values to the dictionary
  #}
  
  //Optional - Files needed for compilation
  codeInclude
  #{
    #include "fvCFD.H"
    #include <cmath>
    #include <iostream>
  #};

  //Optional - Compilation options
  codeOptions
  #{
    -I$(LIB_SRC)/finiteVolume/lnInclude \
    -I$(LIB_SRC)/meshTools/lnInclude
  #};

  //Optional - Libraries needed for compilation, required only to visualize 
  //the output of the boundary condition at time zero
  codeLibs
  #{
    -lmeshTools \
    -lfiniteVolume
  #};
} 

Wildcard character: If the boundary names end with a certain suffix, wildcard characters can be used to specify boundary conditions in a compact manner: e.g.
Either                             or 
"(lt|rt|bt)Wall"{                  "*Wall"{
  type fixedValue;                    type fixedValue;
  value uniform (0 0 0);              value uniform (0 0 0);
}                                  }

Boundary conditions: Fan

Fan at Inlet

inletZone  {
  type            fanPressure;    //Name of fan boundary condition
  fileName        "fanPQdata";    //Name of file containing P-Q data
  outOfBounds     clamp;          //Instruction for handling out-of-bound values
  direction       in;             //Inflow direction
  p0 uniform      0;              //Initial value only. Gets updated as per fanPQdata
  value uniform   0;              
}

Fan at Outlet

outletZone  {
  type            fanPressure;    //Name of fan boundary condition
  fileName        "fanPQdata";    //Name of file containing P-Q data
  outOfBounds     clamp;          //Instruction for handling out-of-bound values
  direction       out;            //Inflow direction
  p0 uniform      0;              //Initial value only. Gets updated as per fanPQdata
  value uniform   0;              
}

Non-uniform or time-dependent boundary conditions

Example: Specify a ramped velocity at inlet - U = MIN(5.0 [m/s], 0.01 * t)

inletZone  {
    type          codedFixedValue; //Description of B.C. type
    value         uniform 0;       //Initial value
    redirectType  rampedVelcity;   //Name of new boundary condition type

    code
    #{
      const scalar t = this->db().time().value();  //Get time
      operator == (min(5.0, 0.01 * t));
    #};
}
Similarly boundary condition type 'codedMixed' can be used to generate Robin boundary conditions on-the-fly. This is a combination of fixed value and gradient value defined as φFACE = f * φREF + (1-f) * [φCELL + Δ(∇φREF)] where f = value fraction and Δ = distance between face and the centroid of the cell. 'codedFixedValue' and 'mixed' can be combined to get a 'codedMixed' boundary condition type on-the-fly.
inletZone {
    type            mixed;        //It tells the solver it is Robin-type B.C.
    refValue        10.0;         //Fixed component
    refGradient     2.0;          //Gradient component
    valueFraction   0.5;          //Fraction f in the above equation
}

Convective Boundary Conditions

Following setting can be applied in 'T' file.
wallConvective    {
    type        externalWallHeatFluxTemperature; //to model only convection
    Ta          uniform 300.0;    // Reference temperature q''= h*(T-Ta)
    h           uniform 10.0;     // HTC value [W/m^2]
    value       uniform 300.0;    // Boundary Initialization Temperature 
    kappa       solidThermo;      // -kappa x dT/dx = h *(T - Ta)
                //fluidThermo,solidThermo,lookup,directionalSolidThermo
    kappaName 	none;
}

Axi-symmetry and Wedge Boundary Condition

Axi-symmetry and Wedge Boundary Condition


Volumetric Heat Source

Following setting can be applied in 'fvOption' file in the folder containing mesh data and 'fvSchemes' and 'fvSolution' files.
 volumeHeatSource   {
    type        scalarSemiImplicitSource;
    active      true;
    scalarSemiImplicitSourceCoeffs     {
        selectionMode   cellZone;  
                        //cellZone, cellSet, points, all 
                        //Domain where the source is applied 
        cellZone        solidDomain;
        volumeMode      specific;  //specific | absolute
        injectionRateSuSp    {
          h (100000 0);  
             /* S(T) = Su + Sp * T  ->  Su = q, Sp = 0   
             q''' = 'specific' volumetric generation [W/m^3] = 100,000
             q = 'absolute' volumetric generation [W]                      */
	    }
	}
}	

Contact Resistance

Following setting can be applied to the boundary field in 'T' file.
    solidZone_to_waterDomain    {
        //type          calculated;
        type            compressible::turbulentTemperatureCoupledBaffleMixed;
        value           uniform 300;
        //"value" entry is only an 'initialization' value at the interface. 

        Tnbr            T;
        kappa           solidThermo;
        kappaName       none;
		
        /*define thermal contact resistance between regions by giving the 
          thickness and the conductivity of the inter-region layers.           */
        thicknessLayers (1e-3);    // value in [m] - Rk = [K/W] = [m] / [W/m.K]
        kappaLayers 	(5e-4);    // Value in [W/m.K]
    }	
A summary of OpenFOAM tutorials can be found on this page. This is being continuously revised and updated with additional information. The summary of tutorials on Multi-Phase flow are here.
To use SIMPLEC algorithm instead of SIMPLE, add following like in fvSolution files: SIMPLE { consistent true ; }
OpenFOAM by design is a Finite Volume solver (even structural problems which are dominated by Finite Element technique can be solved using OpenFOAM) and can handle any type of mesh (including the polyhedral). Following info-graphics provides a concise difference between the three numerical techniques.

FDM, FEM, FVM



postProcessing Utility While the results from OpenFOAM can be post-processed both quantitatively and qualitatively in ParaView or many other post-proccessors, there are some postProcessing utility available inside the solver. This will help avoid the interpolation error as values inside OpenFOAM are calculated as same discretization and interpolation scheme as the solution of field variables. This feature can be accessed by adding object 'function' in 'controlDict' dictionary. Available options are - value of attribute 'type' in function examples described below. Note that this utility supercedes foamCalc utility available in older version.
  • fieldAverage - temporal (time) averaging of field variables such as U, p, T
  • forces - this function object calculates pressure forces, viscous forces and moments
  • forceCoeffs - use this function to calculate lift, drag and moment coefficients about a given centre of rotation
  • isoSurface - to generate isosurface of given fields in one of the standard sample formats say VTK
  • cuttingPlane - it create surface cut with one of the fields data
  • streamLines - this function generates streamlines in one of the sample formats
Example to calculate lift and drag coefficients are given below:
  functions {
    forces     {
        type            forceCoeffs;      //postProcessing -list: available variables
        libs            ("libforces.so");
        writeControl    timeStep;         //As multiple of timesteps
        writeInterval   1;                //Every timestep

        patches (cylWall);                //Walls to be used for force calc
		
        log         true;
		rhoName     rhoInf;               //Indicates incompressible
        rhoInf      1.185;                //Ref. density - not used in incompressible flows
        CofR        (0 0 0);              //Centre of Rotation
        liftDir     (0 1 0);              //Direction of list:Y-axis in this case
        dragDir     (1 0 0);              //Direction of drag: X-xis in this case
        pitchAxis   (0 0 1);              //Pitching axis: Z-axis in this case
        magUInf     50.0;                 //Reference velocity magnitude
        lRef        0.50;                 //Reference length scale
        Aref        1.00;                 //Reference area
    }
  }
CD = FD / [2 * AREF * ρINF * VINF2]. The reference length scale can be 'diameter' in case of flow over a cylinder, chord length in case of flow over an airfoil, length of the car along flow direction in case of external aerodynamics over a car. Similarly, AREF is usually D×L in case of flow over a cylinder, maximum height * maximum width in case of a car.

Similarly, to get residuals for any field variable, following 'function' object needs to be added inside 'controlDict' dictionary.

  functions  {
    residuals   {
      type            residuals;         //postProcessing -list: get available variables
      functionObjectLibs ("libutilityFunctionObjects.so");
      enabled         true;
      outputControl    timeStep;
      outputInterval   5;                //Every 5 timestep
      fields (p U k epsilon T);
    }
  }

Two other examples to write value of pressure at two 'probe' locations and average pressure of a wall surface can be found in examples multiphase / interDyMFoam / ras / sloshingTank2D / system / controlDict and incompressible / pisoFoam / pitzDaily / system / controlDict. The values can be used to plot as monitor points during and/or after the simulation.

  functions {
    probeSolid    {                    //Name of 'probe' block
      type            probes;
      libs            ("libsampling.so");
      writeControl    writeTime;
	  
      regions         solid;           //Only if mutiple zones such as in CHT
      probeLocations  (
            (0  9.95 19.77)
            (0 -9.95 19.77)
        );
      fixedLocations  false;
      fields          (p);
    }
    //When solver is run, time-value data is written into p files in postProcessing/probes/0.
	
    probeFluid     {
      type            probes;
      libs            ("libsampling.so");
      writeControl    writeTime;
	  
      region          fluid;          //Only if mutiple zones such as in CHT
      probeLocations  (
            (0  5.55 5.555)
            (0 -5.55 5.555)
        );
      fixedLocations  false;
      fields (p);
    }
	
    wallPressure   {
      type            surfaces;      //On surfaces defined below
      libs            ("libsampling.so");
      writeControl    writeTime;
      surfaceFormat   raw;
      fields          (p);
      interpolationScheme cellPoint;

      surfaces (
        walls   {
          type        patch;
          patches     (walls);
          triangulate false;
        }
      );
    }
  } 
Cutting Planes
  functions {
    cuttingPlane {
      type                surfaces;
      functionObjectLibs  ("libsampling.so");
      outputControl       outputTime;
      surfaceFormat       vtk;
      fields              (U p T);
      interpolationScheme cellPoint;
      surfaces (
        yNormal {
          type            cuttingPlane;
          planeType       pointAndNormal;
          pointAndNormalDict {
            basePoint     (0.1 0.0 0.0);
            normalVector  (1.0 0.0 0.0);
          }
          interpolate true;
        }
      );
    }
  }

Streamlines

  functions {  
    streamLines {
      type          streamLine;
      outputControl outputTime;
      setFormat     vtk;     //Options: gnuplot, xmgr, raw, jplot, csv, ensight
      UName         U;
      trackForward  true;
      fields        (p U);   //Streamlines can be coloured by scale of pressure
      lifeTime      1000;
      nSubCycle     5;
      cloudName     particleTracks;
      seedSampleSet uniform; //Options: cloud, triSurfaceMeshPointSet
      uniformCoeffs {
        type        uniform;
        axis        x;       //Option: distance
        start       (0 0 0);
        end         (5 0 0);
        nPoints     20;
      }
    }
  }

sampling

The runtime sampling of data on a line or surface ... can be done using sample utility alongwith sampleDict dictionary. An example of sampleDict dictionary with all relevant comment can be found here.

Disclaimer:

This content is not approved or endorsed by OpenCFD Limited, the producer of the OpenFOAM software and owner of the OpenFOAM and OpenCFD trademarks.

Some historical facts:

  • FOAM was originally written by Henry Weller et al. at Imperial College of London (interestingly, many CFD applications have genesis associated with this academy), which was initially sold as commercial code by company named Nabla Limited. In 2004, it was renamed to OpenFOAM while releasing under GNU Public License.
  • FoamX was dropped from OpenFOAM V1.5 onwards. FoamX was a GUI that can manage cases on a local machine as well as over a distributed network.
  • Excerpts from: "OpenFOAM for Computational Fluid Dynamics - Goong Chen, Qingang Xiong, Philip J. Morris, Eric G. Paterson, Alexey Sergeev, and Yi-Ching Wang" -- OpenFOAM was born in the strong British tradition of fluid dynamics research, specifically at The Imperial College, London, which has been a center of CFD research since the 1960s. The original development of OpenFOAM was begun by Prof. David Gosman and Dr. Radd Issa, with principal developers Henry Weller and Dr. Hrvoje Jasak. It was based on the finite volume method (FVM), an idea to use C++and object-oriented programming to develop a syntactical model of equation mimicking and scalar-vectortensor operations. A large number of Ph.D. students and their theses have contributed to the project. Weller and Jasak founded the company Nabla Ltd, but it was not successful in marketing its product, FOAM (the predecessor of OpenFOAM), and folded in 2004. Weller founded OpenCFD Ltd. in 2004 and released the GNU general public license of OpenFOAM software. OpenFOAM constitutes a C++ CFD toolbox for customized numerical solvers (over sixty of them) that can perform simulations of basic CFD, combustion, turbulence modeling, electromagnetics, heat transfer, multiphase flow, stress analysis, and even financial mathematics modeled by the Black-Scholes equation. In August 2011, OpenCFD was acquired by Silicon Graphics International (SGI). In September 2012, SGI sold OpenCFD Ltd to the ESI Group. --

More examples of blockMeshDict
This is a parametric version of a simple diffuser with rectangular cross-section - blockMeshDict for diffuser.

Axi-symmetrix diffuser

The variable definition are can be found in this file.
Mesh Manipulation Utilities
The mesh mirroring, creation of a face set using topoSet and creation of patch using createPatch is described below. The original geometry and blockMesh is used from tutorial case incompressible\nonNewtonianIcoFoam\offsetCylinder. The mesh generated by blockMesh utility is shown below. One direction option is to user autoPatch command to split all the face zones based on feature angle. The output is naming of all the patches as auto01, auto02... Once the patches have been generated based on connectivity, renaming of patches can be done in constant/polyMesh/boundary file. Another option is combination of setSet / faceSet and createPatch utility. The third option to use topoSet and creatPatch utilities are explained here.

Offset cylinder original mesh

Following mirroMeshDict file was used to create a mirror of the mesh about the lower face of the flow domain.
planeType           pointAndNormal;

pointAndNormalDict  {
    basePoint       (0 -1.5 0);
    normalVector    (0  1.0 0);
}
planeTolerance      1e-3;
This resulted in a new mesh with patch name same as original mesh.

Offset cylinder mirrored mesh

A topoSetDict was created for topoSet utility to generate a face set for upper cylinder.
actions
(
  // Make a set of all face elements of patch 'cylinder'
  {
   name    cylinderFace;   //name of the set
   type    faceSet;        //pointSet/faceSet/cellSet/faceZoneSet/cellZoneSet
   action  new;            //create new, add to existing, delete or subset
   source  patchToFace;    //What is type of 'soure' for points/faces/cells
   sourceInfo   {          //method to specify the source
    name "cylinder";
   }
  }
  
  {
   name    cylinderFace;
   type    faceSet;
   action  subset;
   source  boxToFace;
   sourceInfo    {
     box (-1.01 -1.01 -1.01)(1.01 1.01 1.01);
    }
  }
);

The topoSet utility created a faceSet as shown below.

topoSet Output

Finally, the createPatch utility was used to create a new patch for upper cylinder.

pointSync false;
patches (   {           // Patches to create.
    name cylinder01;    // Name of new patch
    patchInfo  {        // Type of new patch
      type patch;
    }
    constructFrom set;  //How to construct: either from 'patches' or 'set'
    set cylinderFace;   // name of faceSet created by topoSet
  }
);

offset cylinder mirrored with new patch

Other related utilities are:

  • subsetMesh -overwrite c0 -patch newPatch: Here c0 is the cell set defined by topoSetDict. Hence, topoSet or setSet command need to be executed before subsetMesh command. Note that setSet and subsetSet do not require a dictionary.
  • autoPatch: by default it works on all the boundary (external) faces, no particular faceSet or patch name can be specified.

  • With setSet you can define a set of cells (say a rotating domain) interactively - that is directly on command line without need of any dictionary, and then this set of cells can be converted into a zone with setsToZones utility.

References

  • OpenFOAM user manual
  • Introductory OpenFOAM Course, from 16th to 20th July, 2018: University of Genoa, DICCA
  • Questions and answers on www.cfd-online.com
  • Holzmann CFD
Contact us
Disclaimers and Policies

The content on CFDyna.com is being constantly refined and improvised with on-the-job experience, testing, and training. Examples might be simplified to improve insight into the physics and basic understanding. Linked pages, articles, references, and examples are constantly reviewed to reduce errors, but we cannot warrant full correctness of all content.