
User's Manual

Last updated: 04/21/2009
Version: 0.1.2
1. Installation Instructions

Free CFD is an open source code distributed under GPL license v3. You can download the source code and compile on any platform. Below, you will find instructions for a Linux system which should be straightforward to adapt for Unix and OS/X systems. For Windows, on the other hand, you would need cygwin and some familiarity with Linux.
1.1 Dependencies

Free CFD depends on a few third party tools as listed below. All of these are free and open-source. Download each from their websites and follow their installation instructions. Some Linux distributions provide the first three of them through their package management systems (e.g Gentoo portage, Debian/Ubuntu apt-get, ...).

OpenMPI: Needed for parallel communication.

PETSc: Needed for linear system solvers.

ParMETIS: Needed for grid partitioning.

CGNS: Standardized CFD grid/solution formats.
1.2 Environment Variables

Now that the dependencies are installed, we need to let Free CFD know where they are located. Here we will assume that you are using the bash shell. Open your .bashrc file with your favorite text editor

$ nano ~/.bashrc

And add the following environment variables.

export CGNS_BASE=/path/to/cgnslib
export PARMETIS_BASE=/path/to/parMetis
export PETSC_DIR=/path/to/petsc

Of course /path/to/dependency should be replaced by the real path to each dependency. After adding these variables, for just the first time, you need to source your .bashrc file:

$ source ~/.bashrc

Free CFD expects to find the libraries and header files for each dependency at:

/path/to/dependency/lib
/path/to/dependency/include

1.3 Compiling Free CFD

If you haven't done so already, download the latest Free CFD release version. Move the tarball to a directory of your choice and unpack by:

$ tar -zxvf free-cfd-X.X.X.tar.gz

replace X.X.X by the correct version number. Now let's look at what we end up with:

$ cd free-cfd-X.X.X
$ ls
  docs examples src

Here, the src directory holds all the source code while docs and examples hold documentation and a few example cases that we provide with the release. Now hoping that the dependencies are installed and the environment variables are set, let's go to the source directory and compile:

$ cd src
$ make

After a successful make, you will end up with an fcfd executable in the src directory. If the compile step was not so successful, your next stop is our forum where we will do our best to help you.
2. Using Free CFD

Free CFD needs two files to define a case: grid file and input file. These two files need to be located on the same folder and have the same name (except of course the extension).
2.2 Grid file

Free CFD currently only accepts the CGNS format which is supported by most grid generation software. We do not provide a grid generator but if you are interested in using another format, please contact us and if we see it feasible, we can work with you on implementing a new reader.

Note that there are several ways a CGNS file can be structured. Depending on the grid generator, the exact structure may vary and Free CFD may encounter problems reading the file. Although we have tested a range of different grid configurations such as single/multi-block structured/unstructured/mixed-element without any problems, if you bump into any issues, please report on our forum.

Grids need to be 3D. Even if you want to solve a 2D problem, you still need at least 1 layer of cells in the third dimension.

Boundary condition regions need to be identified in the grid generator. Some generators offer a feature of setting the boundary condition type too. This is unnecessary as that assignment is not used by Free CFD. Hovewer, naming each region will help you.

Grid files need to have an extension of ".cgns"
2.3 Input file

Free CFD has a single file for specifying all the options, boundary and initial conditions. The input file has an extension of ".in"

The input file follows a C++ like syntax and it is organized in 3 levels: entries, sections, subsections. Before this gets confusing, let's start off with an example:

/*
An example Free CFD input file format syntax and organization
This is a block comment
*/
// C++ style inline comments are also allowed
 
equations=NS; // An entry, must be followed by a semi-colon
 
/*
Following is a section called timeMarching
Anything inside the curly braces following the section name
belong to that section
*/
timeMarching {
        CFLmax=1.e4; // An entry
        // Ramp is a subsection identified by the parenthesis
        // Entries inside the parenthesis belong to the ramp section
        ramp(initial=1; growth=1.1;);
        // A subsection itself is actually an entry within the
        // parent section. So a semicolon needs to be placed
        // following the closing parenthesis
        numberOfSteps=1000;
} // No need for a semicolon at section closing

Entries, section and subsection blocks do not need to follow a certain order. Also, all the white spaces in the file are ignored. However, the input file is cAsE seNsiTive. i.e. "timemarching" instead of "timeMarching" would not be recognized, however, "time Marching" would be acceptable.

Now let's look at the available options:

equations=NS;
// Choose the equation system to solve.
// Available options are "NS", for Navier-Stokes, and "Euler".
// If not specified, default value is "NS". 
 
turbulence {
model=sst;
// Choice of the model. Available options are
// "none", "k-epsilon", "k-omega", "bsl" and "sst"
// "bsl" corresponds to Menter's BSL model
// "sst" corresponds to Menter's Shear Stress Transport model
// *NOTE* Even if you are using k-epsilon, Free CFD
// will still be using omega instead of epsilon
omegaLowLimit=1.;
// Optional, default value is 1.
kLowLimit=1.e-8;
// Optional, default value is 1.e-8
viscosityRatioLimit=1.e5;
// Optional. Caps the maximum ration of
// eddy viscosity / laminar viscosity
// Default value is 1.e5;
}
 
grid {
dimension=2; // Optional, default is 3
// In 1D or 2D runs, you can still use dimension=3. But specifying the
// correct value will reduce the node interpolation stencil size.
scaleBy=[1.,1.,1.];
// Vector entry "scaleBy" contains factors with which the mesh is scaled
// A vector entry has three components listed within square brackets,
// separated with commas
// In case of scaleBy, the three components contain
// x,y and z scale factors
// Skip this if you don't need scaling
rotationCenter=[0.,0.,0.]; rotationAngles=[10.,0.,0.];
// Rotate the whole grid around a point
// Angles are in degress and represent amount of rotation
// around x, y and z axes.
// Skip this if you don't want to rotate
// **NOTE** every coordinate specification following this point
// must be thought as after scaling and rotation
}
 
reference{
Mach=1.;
// Reference Mach number is used with the AUSM+-up flux function
// to correctly scale the dissipation at low speeds. For fully
// supersonic flows, skip this entry. Otherwise, specify a value
// representative of the low Mach number regions in the domain.
// 1.e-4 should be a safe value
p=0.;
// "p" is the reference pressure. Every other pressure specification is
// treated as relative to this value.
// If skipped, 0. is assumed
T=273.;
// "T" is the reference temperature. Every other temperature
// specification is treated as relative to this value.
// If skipped, 273. is assumed
} 
 
timeMarching {
integrator=backwardEuler;
// Available options for integrator is "forwardEuler" and "backwardEuler"
// Corresponding to explicit and implicit solvers, both 1st order
// If skipped, "backwardEuler" is assumed
stepSize=1.e-3;
// If "stepSize" is specified, a constant time step value is used
/* CFLmax=1.e4; */ // Commented out since stepSize is specified
// If "CFLmax" is specified, time step value is found such as the
// the maximum CFL number in the domain doesn't exceed the
// specified value
/* CFLlocal=1.e3; */ //Commented out since stepSize is specified
// If "CFLlocal" is specified, time step value is variable for each cell
// such that the local CFL number matches the specified value
// This will not be time accurate but maybe useful for steady problems
ramp (initial=1.e-4; growth=1.1);
// Whatever method of time stepping is chosen above, there is an
// option to start with a lower value and ramp up with a growth factor
// If the "ramp" subsection is skipped, ramping is not used
numberOfSteps=1000;
// "numberOfSteps" specifies how many time steps will be marched
}
 
numericalOptions{
convectiveFlux=AUSM+up;
// Select inviscid flux function. Available options are
// "Roe" and "AUSM+up". If skipped, "AUSM+up" is used
order=second;
// Order of accuracy of the convective flux function. "first" or "second"
// If skipped, "second" is used
limiter=doubleMinmod;
// Limit the gradients so as to avoid new extrema at faces.
// Available options are "none", "minmod", "doubleMinmod",
// "harmonic" and "superbee"
// Not needed for first order method
// You may not need this for low speed flows, but if you have
// stability problems, try using one
// If skipped, no limiter is used
preconditioner=ws95;
// low-Ma preconditioning due to Weiss-Smith'95
// options are "none" or "ws95"
// Hurts time accuracy
} 
 
linearSolver {
relTolerance=1.e-5;
// Drop in residual before proceeding to the next time step
absTolerance=1.e-8;
// Absolute value of the residual before proceeding to the next time step
maxIterations=50;
// Maximum number of iterations before giving up, a required entry
// When one of the above criteria is reached, time is marched
} 
 
fluidProperties {
gamma=1.4; // Required
viscosity=1.e-3; // Required if "equations" selection is "NS"
molarMass=0.02897; // in kg/mol
// molarMass is used in calculating the ideal gas constant
// If skipped, air's molar mass is used by default
} 
 
writeOutput {
format=tecplot;
// Available options are "tecplot" and "vtk"
// "tecplot" writes out ASCII format output for Tecplot
// "vtk" writes out parallel unstructured vtk format
// which Paraview can read
plotFrequency=10;
// Frequency of time steps at which output file is written
restartFrequency=100;
// Frequency of time steps at which a restart point is generated
// Frequency of zero will crash the code, so if you don't want
// output, just set the frequency to a large number
} 
 
initialConditions {
// You can have multiple initial conditions for different regions
// Each initial condition is a subsection named as IC_#
// Conditions are applied sequentially based on the number
// "k" and "omega" is required only if using a turbulence model
IC_1 (rho=1; p=1; v=[0,0,0]; k=0.1; omega=1.e5;);
// "IC_1" will initialize the whole domain to the given conditions
// You need to specify two of "p", "rho" and "T" to fix the state
// "p" and "T" should be thought as relative to the values given in
//  the "reference" section
// Note that v is the velocity vector. As such it has three components
// listed within square brackets, separated with commas
IC_2 (region=box; corner_1=[0.5,-1,-1]; corner_2=[1,1,1];
    rho=2; p=2; v=[1,0,0]; k=0.1; omega=1.e5;)
// "IC_2" selects a box region defined by two corner coordinates
// Any cell center of which lies within the defined box is selected
IC_3 (region=cylinder; center=[1,1,1]; radius=0.5; height=1;
    axisDirection=[0,0,1]; rho=2; p=2; v=[0.1,0,0]; k=0.1; omega=1.e5;)
// "IC_3" selects a cylindrical region, note that center
// and axisDirection are vectors. The velocity vector components are
// now treated as axial, radial and circumferential velocities
IC_4 (region=sphere; center=[1,1,1]; radius=0.5; rho=2; p=2; v=[1.,0,0];
      k=0.1; omega=1.e5;)
// "IC_4" selects a spherical region. First velocity component is
// treated as the radial velocity while the rest is ignored
} 
 
boundaryConditions {
// Boundary conditions are also a numbered list of subsections
BC_1(type=symmetry;);
// "BC_1" is defined as a symmetry boundary condition about which
// the variables are reflected. Use this for front and back planes
// in 2D simulations
BC_2(type=slip;);
// "BC_2" is a slip boundary, normal component of the velocity is
// killed, tangential component is kept.
// If "T" is specified, temperature is fixed, else adiabatic assumed
// Other variables are extrapolated from inside
BC_3 (type=noslip;);
// "BC_3" is a noslip wall condition. Velocity vector is set to zero
// If "T" is specified, temperature is fixed, else adiabatic assumed
BC_4 (type=inlet; rho=1; v=[1,0,0]; k=0.1; omega=1.e5;);
// "BC_4" is an inlet. We don't have a separation between subsonic and
// supersonic inlet types. In subsonic cases, you should generally
// specify pressure at the outlet. In supersonic, you need to specify
// the thermodynamic state at the inlet by providing two of
// "rho", "p" and "T"
// "k" and "omega" is required only if using a turbulence model
BC_5 (type=outlet;);
// "BC_5" is an outlet. Every variable is extrapolated from inside
BC_6(type=outlet; p=1;);
// "BC_6" is also an outlet but now the pressure value is specified
// while the rest is extrapolated. Recommended for subsonic outlets
 
/*
All of the above boundary condition regions (which are faces on the grid)
followed from the grid file in the exact order it was written. Sometimes
it is useful to override/split some of those.
 
An example below demonstrates this.
*/
 
BC_8 (
region=box;
// Define a box region with two corner coordinates
corner_1=[-0.5,-1,-1];
corner_2=[-0.4,1,1];
pick=BC2;
type=noslip;
// Any face that was originally part of "BC_2" (slip) and that falls
// within the box specified here, now becomes a noslip condition
// Only the box method is supported for now
}
 
probes { frequency=1;
        probe_1 (coord=[0.,0.05,0.];);
        probe_2 (coord=[1.,0.,0.];);
// Probe a certain point in the flowfield
// probe#.dat file is created in the case folder and
// timeStep time p u v w T rho k omega eddyViscosity
// is appended on specified frequency of timeSteps
// **NOTE** specified coordinate may not be exactly matched
// Nearest cell center value is written
}
 
integrateBoundary { frequency=1;
        flux_1 (bc=2;);
	flux_2 (bc=4;);
// integrated values of fluxes are written to flux_bc_#.dat on specified
// frequency of time steps. The file contains:
// timeStep time mass x-momentum y-momentum z-momentum energy
}

The input file above is detailed and crowded with comments and may look scary, let's look at another example using default values for clarity:

reference { Mach=1.e-3; p=1.e5; }
 
timeMarching { CFLmax=1.e4; numberOfSteps=1000; }
 
linearSolver { relTolerance=1.e-4; absTolerance=1.e-8; maxIterations=50;}
 
fluidProperties {gamma=1.4; viscosity=1.e-5; }
 
writeOutput { plotFrequency=10; restartFrequency=100; }
 
initialConditions { IC_1 (rho=1; p=1; v=[0,0,0];); }
 
boundaryConditions {
    BC_1 (type=symmetry;);
    BC_2 (type=noslip;);
    BC_3 (type=inlet; rho=1;  v=[1,0,0];);
    BC_4 (type=outlet; p=0;);
}

2.4 Running the code

Now you have the grid and the input file, everything is ready for running Free CFD. Let's assume the case you prepared is named "test" located in the folder /home/user/test

$ cd /home/user/test
$ ls
  test.cgns test.in

Run Free CFD as

$ mpirun -np 1 fcfd test

The number following -np defines how many processors to use. This will start the computation from beginning. i.e. the initial condition defined in the input file will be used.

Let's say you ran the case for a certain number of time steps and a restart point was created at the 50th and 100th time steps, depending on the setting you defined in writeOutput section of the input file. You can restart the computation from those restart points as

$ mpirun -np 1 fcfd test 100

If you want to check which restart points are available, just look into the restart folder

$ ls restart
  50 100

2.5 Outputs

Screen Output

When Free CFD is run, it will start with printing progress and summary information and potentially (hopefully not) some warnings and errors. Each line of output starts with square brackets enclosing labels indicating the nature of the message:

[I] Means information
[W] Means warning
[E] Means error
[I Rank=0] Information specific to first processor

You can have a look at the output, it should be self explanatory. But some more useful pieces of information are about the boundary condition names read from the grid file and numbers assigned to them that you should be referring to in the input file as described above. An example output:

[I] In Zone blk-1
[I] ...Number of Nodes= 20402
[I] ...Number of Cells= 10000
[I] ...Number of Sections= 4
[I] ...Number of Boundary Conditions= 3
[I] ...Found boundary condition BC_1 : symmetry
[I] ...Found boundary condition BC_2 : top
[I] ...Found boundary condition BC_3 : walls

"symmetry", "wall" and "inlet" are the names that were assigned in the grid generator. Sometimes grid generators like to switch the ordering of the BC's, so be sure to check this information against your input file.

After the information and summary outputs, 7 columns of numbers start streaming corresponding to (Time marching information will be different if you are using CFLlocal marching method):

   1. Time step number
   2. Simulation time
   3. Time step size
   4. Maximum CFL number in the domain
   5. L2 norm of pressure residual
   6. L2 norm of velocity residual
   7. L2 norm of temperature residual

If you are using a turbulence model you will see 2 additional columns corresponding to the L2 norms of k and omega.

   1. Number of linear solver iterations
   2. Linear solver residual

File Output

While the residuals of flow variables are output to the screen, details about the linear solver iterations and residual norms are logged in a file named:

linear_solver.log

The log file has 3 columns (5 for turbulent flows) corresponding to:

   1. Time step number
   2. Number of linear solver iterations
   3. Linear solver residual norm
   4. (If turbulent) Number of linear solver iterations for k and omega equations
   5. (If turbulent) k and omega linear system residual norm

When the plot and restart time step intervals, as specified in the input file, are reached, corresponding files are written to "output" and "restart" directories.
