Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
123 views

Supplement Programming Openfoam

Uploaded by

Văn Đức Anh
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
123 views

Supplement Programming Openfoam

Uploaded by

Văn Đức Anh
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 78

Supplement

High level programming in OpenFOAM®


Building blocks

1
Roadmap

1. Programming in OpenFOAM®. Building blocks.


2. Implementing boundary conditions using high level
programming
3. Modifying applications – Highlights
4. Implementing an application from scratch
5. Adding the scalar transport equation to icoFoam

2
Programming in OpenFOAM®. Building blocks

• In the directory $WM_PROJECT_DIR/applications/test, you will


find the source code of several test cases that show the usage of most
of the OpenFOAM® classes.
• We highly encourage you to take a look at these test cases and try to
understand how to use the classes.
• We will use these basic test cases to understand the following base
classes: tensors, fields, mesh, and basic discretization.
• For your convenience, we already copied the directory
$WM_PROJECT_DIR/applications/test into the directory
$PTOFC/programming_playground/test

3
Programming in OpenFOAM®. Building blocks
• During this session we will study the building blocks to write basic programs in OpenFOAM®:
• First, we will start by taking a look at the algebra of tensors in OpenFOAM®.
• Then, we will take a look at how to generate tensor fields from tensors.
• Next, we will learn how to access mesh information.
• Finally we will see how to discretize a model equation and solve the linear system of
equations using OpenFOAM® classes and templates.
• And of course, we are going to program a little bit in C++. But do not be afraid, after all this
is not a C++ course.

• Remember, all OpenFOAM® components are implemented in library form for easy re-use.
• OpenFOAM® encourage code re-use. So basically, we are going to take something that
already exist, and we are going to modify it to fix our needs.
• We like to call this method CPAC (copy-paste-adapt-compile).

4
Programming in OpenFOAM®. Building blocks
Basic tensor classes in OpenFOAM®
• OpenFOAM® represents scalars, vectors and matrices as tensor fields. A zero rank tensor is a
scalar, a first rank tensor is a vector and a second rank tensor is a matrix.
• OpenFOAM® contains a C++ class library named primitive
($FOAM_SRC/OpenFOAM/primitives/). In this library, you will find the classes for the tensor
mathematics.
• In the following table, we show the basic tensor classes available in OpenFOAM®, with their
respective access functions.

Tensor Rank Common name Basic class Access function

0 Scalar scalar

1 Vector vector x(), y(), z()

2 Tensor tensor xx(), xy(), xz() …

5
Programming in OpenFOAM®. Building blocks
Basic tensor classes in OpenFOAM®
• In OpenFOAM®, the second rank tensor (or matrix)

can be declared in the following way

tensor T(1, 2, 3, 4, 5, 6, 7, 8, 9);

• We can access the component or using the xz ( ) access function,

6
Programming in OpenFOAM®. Building blocks
Basic tensor classes in OpenFOAM®
• For instance, the following statement,

Info << “Txz = “ << T.xz ( ) << endl;

• Will generate the following screen output,

$> Txz = 3

• Notice that to output information to the screen in OpenFOAM®, we use the function Info instead
of the function cout (used in standard C++).
• The function cout will work fine, but it will give you problems when running in parallel.
7
Programming in OpenFOAM®. Building blocks
Algebraic tensor operations in OpenFOAM®
• Tensor operations operate on the entire tensor entity.
• OpenFOAM® syntax closely mimics the syntax used in written mathematics, using descriptive
functions (e.g. mag) or symbolic operators (e.g. +).
• OpenFOAM® also follow the standard rules of linear algebra when working with tensors.
• Some of the algebraic tensor operations are listed in the following table (where a and b are
vectors, s is a scalar, and T is a tensor).

Mathematical OpenFOAM®
Operation Remarks
description description

Addition a+b a + b

Scalar multiplication sa s * a

Outer product rank a, b >=1 ab a * b

Inner product rank a, b >=1 a.b a & b

Double inner product rank a, b >=2 a:b a && b

Magnitude |a| mag(a)

Determinant det T det(T)

You can find a complete list of all operators in the programmer’s guide 8
Programming in OpenFOAM®. Building blocks
Dimensional units in OpenFOAM®
• As we already know, OpenFOAM® is fully dimensional.
• Dimensional checking is implemented as a safeguard against implementing a meaningless
operation.
• OpenFOAM® encourages the user to attach dimensional units to any tensor and it will perform
dimension checking of any tensor operation.
• You can find the dimensional classes in the directory
$FOAM_SRC/OpenFOAM/dimensionedTypes/
• The dimensions can be hardwired directly in the source code or can be defined in the input
dictionaries.
• From this point on, we will be attaching dimensions to all the tensors.

9
Programming in OpenFOAM®. Building blocks
Dimensional units in OpenFOAM®
• Units are defined using the dimensionSet class tensor, with its units defined using the
dimensioned<Type> template class, the <Type> being scalar, vector, tensor, etc. The
dimensioned<Type> stores the variable name, the dimensions and the tensor values.
• For example, a tensor with dimensions is declare in the following way:

1 dimensionedTensor sigma
2 (
3 “sigma”,
4 dimensionSet(1, -1, -2, 0, 0, 0, 0),
5 tensor(10e6,0,0,0,10e6,0,0,0,10e6)
6 );

• In line 1 we create the object sigma.


• In line 4, we use the class dimensonSet to attach units to the object sigma.
• In line 5, we set the input values of the tensor sigma.

10
Programming in OpenFOAM®. Building blocks
Units correspondence in dimensionSet
• The units of the class dimensionSet are defined as follows

dimensionSet (kg, m, s, K, mol, A, cd)

• Therefore, the tensor sigma,

1 dimensionedTensor sigma
2 (
3 “sigma”,
4 dimensionSet(1, -1, -2, 0, 0, 0, 0),
5 tensor(10e6,0,0,0,10e6,0,0,0,10e6)
6 );

• Has pressure units or

11
Programming in OpenFOAM®. Building blocks
Dimensional units examples
• To attach dimensions to any tensor, you need to access dimensional units class.
• To do so, just add the header file dimensionedTensor.H to your program.

#include “dimensionedTensor.H”
...
...
...
dimensionedTensor sigma
(
"sigma",
dimensionSet(1, -1, -2, 0, 0, 0, 0),
tensor(1e6,0,0,0,1e6,0,0,0,1e6)
);
Info<< "Sigma: " << sigma << endl;
...
...
...

• The output of the previous program should look like this:


sigma sigma [1 -1 -2 0 0 0 0] (1e+06 0 0 0 1e+06 0 0 0 1e+06)
12
Programming in OpenFOAM®. Building blocks
Dimensional units examples
• As for base tensors, you can access the information of dimensioned tensors.
• For example, to access the name, dimensions, and values of a dimensioned tensor, you can
proceed as follows:

Info << “Sigma name: “ << sigma.name ( ) << endl;


Info << “Sigma dimensions: “ << sigma.dimensions ( ) << endl;
Info << “Sigma value: “ << sigma.value ( ) << endl;

• To extract a value of a dimensioned tensor, you can proceed as follows:

Info<< "Sigma yy (22) value: " << sigma.value().yy() << endl;

• Note that the value() member function first converts the expression to a tensor, which has a yy()
member function.
• The dimensionedTensor class does not have a yy() member function, so it is not possible to
directly get its value by using sigma.yy().
13
Programming in OpenFOAM®. Building blocks
OpenFOAM® lists and fields
• OpenFOAM® frequently needs to store sets of data and perform mathematical operations.
• OpenFOAM® provides an array template class List<Type>, making it possible to create a list of
any object of class Type that inherits the functions of the Type. For example a List of vector is
List<vector>.
• Lists of the tensor classes are defined in OpenFOAM® by the template class Field<Type>.
• For better code legibility, all instances of Field<Type>, e.g. Field<vector>, are renamed using
typedef declarations as scalarField, vectorField, tensorField, symmTensorField,
tensorThirdField and symmTensorThirdField.
• You can find the field classes in the directory $FOAM_SRC/OpenFOAM/fields/Fields.
• Algebraic operations can be performed between fields, subject to obvious restrictions such as
the fields having the same number of elements.
• OpenFOAM® also supports operations between a field and a zero-rank tensor, e.g. all values of
a Field U can be multiplied by the scalar 2 by simple coding the following line, U = 2.0 * U.

14
Programming in OpenFOAM®. Building blocks
Construction of a tensor field in OpenFOAM®
• To create fields, you need to access the tensor class.
• To do so, just add the header file tensorField.H to your program. This class inherit all the
tensor algebra.

#include "tensorField.H"
...
...
...
tensorField tf1(2, tensor::one);
Info<< "tf1: " << tf1 << endl;
tf1[0] = tensor(1, 2, 3, 4, 5, 6, 7, 8, 9);
Info<< "tf1: " << tf1 << endl;
Info<< "2.0*tf1: " << 2.0*tf1 << endl;
...
...
...

• In this example, we created a list of two tensor fields (tf1), and both tensors are initialized to
one.
• We can access components on the list using the access operator [ ].
15
Programming in OpenFOAM®. Building blocks
Example of use of tensor and field classes
• In the directory $PTOFC/programming_playground/my_tensor you will find a tensor
class example.
• The original example is located in the directory $HOME/OpenFOAM/OpenFOAM-
8/applications/test. Feel free to compare the files to spot the differences.
• Before compiling the file, let us recall how applications are structure,

working_directory/
├── applicationName.C
├── header-files.H
└── Make
├── files
└── options

• applicationName.C: is the actual source code of the application.


• header_files.H: header files required to compile the application.

16
Programming in OpenFOAM®. Building blocks
Example of use of tensor and field classes
• Before compiling the file, let us recall how applications are structure.

working_directory/
├── applicationName.C
├── header-files.H
└── Make
├── files
└── options

• The Make directory contains compilation instructions.


• files: names all the source files (.C), it specifies the name of the new application and
the location of the output file.
• options: specifies directories to search for include files and libraries to link the solver
against.
• At the end of the file files, you will find the following line of code,
EXE = $(FOAM_USER_APPBIN)/my_Test-tensor
• This is telling the compiler to name your application my_Test-tensor and to copy the executable
in the directory $FOAM_USER_APPBIN.
• To avoid conflicts between applications, always remember to give a proper name and a location
to your programs and libraries. 17
Programming in OpenFOAM®. Building blocks
Example of use of tensor and field classes
• Let us now compile the tensor class example. Type in the terminal:

1. $> cd $PTOFC/programming_playground/my_tensor
2. $> wmake
3. $> my_Test-tensor

• In step 2, we used wmake (distributed with OpenFOAM®) to compile the source code.
• The name of the executable will be my_Test-tensor and it will be located in the directory
$FOAM_USER_APPBIN (as specified in the file Make/files)
• At this point, take a look at the output and study the file Test-tensor.C. Try to understand
what we have done.
• After all, is not that difficult. Right?

18
Programming in OpenFOAM®. Building blocks

• At this point, we are a little bit familiar with tensor, fields, and lists in
OpenFOAM®.
• They are the base to building applications in OpenFOAM®.
• Let us now take a look at the whole solution process:
• Creation of the tensors.
• Mesh assembly.
• Fields creation.
• Equation discretization.
• All by using OpenFOAM® classes and template classes

19
Programming in OpenFOAM®. Building blocks
Discretization of a tensor field in OpenFOAM®
• The discretization is done using the FVM (Finite Volume Method).
• The cells are contiguous, i.e., they do not overlap and completely fill the domain.
• Dependent variables and other properties are stored at the cell centroid.
• No limitations on the number of faces bounding each cell.
• No restriction on the alignment of each face.
• The mesh class polyMesh is used to construct the polyhedral mesh using the minimum
information required.
• You can find the polyMesh classes in the directory $FOAM_SRC/OpenFOAM/meshes
• The fvMesh class extends the polyMesh class to include additional data needed for the FVM
discretization.
• You can find the fvMesh classes in the directory $FOAM_SRC/src/finiteVolume/fvMesh

20
Programming in OpenFOAM®. Building blocks
Discretization of a tensor field in OpenFOAM®
• The template class geometricField relates a tensor
field to a fvMesh.
• Using typedef declarations geometricField is renamed
to volField (cell center), surfaceField (cell faces), and
pointField (cell vertices).
• You can find the geometricField classes in the directory
$FOAM_SRC/OpenFOAM/fields/GeometricFields.
• The template class geometricField stores internal
fields, boundary fields, mesh information, dimensions,
old values and previous iteration values.
• A geometricField inherits all the tensor algebra of its
corresponding field, has dimension checking, and can
be subjected to specific discretization procedures.
• Let us now access the mesh information of a simple
case.

21
Programming in OpenFOAM®. Building blocks
Data stored in the fvMesh class

Access
Class Description Symbol
function
volScalarField Cell volumes V()

surfaceVectorField Face area vector Sf()

surfaceScalarField Face area magnitude magSf()

volVectorField Cell centres C()

surfaceVectorField Face centres Cf()

surfaceScalarField Face fluxes Phi()

22
Programming in OpenFOAM®. Building blocks
Accessing fields defined in a mesh
• To access fields defined at cell centers of the mesh you need to use the class volField.
• The class volField can be accessed by adding the header volFields.H to your program.

volScalarField p Create scalar volField p


(
IOobject
(
"p",
runTime.timeName(), Assign and initialization of
mesh, scalar volField to the
IOobject::MUST_READ, mesh
IOobject::AUTO_WRITE
),
mesh
);
Info<< p << endl;
Output some information
Info<< p.boundaryField()[0] << endl;

23
Programming in OpenFOAM®. Building blocks
Accessing fields using for loops
• To access fields using for loops, we can use OpenFOAM® macro forAll, as follows,

Outputs name of patch


forAll(mesh.boundaryMesh(), patchI)
Info << "Patch " << patchI << ": " << mesh.boundary()[patchI].name() << " with "
<< mesh.boundary()[patchI].Cf().size() << " faces. Starts at total face "
<< mesh.boundary()[patchI].start() << endl;
Outputs size of patch (number of faces)

• In the previous statement mesh.boundaryMesh() is the size of the loop, and patchI is the
iterator. The iterator always starts from zero.
• The forAll loop is equivalent to the standard for loop in C++.

for (int i = 0; i < mesh.boundaryMesh().size(); i++)


Info << "Patch " << i << ": " << mesh.boundary()[i].name() << " with "
<< mesh.boundary()[i].Cf().size() << " faces. Starts at total face "
<< mesh.boundary()[i].start() << endl;

Outputs starting face of patch

• Notice that we used as iterator i instead of patchI, this does not make any difference. 24
Programming in OpenFOAM®. Building blocks
Equation discretization in OpenFOAM®
• At this stage, OpenFOAM® converts the PDEs into a set of linear algebraic equations, A x = b,
where x and b are volFields (geometricField).
• A is a fvMatrix, which is created by the discretization of a geometricField and inherits the
algebra of its corresponding field, and it supports many of the standard algebraic matrix
operations.
• The fvm (finiteVolumeMethod) and fvc (finiteVolumeCalculus) classes contain static
functions for the differential operators and discretize any geometricField.
• fvm returns a fvMatrix, and fvc returns a geometricField.
• In the directories $FOAM_SRC/finiteVolume/finiteVolume/fvc and
$FOAM_SRC/finiteVolume/finiteVolume/fvm you will find the respective classes.
• Remember, the PDEs or ODEs we want to solve involve derivatives of tensor fields with respect
to time and space. What we re doing at this point, is applying the finite volume classes to the
fields, and assembling a linear system.

25
Programming in OpenFOAM®. Building blocks
Discretization of the basic PDE terms in OpenFOAM®
The list is not complete

Mathematical fvm::
Term description
expression fvc::

laplacian(phi)
Laplacian , laplacian(Gamma, phi)

, ddt(phi)
Time derivative
ddt(rho,phi)

div(psi,scheme)
Convection ,
div(psi,phi)

Sp(rho,phi)
Source
SuSp(rho,phi)

vol<type>Field scalar, volScalarField surfaceScalarField


26
Programming in OpenFOAM®. Building blocks
Discretization of the basic PDE terms in OpenFOAM®
• To discretize the fields in a valid mesh, we need to access the finite volume class. This class can
be accessed by adding the header fvCFD.H to your program.
• To discretize the scalar transport equation in a mesh, we can proceed as follows,

Assemble and solve


solve linear system arising form
the discretization
(
fvm::ddt(T)
+ fvm::div(phi,T) Discretize equations
- fvm::laplacian(DT,T)
);

• Remember, you will need to first create the mesh, and initialize the variables and constants.
That is, all the previous steps.
• Finally, everything we have done so far inherits all parallel directives. There is no need for
specific parallel programming.
27
Programming in OpenFOAM®. Building blocks
Discretization of the basic PDE terms in OpenFOAM®
• The previous discretization is equivalent to,

Creates object TEqn that


fvScalarMatrix TEqn contains the coefficient matrix
arising from the discretization
(
fvm::ddt(T)
+ fvm::div(phi,T) Discretize equations
- fvm::laplacian(DT,T)
);

Teqn.solve(); Solve the linear system Teqn

• Here, fvScalarMatrix contains the matrix derived from the discretization of the model equation.
• fvScalarMatrix is used for scalar fields and fvVectorMatrix is used for vector fields.
• This syntax is more general, since it allows the easy addition of terms to the model equations.
28
Programming in OpenFOAM®. Building blocks
Discretization of the basic PDE terms in OpenFOAM®
• At this point, OpenFOAM® assembles and solves the following linear system,

Coefficient Matrix (sparse, square)


The coefficients depend on geometrical quantities, Boundary conditions
fluid properties and non-linear equations and source terms

Unknow quantity 29
Programming in OpenFOAM®. Building blocks
Example of use of tensor and field classes
• Let us study a fvMesh example. First let us compile the program my_Test-mesh. Type in the
terminal,

1. $> cd $PTOFC/programming_playground/my_mesh/
2. $> wmake

• To access the mesh information, we need to use this program in a valid mesh.

1. $> cd $PTOFC/programming_playground/my_mesh/cavity
2. $> blockMesh
3. $> my_Test-mesh

• At this point, take a look at the output and study the file Test-mesh.C. Try to understand what
we have done.
• FYI, the original example is located in the directory
$PTOFC/programming_playground/test/mesh.
30
Programming in OpenFOAM®. Building blocks
A few OpenFOAM® programming references

• You can access the API documentation in the following link, https://cpp.openfoam.org/v5/
• You can access the coding style guide in the following link, https://openfoam.org/dev/coding-style-guide/
• You can report programming issues in the following link, https://bugs.openfoam.org/rules.php
• You can access openfoamwiki coding guide in the following link,
http://openfoamwiki.net/index.php/OpenFOAM_guide
• You can access the user guide in the following link, https://cfd.direct/openfoam/user-guide/
• You can read the OpenFOAM® Programmer’s guide in the following link (it seems that this guide is not
supported anymore), http://foam.sourceforge.net/docs/Guides-a4/ProgrammersGuide.pdf

A few good C++ references


• The C++ Programming Language. B. Stroustrup. 2013, Addison-Wesley.
• The C++ Standard Library. N. Josuttis. 2012, Addison-Wesley.
• C++ for Engineers and Scientists. G. J. Bronson. 2012, Cengage Learning.
• Sams Teach Yourself C++ in One Hour a Day. J. Liberty, B. Jones. 2004, Sams Publishing.
• C++ Primer. S. Lippman, J. Lajoie, B. Moo. 2012, Addison-Wesley.
• http://www.cplusplus.com/
• http://www.learncpp.com/
• http://www.cprogramming.com/
• http://www.tutorialspoint.com/cplusplus/
• http://stackoverflow.com/
31
Roadmap

1. Programming in OpenFOAM®. Building blocks.


2. Implementing boundary conditions using high level
programming
3. Modifying applications – Highlights
4. Implementing an application from scratch
5. Adding the scalar transport equation to icoFoam

32
Implementing boundary conditions using high level programming

• Hereafter we will work with high level programming, this is the hard part of programming in
OpenFOAM®.
• High level programming requires some knowledge on C++ and OpenFOAM® API library.
• Before doing high level programming, we highly recommend you to try with codeStream, most
of the time it will work.
• We will implement the parabolic profile, so you can compare this implementation with
codeStream ad codedFixedValue BCs.
• When we program boundary conditions, we are building a new library that can be linked with any
solver. To compile the library, we use the command wmake (distributed with OpenFOAM®).
• At this point, you can work in any directory, but we recommend you to work in your
OpenFOAM® user directory, type in the terminal,

1. $> cd $WM_PROJECT_USER_DIR/run

33
Implementing boundary conditions using high level programming

• Let us create the basic structure to write the new boundary condition, type in the terminal,

1. $> foamNewBC –f –v myParabolicVelocity


2. $> cd myParabolicVelocity

• The utility foamNewBC, will create the directory structure and all the files needed to write your
own boundary conditions.
• We are setting the structure for a fixed (the option –f) velocity (the option –v), boundary
condition, and we name our boundary condition ParabolicVelocity .
• If you want to get more information on how to use foamNewBC, type in the terminal,

1. $> foamNewBC –help

34
Implementing boundary conditions using high level programming

Directory structure of the new boundary condition

./myParabolicVelocity
├── Make
│ ├── files
│ └── options
├── myParabolicVelocityFvPatchVectorField.C
└── myParabolicVelocityFvPatchVectorField.H

The directory contains the source code of the boundary condition.


• myParabolicVelocityFvPatchVectorField.C: is the actual source code of the
application. This file contains the definition of the classes and functions.
• myParabolicVelocityFvPatchVectorField.H: header files required to compile the
application. This file contains variables, functions and classes declarations.
• The Make directory contains compilation instructions.
• Make/files: names all the source files (.C), it specifies the boundary condition
library name and location of the output file.
• Make/options: specifies directories to search for include files and libraries to link the
solver against.
35
Implementing boundary conditions using high level programming

The header file (.H)


• Let us start to do some modifications. Open the header file using your favorite text editor (we
use gedit).

96 //- Single valued scalar quantity, e.g. a coefficient


97 scalar scalarData_;
• In lines 96-123 different types of
98 private data are declared.
99 //- Single valued Type quantity, e.g. reference pressure pRefValue_
100 // Other options include vector, tensor • These are the variables we will use for
101 vector data_; the implementation of the new BC.
102
103 //- Field of Types, typically defined across patch faces • In our implementation we need to use
104 // e.g. total pressure p0_. Other options include vectorField vectors and scalars, therefore we can
105 vectorField fieldData_; keep the lines 97 and 101.
106
107 //- Type specified as a function of time for time-varying BCs • We can delete lines 103-117, as we
108 autoPtr<Function1<vector>> timeVsData_; do not need those datatypes.
109
110 //- Word entry, e.g. pName_ for name of the pressure field on database • Also, as we will use two vectors in our
111 word wordData_; implementation, we can duplicate line
112 101.
113 //- Label, e.g. patch index, current time index
114 label labelData_; • You can leave the rest of the file as
115
they are.
116 //- Boolean for true/false, e.g. specify if flow rate is volumetric_
117 bool boolData_;
118
119
120 // Private Member Functions
121
122 //- Return current time
123 scalar t() const;
36
Implementing boundary conditions using high level programming

The header file (.H)


• At this point, your header file should looks like this one,

96 //- Single valued scalar quantity, e.g. a coefficient


97 scalar scalarData_;
98
99 //- Single valued Type quantity, e.g. reference pressure pRefValue_
100 // Other options include vector, tensor
101 vector data_;
102 vector data_;

• Change the name of scalarData_ to maxValue_ (line 97).


• Change the names of the two vectors data_ (lines 101-102). Name the first one n_ and the last
one y_.

96 //- Single valued scalar quantity, e.g. a coefficient


97 scalar maxValue_;
98 It is recommended to initialize
99 //- Single valued Type quantity, e.g. reference pressure pRefValue_
100 // Other options include vector, tensor them in the same order as you
101 vector n_; declare them in the header file
102 vector y_;

• We just declared the variables that we will use. You can now save and close the file.
37
Implementing boundary conditions using high level programming

The source file (.C)

• Let us start to modify the source file. Open the source file with your favorite editor.
• Lines 34-37 refers to a private function definition. This function allows us to access simulation
time. Since in our implementation we do not need to use time, we can safely remove these lines.

34 Foam::scalar Foam::myParabolicVelocityFvPatchVectorField::t() const


35 {
36 return db().time().timeOutputValue();
37 }

• Let us compile the library to see what errors we get. Type in the terminal,

1. $> wmake

• You will get a lot of errors.


• Since we deleted the datatypes fieldData, timeVsData, wordData, labelData and boolData in
the header file, we need to delete them as well in the C file. Otherwise the compiler complains.

38
Implementing boundary conditions using high level programming

The source file (.C)

• At this point, let us erase all the occurrences of the datatypes fieldData, timeVsData,
wordData, labelData, and boolData.
• Locate line 38,

38 Foam::myParabolicVelocityFvPatchVectorField::
...
...
...

• Using this line as your reference location in the source code, follow these steps,
• Erase the following lines in incremental order (be sure to erase only the lines that contain
the words fieldData, timeVsData, wordData, labelData and boolData):
48-52, 63-67, 90-94, 102-106, 115-119, 172-175.
• Erase the following lines (they contain the word fieldData), 126, 140, 151-153.
• Replace all the occurrences of the word scalarData with maxValue (11 occurrences).

39
Implementing boundary conditions using high level programming

The source file (.C)

• Duplicate all the lines where the word data appears (6 lines), change the word data to n in the
first line, and to y in the second line, erase the comma in the last line. For example,

Original statements

45 fixedValueFvPatchVectorField(p, iF),
46 maxValue_(0.0),
47 data_(Zero),
48 data_(Zero),

Modified statements

45 fixedValueFvPatchVectorField(p, iF),
46 maxValue_(0.0),
47 n_(Zero),
48 y_(Zero) Remember to erase the comma

40
Implementing boundary conditions using high level programming

The source file (.C)

• We are almost done; we just defined all the datatypes. Now we need to implement the actual
boundary condition.
• Look for line 147 ( updateCoeffs() member function), and add the following statements,

The actual
147 void Foam::myParabolicVelocityFvPatchVectorField::updateCoeffs() implementation of
148 { the BC is always
149 if (updated()) done in this class
150 {
151 return;
152 }
153 Find patch bounds (minimum
154 boundBox bb(patch().patch().localPoints(), true); and maximum points)
Add these lines

155
156 vector ctr = 0.5*(bb.max() + bb.min()); Coordinates of patch midpoint
157
158 const vectorField& c = patch().Cf(); Access patch face centers
159
160 scalarField coord = 2*((c - ctr) & y_)/((bb.max() - bb.min()) & y_);

x
x
Computes scalar field to be used for defining the parabolic profile
41
Implementing boundary conditions using high level programming

The source file (.C)

• Add the following statement in line 164,

The access function operator== is


used to assign the values to the
162 fixedValueFvPatchVectorField::operator== boundary patches
163 (
164 n_*maxValue_*(1.0 - sqr(coord)) Our boundary condition
165 );
166

• The last step before compiling the new BC is to erase a few commas.
• Look for lines 48, 64, 92, 105, 119, and erase the comma at the end of each line.
• At this point we have a valid library where we implemented a new BC.
• Finally, you can go back to the header file (*.H) and document your boundary condition
implementation.
• You can add the comments in the header of the file (lines 1-73).

42
Implementing boundary conditions using high level programming

The source file (.C)

• At this point we have a valid library where we have implemented a new BC.
• Try to compile it, we should not get any error (maybe one warning). Type in the terminal,

1. $> wmake

• If you are feeling lazy, or if you can not fix the compilation errors, you will find the source code in
the directory,
• $PTOFC/101programming/src/myParabolicVelocity

43
Implementing boundary conditions using high level programming

The source file (.C)

• Before moving forward, let us comment a little bit the source file.
• First at all, there are five classes constructors and each of them have a specific task.
• In our implementation we did not use all the classes, we only use the first two classes.
• The first class is related to the initialization of the variables.
• The second class is related to reading the input dictionaries.
• We will not comment on the other classes as it is out of the scope of this example (they deal
with input tables, mapping, and things like that).
• The implementation of the boundary condition is always done using the updateCoeffs()
member function.
• When we compile the source code, it will compile a library with the name specified in the file
Make/file. In this case, the name of the library is libmyParabolicVelocity.
• The library will be located in the directory $(FOAM_USER_LIBBIN), as specified in the file
Make/file.

44
Implementing boundary conditions using high level programming

The source file (.C)

• The first class is related to the initialization of the variables declared in the header file.
• In line 47 we initialize maxValue with the value of zero. The vectors n and y are initialized as a
zero vector by default or (0, 0, 0).
• It is not a good idea to initialize these vectors as zero vectors by default. Let us use as default
initialization (1, 0, 0) for vector n and (0,1,0) for vector y.

38 Foam::myParabolicVelocityFvPatchVectorField::
39 myParabolicVelocityFvPatchVectorField
40 (
41 const fvPatch& p,
42 const DimensionedField<vector, volMesh>& iF
43 )
44 :
45 fixedValueFvPatchVectorField(p, iF),
46 maxValue_(0.0),
47 n_(Zero), Change to n_(1,0,0)
48 y_(Zero)
49 {
50 } Change to y_(0,1,0)

45
Implementing boundary conditions using high level programming

The source file (.C)

• The second class is used to read the input dictionary.


• Here we are reading the values defined by the user in the dictionary U.
• The function lookup will search the specific keyword in the input file.

53 Foam::myParabolicVelocityFvPatchVectorField::
54 myParabolicVelocityFvPatchVectorField
55 (
56 const fvPatch& p,
57 const DimensionedField<vector, volMesh>& iF,
58 const dictionary& dict
59 )
60 :
61 fixedValueFvPatchVectorField(p, iF),
dict.lookup will look for
62 maxValue_(readScalar(dict.lookup("maxValue"))),
63 n_(pTraits<vector>(dict.lookup("n"))), these keywords in the
64 y_(pTraits<vector>(dict.lookup("y"))) input dictionary
65 {
66
67
68 fixedValueFvPatchVectorField::evaluate();

77 }

46
Implementing boundary conditions using high level programming

The source file (.C)

• Since we do not want the vectors n and y to be zero vectors, we add the following sanity check
starting form line 67.
• These statements check if the given n and y vectors in the input dictionary is zero or not.
• If any of the vectors are zero it gives the fatal error and terminate the program.
• On the other hand, if everything is ok it will normalize n and y (since in our implementation they
are direction vectors).

66

Add these statements


67 if (mag(n_) < SMALL || mag(y_) < SMALL)
68 {
69 FatalErrorIn("parabolicVelocityFvPatchVectorField(dict)")
70 << "n or y given with zero size not correct"
71 << abort(FatalError);
72 }
73
74 n_ /= mag(n_); //This is equivalent to n_ = n_/mag(n_)
75 y_ /= mag(y_); //This is equivalent to y_ = y_/(mag(y_)
76
77 fixedValueFvPatchVectorField::evaluate();
78

47
Implementing boundary conditions using high level programming

The source file (.C)

• At this point, we are ready to go.


• Save the files and recompile. Type in the terminal,

1. $> wmake

• We should not get any error (maybe one warning).


• At this point we have a valid library that can be linked with any solver.
• If you get compilation errors, read the screen and try to sort it out, the compiler is always telling
you what is the problem.
• If you are feeling lazy, or if you can not fix the compilation errors, you will find the source code in
the directory,
• $PTOFC/101programming/src/myParabolicVelocity

48
Implementing boundary conditions using high level programming

The source file (.C)

• Before using the new BC, let us take a look at the logic behind the implementation.

ound ox ( a c (). a c ().local oin s(), rue);

cons vec or ield c a c (). f(); vec or c r . ( .max() .min());

scalar ield coord ((c c r) y ) (( .max() .min()) y );

ser defined

n max alue ( . s r(coord))

49
Implementing boundary conditions using high level programming

Running the case


• This case is ready to run, the input files are located in the directory
$PTOFC/101programming/src/case_elbow2d
• Go to the case directory,

1. $> cd $PTOFC/101programming/src/case_elbow2d

• Open the file 0/U, and look for the definition of the new BC velocity-inlet-5,

velocity-inlet-5
{
type myParabolicVelocity; Name of the boundary condition

maxValue 2.0;
n (1 0 0); User defined values
y (0 1 0); max value, n, y
} If you set n or y to (0 0 0), the solver will
abort execution

50
Implementing boundary conditions using high level programming

Running the case


• We also need to tell the application that we want to use the library we just compiled.
• To do so, we need to add the new library in the dictionary file controlDict,

15 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
16
17 libs ("libmyParabolicVelocity.so"); Name of the library
18 You can add as many libraries as you like
19 application icoFoam;

• The solver will dynamically link the library.


• At this point, we are ready to launch the simulation.

51
Implementing boundary conditions using high level programming

Running the case


• This case is ready to run, the input files are located in the directory
$PTOFC/101programming/src/case_elbow2d
• To run the case, type in the terminal,

1. $> foamCleanTutorials
2. $> fluentMeshToFoam ../../../meshes_and_geometries/fluent_elbow2d_1/ascii.msh

3. $> icoFoam | tee log.solver


4. $> paraFoam

• At this point, you can compare the three implementations (codeStream, codedFixedValue and
high-level programming).
• All of them will give the same outcome.

52
Implementing boundary conditions using high level programming

Adding some verbosity to the BC implementation

• Let us add some outputs to the BC.


• After the member function updateCoeffs (line 177), add the following lines,

177 fixedValueFvPatchVectorField::updateCoeffs();
178
179 Info << endl << "Face centers (c):" << endl;
180 Info << c << endl;
181 Info << endl << "Patch center (ctr):" << endl;
182 Info << ctr << endl;
183 Info << endl << "Patch (c - ctr):" << endl;
184 Info << c - ctr << endl;
185 Info << endl << "Patch max bound (bb.max):" << endl;
186 Info << bb.max() << endl;
187 Info << endl << "Patch min bound (bb.max):" << endl;
188 Info << bb.min() << endl;
189 Info << endl << "Patch coord ( 2*((c - ctr) & y_)/((bb.max() - bb.min()) & y_) ):" << endl;
190 Info << coord << endl;
191 Info << endl << "Patch ( 1.0 - sqr(coord)) :" << endl;
192 Info << n_*maxValue_*(1.0 - sqr(coord))<< endl;
193 Info << endl << "Loop for c, BC assigment << endl;
194 forAll(c, faceI)
195 {
196 Info << c[faceI] << " " << n_*maxValue_*(1.0 - sqr(coord[faceI])) << endl;
197 }
198
199

• Recompile, rerun the simulation, look at the output, and do the math.
53
Implementing boundary conditions using high level programming

• In the directory $PTOFC/101programming/src/myParabolicVelocityMod, you will find


an implementation of this boundary condition with conditional switches and screen output
information.
• Try to figure out how this BC works.

• Do you take the challenge?


• Starting from this boundary condition, try to implement a paraboloid BC.
• If you are feeling lazy or at any point do you get lost, in the directory
$PTOFC/101programming/src/myParaboloidVelocity you will find a working
implementation of the paraboloid profile.
• Open the source code and try to understand what we did (pretty much similar to the
previous case).
• In the directory $PTOFC/101programming/src/case_elbow3d you will find a case
ready to use.

54
Roadmap

1. Programming in OpenFOAM®. Building blocks.


2. Implementing boundary conditions using high level
programming
3. Modifying applications – Highlights
4. Implementing an application from scratch
5. Adding the scalar transport equation to icoFoam

55
Modifying applications – Highlights
• Implementing a new application from scratch in OpenFOAM® (or any other high-level
programming library), can be an incredible daunting task.
• OpenFOAM® comes with many solvers, and as it is today, you do not need to implement new
solvers from scratch.
• Of course, if your goal is to write a new solver, you will need to deal with programming. What
you usually do, is take an existing solver and modify it.
• But in case that you would like to take the road of implementing new applications from scratch,
we are going to give you the basic building blocks.
• We are also going to show how to add basic modifications to existing solvers.
• We want to remind you that this requires some knowledge on C++ and OpenFOAM® API library.
• Also, you need to understand the FVM, and be familiar with the basic algebra of tensors.
• Some common sense is also helpful.

56
Roadmap

1. Programming in OpenFOAM®. Building blocks.


2. Implementing boundary conditions using high level
programming
3. Modifying applications – Highlights
4. Implementing an application from scratch
5. Adding the scalar transport equation to icoFoam

57
Implementing an application from scratch
• Let us do a little bit of high-level programming, this is the hard part of working with
OpenFOAM®.
• At this point, you can work in any directory. But we recommend you to work in your
OpenFOAM® user directory, type in the terminal,

1. $> cd $WM_PROJECT_USER_DIR/run

• To create the basic structure of a new application, type in the terminal,

1. $> foamNewApp scratchFoam


2. $> cd scratchFoam

• The utility foamNewApp, will create the directory structure and all the files needed to create the
new application from scratch. The name of the application is scratchFoam.
• If you want to get more information on how to use foamNewApp, type in the terminal,

1. $> foamNewApp –help


58
Implementing an application from scratch
Directory structure of the new boundary condition
scratchFoam/
├── createFields.H Does not exist, we will create it later
├── scratchFoam.C
└── Make
├── files
└── options

The scratchFoam directory contains the source code of the solver.


• scratchFoam.C: contains the starting point to implement the new application.
• createFields.H: in this file we declare all the field variables and initializes the solution.
This file does not exist at this point, we will create it later.
• The Make directory contains compilation instructions.
• Make/files: names all the source files (.C), it specifies the name of the solver and
location of the output file.
• Make/options: specifies directories to search for include files and libraries to link the
solver against.
• To compile the new application, we use the command wmake.
59
Implementing an application from scratch
• Open the file scratchFoam.C using your favorite text editor, we will use gedit.
• At this point you should have this file that does not do anything. We need to add the statements
to create a working applications.
• This is the starting point for new applications.

This header is extremely important, it will add all the class


30 declarations needed to access mesh, fields, tensor algebra, fvm/fvc
31 #include "fvCFD.H" operators, time, parallel communication, linear algebra, and so on.
32
33 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
34
35 int main(int argc, char *argv[])
36 {
37 #include "setRootCase.H"
38 #include "createTime.H"
39
40 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
41
42 Info<< nl << "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
43 << " ClockTime = " << runTime.elapsedClockTime() << " s"
44 << nl << endl;
45
46 Info<< "End\n" << endl;
47
48 return 0;
49 }
50

60
Implementing an application from scratch
• Stating from line 31, add the following statements.
• We are going to use the PISO control options, even if we do not have to deal with velocity-
pressure coupling.

30
31 #include "fv D.H“

32 #include "pisoControl.H" Solution control using PISO class


33
34 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
35
36 int main(int argc, char *argv[])
37 {
38 #include "se Roo ase.H“ Set directory structure

39 #include "crea eTime.H“ Create time (object runtime)

41 #include "crea eMes .H“ Create time (object mesh)

42 #include "crea e ields.H“ Initialize fields


This source file does not exist yet, we need to create it
43 #include " ouran No.H“ Calculates and outputs the Courant Number

44 #include "ini on inui yErrs.H“ Declare and initialize the cumulative continuity error
Assign PISO controls to object mesh. Creates object piso.
49 pisoControl piso(mesh);
Alternatively, you can use the header file createControl.H
51 Info<< "\nStarting time loop\n" << endl; Output some information
61
Implementing an application from scratch
• We are going to use the PISO control options, even if we do not have to deal with velocity-
pressure coupling.

53 while (runTime.loop()) Time loop


54 {
55 Info<< "Time = " << runTime.timeName() << nl << endl;
56
57 #include "CourantNo.H" Calculates and outputs the Courant Number
58
59 while (piso.correct()) PISO options (correct loop)
60 {
PISO options (non orthogonal corrections
61 while (piso.correctNonOrthogonal())
loop)
62 {
63 fvScalarMatrix Teqn Create object TEqn.
fvScalarMatrix is a scalar instance of fvMatrix
64 ( Model equation (convection-diffusion)
65 fvm::ddt(T) We need to create the scalar field T, vector
66 + fvm::div(phi, T) field U (used in phi or face fluxes), and the
67 - fvm::laplacian(DT, T) constant DT.
68 ); We will declare these variables in the
createFields.H header file.
In the dictionary fvSchemes, you will need to
define how to compute the differential
operators, that is,
ddt(T)
70 TEqn.solve(); div(phi, T)
71 } laplacian(DT, T)
Solve TEqn
72 } You will need to define the linear solver for T
At this point the object
TEqn holds the solution. in the dictionary fvSolution
62
Implementing an application from scratch
• We are going to use the PISO control options, even if we do not have to deal with velocity-
pressure coupling.

If you want to compute the CPU time of each iteration,


74 #include "continuityErrs.H" Computes continuity errors

add the same statement inside the time loop


Write CPU time at the end of the time loop.
76 runTime.write(); Write the solution in the runtime folder
It will write the data requested in the file createFields.H

78 } At this point we are outside of the time loop


79
80 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
81
82 Info<< nl << "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
83 << " ClockTime = " << runTime.elapsedClockTime() << " s"
84 << nl << endl;
85
86 Info<< "End\n" << endl; Output this message
87

88 return 0; End of the program (exit status).


89 } If everything went fine, the program should return 0.
90 To now the return value, type in the terminal,
91 $> echo $?

63
Implementing an application from scratch
• Let us create the file createFields.H, type in the terminal,

1. $> touch createFields.H

• Now open the file with your favorite editor, and start to add the following information,

1 Info<< "Reading field T\n" << endl;


2
3 volScalarField T Create scalar field T
4 (
5 IOobject Create object for input/output operations
6 (
7 "T", Name of the dictionary file to read/write
8 runTime.timeName(), runtime directory
9 mesh, Object registry
10 IOobject::MUST_READ,
11 IOobject::AUTO_WRITE Read the dictionary in the runtime directory
12 ), (MUST_READ, and write the value in the runtime
13 mesh Link object to mesh directory (AUTO_WRITE).
14 ); If you do not want to write the value, use the option
NO_WRITE

64
Implementing an application from scratch
• Remember, in the file createFields.H, we declare all the variables (or fields) that we will use
(U and T in this case).
• The dimensions of the fields are defined in the input dictionaries, you also have the option to
define the dimensions in the source code.
• You can also define the fields directly in the source file scratchFoam.C, but it is good practice
to do it in the header. This improves code readability.

17 Info<< "Reading field U\n" << endl;


18
19 volVectorField U Create vector field U
20 (
21 IOobject
22 (
23 "U", Name of the dictionary file to read/write
24 runTime.timeName(),
25 mesh,
26 IOobject::MUST_READ,
27 IOobject::AUTO_WRITE
28 ),
29 mesh
30 );
31

65
Implementing an application from scratch
• We also need to declare the constant DT, that is read from the dictionary
transportProperties.
• The dimensions are defined in the input dictionary.

33 Info<< "Reading transportProperties\n" << endl;


34
35 IOdictionary transportProperties Create object transportProperties used to
36 ( read data
37 IOobject
38 ( Name of the input dictionary
39 "transportProperties",
40 runTime.constant(), Location of the input dictionary, in this case
41 mesh, is located in the directory constant
42 IOobject::MUST_READ_IF_MODIFIED, Re-read data if it is modified
43 IOobject::NO_WRITE
44 ) Do not write anything in the dictionary
45 );
46
47
48 Info<< "Reading diffusivity DT\n" << endl;
49
50 dimensionedScalar DT Create scalar DT (diffusion coefficient)
51 (
52 transportProperties.lookup("DT") Access value of DT in the object
53 ); transportProperties
54
55 #include "createPhi.H" Creates and initializes the relative face-
56 flux field phi.

66
Implementing an application from scratch
• At this point, we are ready to compile. Type in the terminal,

1. $> wmake

• If everything went fine, you should have a working solver named scratchFoam.
• If you are feeling lazy or you can not fix the compilation errors, you will find the source code in
the directory,

• $PTOFC/101programming/applications/solvers/scratchFoam

• You will find a case ready to run in the directory,

$PTOFC/101programming/applications/solvers/scratchFoam/test_case

• At this point, we are all familiar with the convection-diffusion equation and OpenFOAM®, so you
know how to run the case. Do your magic.

67
Implementing an application from scratch
• Let us now add a little bit more complexity, a non-uniform initialization of the scalar field T.
• Remember codeStream? Well, we just need to proceed in a similar way.
• As you will see, initializing directly in the source code of the solver is more intrusive than using
codeStream in the input dicitionaries.
• It also requires recompiling the application.
• Add the following statements to the createFields.H file, recompile and run again the test
case.

16
17 forAll(T, i) We add the initialization of T after the its declaration
18 {
19 const scalar x = mesh.C()[i][0];
20 const scalar y = mesh.C()[i][1]; Access cell center coordinates.
21 const scalar z = mesh.C()[i][2]; In this case y and z coordinates are not used.
22
23 if ( 0.3 < x && x < 0.7) Conditional structure
24 {
25 T[i] = 1.;
26 }
27 }
28 T.write(); Write field T. As the file createFields.H is outside the time loop
the value is saved in the time directory 0

68
Implementing an application from scratch
• Let us compute a few extra fields. We are going to compute the gradient, divergence, and
Laplacian of T.
• We are going to compute these fields in an explicit way, that is, after finding the solution of T.
• Therefore we are going to use the operator fvc.
• Add the following statements to the source code of the solver (scratchFoam.C),

68 }
69
70 #include "continuityErrs.H"
71 #include "write.H" Add this header file
72 runTime.write();
73 The file is located in the directory
74 } $PTOFC/101programming/applications/solvers/scratchFoam
In this file we declare and define the new variables, take a look at it

• Recompile the solver and rerun the test case.


• The solver will complain, try to figure out what is the problem (you are missing some information
in the fvSchemes dictionary).
69
Implementing an application from scratch
• Let us talk about the file write.H,

1 volVectorField gradT(fvc::grad(T)); Compute gradient of T.


2 fvc is the explicit operator, it will compute the
3 volVectorField gradT_vector
requested value using the solution of T
4 (
5 IOobject
6 (
7 "gradT",
8 runTime.timeName(), Save vector field in output dictionary gradT
9 mesh,
10 IOobject::NO_READ,
11 IOobject::AUTO_WRITE
12 ),
13 gradT
14 );
15
...
56
57 volScalarField divGradT
58 (
59 IOobject
60 (
Compute divergence of gradT.
61 "divGradT", The output of this operation is a scalar field.
62 runTime.timeName(), In this case we compute the quantity inside the scalar field
63 mesh, declaration (line 67).
64 IOobject::NO_READ, We use the fvc operator because the solution of gradT is
65 IOobject::AUTO_WRITE already known.
66 ),
67 fvc::div(gradT)
68 ); In the dictionary fvSchemes, you will need to tell the solver how to do
69 ... the interpolation of the term div(grad(T))
70
Roadmap

1. Programming in OpenFOAM®. Building blocks.


2. Implementing boundary conditions using high level
programming
3. Modifying applications – Highlights
4. Implementing an application from scratch
5. Adding the scalar transport equation to icoFoam

71
Adding the scalar transport equation to icoFoam
• Let us modify a solver, we will work with icoFoam.
• We will add a passive scalar (convection-diffusion equation).
• At this point, you can work in any directory. But we recommend you to work in your
OpenFOAM® user directory, type in the terminal,

1. $> cd $WM_PROJECT_USER_DIR/run

• Let us clone the original solver, type in the terminal,

1. $> cp -r $FOAM_APP/solvers/incompressible/icoFoam/ my_icoFoam

2. $> cd my_icoFoam

• At this point, we are ready to modify the solver.

72
Adding the scalar transport equation to icoFoam
• Open the file icoFoam.C using your favorite editor and add the new equation in lines 115-120,

111 U = HbyA - rAU*fvc::grad(p);


112 U.correctBoundaryConditions();
113 } Scalar transport equation.
The name of the scalar is S1.
114
We need to declare it in the
createFields.H file.
116 solve We also need to read the coefficient DT.
117 (
118 fvm::ddt(S1) In the dictionary fvSchemes, you will need
119 + fvm::div(phi, S1) to define how to compute the differential
operators, that is,
120 - fvm::laplacian(DT, S1)
ddt(S1)
121 ); div(phi, S1)
laplacian(DT, S1)
122
123 You will need to define the linear solver
124 runTime.write(); for S1 in the dictionary fvSolution

• As the passive scalar equation depends on the vector field U, we need to add this equation after
solving U.
73
Adding the scalar transport equation to icoFoam
• Open the file createFields.H using your favorite editor and add the following lines at the
beginning of the file,

1
2 volScalarField S1
3 (
4 IOobject
5 ( Declaration of scalar field S1.
6 "S1", The solver will read the input file S1
7 runTime.timeName(), (BC and IC).
8 mesh,
9 IOobject::MUST_READ, You will need to create the file S1 in
10 IOobject::AUTO_WRITE the time directory 0.
11 ),
12 mesh
13 );
14
15 Info<< "Reading diffusionProperties\n" << endl;
16
17 IOdictionary diffusionProperties
18 (
19 IOobject Declaration of input/output dictionary
20 ( file.
21 "diffusionProperties", The name of the dictionary is
22 runTime.constant(), diffusionProperties and is located in
23 mesh,
24 IOobject::MUST_READ_IF_MODIFIED,
the directory constant.
25 IOobject::NO_WRITE
26 )
27 );
28
29 Info<< "Reading diffusivity DT\n" << endl;
30 dimensionedScalar DT
31 (
Read DT value from the dictionary
32 diffusionProperties.lookup("DT") diffusionProperties.
33 ); 74
Adding the scalar transport equation to icoFoam
• Those are all the modifications we need to do.
• But before compiling the new solver, we need to modify the compilation instructions.
• Using your favorite editor, open the file Make/files,

Original file

1 icoFoam.C
2
3 EXE = $(FOAM_APPBIN)/icoFoam

Modified file

Name of the executable.


1 icoFoam.C Name of the input file To avoid conflicts with the original
installation, we give a different
2 name to the executable
3 EXE = $(FOAM_USER_APPBIN)/my_icoFoam
Location of the executable.
To avoid conflicts with the original installation, we install the
executable in the user’s personal directory
75
Adding the scalar transport equation to icoFoam
• At this point we are ready to compile, type in the terminal,

1. $> wmake

• If everything went fine, you should have a working solver named my_icoFoam.

• If you are feeling lazy or you can not fix the compilation errors, you will find the source code in
the directory,

• $PTOFC/101programming/applications/solvers/my_icoFoam

• You will find a case ready to run in the directory,

$PTOFC/101programming/applications/solvers/my_icoFoam/test_case

76
Adding the scalar transport equation to icoFoam
Running the case
• This case is ready to run, the input files are located in the directory
$PTOFC/101programming/applications/solvers/my_icoFoam/test_case
• To run the case, type in the terminal,

1. $> foamCleanTutorials
2. $> fluentMeshToFoam ../../../../../meshes_and_geometries/fluent_elbow2d_1/ascii.msh

3. $> my_icoFoam | tee log


4. $> paraFoam

• Remember, you will need to create the file 0/S1 (boundary conditions and initial conditions for
the new scalar).
• You will also need to create the input dictionary constant/diffusionProperties, from this
dictionary we will read the diffusion coefficient value.
• Finally, remember to update the files system/fvSchemes and
system/fvSolution to take into account the new equation.

77
Adding the scalar transport equation to icoFoam
Running the case
• If everything went fine, you should get something like this

S1 = 300

S1 = 350
S1 = 400

S1 inlet values Visualization of velocity magnitude and passive scalar S1


www.wolfdynamics.com/wiki/BCIC/2delbow_S1

78

You might also like