Professional Documents
Culture Documents
FLUENT IC Tut 04 Premixed PDF
FLUENT IC Tut 04 Premixed PDF
Introduction
For spark-ignited (SI) engines and some natural gas combustion engines, fuel and air are
mixed before entering into the combustion chamber. At the spark event, the mixture can
be assumed to be homogeneous and the combustion process to be premixed.
This tutorial demonstrates how to do the following:
Set up in-cylinder (IC) premixed combustion.
Set up the spark model.
Use the user-defined functions (UDFs) to modify laminar flame speed.
Use UDF for some IC postprocessing.
Prerequisites
This tutorial is written with the assumption that you have completed Tutorial 1 from
ANSYS FLUENT 13.0 Tutorial Guide, and that you are familiar with the ANSYS FLUENT
navigation pane and menu structure. Some steps in the setup and solution procedure will
not be shown explicitly.
It also assumes that you are familiar with ANSYS FLUENT moving deforming mesh (MDM)
layering approach. For more information, see Section 11.6, Using Dynamic Meshes in ANSYS
FLUENT 13.0 Users Guide.
Problem Description
This tutorial considers a 2D axi-symmetric geometry of the IC engine cylinder configuration. Simulation starts at IVC and ends at EVO, hence there are no valves involved. The
schematic is as shown in Figure 1.
The initial configuration of the system has piston at TDC, hence first mesh motion is
performed to bring the piston to IVC position.
Figure 1: Schematic
Step 1: Mesh
1. Read the mesh file (IC premixed com.msh).
File Read Mesh...
As the mesh file is read, ANSYS FLUENT will report the progress in the console.
Step 2: General Settings
1. Define the solver settings.
General
Parameter
Crank Shaft Speed(rpm)
Starting Crank Angle(deg)
Crank Period(deg)
Crank Angle Step Size(deg)
Piston Stroke(mm)
Connecting Rod Length(mm)
Piston Stroke Cutoff(mm)
Minimum Valve Lift(mm)
Value
3000
360
720
0.25
80
140
0
0
(a) Click Edit... for Initialization to open Initialization Functions dialog box.
i. Select my init function::libudf from the Available Initialization Functions list.
ii. Click Add to add it in the Selected Initialization Functions list.
iii. Click OK.
(b) Click Edit... for Adjust to open Adjust Functions dialog box.
i. Select my T u::libudf from the Available Initialization Functions list.
ii. Click Add to add it in the Selected Initialization Functions list.
iii. Click OK.
(c) Click Edit... for Execture At End to open Execture At End Functions dialog box.
i. Select output results::libudf from the Available Initialization Functions list.
ii. Click Add to add it in the Selected Initialization Functions list.
iii. Click OK.
(d) Click Edit... for Read Data to open Read Data Functions dialog box.
i. Select read data::libudf from the Available Initialization Functions list.
ii. Click Add to add it in the Selected Initialization Functions list.
iii. Click OK.
(e) Click Edit... for Write Data to open Write Data Functions dialog box.
i. Select write data::libudf from the Available Initialization Functions list.
ii. Click Add to add it in the Selected Initialization Functions list.
iii. Click OK.
Viscous Edit...
(a) Select k-epsilon (2 eqn) in the Model group box to open Viscous Model dialog box.
(b) Retain the default settings and click OK to close Viscous Model dialog box.
5. Define the species model.
Models
10
Species Edit...
11
Fluid Create/Edit...
13
2. Select piecewise-polynomial from the Cp (Specific Heat) drop-down list. The PiecewisePolynomial Profile dialog box opens.
(a) Set Range to 2.
14
axis
15
Step 7: Solution
1. Set the solution parameters.
Solution Methods
16
Residuals Edit...
17
18
19
20
21
22
23
24
/*********************************************************************************************
UDF for IC initialization with swirl
For IC flow, if only combustion and power stroke is of interest. The initial
condition normally contains swirl flow. This udf provides a tool to initialize
the flow field with user specified swirl ratio
How to use the udf:
- Set up your IC case
- Modify the user inputs part of the udf.
- Build the library
- Hook the DEFINE\_INIT udf
- Initialize your flow field
Note:
- UDF works in 2d axisymmetry, and 3d.
- Pure 2d case does not have swirl and thus not supported (a warning will be given).
- UDF works in both serial and parallel.
***********************************************************************************************/
# include "udf.h"
# define RPM RP_Get_Real("dynamesh/in-cyn/crank-rpm")
/********************************* User input starts *****************************************/
25
#if RP_2D
if (rp_axi)
{
C_U(c,t)=NV_CROSS_X(omega, x);
C_V(c,t)=NV_CROSS_Y(omega, x);
C_W(c,t)=NV_CROSS_Z(omega, x);
}
%
\end{minipage}
% \pagebreak
else
{
if(counter == 0)
{
Message0("No initialization for pure 2D.
counter++;
}
}
#else
C_U(c,t)=NV_CROSS_X(omega, x);
C_V(c,t)=NV_CROSS_Y(omega, x);
C_W(c,t)=NV_CROSS_Z(omega, x);
#endif
}
end_c_loop(c,t)
}
DEFINE_INIT(my_init_function, domain)
Thread *t;
int i;
real omega[ND_ND], mag;
/* Normalize swirl axis */
mag=NV_MAG(swirl_axis);
NV_S(swirl_axis, /=, mag);
if (RP_Get_Boolean("dynamesh/models/in-cylinder?")==TRUE)
{
NV_VS(omega, =, swirl_axis, *, RPM/60.*2.*M_PI*init_swirl_ratio);
if(method == whole_domain)
{
/* loop over all cell threads in the domain
thread_loop_c (t,domain)
{
initialize_cell_zone(t, omega);
}
}
else if (method == defined_cell_zones)
{
i=0;
while(Zone_ID[i]>=0)
{
t=Lookup_Thread(domain, Zone_ID[i]);
*/
initialize_cell_zone(t, omega);
i++;
}
}
26
{
else
{
Message0("Wrong method for initialization calculation--aborting!!");
exit(0);
}
Init_Face_Flux(domain);
}
else
{
Message0("IC not turned on.
No initialization is performed.");
}
}
% \end{minipage}
27
/*********************************************************************************************
UDF for IC indicated work
This UDF does the following
- Calculate indicated work
- Output volume as a function of CA
- Output pressure as a function of CA
- Output burnt fuel mass fraction as a function of CA
How to use the udf:
- Set up your case
- Build the library
- Hook the DEFINE_EXECUTE_AT_END udf
- Hook the two DEFINE_RW_FILE udfs
Note:
- The indicated work will be saved with the data file. So, you CAN restart from
a previously saved cas/dat and continue the run to obtain the indicated work.
- UDF works in 2d, 2d axisymmetry, and 3d. And it works in both serial and parallel
***********************************************************************************************/
# include "udf.h"
# define RPM RP_Get_Real("dynamesh/in-cyn/crank-rpm")
/********************************* User input starts *****************************************/
/* Cell zone ID list for pressure output (cell zone ID for combustion chamber).
so please keep it. */
static int Zone_ID[]={2, -1};
/* Face zone ID list for work output (face zone ID for the piston) */
static int Piston_ID[]={6, -1};
-1 is a flag
28
#if RP_2D
if (rp_axi) factor=2*M_PI;
#endif
NV_S(x, *=, factor);
}
DEFINE_ON_DEMAND(Indicated_work)
{
if(counter==0)
{
Message0("\n\n********************** IC Indicated Work Results *****************************\n");
Message0("\nIndicated work calculation has not started. Please do at least one time step.\n");
Message0("\nStart CA :%5.2f (deg) End CA :%5.2f (deg) Work : %9.3e (J)", start_CA, end_CA, work);
Message0("\n\n******************************************************************************\n");
}
else
{
Message0("\n\n********************** IC Indicated Work Results *****************************\n");
Message0("\nIndicated work calculation started at :%7.2f (deg)", start_CA);
Message0("\nIndicated work calculation finished at :%7.2f (deg)", end_CA);
Message0("\nFor the above duration, the indicated work is :%12.4e (J)", work);
Message0("\n\n******************************************************************************\n");
}
}
DEFINE_ON_DEMAND(reset)
{
counter=0;
work=0;
start_CA=0;
end_CA=0;
Message0("\n\n******************************** WARNING *************************************\n");
Message0("\nNote that this resets indicated work and the calculation start CA to zero.");
Message0("\nPlease save the data file to save the new values.");
Message0("\n\n******************************************************************************\n");
}
DEFINE_EXECUTE_AT_END(output_results)
{
#if !RP_HOST
int i;
real pressure, volume, fmf, mass, work_one_dt, x[ND_ND];
Thread *tc, *tf;
cell_t c;
face_t f;
FILE *fp_results;
Domain* domain;
domain=Get_Domain(1);
#if PARALLEL
if(I_AM_NODE_ZERO_P)
#endif
{
if(!(fp_results=fopen("work.txt","a")))
{
Message0("\nCan not open file-aborting!!");
exit(0);
}
}
if(counter==0)
{
start_CA = (CURRENT_TIME-CURRENT_TIMESTEP)*RPM*6.0+RP_Get_Real("dynamesh/in-cyn/crank-start-angle");
29
#if PARALLEL
if(I_AM_NODE_ZERO_P)
#endif
{
fprintf(fp_results, "
CA
Volume
Pressure
Yfb
Work\n");
}
counter ++;
}
end_CA=CURRENT_TIME*RPM*6.0+RP_Get_Real("dynamesh/in-cyn/crank-start-angle");
#endif
node_to_host_int_1(counter);
node_to_host_real_2(start_CA, end_CA);
#if !RP_HOST
/* Calculate volume weighted pressure and burnt fuel mass fraction */
pressure=0;
volume=0;
fmf=0;
mass=0;
i=0;
while(Zone_ID[i]>=0)
{
tc=Lookup_Thread(domain, Zone_ID[i]);
begin_c_loop_int(c, tc)
{
pressure += C_P(c,tc) * C_MYVOLUME(c,tc);
volume += C_MYVOLUME(c,tc);
if(sg_premixed)
{
fmf += C_PREMIXC(c,tc) * C_R(c,tc) * C_MYVOLUME(c,tc);
}
mass += C_R(c,tc) * C_MYVOLUME(c,tc);
}
end_c_loop_int(c, tc)
i++;
}
pressure = PRF_GRSUM1(pressure);
volume = PRF_GRSUM1(volume);
fmf = PRF_GRSUM1(fmf);
mass = PRF_GRSUM1(mass);
pressure /= volume;
fmf /= mass;
/* Calcualte work by piston.
work_one_dt=0;
i=0;
while(Piston_ID[i]>=0)
{
tf=Lookup_Thread(domain, Piston_ID[i]);
begin_f_loop(f, tf)
{
F_MYAREA(x, f, tf);
work_one_dt += CURRENT_TIMESTEP * F_P(f,tf) * NVD_DOT(x, WALL_F_GRID_VV(f, tf)[0],
WALL_F_GRID_VV(f, tf)[1], WALL_F_GRID_VV(f, tf)[2]);
}
end_f_loop(f, tf)
i++;
}
30
work_one_dt = PRF_GRSUM1(work_one_dt);
work += work_one_dt;
#endif
node_to_host_real_1(work);
#if !RP_HOST
/* Output volume, pressure, burnt fuel mass fraction */
#if PARALLEL
if(I_AM_NODE_ZERO_P)
#endif
{
fprintf(fp_results, "%8.2f %12.4e %12.4e %12.4e %12.4e\n", end_CA, volume, pressure, fmf, work);
fclose(fp_results);
}
#endif
}
DEFINE_RW_FILE(write_data, fp)
{
Message0("\nWriting user defined data to the data file...\n");
#if PARALLEL
#if RP_HOST
fprintf(fp,
fprintf(fp,
fprintf(fp,
fprintf(fp,
#endif
#else
fprintf(fp,
fprintf(fp,
fprintf(fp,
fprintf(fp,
#endif
}
"\n%d",
"\n%e",
"\n%e",
"\n%e",
counter);
work);
start_CA);
end_CA);
"\n%d",
"\n%e",
"\n%e",
"\n%e",
counter);
work);
start_CA);
end_CA);
DEFINE_RW_FILE(read_data, fp)
{
Message0("\nReading user defined data from the data file...\n");
#if PARALLEL
#if RP_HOST
fscanf(fp, "%d",
fscanf(fp, "%e",
fscanf(fp, "%e",
fscanf(fp, "%e",
#endif
#else
fscanf(fp,
fscanf(fp,
fscanf(fp,
fscanf(fp,
#endif
"%d",
"%e",
"%e",
"%e",
&counter);
&work);
&start_CA);
&end_CA);
&counter);
&work);
&start_CA);
&end_CA);
host_to_node_int_1(counter);
host_to_node_real_3(work,start_CA,end_CA);
}
31
/*********************************************************************************************
UDF to modify laminar flame speed for premixed combustion
In Fluent Zimont model, the laminar flame speed by default is a constant. Laminar
flame speed is a strong function of temperature, equivalence ratio. A udf is used
to modify that to be a more realistic value. The correlation is from Metghalchi
and Keck.
How to use the udf:
- Set up your premixed combustion case
- Define one user defined memory
- Modify the user input part of the udf
- Build the library
- Hook up the DEFINE_ADJUST function
- Use the laminar_flame_speed udf in the material panel to replace the default
constant value
Note:
- UDF works in 2d, 2d axisymmetry, and 3d. And it works in both serial and parallel
***********************************************************************************************/
# include "udf.h"
/********************************* User input starts *****************************************/
/* Ydil is the mass fraction of diluent, included to account for any EGR product. */
static real Ydil = 0;
/* Fuel type. Supported ones are methane, methanol, isooctane, RMFD_303_indolene. RMFD_303_indolene is a
reserch fuel (also called indolene), which has a controlled composition simulating typical gasolines.*/
enum
{
methane, methanol, propane, isooctane, RMFD_303_indolene, FLAG
}fuel = methane;
/* Fuel mass fraction (required for partially premixed model) */
real Fuel_Mass_Fraction = 0.05;
/********************************** User input ends ******************************************/
/* Fuel molecular weight for each fuel. Assuming RMFD_303_indolene has the same molecuar weight as
isooctance */
static real molecular_weight[]={16.043, 32.040, 44.096, 114.23, 114.23};
/* For one mole of fuel, how many moles of air needed for stoic combustion */
static real stoic_air_moles[]={2.0, 1.5, 5.0, 12.5, 12.5};
32
else
{
if( C_T(c,t) < T_u_min )
{
T_u_min = C_T(c,t);
}
}
}
end_c_loop_int (c,t)
T_u_min=PRF_GRLOW1(T_u_min);
PRF_GRSUM2(T_u, vol);
if(T_u>0. && vol>0.)
{
return T_u/vol;
}
else
{
return T_u_min;
}
}
/* Calculate unburnt gas temperature for laminar flame speed calculation */
DEFINE_ADJUST(my_T_u, domain)
{
#if !RP_HOST
Thread *t;
cell_t c;
real T_u;
thread_loop_c (t,domain)
{
T_u=f_T_u(t);
begin_c_loop_int(c, t)
{
C_UDMI(c, t, 0)= T_u;
}
end_c_loop_int(c, t)
}
#endif
}
33
if(sg_premixed)
{
fm = THREAD_PROP(t,PROP_premix_unburnt_fuel_mf,0);
}
else
{
fm = Fuel_Mass_Fraction; /* C_FMEAN(c,t) */
}
if(fm<1e-5)
fm=1e-5;
fi = (4.76*stoic_air_moles[fuel]*29/molecular_weight[fuel])/(1.0/fm-1);
SL_ref = Bm[fuel]+B2[fuel]*pow(fi-FIm[fuel],2);
gama = 2.18-0.8*(fi-1);
beta = -0.16+0.22*(fi-1);
T_u = C_UDMI(c,t,0);
SL = SL_ref*pow(T_u/298, gama)*pow((C_P(c, t)+RP_Get_Real("operating-pressure"))/
1.013e5, beta)*(1-2.1*Ydil);
if (SL>0)
return SL;
else
return 0;
}
34
Further Improvement
UDF will automatically create the file work.txt. This file has combustion chamber pressure
and burnt fuel mass fraction as a function of Crank Angle (CA). These can be used to
generate plots as shown (see Figures 14, 15, and 16).
35
Summary
This tutorial demonstrated the use of premixed combustion model using ANSYS FLUENT.
36