|
FEATool Multiphysics
v1.17.5
Finite Element Analysis Toolbox
|
EX_NAVIERSTOKES3 Stationary laminar 2D flow around a cylinder (Re=20).
[ FEA, OUT ] = EX_NAVIERSTOKES3( VARARGIN ) 2D validation and CFD benchmark for stationary laminar incompressible flow around a cylinder (Reynolds number, Re = 20).
The drag and lift coefficients, and pressure difference between the front and back of the cylinder are computed and compared with reference values [1, 2].
[1] John V, Matthies G. Higher-order finite element discretizations in a benchmark problem for incompressible flows. International Journal for Numerical Methods in Fluids, 37(8):885–903, 2001.
[2] Nabh G. On higher order methods for the stationary incompressible Navier-Stokes equations. PhD Thesis, Universitaet Heidelberg, 1998.
Accepts the following property/value pairs.
Input Value/{Default} Description
-----------------------------------------------------------------------------------
igrid scalar {2} Grid type: >0 regular (igrid refinements)
<0 unstruc. grid (with hmax=|igrid|)
sf_u string {sflag1} Shape function for velocity
sf_p string {sflag1} Shape function for pressure
solver string {default} Solver selection default, openfoam, su2, or fenics
iplot logical false/{true} Plot and visualize solution
.
Output Value/(Size) Description
-----------------------------------------------------------------------------------
fea struct Problem definition struct
out struct Output struct
cOptDef = { 'igrid', 2;
'sf_u', 'sflag1';
'sf_p', 'sflag1';
'solver', '';
'iplot', true;
'tol', [0.05, 0.35, 0.1];
'fid', 1;
'iphys', true };
[got,opt] = parseopt(cOptDef,varargin{:});
% Model parameters.
rho = 1; % Density.
miu = 0.001; % Molecular/dynamic viscosity.
umax = 0.3; % Maximum magnitude of inlet velocity.
umean = 0.2; % Mean inlet velocity (2/3 umax).
cd_ref = 5.5795352338; % Reference drag coefficient.
cl_ref = 0.010618937712; % Reference lift coefficient.
dp_ref = 0.11752016697; % Reference pressure difference.
% Geometry.
h = 0.41; % Height of rectangular domain.
l = 2.2; % Length of rectangular domain.
xc = 0.2; % x-coordinate of cylinder center.
yc = 0.2; % y-coordinate of cylinder center.
diam = 0.1; % Diameter of cylinder.
fea.sdim = { 'x', 'y' };
R1 = gobj_rectangle( 0, l, 0, h, 'R1' );
C1 = gobj_circle( [xc, yc], diam/2, 'C1' );
fea.geom.objects = { R1, C1 };
fea = geom_apply_formula( fea, 'R1-C1' );
% Grid/mesh generation.
if ( opt.igrid >= 1 )
fea.grid = l_cylbenchgrid_2d( opt.igrid );
else
fea.grid = gridgen( fea, 'hmax', abs(opt.igrid), 'fid', opt.fid );
end
if ( strcmpi(opt.solver,'FENICS') && size(fea.grid.c,1) == 4 )
warning( 'Converting quadrilateral mesh to triangular to support FEniCS.' )
fea.grid = quad2tri( fea.grid );
end
% Boundary identification.
dtol = sqrt(eps) * 1e3;
ind_inflow = findbdr(fea, sprintf('x <= %.16g', dtol)); % Inflow boundary number.
s_inflow = sprintf('4*%.16g*y*(%.16g-y)/%.16g^2', umax, h, h); % Inflow profile definition.
ind_outflow = findbdr(fea, sprintf('x >= (%.16g - %.16g)', l, dtol )); % Outflow boundary number.
ind_cylinder = findbdr(fea, sprintf('sqrt((x-%.16g).^2+(y-%.16g).^2) <= %.16g', xc, yc, diam/2 + dtol)); % Cylinder boundary numbers.
% Problem definition.
srho = sprintf('%.16g', rho);
if ( opt.iphys ) % Use pre-defined Navier-Stokes equations physics mode.
fea = addphys(fea, @navierstokes);
fea.phys.ns.eqn.coef{1,end} = { rho };
fea.phys.ns.eqn.coef{2,end} = { miu };
fea.phys.ns.sfun = { opt.sf_u, opt.sf_u, opt.sf_p };
% Boundary condition definitions.
fea.phys.ns.bdr.sel(ind_inflow) = 2;
fea.phys.ns.bdr.sel(ind_outflow) = 4;
fea.phys.ns.bdr.coef{2,end}{1,ind_inflow} = s_inflow;
fea = parsephys(fea);
else % Manual equation definition.
fea.dvar = { 'u', 'v', 'p' }; % Dependent variable names.
fea.sfun = { opt.sf_u, opt.sf_u, opt.sf_p }; % Shape functions.
% Define equation system.
cvelx = [srho,'*u']; % Convection velocity in x-direction.
cvely = [srho,'*v']; % Convection velocity in y-direction.
fea.eqn.a.form = { [2 3 2 3;2 3 1 1] [2;3] [1;2];
[3;2] [2 3 2 3;2 3 1 1] [1;3];
[2;1] [3;1] [] };
fea.eqn.a.coef = { {2*miu miu cvelx cvely} miu -1;
miu {miu 2*miu cvelx cvely} -1;
1 1 [] };
fea.eqn.f.form = { 1 1 1 };
fea.eqn.f.coef = { 0 0 0 };
% Boundary condition definitions.
n_bdr = max(fea.grid.b(3,:)); % Number of boundaries.
fea.bdr.d = cell(3, n_bdr);
[fea.bdr.d{1:2,:}] = deal(0);
fea.bdr.d{1,ind_inflow} = s_inflow;
[fea.bdr.d{:,ind_outflow}] = deal([]);
fea.bdr.n = cell(3, n_bdr);
end
% Call solver.
fea = parseprob(fea); % Check and parse problem struct.
switch ( upper(opt.solver) )
case 'FENICS'
fea = fenics( fea, 'fid', opt.fid, 'nproc', 1 );
case 'OPENFOAM'
fid = opt.fid; if( ~got.fid ), fid = []; end
fea.sol.u = openfoam( fea, 'fid', fid, 'logfid', opt.fid );
case 'SU2'
fid = opt.fid; if( ~got.fid ), fid = []; end
fea.sol.u = su2( fea, 'fid', fid, 'logfid', opt.fid );
otherwise % Default
jacobian.form = {[1;1] [1;1] []; [1;1] [1;1] []; [] [] []}; % Analytic Newton jacobian.
jacobian.coef = {[srho,'*ux'] [srho,'*uy'] []; [srho,'*vx'] [srho,'*vy'] []; [] [] []};
nlrlx = '(1 + (it > 2)) / 2'; % Dynamic non-linear relaxation parameter (it = iteration number).
solve_param = {'nlrlx', nlrlx, 'nsolve', 2, 'jac', jacobian, 'linsolv', ''};
fea.sol.u = solvestat( fea, 'fid', opt.fid, solve_param{:} );
end
% Visualization.
s_velm = 'sqrt(u^2+v^2)';
if ( opt.iplot )
figure
subplot(2,1,1)
postplot( fea, 'surfexpr', s_velm )
title( 'Velocity field' )
subplot(2,1,2)
postplot( fea, 'surfexpr', 'p' )
title( 'Pressure' )
end
% Postprocessing.
[cd_l, cd_v, cl_l, cl_v, dp] = calc_benc_quants( fea, opt, ind_cylinder );
if ( ~isempty(opt.fid) )
fprintf(opt.fid,'\n\nBenchmark quantities:\n\n')
fprintf(opt.fid,'Drag coefficient, cd = %6f (l), %6f (v) (Reference: %6f)\n', cd_l, cd_v, cd_ref)
fprintf(opt.fid,'Lift coefficient, cl = %6f (l), %6f (v) (Reference: %6f)\n', cl_l, cl_v, cl_ref)
fprintf(opt.fid,'Pressure difference, dp = %6f (Reference: %6f)\n', dp, dp_ref)
end
% Error checking.
out.cd = [cd_l, cd_v];
out.cl = [cl_l, cl_v];
out.dp = dp;
out.err = [abs(out.cd - cd_ref) / cd_ref;
abs(out.cl - cl_ref) / cl_ref;
nan, abs(out.dp - dp_ref) / dp_ref];
out.pass = all(out.err(:,2) < opt.tol(:));
if ( ~nargout )
clear fea out
end
%