├── .gitignore ├── README.md ├── case ├── 0 │ ├── U │ ├── nuTilda │ ├── nut │ └── p ├── constant │ ├── transportProperties │ └── turbulenceProperties ├── system │ ├── changeDictionaryDict │ ├── controlDict │ ├── fvSchemes │ └── fvSolution └── view.foam ├── clean.py ├── mesh ├── WindTunnel.geo ├── main.geo ├── naca.geo └── parameters.geo ├── run.sh └── sample_results.xlsx /.gitignore: -------------------------------------------------------------------------------- 1 | *.msh 2 | polyMesh/* 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # airfoil_validation 2 | 3 | NACA0012 OpenFOAM results are compared to experimental data. 4 | 5 | 1. Set the desired angle of attack: variable "aoa" (degrees) in mesh/parameters.geo. 6 | 2. ./run.sh (see script for sub-steps) 7 | 3. Open "view.foam" in ParaView and/or view force coefficients in ./case/postProcessing/. 8 | 9 | TODO: 10 | 1. Implement batch run, post-processing, and plotting script. 11 | -------------------------------------------------------------------------------- /case/0/U: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: plus | 5 | | \\ / A nd | Web: www.OpenFOAM.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class volVectorField; 13 | object U; 14 | } 15 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 16 | 17 | dimensions [0 1 -1 0 0 0 0]; 18 | 19 | internalField uniform (9 0 0); 20 | 21 | boundaryField 22 | { 23 | inlet 24 | { 25 | type freestream; 26 | freestreamValue $internalField; 27 | } 28 | 29 | outlet 30 | { 31 | type freestream; 32 | freestreamValue $internalField; 33 | } 34 | 35 | walls 36 | { 37 | type noSlip; 38 | } 39 | 40 | airfoil 41 | { 42 | type noSlip; 43 | } 44 | 45 | frontAndBack 46 | { 47 | type empty; 48 | } 49 | } 50 | 51 | // ************************************************************************* // 52 | -------------------------------------------------------------------------------- /case/0/nuTilda: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: plus | 5 | | \\ / A nd | Web: www.OpenFOAM.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class volScalarField; 13 | object nuTilda; 14 | } 15 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 16 | 17 | dimensions [0 2 -1 0 0 0 0]; 18 | 19 | internalField uniform 0.14; 20 | 21 | boundaryField 22 | { 23 | inlet 24 | { 25 | type freestream; 26 | freestreamValue uniform 0.14; 27 | } 28 | 29 | outlet 30 | { 31 | type freestream; 32 | freestreamValue uniform 0.14; 33 | } 34 | 35 | walls 36 | { 37 | type fixedValue; 38 | value uniform 0; 39 | } 40 | 41 | airfoil 42 | { 43 | type fixedValue; 44 | value uniform 0; 45 | } 46 | 47 | frontAndBack 48 | { 49 | type empty; 50 | } 51 | } 52 | 53 | // ************************************************************************* // 54 | -------------------------------------------------------------------------------- /case/0/nut: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: plus | 5 | | \\ / A nd | Web: www.OpenFOAM.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class volScalarField; 13 | object nut; 14 | } 15 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 16 | 17 | dimensions [0 2 -1 0 0 0 0]; 18 | 19 | internalField uniform 0.14; 20 | 21 | boundaryField 22 | { 23 | inlet 24 | { 25 | type freestream; 26 | freestreamValue uniform 0.14; 27 | } 28 | 29 | outlet 30 | { 31 | type freestream; 32 | freestreamValue uniform 0.14; 33 | } 34 | 35 | walls 36 | { 37 | type nutUSpaldingWallFunction; 38 | value uniform 0; 39 | } 40 | 41 | airfoil 42 | { 43 | type nutUSpaldingWallFunction; 44 | value uniform 0; 45 | } 46 | 47 | frontAndBack 48 | { 49 | type empty; 50 | } 51 | } 52 | 53 | // ************************************************************************* // 54 | -------------------------------------------------------------------------------- /case/0/p: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: plus | 5 | | \\ / A nd | Web: www.OpenFOAM.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class volScalarField; 13 | object p; 14 | } 15 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 16 | 17 | dimensions [0 2 -2 0 0 0 0]; 18 | 19 | internalField uniform 0; 20 | 21 | boundaryField 22 | { 23 | inlet 24 | { 25 | type freestreamPressure; 26 | freestreamValue $internalField; 27 | } 28 | 29 | outlet 30 | { 31 | type freestreamPressure; 32 | freestreamValue $internalField; 33 | } 34 | 35 | walls 36 | { 37 | type zeroGradient; 38 | } 39 | 40 | airfoil 41 | { 42 | type zeroGradient; 43 | } 44 | 45 | frontAndBack 46 | { 47 | type empty; 48 | } 49 | } 50 | 51 | // ************************************************************************* // 52 | -------------------------------------------------------------------------------- /case/constant/transportProperties: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: plus | 5 | | \\ / A nd | Web: www.OpenFOAM.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class dictionary; 13 | location "constant"; 14 | object transportProperties; 15 | } 16 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 17 | 18 | transportModel Newtonian; 19 | 20 | rho 1.18; 21 | 22 | nu 1.5e-05; 23 | 24 | // ************************************************************************* // 25 | -------------------------------------------------------------------------------- /case/constant/turbulenceProperties: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: plus | 5 | | \\ / A nd | Web: www.OpenFOAM.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class dictionary; 13 | location "constant"; 14 | object turbulenceProperties; 15 | } 16 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 17 | 18 | simulationType RAS; 19 | 20 | RAS 21 | { 22 | RASModel SpalartAllmaras; 23 | 24 | turbulence on; 25 | 26 | printCoeffs on; 27 | } 28 | 29 | // ************************************************************************* // 30 | -------------------------------------------------------------------------------- /case/system/changeDictionaryDict: -------------------------------------------------------------------------------- 1 | 2 | FoamFile 3 | { 4 | version 2.0; 5 | format ascii; 6 | class dictionary; 7 | location "system"; 8 | object changeDictionaryDict; 9 | } 10 | 11 | boundary 12 | { 13 | inlet 14 | { 15 | type patch; 16 | physicalType patch; 17 | } 18 | outlet 19 | { 20 | type patch; 21 | physicalType patch; 22 | } 23 | airfoil 24 | { 25 | type wall; 26 | physicalType wall; 27 | } 28 | walls 29 | { 30 | type wall; 31 | physicalType wall; 32 | } 33 | frontAndBack 34 | { 35 | type empty; 36 | physicalType empty; 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /case/system/controlDict: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: plus | 5 | | \\ / A nd | Web: www.OpenFOAM.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class dictionary; 13 | location "system"; 14 | object controlDict; 15 | } 16 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 17 | 18 | application simpleFoam; 19 | 20 | startFrom latestTime; 21 | 22 | startTime 0; 23 | 24 | stopAt endTime; 25 | 26 | endTime 10000; 27 | 28 | deltaT 1; 29 | 30 | writeControl timeStep; 31 | 32 | writeInterval 100; 33 | 34 | purgeWrite 0; 35 | 36 | writeFormat ascii; 37 | 38 | writePrecision 6; 39 | 40 | writeCompression off; 41 | 42 | timeFormat general; 43 | 44 | timePrecision 6; 45 | 46 | runTimeModifiable true; 47 | 48 | functions 49 | { 50 | forceCoeffs1 51 | { 52 | type forceCoeffs; 53 | libs ("libforces.so"); 54 | writeControl timeStep; 55 | writeInterval 10; 56 | log true; 57 | patches (airfoil); 58 | rho rhoInf; // Indicates incompressible. 59 | rhoInf 1.18; // Redundant for incompressible (value does not matter). 60 | liftDir (0 1 0); 61 | dragDir (1 0 0); 62 | CofR (0.25 0 0); // Quarter-chord. 63 | pitchAxis (0 0 1); 64 | magUInf 9; // Matches 0/U. 65 | lRef 1.0; // Normalized chord. 66 | Aref 0.1; // Cell depth * chord. 67 | } 68 | } 69 | 70 | 71 | 72 | 73 | 74 | // ************************************************************************* // 75 | -------------------------------------------------------------------------------- /case/system/fvSchemes: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: plus | 5 | | \\ / A nd | Web: www.OpenFOAM.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class dictionary; 13 | location "system"; 14 | object fvSchemes; 15 | } 16 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 17 | 18 | ddtSchemes 19 | { 20 | default steadyState; 21 | } 22 | 23 | gradSchemes 24 | { 25 | default Gauss linear; 26 | } 27 | 28 | divSchemes 29 | { 30 | default none; 31 | div(phi,U) bounded Gauss linearUpwind grad(U); 32 | div(phi,nuTilda) bounded Gauss linearUpwind grad(nuTilda); 33 | div((nuEff*dev2(T(grad(U))))) Gauss linear; 34 | } 35 | 36 | laplacianSchemes 37 | { 38 | default Gauss linear corrected; 39 | } 40 | 41 | interpolationSchemes 42 | { 43 | default linear; 44 | } 45 | 46 | snGradSchemes 47 | { 48 | default corrected; 49 | } 50 | 51 | wallDist 52 | { 53 | method meshWave; 54 | } 55 | 56 | 57 | // ************************************************************************* // 58 | -------------------------------------------------------------------------------- /case/system/fvSolution: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: plus | 5 | | \\ / A nd | Web: www.OpenFOAM.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class dictionary; 13 | location "system"; 14 | object fvSolution; 15 | } 16 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 17 | 18 | solvers 19 | { 20 | p 21 | { 22 | solver GAMG; 23 | tolerance 1e-06; 24 | relTol 0.1; 25 | smoother GaussSeidel; 26 | } 27 | 28 | U 29 | { 30 | solver smoothSolver; 31 | smoother GaussSeidel; 32 | nSweeps 2; 33 | tolerance 1e-08; 34 | relTol 0.1; 35 | } 36 | 37 | nuTilda 38 | { 39 | solver smoothSolver; 40 | smoother GaussSeidel; 41 | nSweeps 2; 42 | tolerance 1e-08; 43 | relTol 0.1; 44 | } 45 | } 46 | 47 | SIMPLE 48 | { 49 | nNonOrthogonalCorrectors 0; 50 | pRefCell 0; 51 | pRefValue 0; 52 | 53 | residualControl 54 | { 55 | p 1e-5; 56 | U 1e-5; 57 | nuTilda 1e-5; 58 | } 59 | } 60 | 61 | relaxationFactors 62 | { 63 | fields 64 | { 65 | p 0.3; 66 | } 67 | equations 68 | { 69 | U 0.7; 70 | nuTilda 0.7; 71 | } 72 | } 73 | 74 | 75 | // ************************************************************************* // 76 | -------------------------------------------------------------------------------- /case/view.foam: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openfoamtutorials/airfoil_validation/8240af3851234d2708648336725637dc4b6f783d/case/view.foam -------------------------------------------------------------------------------- /clean.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | 5 | def delete_if_exists(path): 6 | if os.path.exists(path): 7 | os.system("rm -r " + path) 8 | 9 | folders = [x for x in os.listdir("case/") if os.path.isdir("case/" + x)] 10 | for f in folders: 11 | if "processor" in f: # in the case of parallel runs. 12 | delete_if_exists("case/" + f) 13 | continue 14 | dotsep = f.split(".") 15 | isfloat = len(dotsep) > 1 and all([x.isdigit() for x in dotsep]) 16 | esep = f.split("e-") 17 | issci = len(esep) > 1 and all([x.isdigit() for x in esep]) 18 | isnum = f.isdigit() or isfloat or issci 19 | if isnum and float(f) != 0: 20 | delete_if_exists("case/" + f) 21 | 22 | delete_if_exists("main.msh") 23 | delete_if_exists("case/constant/polyMesh") 24 | delete_if_exists("case/postProcessing") 25 | -------------------------------------------------------------------------------- /mesh/WindTunnel.geo: -------------------------------------------------------------------------------- 1 | 2 | Macro WindTunnel 3 | WindTunnelLines[] ={}; 4 | Point(ce++) = {WindTunnelLength / 2, -WindTunnelHeight / 2, 0, WindTunnelLc}; 5 | StartPoint = ce - 1; 6 | Point(ce++) = {WindTunnelLength / 2, WindTunnelHeight / 2, 0, WindTunnelLc}; 7 | Line(ce++) = {ce - 3, ce - 2}; 8 | WindTunnelLines += ce - 1; 9 | 10 | Point(ce++) = {-WindTunnelLength / 2, WindTunnelHeight / 2, 0, WindTunnelLc}; 11 | Line(ce++) = {ce - 4, ce - 2}; 12 | WindTunnelLines += ce - 1; 13 | 14 | Point(ce++) = {-WindTunnelLength / 2, -WindTunnelHeight / 2, 0, WindTunnelLc}; 15 | Line(ce++) = {ce - 4, ce - 2}; 16 | WindTunnelLines += ce - 1; 17 | 18 | Line(ce++) = {ce - 3, StartPoint}; 19 | WindTunnelLines += ce - 1; 20 | 21 | Line Loop(ce++) = WindTunnelLines[]; 22 | WindTunnelLoop = ce - 1; 23 | Return 24 | 25 | 26 | -------------------------------------------------------------------------------- /mesh/main.geo: -------------------------------------------------------------------------------- 1 | Include "naca.geo"; 2 | Include "WindTunnel.geo"; 3 | Include "parameters.geo"; 4 | 5 | // Units are multiples of chord. 6 | 7 | ce = 0; 8 | Point(ce++) = {0, 0, 0}; 9 | 10 | Call SymmetricAirfoil; 11 | 12 | WindTunnelHeight = 20; 13 | WindTunnelLength = 40; 14 | WindTunnelLc = 1; 15 | Call WindTunnel; 16 | 17 | Surface(ce++) = {WindTunnelLoop, AirfoilLoop}; 18 | TwoDimSurf = ce - 1; 19 | Recombine Surface{TwoDimSurf}; 20 | 21 | ids[] = Extrude {0, 0, 0.1} 22 | { 23 | Surface{TwoDimSurf}; 24 | Layers{1}; 25 | Recombine; 26 | }; 27 | 28 | Physical Surface("outlet") = {ids[2]}; 29 | Physical Surface("walls") = {ids[{3, 5}]}; 30 | Physical Surface("inlet") = {ids[4]}; 31 | Physical Surface("airfoil") = {ids[{6:8}]}; 32 | Physical Surface("frontAndBack") = {ids[0], TwoDimSurf}; 33 | Physical Volume("volume") = {ids[1]}; 34 | 35 | -------------------------------------------------------------------------------- /mesh/naca.geo: -------------------------------------------------------------------------------- 1 | // This returns normalized y for a symmetric airfoil. 2 | Macro NACA00 3 | // x is the normalized chord position in [0, c]. 4 | // XX is the last 2 digits, which dictates maximum thickness. 5 | // NACA0012 for XX = 12, and maximum thickness is 0.12 of chord. 6 | y = 0.2969 * x^0.5; 7 | y += -0.1260 * x; 8 | y += -0.3516 * x^2; 9 | y += 0.2843 * x^3; 10 | y += -0.1015 * x^4; 11 | y *= 5.0 * XX / 100.0; 12 | Return 13 | 14 | Macro RotateAirfoilPoint 15 | // rotates pointId about quarter-chord. 16 | // aoa is the angle of attack in degrees. 17 | Rotate {{0, 0, 1}, {0.25, 0, 0}, -aoa * Pi / 180.0} 18 | { 19 | Point{pointId}; 20 | } 21 | Return 22 | 23 | Macro SymmetricAirfoil 24 | // draws a symmetric airfoil, given XX as in NACA00XX. 25 | // PointCount specifies number of points. 26 | // Draws le at {0, 0} and te at {1, 0}. 27 | // ce is the current point id. 28 | // AirfoilLc is the length characteristic on airfoil surface. 29 | // aoa is the angle of attack in degrees. 30 | // Results: le, te, upper[], lower[], AirfoilSurface 31 | x = 0; 32 | increment = 1.0 / PointCount; 33 | Point(ce++) = {0, 0, 0, AirfoilLc}; 34 | pointId = ce - 1; 35 | Call RotateAirfoilPoint; 36 | le = pointId; 37 | Point(ce++) = {1, 0, 0, AirfoilLc}; 38 | pointId = ce - 1; 39 | Call RotateAirfoilPoint; 40 | te = pointId; 41 | upper[] = {}; 42 | lower[] = {}; 43 | For x In {increment: 1 - increment: increment} 44 | // Printf("%f", x); 45 | Call NACA00; 46 | Point(ce++) = {x, y, 0, AirfoilLc}; 47 | pointId = ce - 1; 48 | Call RotateAirfoilPoint; 49 | upper = {pointId, upper[]}; 50 | Point(ce++) = {x, -y, 0, AirfoilLc}; 51 | pointId = ce - 1; 52 | Call RotateAirfoilPoint; 53 | lower += pointId; 54 | EndFor 55 | Line(ce++) = {te, upper[0]}; 56 | upperTe = ce - 1; 57 | Line(ce++) = {lower[#lower[] - 1], te}; 58 | lowerTe = ce - 1; 59 | BSpline(ce++) = {upper[], le, lower[]}; 60 | AirfoilSurface = ce - 1; 61 | Line Loop(ce++) = {upperTe, AirfoilSurface, lowerTe}; 62 | AirfoilLoop = ce - 1; 63 | Return 64 | 65 | -------------------------------------------------------------------------------- /mesh/parameters.geo: -------------------------------------------------------------------------------- 1 | XX = 12; // As in NACA00XX. 2 | aoa = 17.13; // Angle of attack, in degrees. 3 | AirfoilLc = 0.0025; // Grid cell size on surface of airfoil. 4 | PointCount = 100; // Number of points to use on BSpline. 5 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Quit script if any step has error: 4 | set -e 5 | 6 | # Generate the mesh from script (msh2 format is currently the latest gmshToFoam recognizes): 7 | gmsh -3 -o main.msh -format msh2 mesh/main.geo 8 | # Convert the mesh to OpenFOAM format: 9 | gmshToFoam main.msh -case case 10 | # Adjust polyMesh/boundary: 11 | changeDictionary -case case 12 | # Finally, run the simulation: 13 | simpleFoam -case case 14 | 15 | -------------------------------------------------------------------------------- /sample_results.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openfoamtutorials/airfoil_validation/8240af3851234d2708648336725637dc4b6f783d/sample_results.xlsx --------------------------------------------------------------------------------