19_firstSol
Important
Visit https://aerosand.cc for the latest updates.
0. Preface
Through the discussions in the previous two stages, we have become familiar with the architecture of numerical applications in OpenFOAM, the key elements of numerical computation (time, mesh, fields), as well as some programming syntax and workflows. Now, using the tools we have acquired, we will attempt to write the simplest possible OpenFOAM solver (without involving numerical algorithms).
The general fundamental equation in computational fluid dynamics is:
We use to denote the physical field to be solved, taking care not to confuse it with the common flux phi in OpenFOAM.
For simplicity, we consider the following governing equation:
This is a transient, incompressible, source-free transport problem.
We will attempt to programmatically solve this governing equation.
This section primarily discusses:
- Refining script writing
- Briefly understanding the correspondence between equation construction and code
- Understanding the simple workflow of numerical computation
- Compiling and running the firstSol project
1. Project Preparation
Run the following commands in the terminal to create the project:
ofsp
foamNewApp ofsp_19_firstSol
cd ofsp_19_firstSol
cp -r $FOAM_TUTORIALS/incompressible/icoFoam/cavity/cavity debug_case
code .Test the initial solver, and provide scripts and documentation.
To further facilitate test case management, we will split the scripts into four parts:
- Pre-processing
casepre- Backup and restore initial conditions
- Mesh generation (optional)
- Domain setup (optional)
- etc.
- Computation processing
caserun- Run the solver on the test case
- Post-processing
casepost- Post-processing of results (optional)
- Result visualization
- Case cleaning
caseclean- Clean up the test case
- Restore the case to its initial state
Note
Unless otherwise specified, these scripts can be directly copied for subsequent use.
Pre-processing casepre is as follows:
| |
Computation processing caserun is as follows:
| |
Post-processing casepost is as follows:
| |
Case cleaning caseclean is as follows:
| |
2. Field Inclusion
The field inclusion createFields.H is as follows:
| |
3. Equation Construction
We modify the main source code to implement one computation of the mathematical equation.
The main source code ofsp_19_firstSol.C is as follows:
| |
The correspondence between the mathematical equation and the programming language can be seen:
Corresponds to:
fvm::ddt(A)
+ fvm::div(phi,A)
- fvm::laplacian(gamma,A)3.1. Time Term
The time term is constructed using the function ddt():
fvm::ddt(A)We can search for this function (or access the code directly via the OFextension plugin):
find $FOAM_SRC -iname fvmddt.cTo aid understanding, a few excerpts from the code declaration in fvmDdt.C are discussed briefly below (it is not recommended to delve too deeply into the code at this stage, as it may hinder progress):
| |
We now understand the formal parameter type of this function and that it returns a variable of type fvMatrix, which mathematically corresponds to the matrix associated with the unknown quantity A
3.2. Convection Term
The convection term is constructed using the function div():
fvm::div(phi,A)We can search for this function (or access the code directly via the OFextension plugin):
find $FOAM_SRC -iname fvmdiv.CTo aid understanding, a few excerpts from the code declaration in fvmDiv.C are discussed briefly below:
| |
We now understand the formal parameter types of this function and that it returns a variable of type fvMatrix, which mathematically corresponds to the matrix associated with the unknown quantity A.
3.3. Diffusion Term
The diffusion term is constructed using the function laplacian().
We can search for this function (or access the code directly via the OFextension plugin; this will not be repeated):
find $FOAM_SRC -iname fvlaplacian.CSimilarly, a portion of the code is excerpted as follows:
| |
Again, we understand the formal parameter types of this function and that it returns a variable of type fvMatrix, which mathematically corresponds to the matrix associated with the unknown quantity A.
3.4. Equation Solution
The final discretized form of the equation is:
The matrices from the convection and diffusion terms are added together to form the left-hand side. Since there is no source term, the right-hand side is empty and can be omitted.
The convection and diffusion terms are combined and solved using the solve() function:
solve // Solve the governing equation
(
fvm::ddt(A)
+ fvm::div(phi,A)
- fvm::laplacian(gamma,A)
);The implementation details of the solve() function will not be explored here.
4. Adjusting the Test Case
Since the project now includes computation of the unknown field A, the test case needs to be adjusted accordingly.
4.1. Initial Field A
Provide the initial field A for the project as follows:
| |
4.2. transportProperties
Add the new diffusion coefficient to the transportProperties dictionary:
...
gamma 1.0;
...4.3. fvSchemes
Specify discretization schemes for the numerical terms, ensuring the following specifications are present:
| |
The underlying mathematical physics of these specifications will not be explored here.
4.4. fvSolution
Specify the algebraic solver for the linear system, ensuring the following specifications are present:
| |
The underlying mathematical physics of these specifications will not be explored here.
5. Compilation and Execution
Compile and run this project:
wclean
wmake
./casepre & ./caserun & ./casepostThrough the computation, we obtain the result for a single time step. Visualize the results using ParaView, and examine the distribution of the A field at that time step.
6. Complete Problem
After gaining a basic understanding of how OpenFOAM constructs equations, we will now consider the complete problem described above.
6.1. Problem Description
![[image.png]]
In a square container identical to the cavity test case, the velocity field has a velocity of at the top boundary, while the other boundaries are fixed (no normal velocity exchange). For the dimensionless A field, the internal domain has a value of 500, the top boundary has a value of 100, and the other boundaries have a value of 0. Consider the transient, incompressible, source-free transport problem described by the following mathematical-physical equation:
6.2. Solver
The main source code of the solver is as follows:
| |
6.3. Test Case
We continue to use the test case files from the previous section (including initial conditions, boundary conditions, mesh dictionary, and transport properties).
However, to observe significant changes in the visualized results, adjust the control dictionary:
| |
6.4. Compilation and Execution
Recompile and run this project:
wclean
wmake
./caseclean & ./casepre & ./caserun & ./casepostThrough the computation, we obtain results that evolve over time. Visualize the results using ParaView, and examine how the A field distribution changes over time.
7. Summary
Some readers may notice that many questions remain unanswered. For example:
- Why is the flux
phiused in the divergence calculation instead ofUas in the equation?
In brief, if one has studied the finite volume method, one understands that in FVM, the conserved quantity is the flux, which is the core and advantage of FVM.
- Why is
fvmused? What is the difference from the commonly seenfvc?
In simple terms, fvm in solvers discretizes all terms that contribute to the coefficient matrix (implicit discretization). In contrast, fvc discretizes terms that are not associated with the coefficient matrix (explicit discretization).
However, such a brief explanation is often difficult for beginners to fully grasp. To address these two questions, we would need to return to the numerical solution of the partial differential equation governing the problem, starting from the finite volume method and deriving step by step until matrix solution, only then can we truly understand why flux is used in computation and why there is a distinction between implicit and explicit discretization. These topics will not be explored here; refer to the CFD Fundamentals series (cfdb) and the OpenFOAM Solver Series (ofss) for further discussion.
Fortunately, the syntax of the solver code is already very close to the mathematical formulation, so even with these lingering questions, we can still write simple solvers.
This section has completed the following discussions:
- Refining script writing
- Briefly understanding the correspondence between equation construction and code
- Understanding the simple workflow of numerical computation
- Compiling and running the firstSol project
Support us
Tip
Hopefully, the sharing here can be helpful to you.
If you find this content helpful, your comments or donations would be greatly appreciated. Your support helps ensure the ongoing updates, corrections, refinements, and improvements to this and future series, ultimately benefiting new readers as well.
The information and message provided during donation will be displayed as an acknowledgment of your support.
Copyright @ 2026 Aerosand
- Course (text, images, etc.):CC BY-NC-SA 4.0
- Code derived from OpenFOAM:GPL v3
- Other code:MIT License
