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 UNIXmake 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 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.
Figure 3.1:
Header files, source files, compilation and linking.
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.
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
3.2.
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.
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.
The compiler links to shared object library files in the following directory
paths, specified with the -L option in wmake:
the $FOAM_LIBBIN directory;
platform dependent paths set
in files in the $WM_DIR/rules/$WM_ARCH/ directory, e.g./usr/X11/lib
and $(MPICH_ARCH_PATH)/lib;
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:
the libOpenFOAM.so library from the $FOAM_LIBBIN directory;
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;
other libraries specified in the Make/options file.
The Make/options file contains the full directory paths and library names using the
syntax:
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 $FOAM_APPBIN; applications developed by the user are stored in
$FOAM_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 $FOAM_USER_APPBIN
directory. The Make/files file for our example would appear as follows:
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 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
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.
The source code for application turbFoam is in the $FOAM_APP/solvers/turbFoam
directory and the top level source file is named turbFoam.C. The turbFoam.C
source code is:
1 /*---------------------------------------------------------------------------*\ 2 ========= | 3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox 4 \\ / O peration | 5 \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. 6 \\/ M anipulation | 7 ------------------------------------------------------------------------------- 8 License 9 This file is part of OpenFOAM. 10 11 OpenFOAM is free software; you can redistribute it and/or modify it 12 under the terms of the GNU General Public License as published by the 13 Free Software Foundation; either version 2 of the License, or (at your 14 option) any later version. 15 16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT 17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 19 for more details. 20 21 You should have received a copy of the GNU General Public License 22 along with OpenFOAM; if not, write to the Free Software Foundation, 23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 25 Application 26 turbFoam 27 28 Description 29 Transient solver for incompressible, turbulent flow. 30 31 \*---------------------------------------------------------------------------*/ 32 33 #include "fvCFD.H" 34 #include "incompressible/singlePhaseTransportModel/singlePhaseTransportModel.H" 35 #include "incompressible/RASModel/RASModel.H" 36 37 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 38 39 int main(int argc, char *argv[]) 40 { 41 42 # include "setRootCase.H" 43 44 # include "createTime.H" 45 # include "createMesh.H" 46 # include "createFields.H" 47 # include "initContinuityErrs.H" 48 49 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 50 51 Info<< "\nStarting time loop\n" << endl; 52 53 for (runTime++; !runTime.end(); runTime++) 54 { 55 Info<< "Time = " << runTime.timeName() << nl << endl; 56 57 # include "readPISOControls.H" 58 # include "CourantNo.H" 59 60 // Pressure-velocity PISO corrector 61 { 62 // Momentum predictor 63 64 fvVectorMatrix UEqn 65 ( 66 fvm::ddt(U) 67 + fvm::div(phi, U) 68 + turbulence->divDevReff(U) 69 ); 70 71 if (momentumPredictor) 72 { 73 solve(UEqn == -fvc::grad(p)); 74 } 75 76 // --- PISO loop 77 78 for (int corr=0; corr<nCorr; corr++) 79 { 80 volScalarField rUA = 1.0/UEqn.A(); 81 82 U = rUA*UEqn.H(); 83 phi = (fvc::interpolate(U) & mesh.Sf()) 84 + fvc::ddtPhiCorr(rUA, U, phi); 85 86 adjustPhi(phi, U, p); 87 88 // Non-orthogonal pressure corrector loop 89 for (int nonOrth=0; nonOrth<=nNonOrthCorr; nonOrth++) 90 { 91 // Pressure corrector 92 93 fvScalarMatrix pEqn 94 ( 95 fvm::laplacian(rUA, p) == fvc::div(phi) 96 ); 97 98 pEqn.setReference(pRefCell, pRefValue); 99 pEqn.solve(); 100 101 if (nonOrth == nNonOrthCorr) 102 { 103 phi -= pEqn.flux(); 104 } 105 } 106 107 # include "continuityErrs.H" 108 109 U -= rUA*fvc::grad(p); 110 U.correctBoundaryConditions(); 111 } 112 } 113 114 turbulence->correct(); 115 116 runTime.write(); 117 118 Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s" 119 << " ClockTime = " << runTime.elapsedClockTime() << " s" 120 << nl << endl; 121 } 122 123 Info<< "End\n" << endl; 124 125 return(0); 126 } 127 128 129 // ************************************************************************* //
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, incompressibleRASModels and
incompressibleTransportModels 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: