Nabla Logo user
  Advanced Search
  
  Send us a comment/query
 
  Back to main web site
 
  OpenFOAM guides
  - User guide
  - Programmer’s guide
 
  Index
 
  Changes from OpenFOAM 2.2 to 2.3
 
  Trademarks in the guides
  ©2000-2007 Nabla Ltd.

3.2 Compiling applications and libraries

Compilation is an integral part of application development that requires careful management since every piece of code requires its own set instructions to access dependent components of the OpenFOAM library. In UNIX/Linux systems these instructions are often organised and delivered to the compiler using the standard UNIX make utility. OpenFOAM, however, is supplied with the wmake compilation script that is based on make but is considerably more versatile and easier to use; wmake can, in fact, be used on any code, not simply the OpenFOAM library. To understand the compilation process, we first need to explain certain aspects of C++ and its file structure, shown schematically in Figure 3.1. A class is defined through a set of instructions such as object construction, data storage and class member functions. The file containing the class definition takes a .C extension, e.g. a class nc would be written in the file nc.C. This file can be compiled independently of other code into a binary executable library file known as a shared object library with the .so file extension, i.e. nc.so. When compiling a piece of code, say newApp.C, that uses the nc class, nc.C need not be recompiled, rather newApp.C calls nc.so at runtime. This is known as dynamic linking.


            Main  code                                 nc class


        newApp.C                  Header  file     nc.H
        #include   "nc.H "        - I option       Definition...
        int  main()
        {
        ...
                                                  nc.C
        ...
        return(0);                                #include   "nc.H "
        }                                         Code...

Compiled                                                             Compiled

        newApp                                    nc.so
                                   Linked
        Executable                -l option       Library
\special {t4ht=


Figure 3.1: Header files, source files, compilation and linking.


3.2.1 Header .H files

As a means of checking errors, the piece of code being compiled must know that the classes it uses and the operations they perform actually exist. Therefore each class requires a class declaration, contained in a header file with a .H file extension, e.g. nc.H, that includes the names of the class and its functions. This file is included at the beginning of any piece of code using the class, including the class declaration code itself. Any piece of .C code can resource any number of classes and must begin with all the .H files required to declare these classes. The classes in turn can resource other classes and begin with the relevant .H files. By searching recursively down the class hierarchy we can produce a complete list of header files for all the classes on which the top level .C code ultimately depends; these .H files are known as the dependencies. With a dependency list, a compiler can check whether the source files have been updated since their last compilation and selectively compile only those that need to be.

Header files are included in the code using # include statements, e.g.


    # include "otherHeader.H";
causes the compiler to suspend reading from the current file to read the file specified. Any self-contained piece of code can be put into a header file and included at the relevant location in the main code in order to improve code readability. For example, in most OpenFOAM applications the code for creating fields and reading field input data is included in a file createFields.H which is called at the beginning of the code. In this way, header files are not solely used as class declarations. It is wmake that performs the task of maintaining file dependency lists amongst other functions listed below.
  • Automatic generation and maintenance of file dependency lists, i.e. lists of files which are included in the source files and hence on which they depend.
  • Multi-platform compilation and linkage, handled through appropriate directory structure.
  • Multi-language compilation and linkage, e.g. C, C++, Java.
  • Multi-option compilation and linkage, e.g. debug, optimised, parallel and profiling.
  • Support for source code generation programs, e.g. lex, yacc, IDL, MOC.
  • Simple syntax for source file lists.
  • Automatic creation of source file lists for new codes.
  • Simple handling of multiple shared or static libraries.
  • Extensible to new machine types.
  • Extremely portable, works on any machine with: make; sh, ksh or csh; lex, cc.
  • Has been tested on Apollo, SUN, SGI, HP (HPUX), Compaq (DEC), IBM (AIX), Cray, Ardent, Stardent, PC Linux, PPC Linux, NEC, SX4, Fujitsu VP1000.

3.2.2 Compiling with wmake

OpenFOAM applications are organised using a standard convention that the source code of each application is placed in a directory whose name is that of the application. The top level source file takes the application name with the .C extension. For example, the source code for an application called newApp would reside is a directory newApp and the top level file would be newApp.C as shown in Figure 3.2.


 newApp

newApp.C

otherHeader.H

      Make

     files

     options
\special {t4ht=


Figure 3.2: Directory structure for an application


The directory must also contain a Make subdirectory containing 2 files, options and files, that are described in the following sections.
3.2.2.1 Including headers

The compiler searches for the included header files in the following order, specified with the -I option in wmake:

  1. the $WM_PROJECT_DIR/src/foam/lnInclude directory;
  2. a local lnInclude directory, i.e. newApp/lnInclude;
  3. the local directory, i.e. newApp;
  4. platform dependent paths set in files in the $WM_PROJECT_DIR/wmake/rules/$WM_ARCH/ directory, e.g. /usr/X11/include and $(MPICH_ARCH_PATH)/include;
  5. other directories specified explicitly in the Make/options file with the -I option.

The Make/options file contains the full directory paths to locate header files using the syntax:


    EXE_INC = \
        -I<directoryPath1> \
        -I<directoryPath2> \
        ...                \
        -I<directoryPathN>
Notice first that the directory names are preceeded by the -I flag and that the syntax uses the \ to continue the EXE_INC across several lines, with no \ after the final entry.
3.2.2.2 Linking to libraries

The compiler links to shared object library files in the following directory paths, specified with the -L option in wmake:

  1. the $OpenFOAM_LIBBIN directory;
  2. platform dependent paths set in files in the $WM_DIR/rules/$WM_ARCH/ directory, e.g. /usr/X11/lib and $(MPICH_ARCH_PATH)/lib;
  3. other directories specified in the Make/options file.

The actual library files to be linked must be specified using the -l option and removing the lib prefix and .so extension from the library file name, e.g. libnew.so is included with the flag -lnew. By default, wmake loads the following libraries:

  1. the libfoam.so library from the $OpenFOAM_LIBBIN directory;
  2. platform dependent libraries specified in set in files in the $WM_DIR/rules/$WM_ARCH/ directory, e.g. libm.so from /usr/X11/lib and liblam.so from $(LAM_ARCH_PATH)/lib;
  3. other libraries specified in the Make/options file.

The Make/options file contains the full directory paths and library names using the syntax:


    EXE_LIBS = \
        -L<libraryPath1> \
        -L<libraryPath2> \
        ...              \
        -L<libraryPathN> \
        -l<library1>     \
        -l<library2>     \
        ...              \
        -l<libraryN>
Let us reiterate that the directory paths are preceeded by the -L flag, the library names are preceeded by the -l flag.

3.2.2.3 Source files to be compiled

The compiler requires a list of .C source files that must be compiled. The list must contain the main .C file but also any other source files that are created for the specific application but are not included in a class library. For example, users may create a new class or some new functionality to an existing class for a particular application. The full list of .C source files must be included in the Make/files file. As might be expected, for many applications the list only includes the name of the main .C file, e.g. newApp.C in the case of our earlier example.

The Make/files file also includes a full path and name of the compiled executable, specified by the EXE = syntax. Standard convention stipulates the name is that of the application, i.e. newApp in our example. The OpenFOAM release offers two useful choices for path: standard release applications are stored in $OpenFOAM_APPBIN; applications developed by the user are stored in $OpenFOAM_USER_APPBIN.

If the user is developing their own applications, we recommend they create an applications subdirectory in their $WM_PROJECT_USER_DIR directory containing the source code for personal OpenFOAM applications. As with standard applications, the source code for each OpenFOAM application should be stored within its own directory. The only difference between a user application and one from the standard release is that the Make/files file should specify that the user’s executables are written into their $OpenFOAM_USER_APPBIN directory. The Make/files file for our example would appear as follows:


    newApp.C

    EXE = $(OpenFOAM_USER_APPBIN)/newApp

3.2.2.4 Running wmake

The wmake script is executed by typing:


    wmake <optionalArguments> <optionalDirectory>
The <optionalDirectory> is the directory path of the application that is being compiled. Typically, wmake is executed from within the directory of the application being compiled, in which case <optionalDirectory> can be omitted.

If a user wishes to build an application executable, then no <optionalArguments> are required. However <optionalArguments> may be specified for building libraries etc. as described in Table 3.1.


Argument Type of compilation


lib Build a statically-linked library
libso Build a dynamically-linked library
libo Build a statically-linked object file library
jar Build a JAVA archive
exe Build an application independent of the specified project library.



Table 3.1: Optional compilation arguments to wmake.

3.2.2.5 wmake environment variables

For information, the environment variable settings used by wmake are listed in Table 3.2.


Main paths


$WM_PROJECT_INST_DIR

Full path to installation directory, e.g. $HOME/foam

$WM_PROJECT

Name of the project being compiled: foam

$WM_PROJECT_VERSION

Version of the project being compiled: 2.3

$WM_PROJECT_DIR

Full path to locate binary executables of OpenFOAM release, e.g. $HOME/foam/foam2.3

$WM_PROJECT_USER_DIR

Full path to locate binary executables of the user e.g. $HOME/foam/${USER}2.3

Other paths/settings


$WM_ARCH

Machine architecture: cray decAlpha dec ibm linux linuxPPC sgi3 sgi32 sgi64 sgiN32 solaris sx4 t3d

$WM_COMPILER

Compiler being used: Gcc3 - gcc 3.4.2, KAI - KAI

$WM_COMPILER_DIR

Compiler installation directory

$WM_COMPILER_BIN

Compiler installation binaries $WM_COMPILER_BIN/bin

$WM_COMPILER_LIB

Compiler installation libraries $WM_COMPILER_BIN/lib

$WM_COMPILE_OPTION

Compilation option: Debug - debugging, Opt optimisation.

$WM_DIR

Full path of the wmake directory

$WM_JAVAC_OPTION

Compilation option for JAVA: Debug - debugging, Opt optimisation.

$WM_LINK_LANGUAGE

Compiler used to link libraries and executables. In multi-language projects a $WM_LINK_LANGUAGE is set to the primary language.

$WM_MPLIB

Parallel communications library: LAM, MPI, MPICH, PVM

$WM_OPTIONS

= $WM_ARCH$WM_COMPILER...

   ...$WM_COMPILE_OPTION$WM_MPLIB

e.g. linuxGcc3OptMPICH

$WM_PROJECT_LANGUAGE

Programming language of project, e.g. c++

$WM_SHELL

Shell used for the wmake scripts bash, csh, ksh, tcsh




Table 3.2: Environment variable settings for wmake.

3.2.3 Removing dependency lists: wclean and rmdepall

On execution, wmake builds a dependency list file with a .dep file extension, e.g. newApp.dep in our example, and a list of files in a Make/$WM_OPTIONS directory. If the user wishes to remove these files, perhaps after making code changes, the user can run the wclean script by typing:


    wclean <optionalArguments> <optionalDirectory>
Again, the <optionalDirectory> is a path to the directory of the application that is being compiled. Typically, wclean is executed from within the directory of the application, in which case the path can be omitted.

If a user wishes to remove the dependency files and files from the Make directory, then no <optionalArguments> are required. However if lib is specified in <optionalArguments> a local lnInclude directory will be deleted also.

An additional script, rmdepall removes all dependency .dep files recursively down the directory tree from the point at which it is executed. This can be useful when updating OpenFOAM libraries.

3.2.4 Compilation example: the turbFoam application

The source code for application turbFoam is in the $OpenFOAM_APP/solvers/turbFoam directory and the top level source file is named turbFoam.C. The turbFoam.C source code is:


1  // The OpenFOAM Project // File: turbFoam/turbFoam.C
2  /*
3  -------------------------------------------------------------------------------
4   =========         | Application
5   \\      /         |
6    \\    /          | Name:   turbFoam
7     \\  /           | Family: CFD
8      \\/            |
9      F ield         | OpenFOAM version: 2.3
10      O peration     |
11      A and          | Copyright (C) 2000-2007 Nabla Ltd.
12      M anipulation  |          All Rights Reserved.
13  -------------------------------------------------------------------------------
14  APPLICATION
15      turbFoam
16  
17  DESCRIPTION
18      Transient solver for incompressible, turbulent flow.
19  
20  AUTHOR
21      Henry G Weller.
22  
23  -------------------------------------------------------------------------------
24  */
25  
26  #include "fvCFD.H"
27  #include "incompressible/turbulenceModel/turbulenceModel.H"
28  
29  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
30  
31  int main(int argc, char *argv[])
32  {
33  
34  #   include "setRootCase.H"
35  
36  #   include "createDatabase.H"
37  #   include "createMesh.H"
38  #   include "createFields.H"
39  #   include "initContinuityErrs.H"
40  
41  // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
42  
43      Info<< "\n Starting time loop\n" << endl;
44  
45      for (runTime++; !runTime.end(); runTime++)
46      {
47          Info<< "\nTime = " << runTime.timeName() << nl << endl;
48  
49  #       include "readPISOControls.H"
50  #       include "CourantNo.H"
51  
52          // Pressure-velocity PISO corrector
53          {
54              // Momentum predictor
55  
56              fvVectorMatrix UEqn
57              (
58                  fvm::ddt(U)
59                + fvm::div(phi, U)
60                + turbulence->divR(U)
61              );
62  
63              solve(UEqn == -fvc::grad(p));
64  
65              // --- PISO loop
66  
67              for (int corr=0; corr<nCorr; corr++)
68              {
69                  U = UEqn.H()/UEqn.A();
70                  phi = fvc::interpolate(U) & mesh.Sf();
71  
72                  // Non-orthogonal pressure corrector loop
73                  for (int nonOrth=0; nonOrth<=nNonOrthCorr; nonOrth++)
74                  {
75                      // Pressure corrector
76  
77                      fvScalarMatrix pEqn
78                      (
79                          fvm::laplacian(1.0/UEqn.A(), p) == fvc::div(phi)
80                      );
81  
82                      fvScalarMatrix::reference pRef =
83                          pEqn.setReference(pRefCell, pRefValue);
84                      pEqn.solve();
85                      pEqn.unsetReference(pRef);
86  
87                      if (nonOrth == nNonOrthCorr)
88                      {
89                          phi -= pEqn.flux();
90                      }
91                  }
92  
93  #               include "continuityErrs.H"
94  
95                  U -= fvc::grad(p)/UEqn.A();
96                  U.correctBoundaryConditions();
97              }
98          }
99  
100          turbulence->correct();
101  
102          runTime.writeObjects();
103  
104          Info<< "\n    ExecutionTime = "
105              << runTime.elapsedCpuTime() << " s\n" << endl;
106      }
107  
108      Info<< "End" << endl;
109  
110      return(0);
111  }
112  
113  
114  // ************************************************************************* //

The code begins with a brief description of the application contained within comments over 1 line (//) and multiple lines (/*...*/). Following that, the code contains several # include statements, e.g. # include "fvCFD.H", which causes the compiler to suspend reading from the current file, turbFoam.C to read the fvCFD.H.

turbFoam resources the cfdTools, turbulenceModels and transportModels libraries and therefore requires the necessary header files, specified by the EXE_INC = -I... option, and links to the libraries with the EXE_LIBS = -l... option. The Make/options therefore contains the following:


1  EXE_INC = \
2      -I$(LIB_SRC)/cfdTools/incompressible \
3      -I$(LIB_SRC)/cfdTools/lnInclude \
4      -I$(LIB_SRC)/turbulenceModels \
5      -I$(LIB_SRC)/transportModels
6  
7  EXE_LIBS = \
8      -lincompressibleTurbulenceModels \
9      -lincompressibleTransportModels \
10      -lcfdTools \
11      -lmeshTools
12  

turbFoam contains only the turbFoam.C source and the executable is written to the $OpenFOAM_APPBIN directory as all standard applications are. The Make/files therefore contains:


1  turbFoam.C
2  
3  EXE = $(OpenFOAM_APPBIN)/turbFoam

The user can compile turbFoam by going to the $OpenFOAM_CFD/turbFoam directory and typing:


    wmake
The code should compile and produce a message similar to the following


    Making dependency list for source file turbFoam.C

    SOURCE_DIR=.
    SOURCE=turbFoam.C ;
    g++ -DOpenFOAM_EXCEPTION -Dlinux -DlinuxOptMPICH
    -DscalarMachine -DoptSolvers -DPARALLEL -DUSEMPI -Wall -O2 -DNoRepository
    -ftemplate-depth-17 -I/export/warhol/chris/foam/foam2.3/src/foam/lnInclude
    -IlnInclude
    -I.
    -I/export/warhol/chris/foam/foam2.3/src/lam-7.0.6/platforms/linuxOptMPICH/include
    -I/usr/X11/include
    -DWM_PROJECT_VERSION='"'2.3'"'
    -I/export/warhol/chris/foam/foam2.3/src/cfdTools/incompressible
    -I/export/warhol/chris/foam/foam2.3/src/cfdTools/lnInclude
    -I/export/warhol/chris/foam/foam2.3/src/turbulenceModels/incompressible/lnInclude
    -I/export/warhol/chris/foam/foam2.3/src/transportModels/incompressible/lnInclude
    -fPIC -c $SOURCE -o Make/linuxOptMPICH/turbFoam.o
    /export/warhol/chris/foam/foam2.3/wmake/tcshScripts/mkObjectDir
    /export/warhol/chris/foam/foam2.3/applications/bin/linuxOptMPICH/turbFoam
    g++ -DOpenFOAM_EXCEPTION -Dlinux -DlinuxOptMPICH -DscalarMachine -DoptSolvers
    -DPARALLEL -DUSEMPI -Wall -O2 -DNoRepository -ftemplate-depth-17
    -I/export/warhol/chris/foam/foam2.3/src/foam/lnInclude -IlnInclude
    -I.
    -I/export/warhol/chris/foam/foam2.3/src/lam-7.0.6/platforms/linuxOptMPICH/include
    -I/usr/X11/include -DWM_PROJECT_VERSION='"'2.3'"'
    -I/export/warhol/chris/foam/foam2.3/src/cfdTools/incompressible
    -I/export/warhol/chris/foam/foam2.3/src/cfdTools/lnInclude
    -I/export/warhol/chris/foam/foam2.3/src/turbulenceModels/incompressible/lnInclude
    -I/export/warhol/chris/foam/foam2.3/src/transportModels/incompressible/lnInclude
    -fPIC Make/linuxOptMPICH/turbFoam.o
    -L/export/warhol/chris/foam/foam2.3/lib/linuxOptMPICH
    -lincompressibleTurbulenceModels -lincompressibleTransportModels -lcfdTools
    -lfoam
    -L/export/warhol/chris/foam/foam2.3/src/lam-7.0.6/platforms/linuxOptMPICH/lib
    -lmpich -L/usr/X11/lib -lm
    -o /export/warhol/chris/foam/foam2.3/applications/bin/linuxOptMPICH/turbFoam
The user can now try recompiling and will receive a message similar to the following to say that the executable is up to date and compiling is not necessary:


    make: Nothing to be done for `allFiles'.
    make: `Make/linuxOptMPICH/dependencies' is up to date.

    make: `/export/warhol/chris/foam/foam2.3/applications/bin/linuxOptMPICH/turbFoam'
    is up to date.
The user can compile the application from scratch by removing the dependency list with


    wclean
and running wmake.

3.2.5 Debug messaging and optimisation switches

OpenFOAM provides a system of messaging that is written during runtime, most of which are to help debugging problems encountered during running of a OpenFOAM case. The switches are listed in the user’s $HOME/.foam2.3/controlDict file. The list of possible switches is extensive and can be viewed by running the foamDebugSwitches application. Most of the switches correspond to a class or range of functionality and can be switched on by their inclusion in the controlDict file, and by being set to 1. For example, OpenFOAM can perform the checking of dimensional units in all calculations by setting the dimensionSet switch to 1. There are some switches that control messaging at a higher level than most, listed in Table 3.3.

In addition, there are some switches that control certain operational and optimisation issues. These switches are also listed in Table 3.3. Of particular importance is fileModificationSkew. OpenFOAM scans the write time of data files to check for modification. When running over a NFS with some disparity in the clock settings on different machines, field data files appear to be modified ahead of time. This can cause a problem if OpenFOAM views the files as newly modified and attempting to re-read this data. The fileModificationSkew keyword is the time in seconds that OpenFOAM will subtract from the file write time when assessing whether the file has been newly modified.


High level debugging switches - subdictionary DebugSwitches


level

Overall level of debugging messaging for OpenFOAM- - 3 levels 0, 1, 2

FoamX

Debugging information messaging for FoamX

lduMatrix

Messaging for solver convergence during a run - 3 levels 0, 1, 2

Optimisation switches - subdictionary OptimisationSwitches


fileModificationSkew

A time in seconds that should be set higher than the maximum delay in NFS updates and clock difference for running OpenFOAM over a NFS.

nProcsSimpleSum

Optimises global sum for parallel processing; sets number of processors above which hierarchical sum is performed rather than a linear sum (default 16)




Table 3.3: Runtime message switches.

3.2.6 Linking new user-defined libraries to existing applications

The situation may arise that a user creates a new library, say new, and wishes the features within that library to be available across a range of applications. For example, the user may create a new boundary condition, compiled into new, that would need to be recognised by a range of solver applications, pre- and post-processing utilities, mesh tools, etc. Under normal circumstances, the user would need to recompile every application with the new linked to it.

Instead, OpenFOAM uses a special library called foamUser to eliminate the need to recompile. It works by first having the foamUser library compiled into each application by default. The foamUser library is compiled from code located in $OpenFOAM_SRC/foamUser directory. The user simply needs to add the new library to the linked libraries in the Make/options file of foamUser and recompile foamUser.

Taking the example already given, the user should therefore make a local copy of the foamUser directory, and move to that directory, e.g.:


    cp -r $OpenFOAM_USER/src/foamUser $WM_PROJECT_USER_DIR/applications
    cd $WM_PROJECT_USER_DIR/applications/foamUser
It is recommended to edit the Make/files file so that the foamUser library is compiled locally into $OpenFOAM_USER_LIBBIN as follows:


    libfoamUser.C
    LIB = $(OpenFOAM_USER_LIBBIN)/libfoamUser
The new library should be added to the LIB_LIBS in Make/options


    LIB_LIBS = \
        -l...  \
        -lnew
Finally, the library should be recompiled with:


    wmake libso