7/30/2019 User Defined Programming
1/33
1
ME469B/6/GI 1
User Programming
What are User Defined Functions
Introduction to C
Set-Up C User Routines in Fluent
Implementing a Custom Turbulence Model
Programming in other CFD Commercial Codes
Acknowledgement: this handout is partially based on Fluent training material
ME469B/6/GI 2
Introduction to UDF Programming
Why programming in commercial codes?
The codes are general-purpose but cannot anticipate all needs
New (physical) models can be developed in a user-friendly environment
Large number of problems (test-cases) can be addressed with the same implementation
What is a the User Defined Function (UDF)?
C (Fluent) orFORTRAN (StarCD, CFX) routines programmed by the user linked to
the solver to perform certain operations:
initialization
special boundary condition (i.e. space or time dependent)
material properties
source terms reaction rates
postprocessing and reporting
debugging
.
7/30/2019 User Defined Programming
2/33
2
ME469B/6/GI 3
A Simple UDF Example
Specify a Parabolic Velocity Profile at the Inlet
Goal: The UDF (inlet_parab) set the values of the x-velocity component at the cell faces
of the inlet boundary zone
1) Determine the cell-faces belonging to the inlet zone
2) Loop on all those faces3) Determine the coordinate of the face centroid
4) Specify the x-velocity component
Inlet
zone
ME469B/6/GI 4
Parabolic Velocity Profile:
A Simple UDF Example
function inlet_parab
Definitions
Loop over all the inlet cell faces
Evaluate the face centroid coordinates
The function return the velocity
7/30/2019 User Defined Programming
3/33
3
ME469B/6/GI 5
A Simple UDF Example
Compile/interpret the UDF:
Define User Defined
Attach the profile to the inlet zone
Define Boundary Condition
Equivalent to attach the profile from a separate simulation
ME469B/6/GI 6
Solve the equations
Solve Iterate
Final Result
A Simple UDF Example
7/30/2019 User Defined Programming
4/33
4
ME469B/6/GI 7
C Programming
Typical C function:
ME469B/6/GI 8
C vs. FORTRAN
7/30/2019 User Defined Programming
5/33
5
ME469B/6/GI 9
Basic Programming Rules
Statements MUST end with a semicolon ;
Comments are placed anywhere in the program between /* */
Statements are grouped by curly brackets { }
Variables defined within the body functions are local
Variables defined outside the body functions are global and can be used by
all the functions that follows
Variables MUST be ALWAYS defined explicitly
Integer/real/double functions have to return a integer/real/double value
C is case sensitive!
ME469B/6/GI 10
Basic Statements
Arithmetic expressions in C look like FORTRAN
a = y + (i-b)/4;
Functions which return values can be used in assignment
a = mycompute(y,i,b);
Functions which do not return values can be called directly
mystuff(a,y,i,b);
Mathematical and various other default functions are available
a = pow(b,2); /* pow(x,y) returns x raised to y */
7/30/2019 User Defined Programming
6/33
6
ME469B/6/GI 11
Data Types and Arrays
Arrays of variables are defined using the notation
Note the brackets are square [] not round ()!!
Note that the arrays ALWAYS start from 0
Standard C types are: Integer, Real, Double, Char
C allows to define additional types
typedef struct list{int id, float x[3], int id_next};
int a[10]; /*define an array of ten integers */
ME469B/6/GI 12
Pointers
A pointer is a variable which contain the address of another variable
Pointers are defined as:
int *a_p; /* pointer to an integer variable */int a; /* an integer variable */
Set-up a pointer
a = 1;
a_p = &a; /* &a return the address of variable a */
*a_p returns the content of the address pointed by a_p
7/30/2019 User Defined Programming
7/33
7
ME469B/6/GI 13
Operators
Arithmetic Operators Logical Operators
ME469B/6/GI 14
Conditional Statements
if and if-else Example
7/30/2019 User Defined Programming
8/33
8
ME469B/6/GI 15
Loop Procedure
for loops Example
ME469B/6/GI 16
C Preprocessor
It handles Macro substitutions
#define A B#define my_f(x,y) x+y*3-5
The preprocessor replaces A with B
It also handles file inclusion
#include udf.h
#include math.h
The files to be included MUST reside in the currect directory
7/30/2019 User Defined Programming
9/33
9
ME469B/6/GI 17
Programming in C
Of course much more than just this.
Additional information are:
http://www.cs.cf.ac.uk/Dave/C/CE.html
Plenty of books:
The C Programming Language, Kernighan & Ritchie, 1988
ME469B/6/GI 18
UDF in Commercial CFD Codes
Commercial CFD codes allow the development of User Defined Functions
for various applications. Anyway, the core of the software is closed.
UDF must be compiled and linked to the main code
Most codes provide macros and additional tools to facilitate the use of UDFs
In Fluent there are two options:
Interpreted
The code is executed on a line-by-line basis at run time
+ does not need a separate compiler (completely automatic)
- slows down the execution and uses more memory- somewhat limited in scope
Compiled
A library of UDF is compiled and linked to the main code
Overcomes all the disadvantages reported above
7/30/2019 User Defined Programming
10/33
10
ME469B/6/GI 19
Interpret the UDFs
Define User Defined Interpreted
Default stack size might be too small for large arrays!
Display of code translation in assembly
(and eventual compiling errors)
ME469B/6/GI 20
Compile the UDFs
Define User Defined Compiled
The library MUST be precompiled in a directory tree
7/30/2019 User Defined Programming
11/33
11
ME469B/6/GI 21
Directory tree for compiled UDFs
my_library
Makefile src lnx86
makefile my_udf.c
2d 3d
makefile my_udf.c libudf.so
makefile my_udf.c libudf.so
Machine dependent
irix6r10
ultra
hp700
ME469B/6/GI 22
Makefiles for UDFs
In the directory
/usr/local/Fluent.Inc/fluent6/src
There are two files
Makefile.udf to be copied in the directory my_librarymakefile.udf to be copied in the directory my_library/src
The first one does not require modifications.
In the second one two macros MUST be modified
SOURCE = my_udf.c
FLUENT_INC = /usr/local/Fluent.Inc
7/30/2019 User Defined Programming
12/33
12
ME469B/6/GI 23
UDFs in FLUENT
Boundary Conditions
Initial Conditions
Adjust Function
Source Terms
Material Properties
Execute on Demand
User Defined Scalars
User Defined Memory
Pointers to threads
Geometry Macros
Cell and Face Variables
Arithmetic and Trigonometric Functions
Available MACROS
Programming
Tools
ME469B/6/GI 24
Boundary Conditions
The inlet profile specification is based on the macro DEFINE_PROFILE
DEFINE_PROFILE can be used for wall boundary conditions as well
to impose temperature, velocity, shear stress, etc.
It is possible to specify a constant value, a position-dependent or
time-dependent values and to link the values on the boundary to the values
in the internal cells
Note that the BCs are applied to the faces of the cells (face centroids)
x
x
x
BC
Internal
Values
7/30/2019 User Defined Programming
13/33
13
ME469B/6/GI 25
Initial Conditions
The initial condition specification can be performed using the macro DEFINE_INIT
Space-dependent conditions might be imposed
The routine is executed once at the beginning of the solution process
It is attached in the UDFs hooks
Define User Defined Function Hooks
ME469B/6/GI 26
Initial Conditions
Note that the difference between the DEFINE_PROFILE and DEFINE_INIT
is that the former performs a loop on the face-centroids belonging to a certain
zone whereas the latter loops on the cell-centroids
Example:
7/30/2019 User Defined Programming
14/33
14
ME469B/6/GI 27
Adjust Function
Similar to the DEFINE_INIT but it is executed every iteration: DEFINE_ADJUST
Can be used for postprocessing, clipping, etc.
It is attached in the UDFs hooks
Define User Defined Function Hooks
ME469B/6/GI 28
Source Terms
To add a source term in the equations: DEFINE_SOURCE
Can be used for:
Continuity
Momentum (component by component)
Turbulent quantities
Energy
It is different from the previous macros because it works on a cell-by-cell basis
(no need to perform loops!)
7/30/2019 User Defined Programming
15/33
15
ME469B/6/GI 29
Define Boundary Conditions Fluid
Source Terms
Activate source terms
Attach the UDF
ME469B/6/GI 30
Source Terms
In FLUENT the source terms are written in the form
S(f) = A + B f
wheref is the dependent variableA is treated explicitly and B f is treated implicitly
In the DEFINE_SOURCE both terms A and B have to be specified
7/30/2019 User Defined Programming
16/33
16
ME469B/6/GI 31
Material Properties
To define the properties of the materials : DEFINE_PROPERTIES
Can be used for:
Viscosity
Density
Thermal Conductivity
.
As for the source terms works on a cell-by-cell basis
ME469B/6/GI 32
Material Properties
Define Material Property
All the available UDFs
Are shown in the menu
7/30/2019 User Defined Programming
17/33
17
ME469B/6/GI 33
Execute on Demand
Define User Defined Execute on Demand
To perform operations instantaneously : EXECUTE_ON_DEMAND
It is executed when activated by the user
Can be used for:
Debugging
Postprocessing
.
ME469B/6/GI 34
User Defined Scalar
In addition to the Continuity and Momentum Equations (and Energy)
generic transport equations can be solved (up to 50!)
To include scalars in the calculations
1) Define the number of scalars
Define User Defined User Defined Scalars
2) Define the diffusion and source terms in the generic equation
7/30/2019 User Defined Programming
18/33
18
ME469B/6/GI 35
User Defined Scalar
Define Material Property
When UDS are defined in the material property panel the diffusivity of the
scalars MUST be defined
Note that the default diffusivity for the scalars is constant and equal to 1!
ME469B/6/GI 36
User Defined Scalar
Boundary conditions for the scalars can be defined as
Constant Value
Constant Gradient
User Defined
Define Boundary Conditions Wall
7/30/2019 User Defined Programming
19/33
19
ME469B/6/GI 37
User Defined Scalar
The Source terms for the scalars are set using the DEFINE_SOURCE macro
Introduced before
The scalar equations can be further customized
1) Convective terms can be modified using the macro
DEFINE_UDS_FLUX
2) Unsteady term can be modified using the macro
DEFINE_UDS_UNSTEADY
ME469B/6/GI 38
User Defined Memory
The User Defined Scalars are used to solve additional equations eventually
coupled to the mean flow equations
Sometimes it is useful to define temporary field variables to store and retrieve
values not directly available
UDM are defined:
More efficient storage compared to User Defined Scalars
Define User Defined User Defined Memory
7/30/2019 User Defined Programming
20/33
20
ME469B/6/GI 39
I/O in UDF
User Defined Scalars and User Defined Memory are AUTOMATICALLY
Stored in the Fluent Data files
Additional I/O (from and to the Fluent Case and Data files) can be
Accomplished using the macro DEFINE_RW_FILE
Define User Defined Function Hooks
ME469B/6/GI 40
Detailed Programming
The macros introduced before are interpreted/compiled and attached to
the various Fluent panels
The detailed programming is based on additional macros that allow to
loop on cells to retrieve field variables, etc.
Loop Macros
Geometry Macros
Field Variable Macros
Control Macros
Arithmetic and Trigonometric Macros
Before looking at the Macros, the Fluent Data structure in introduced
7/30/2019 User Defined Programming
21/33
21
ME469B/6/GI 41
Data Structure
It is based on a hierarchy of structures
Threads (zones) are collection of cells or faces
Domain is a collections of threads
Domain
Thread
Cell
Thread
Face
Thread
Face
ME469B/6/GI 42
Every zone is associated to a single ID (available in the boundary conditions menu)
Threads
Given the ID of a thread the pointer can be retrieved as:
Thread *tf = Lookup_Thread(domain, ID);
Given the thread pointer the ID of the zone can be retrieved as:
ID = THREAD_ID(thread);
zone
ID
7/30/2019 User Defined Programming
22/33
22
ME469B/6/GI 43
Loop Macros
ME469B/6/GI 44
cell0cell1
x
face
Cell-face connectivity
When looping on faces the surrounding cells can be accessed using the macros:
cell0_thread = F_C0_THREAD(face,thread)
cell1_thread = F_C1_THREAD(face,thread)
cell0_id = F_C0(face,thread)cell1_id = F_C1(face,thread)
When looping on cells adjacent faces and cells can be accessed using the macros:
for(nf=0;nf
7/30/2019 User Defined Programming
23/33
23
ME469B/6/GI 45
Geometry Macros
Many more available; refer to the FLUENT UDF Manual
ME469B/6/GI 46
Field Variables Macros
7/30/2019 User Defined Programming
24/33
24
ME469B/6/GI 47
Field Variables Macros
Many more available; refer to the FLUENT UDF Manual
ME469B/6/GI 48
Control Macros
Many more available; refer to the FLUENT UDF Manual
7/30/2019 User Defined Programming
25/33
25
ME469B/6/GI 49
An example of User Defined Programming
Development of a custom turbulence model can be accomplished using the
UDFs.
k-e model with damping functions formulation:
Low-Re k-e model
Transport
Equations
ME469B/6/GI 50
Low-Re k-e model
An example of User Defined Programming
Eddy Viscosity
Damping functions
Turbulent Reynolds number definitions
Wall boundary conditions
y
P =Turbulent Kinetic Energy Production
S = Strain Rate Magnitude
7/30/2019 User Defined Programming
26/33
26
ME469B/6/GI 51
Required UDF Routines
Source Terms DEFINE_SOURCE(k_source, thread, eqn)
DEFINE_SOURCE(d_source, thread, eqn)
Diffusivity DEFINE_PROPERTY(ke_diffusivity, domain)
Boundary Condition DEFINE_PROFILE(wall_d_bc, domain)
Adjust Routine DEFINE_ADJUST(turb_adjust, domain)
ME469B/6/GI 52
Required field variables
Density C_R(cell,thread)
Molecular viscosity C_MU(cell,thread)
Eddy viscosity C_MU_T(cell,thread)
Strain Rate Magnitude Strain_rate(cell,thread)
Wall distance C_WALL_DIST(cell,thread)
7/30/2019 User Defined Programming
27/33
27
ME469B/6/GI 53
#include "udf.h"
/* Turbulence model constants */#define C_MU 0.09#define SIG_TKE 1.0#define SIG_TDR 1.3#define C1_D 1.44#define C2_D 1.92
/* User-defined scalars */enum{
TKE,TDR,N_REQUIRED_UDS
};
UDF Header
Required: includes all Fluent macros
Constant definitions (global)
Assign a number to each scalar
ME469B/6/GI 54
/* Reynolds number definitions */real Re_y(cell_t c, Thread *t){ return C_R(c,t)*sqrt(C_UDSI(c,t,TKE))*C_WALL_DIST(c,t)/C_MU_L(c,t);}
real Re_t(cell_t c, Thread *t){ return C_R(c,t)*SQR(C_UDSI(c,t,TKE))/C_MU_L(c,t)/C_UDSI(c,t,TDR);}
/* Damping Functions */real f_mu(cell_t c, Thread *t){ return tanh(0.008*Re_y(c,t))*(1.+4/pow(Re_t(c,t),0.75));}
real f_1(cell_t c, Thread *t){ return 1.;}
real f_2(cell_t c, Thread *t){ return (1.-2/9*exp(-Re_t(c,t)*Re_t(c,t)/36))*(1.-exp(-Re_y(c,t)/12));}
Damping Functions
These are defined on a cell-by-cell basis
7/30/2019 User Defined Programming
28/33
28
ME469B/6/GI 55
Source Term Routines
DEFINE_SOURCE(k_source, c, t, dS, eqn){
real G_k;
G_k = C_MU_T(c,t)*SQR(Strainrate_Mag(c,t));
dS[eqn] = -2.*C_R(c,t)*C_R(c,t)*C_MU*f_mu(c,t)*C_UDSI(c,t,TKE)/C_MU_T(c,t);
return G_k - C_R(c,t)*C_R(c,t)*C_MU*f_mu(c,t)*SQR(C_UDSI(c,t,TKE))/C_MU_T(c,t);}
The production term in the k equation is:
e is obtained from the definition of the eddy viscosity to increase the coupling
between the equations and to define an implicit term
ME469B/6/GI 56
Source Term Routines
DEFINE_SOURCE(d_source, c, t, dS, eqn){
real G_k;
G_k = C_MU_T(c,t)*SQR(Strainrate_Mag(c,t));
dS[eqn] = C1_D*f_1(c,t)*G_k/C_UDSI(c,t,TKE)- 2.*C2_D*f_2(c,t)*C_R(c,t)*C_UDSI(c,t,TDR)/C_UDSI(c,t,TKE);
return C1_D*f_1(c,t)*G_k*C_UDSI(c,t,TDR)/C_UDSI(c,t,TKE)
- C2_D*f_2(c,t)*C_R(c,t)*SQR(C_UDSI(c,t,TDR))/C_UDSI(c,t,TKE);}
The production term in the e equation is:
It contains already both k and e. No need for manipulations!
7/30/2019 User Defined Programming
29/33
29
ME469B/6/GI 57
Diffusivity
DEFINE_DIFFUSIVITY(ke_diffusivity, c, t, eqn){
real diff;real mu = C_MU_L(c,t);real mu_t = C_R(c,t)*C_MU*f_mu(c,t)*SQR(C_UDSI(c,t,TKE))/C_UDSI(c,t,TDR);
switch (eqn)
{case TKE:
diff = mu_t/SIG_TKE + mu;break;
case TDR:diff = mu_t/SIG_TDR + mu;break;
default:
diff = mu_t + mu;}return diff;
}
The diffusion terms in the scalar equations are set-up together
But each equation can have
a different value
ME469B/6/GI 58
Eddy Viscosity
DEFINE_ADJUST(turb_adjust, domain){
Thread *t;cell_t c;
/* Set the turbulent viscosity */thread_loop_c (t, domain)if (FLUID_THREAD_P(t)){begin_c_loop(c,t){
C_MU_T(c,t) = C_R(c,t)*C_MU*f_mu(c,t)*SQR(C_UDSI(c,t,TKE))/C_UDSI(c,t,TDR);}end_c_loop(c,t)
}}
The eddy viscosity is set in the adjust routine (called at the beginning of each
Iteration) and it is used in the mean flow and in the scalar equations
7/30/2019 User Defined Programming
30/33
30
ME469B/6/GI 59
Wall Boundary Conditions
DEFINE_PROFILE(wall_d_bc, t, position){
face_t f;cell_t c0;Thread *t0 = t->t0; /* t0 is cell thread */real xw[ND_ND], xc[ND_ND], dx[ND_ND], rootk, dy, drootkdy;
begin_f_loop(f,t){c0 = F_C0(f,t);rootk = sqrt(MAX(C_UDSI(c0,t0,TKE), 0.));F_CENTROID(xw,f,t);C_CENTROID(xc,c0,t0);NV_VV(dx, =, xc, -, xw);
dy = ND_MAG(dx[0], dx[1], dx[2]);drootkdy = rootk/dy;F_PROFILE(f,t,position) = 2.*C_MU_L(c0,t0)/C_R(c0,t0)*drootkdy*drootkdy;
}end_f_loop(f,t)
}
Only the boundary condition fore is complicated because it requires the value of thederivative of k (the square root of k)
The derivative is rootk/dy
rootk is the sqrt of k in
the adjacent cell center
dy is the distance between
cell and face center
ME469B/6/GI 60
Set-Up the Problem
Set-Up a case using the standard k-e
Define two scalars (TKE, TDR)
Compile and Attach the UDFs
Deactivate the Equations for k and e
Initialize and solve the RANS + TKE and TDR
7/30/2019 User Defined Programming
31/33
31
ME469B/6/GI 61
Attach the UDF
Source terms
Boundary conditions
ME469B/6/GI 62
Open UDF Library
Output in the text window
Are the functions available
After compiling the library
It can be opened in Fluent
7/30/2019 User Defined Programming
32/33
32
ME469B/6/GI 63
Perform the Simulation
The convergence is for the mean flow + the two scalars(turbulent quantities deactivated!)
For postprocessing purposes the UDS have to be used instead of turbulent quantities
ME469B/6/GI 64
Additional Information
Many additional macros are available to implement different physical models
combustion models
particles-based models
.
It is formally possible to develop additional numerical methods
flux discretizations
variable reconstruction and clipping
.
Information are available in the FLUENT UDF manual (class web site)
7/30/2019 User Defined Programming
33/33
ME469B/6/GI 65
UDF in other commercial CFD CodesCFX
CFX (v4) is a structured code; the data structure is much simpler because the
field variables are accessed directly. It uses 1D arrays where the quantities are
stored in succession
CFX UDFs are written in FORTRAN
For example:
U(I,J,K)U(IJK) where IJK = (K-1)*NI*NJ+(J-1)*NI
There are no macros, but examples of subroutines to perform the customization
USRBCUSRSRCUSRDIF.
ME469B/6/GI 66
UDF in other commercial CFD CodesStar-CD
StarCD is an unstructured code similar to Fluent in term of data organization
But similar to CFX for the organization of the UDF.
StarCD has threads (as Fluent) and the UDF work normally on a cell-by-cell
basis
StarCD UDFs are written in FORTRAN
There are no macros, but examples of subroutines to perform the customization
BCDEFW
SORSCADIFFUS
.
Top Related