Programming Tutorial
Programming Tutorial
Tommaso Lucchini
Department of Energy
Politecnico di Milano
• A look at icoFoam
• Customizing an application
• General information
• Environment variables:
◮ $FOAM_APP = $WM_PROJECT_DIR/applications
◮ $FOAM_SOLVERS = $WM_PROJECT_DIR/applications/solvers
◮ $FOAM_UTILITIES = $WM_PROJECT_DIR/applications/utilities
◮ $FOAM_SRC = $WM_PROJECT_DIR/src
# include "createTime.H"
# include "createMesh.H"
# include "createFields.H"
# include "initContinuityErrs.H"
where all the included files except createFields.H are in
$FOAM_SRC/finiteVolume/lnInclude.
• createFields.H is located in the icoFoam directory. It initializes all the
variables used in icoFoam. Have a look inside it and see how variables are
created.
• The momentum equations are defined and a velocity predictor is solved by:
fvVectorMatrix UEqn
(
fvm::ddt(U)
+ fvm::div(phi, U)
- fvm::laplacian(nu, U)
);
solve(UEqn == -fvc::grad(p));
Tommaso Lucchini/ OpenFOAM programming tutorial
POLITECNICO DI MILANO CHALMERS
Walk through icoFoam
A look into icoFoam.C, the PISO loop
runTime.write();
• write() makes sure that all the variables that were defined as an IOobject
with IOobject::AUTO_WRITE are written to the time directory according to the
settings in the $FOAM_CASE/system/controlDict file.
• elapsedCPUTime() is the elapsed CPU time.
• elapsedClockTime() is the elapsed wall clock time.
• Most changes do not require surgery on the library level: code is developed in
local work space for results and custom executables
• Environment variables and library structure control the location of the library,
external packages (e.g. gcc, Paraview) and work space
• For model development, start by copying a model and changing its name: library
functionality is unaffected
• Local workspace:
◮ Run directory: $FOAM_RUN. Ready-to-run cases and results, test loop etc.
May contain case-specific setup tools, solvers and utilities.
◮ Local work space: ˜/OpenFOAM/tommaso-1.5-dev/. Contains
applications, libraries and personal library and executable space.
1. Find appropriate code in OpenFOAM which is closest to the new use or provides
a starting point
2. Copy into local work space and rename
3. Change file name and location of library/executable: Make/files
4. Environment variables point to local work space applications and libraries:
$FOAM_PROJECT_USER_DIR, $FOAM_USER_APPBIN and
$FOAM_USER_LIBBIN
5. Change the code to fit your needs
• Rename the directory and the source file name, clean all the dependancies and
◮ mv icoFoam myIcoFoam
◮ cd icoFoam
◮ mv icoFoam.C myIcoFoam.C
◮ wclean
• Go the the Make directory and change files as follows:
myIcoFoam.C
EXE = $(FOAM_USER_APPBIN)/myIcoFoam
• Now compile the application with wmake in the myIcoFoam directory. rehash if
necessary.
Example:
• Creating the application icoScalarTransportFoam. It is an incompressible
solver with a scalar transport equation (species mass fraction, temperature, . . . ).
• To do this, we need to create a new application based on the icoFoam code.
• Rename the directory and the source file name, clean all the dependancies and
◮ mv icoFoam icoScalarTransportFoam
◮ cd icoFoam
◮ mv icoFoam.C icoScalarTransporFoam.C
◮ wclean
• Go the the Make directory and change files as follows:
icoScalarTransportFoam.C
EXE = $(FOAM_USER_APPBIN)/icoScalarTransportFoam
• We want to solve the following transport equation for the scalar field T
• It is an unsteady, convection-diffusion transport equation. ν is the kinematic
viscosity.
∂T
+ ∇ · (UT ) − ∇ · (ν∇T ) = 0 (1)
∂t
• What to do:
◮ Create the geometric field T in the createFields.H file
◮ Solve the transport equation for T in the icoScalarTransportFoam.C file.
# include "TEqn.H"
∂T
+ ∇ · (UT ) − ∇ · (ν∇T ) = 0
∂t
solve
(
fvm::ddt(T)
+ fvm::div(phi, T)
- fvm::laplacian(nu, T)
);
• Copy the cavity tutorial case in your $FOAM_RUN directory and rename it
◮ cp -r $FOAM_TUTORIALS/icoFoam/cavity $FOAM_RUN
◮ mv cavity cavityScalarTransport
• Introduce the field T in cavityScalarTransport/0 directory:
◮ cp p T
dimensions [0 0 0 0 0 0 0];
internalField uniform 0;
boundaryField
{
movingWall
{
type fixedValue;
value uniform 1;
}
fixedWalls
{
type fixedValue;
value uniform 0;
}
frontAndBack
{
type empty;
}
}
T PBiCG
{
preconditioner
{
type DILU;
}
minIter 0;
maxIter 500;
tolerance 1e-05;
relTol 0;
};
• Nice picture:
10
high ref. value
8
End ramp
6
data
4
low ref. value
2
Start ramp
0
0 3 6 9 12
Time
• cp $FOAM_SOLVERS/compressible/icoFoam \
$FOAM_USER_DIR/applications/icoFoamRamped
• Copy the content of
$FOAM_SRC/fields/fvPatchFields/derived/oscillatingFixedValue/
to $WM_PROJECT_USER_DIR/applications/icoFoamRamped/
• wclean
◮ Write to file:
virtual void write(Ostream&) const;
if (dict.found("value"))
{
fixedValueFvPatchField<Type>::operator==
(
Field<Type>("value", dict, p.size())
);
}
else
{
fixedValueFvPatchField<Type>::operator==
(
refValueLow_ + (refValueHigh_ - refValueLow_)*currentScale()
);
}
}
if (curTimeIndex_ != this->db().time().timeIndex())
{
Field<Type>& patchField = *this;
patchField =
refValueLow_
+ (refValueHigh_ - refValueLow_)*currentScale();
curTimeIndex_ = this->db().time().timeIndex();
}
fixedValueFvPatchField<Type>::updateCoeffs();
}
• This function writes to a file os the boundary condition values. Useful when the
simulation is restarted from the latest time.
template<class Type>
void rampedFixedValueFvPatchField<Type>::write(Ostream& os) const
{
fvPatchField<Type>::write(os);
refValueLow_.writeEntry("refValueLow", os);
refValueHigh_.writeEntry("refValueHigh", os);
os.writeKeyword("startRamp")
<< startRamp_ << token::END_STATEMENT << nl;
os.writeKeyword("endRamp")
<< endRamp_ << token::END_STATEMENT << nl;
this->writeEntry("value", os);
}
• In this way, the new boundary condition can be used for volScalarField,
volVectorField, volTensorField, . . . just typing in the field file:
boundaryField // example for a volScalarField
{
// some patches
// ....
inlet
{
type rampedFixedValue;
refValueLow uniform 10;
refValueHigh uniform 20;
startRamp 20;
endRamp 50;
}
}
icoFoamRamped.C
rampedFixedValueFvPatchFields.C
EXE = $(FOAM_USER_APPBIN)/icoFoamRamped
• wmake
• In this way, the new boundary condition can be only used by the
icoFoamRamped application.
LIB = $(FOAM_USER_LIBBIN)/libMyBCs
◮ Make/options
EXE_INC = \
-I$(LIB_SRC)/finiteVolume/lnInclude
EXE_LIBS = \
-lfiniteVolume
• The boundary condition will not be recognized by any of the original OpenFOAM
solvers unless we tell OpenFOAM that the library exists. In OpenFOAM-1.5 this
is done by adding a line in the system/controlDict file:
libs ("libMyBCs.so");
i.e. the library must be added for each case that will use it, but no re-compilation
is needed for any solver. libMyBCs.so is found using the LD_LIBRARY_PATH
environment variable, and if you followed the instructions on how to set up
OpenFOAM and compile the boundary condition this should work automatically.
• You can now set up the case as we did earlier and run it using the original
icoFoam solver. icoFoam does not need to be recompiled, since libMyBCs.so
is linked at run-time using dlopen.
• Example. Solve the cavity tutorial with the user defined library of boundary
conditions.
• Creating a new turbulence model (based on the k − ε model) that can be used by
all the existing OpenFOAM applications.
• A user library, called myTurbulenceModels will be created. It will be included
run-time as for the ramped fixed value boundary condition.
• The turbulence model will be tested on the pitzDaily tutorial case of the
simpleFoam application.
• A RASModel object is created in the createFields.H file of the simpleFoam
application:
autoPtr<incompressible::RASModel> turbulence
(
incompressible::RASModel::New(U, phi, laminarTransport)
);
• At the end of the PISO Loop, the function turbulence->correct() will be
called. This function solves the transport equation of the turbulence fields
(k , ε, ω, . . . ) and updates the turbulence viscosity field
(turbulence->muEff()).
void mykEpsilon::correct()
{
transportModel_.correct();
if (!turbulence_)
{
return;
}
RASModel::correct();
volScalarField G = nut_*2*magSqr(symm(fvc::grad(U_)));
# include "wallFunctionsI.H"
// Dissipation equation
tmp<fvScalarMatrix> epsEqn
(
fvm::ddt(epsilon_)
+ fvm::div(phi_, epsilon_)
+ fvm::SuSp(-fvc::div(phi_), epsilon_)
- fvm::laplacian(DepsilonEff(), epsilon_)
==
C1_*G*epsilon_/k_
- fvm::Sp(C2_*epsilon_/k_, epsilon_)
);
epsEqn().relax();
# include "wallDissipationI.H"
solve(epsEqn);
bound(epsilon_, epsilon0_);
kEqn().relax();
solve(kEqn);
bound(k_, k0_);
// Re-calculate viscosity
nut_ = Cmu_*sqr(k_)/epsilon_;
# include "wallViscosityI.H"
• The same procedure (equation definition, relax, solving and bounding) is also
used fo the k field.
• The turbulent viscosity is updated.
• And finally wallViscosityI.H calculates the turbulence viscosity at the wall
boundary cells.
LIB = $(FOAM_USER_LIBBIN)/libmyTurbulenceModels
◮ options:
EXE_INC = \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/transportModels \
-I$(LIB_SRC)/turbulenceModels/RAS/incompressible/lnInclude \
-I$(LIB_SRC)/transportModels/incompressible/lnInclude
LIB_LIBS = \
-lfiniteVolume \
-lmeshTools \
-lincompressibleRASModels \
-lincompressibleTransportModels
• Add the following lines after the constructor of the mykEpsilon turbulence
model:
Info << "hello mykEpsilon!!!!!!!" << endl;
• Copy the pitzDaily tutorial case to your run directory and rename it as
pitzDailyMykEpsilon.
cp -r $FOAM_TUTORIALS/simpleFoam/pitzDaily pitzDailyMykEpsilon
• Modify the pitzDailyMykEpsilon/constant/RASProperties
• Specify in the constant/RASProperties file of the case that the
mykEpsilon turbulence model must be used:
RASModel mykEpsilon;
• Rename the sub-dictionary called kEpsilonCoeffs to mykEpsilonCoeffs
• Add the following line to the system/controlDict file of the case:
libs ("libmyTurbulenceModels.so");
• Run the case...
◮ where provides full trace-back with function names, file and line numbers
◮ Similar tricks for debugging parallel runs: attach gdb to a running process
• Debug switches
◮ Each set of classes or class hierarchy provides own debug stream
◮ . . . but complete flow of messages would be overwhelming!
◮ Choosing debug message source:
$HOME/OpenFOAM/OpenFOAM-1.5/etc/controlDict
• OpenFOAM Programming